/*
	Combat Team II - game engine
	Made by Ismo Horppu on 1996 - 1997
*/

#include <stdio.h>
#include <mem.h>
#include <go32.h>
#include <dos.h>
#include <stdlib.h>
#include <dpmi.h>
#include <conio.h>
#include <math.h>

#include "types.h"
#include "ct2egen.h"
#include "ct2graph.h"
#include "ct2pal.h"
#include "m320x200.h"
#include "mouse.h"
#include "ct2egrx.h"
#include "line3d.h"
#include "kb.h"
#include "okb.h"
#include "font.h"
#include "okb.h"
#include "rnd.h"
#include "timer.h"
#include "sb_defs.h"
#include "sb_digi.h"
#include "eng.h"
#include "button.h"
#include "aigen.h"
#include "ecadd.h"
#include "window.h"

/*
	returns wound type
*/
long ReturnWoundType (long HP, long OHP)
{
	long percent;

	if (HP < 0){
		HP = -HP;
	}
	
	else{
		HP += OHP;
	}

	OHP *= 2;
	if (HP > OHP) return -1;	// bad
	if (OHP == 0) return -1;	// bad
		
	percent = (HP * 100) / OHP;
	percent = 100 - percent;
	
	if (percent == 0){
		return 0;	// no wound
	}
	
	if (percent > 0 && percent < 21){
		return 1;	// slight wound
	}
	
	if (percent > 20 && percent < 51){
		return 2;	// serious wound
	}

	return 3;		// critical wound !
}

char AbovePercent (long percent, long HP, long OHP)
{
	if (HP < 0){
		HP = -HP;
	}
	
	else{
		HP += OHP;
	}
	
	OHP *= 2;
	if (HP > OHP) return 0;	// bad
	if (OHP == 0) return 0;	// bad
	if ((HP * 100) / OHP >= percent) return 1;
	return 0;
}

/*
	kills last soldiers
*/
void KillSoldiers (int player, int scnt)
{
	int cnt, xc, hc;
	
	cnt = player;
	xc = 8 - scnt;
	
	while (1){
		for (hc = 0; hc < 7; hc++){
			SI[player * 8 + xc].HP[hc] = -666;
		}
		
		//health[cnt][xc] = 0;
		PlayerStartX[xc][cnt] = 0xFF;
		PlayerStartY[xc][cnt] = 0xFF;
		PlayerStartZ[xc][cnt] = 0xFF;
		xc++;
		if (xc > 7) break;
	}
}

/*
	checks if there's any alive soldiers in the team
*/
int CheckAlive (void)
{
	int c, dc;
	char dead;
		
	for (c = 0; c < MAX_START; c++){
		dead = 0;
				
		for (dc = 0; dc < 7; dc++){
			if (SI[player * 8 + c].HP[dc] <= -SI[player * 8 + c].OHP[dc]){
				dead = 1;
			}
		}
		
		if (!dead){
			if (Object[PlayerStartX[c][player]]
				[PlayerStartY[c][player]]
				[PlayerStartZ[c][player]] == 254){
			}
			
			else{
				counter_soldier = c;
				return 1;
			}
		}
	}
	
	return -1;
}

/*
	check is the soldier alive
*/
int CheckAliveSoldier (void)
{
	int xc;
	
	for (xc = 0; xc < 7; xc++){
		if (SI[player * 8 + soldier].HP[xc] <= -SI[player * 8 + soldier].OHP[xc]){
			return -1;
		}
	}

	return 1;
}

/*
	finds prober player
*/
void FindProberPlayer (void)
{
	int new_player, new_soldier;
	int select_soldier;
	int okay = 0;
	
	while (1){
		new_player = player + 1;
		if (new_player >= default_players) new_player = 0;
		player = new_player;
		okay = CheckAlive ();
		select_soldier = counter_soldier;
		if (okay == 1) break;
	}
	
	player = new_player;
	soldier = select_soldier;
}

/*
	calculate moving points
*/
void CalcAPs (void)
{
	float ftemp;
	int c, xc;
	signed long temp, temp2, aps;
		
	for (c = 0; c < TI[player].soldiers; c++){
		aps = (signed long) SI[player * 8 + c].Strength;
		aps += (signed long) SI[player * 8 + c].Constitution;
		aps /= 2;
		aps += 35;

		for (xc = 0; xc < 7; xc++){
			if (SI[player * 8 + c].OHP[xc] < 1){
				printf ("Bad OHP%d at player's %ld soldier %ld\n",
				xc + 1, player + 1, c + 1);
			}
			
			else{
				// positive hit points ?
				if (SI[player * 8 + c].HP[xc] >= 0){
					temp = (signed long) SI[player * 8 + c].HP[xc];
					temp += (signed long) SI[player * 8 + c].OHP[xc];
				}
				
				// nope negative (neg hp)
				else{
					temp = (signed long) SI[player * 8 + c].HP[xc];
					temp = -temp;
				}
	
				temp2 = (signed long) SI[player * 8 + c].OHP[xc];
				temp2 *= 2;
				aps *= temp;
				aps /= temp2;
			}
		}
		
		ftemp = pow (0.995, (float) SI[player * 8 + c].Load);
		ftemp *= (float) aps;
		aps = (int) ftemp;
		
		// now TAPs = APs
		APs[player][c] = (int) aps;
		
		// you can always atleast turn your head !!! :)
		if (APs[player][c] < 1) APs[player][c] = 1;
	}	
}

/*
	Gets original APs (at start of turn)
*/
long GetOriginalAPs (int xplayer, int zsoldier)
{
	int c, xc;
	signed long temp, temp2, aps;
		
	c = zsoldier;
	aps = (signed long) SI[player * 8 + c].Strength;
	aps += (signed long) SI[player * 8 + c].Constitution;
	aps /= 2;
	aps += 35;

	for (xc = 0; xc < 7; xc++){
		if (SI[player * 8 + c].OHP[xc] < 1){
			printf ("Bad OHP%d at player's %ld soldier %ld\n",
			xc + 1, player + 1, c + 1);
		}
			
		else{
			// positive hit points ?
			if (SI[player * 8 + c].HP[xc] >= 0){
				temp = (signed long) SI[player * 8 + c].HP[xc];
				temp += (signed long) SI[player * 8 + c].OHP[xc];
			}
			
			// nope negative (neg hp)
			else{
				temp = (signed long) SI[player * 8 + c].HP[xc];
				temp = -temp;
			}

			temp2 = (signed long) SI[player * 8 + c].OHP[xc];
			temp2 *= 2;
			aps *= temp;
			aps /= temp2;
		}
	}
		
	if (aps < 1) aps = 1;
	return aps;
}

/*
	save moving points
*/
void SaveAPs (int xplayer, int zsoldier, int newAPs)
{
	APs[xplayer][zsoldier] = newAPs;
}

/*
	get moving points
*/
int GetAPs (int xplayer, int zsoldier)
{
	return APs[xplayer][zsoldier];
}

/*
	check if there's a soldier in 
	specified location (returns soldier's number)
	you can walk over dead soldier(s) !!!
*/
int Soldier (long x, long y, long z)
{
	register long c;
	register int xc;
	int alive, ac;
	
	if (x == startX && y == startY && z == startZ) return -1;

	for (c = 0; c < default_players; c++){
		for (xc = 0; xc < MAX_START; xc++){
			
			alive = 1;
			
			for (ac = 0; ac < 7; ac++){
				if (SI[c * 8 + xc].HP[ac] <= 
				-SI[c * 8 + xc].OHP[ac]) alive = 0;
			}
			
			if (x == PlayerStartX[xc][c] &&
			y == PlayerStartY[xc][c] &&
			z == PlayerStartZ[xc][c] && 
			Object[x][y][z] != 254 &&
			alive == 1){
				return 0;
			}
		}
	}

	return -1;
}

/*
	check if move to specified
	direction is valid
	(direction isn't blocked)
*/
int CheckMove (int x, int y, int z)
{
	BYTE block;
	int stat;
	
	// there must not be soldier
	stat = Soldier (x, y, z);

	if (stat == 0){
		return 3;
	}

	block = Map[x][y][z];

	/*
		auto door open (better code coming some day...)
	*/
	if (block >= 30 && block <= 33){
		if (moving >= DOOR_COST){
			Map[x][y][z] = 0;
			moving -= DOOR_COST;
			return 1;
		}
		
		else{
			return 0;
		}
	}

	if (BlockFlags[block] == SWable){
		return 1;
	}

	if (BlockFlags[block] == Seeable){
		return 0;
	}

	if (BlockFlags[block] == Walkable){
		return 1;
	}

	if (BlockFlags[block] == RWable){
		return 2;
	}

	return 0;
}

/*
	doesn't have a auto door open code,
	ideal for bullet fly trace...
	returns 0 for not blocked, -1 for blocked...
*/
int CheckMove2 (int x, int y, int z)
{
	BYTE block;
	int stat;
	
	// there must not be soldier
	stat = Soldier (x, y, z);

	if (stat == 0){
		return -1;
	}

	block = Map[x][y][z];

	/*
		auto door open (better code coming some day...)
	*/
	if (block >= 30 && block <= 33){
			return -1;
	}

	if (BlockFlags[block] == SWable){
		return 0;
	}

	if (BlockFlags[block] == Seeable){
		return -1;
	}

	if (BlockFlags[block] == Walkable){
		return 0;
	}

	if (BlockFlags[block] == RWable){
		return -1;
	}

	return 0;
}
/*
	mouse stuff (disabled)
*/
int MousePointerDirection (void)
{
	int stat;

	stat = InArea (0, 0, 159, 99);

	if (stat == 1){
		return 0;
	}

	stat = InArea (160, 0, 319, 99);
	if (stat == 1){
		return 1;
	}

	stat = InArea (160, 100, 319, 199);
	if (stat == 1){
		return 2;
	}

	stat = InArea (0, 100, 159, 199);
	if (stat == 1){
		return 3;
	}
}

/*
	mouse stuff (disabled)
*/
int UpdateEvent (int esx, int esy)
{
	int nesx, nesy;

	if (old_event != -1){
		nesx = esx + 3;
		nesy = esy + (cur_event * 9) + 13;
		Box (nesx - 1, nesy - 1, 122 + 2, 8 + 2, 0);
	}

	if (cur_event != -1){
		nesx = esx + 3;
		nesy = esy + (cur_event * 9) + 13;
		Box (nesx - 1, nesy - 1, 122 + 2, 8 + 2, 15);
	}
}

/*
	mouse stuff (disabled)
*/
int CheckEvent (int esx, int esy)
{
	int c;
	int stat;

	esx += 3;
	esy += 13;


	for (c = 0; c < 7; c++){
		stat = InArea (esx, esy + c * 9, 122, 8);

		if (stat == 1){
			old_event = cur_event;
			cur_event = c;
			return 0;
		}
	}

	return -1;
}

/*
	horizontal line
*/
int hline (int sx, int sy, int w, BYTE color)
{
	int c;

	for (c = sx; c < sx + w; c++){
		if (c >= minx && c <= maxx && sy >= miny && sy <= maxy){
			PutPixel (c, sy, color, VB);
		}
	}
}

/*
	vertical line
*/
int vline (int sx, int sy, int h, BYTE color)
{
	int c;

	for (c = sy; c < sy + h; c++){
		if (c >= miny && c <= maxy && sx >= minx && sx <= maxx){
			PutPixel (sx, c, color, VB);
		}
	}
}

/*
	draw box
*/
int Box (int sx, int sy, int w, int h, BYTE color)
{
	hline (sx, sy, w, color);
	hline (sx, sy + h - 1, w, color);
	vline (sx, sy, h, color);
	vline (sx + w - 1, sy, h, color);
}

/*
	check if mouse pointer in specified area
*/
int InArea (int sx, int sy, int w, int h)
{
	if (mousex >= sx && mousex <= sx + w - 1 &&
	mousey >= sy && mousey <= sy + h - 1){
		return 1;
	}

	return 0;
}

// current soldier
void UpdateMapCoordinates (void)
{
	mx = manX - 10;
	my = manY - 10;
	if (mx < 0) mx = 0;
	if (my < 0) my = 0;
	if (mx > 63 - 16) mx = 63 - 16;
	if (my > 63 - 16) my = 63 - 16;
	curz = manZ;

	if (viewmode == 0){
		endz = curz + 1;
	}

	else{
		endz = Zlevels;
	}
}

// any soldier
void UpdateAnyMapCoordinates (int x, int y, int z)
{
	mx = x - 10;
	my = y - 10;
	if (mx < 0) mx = 0;
	if (my < 0) my = 0;
	if (mx > 63 - 16) mx = 63 - 16;
	if (my > 63 - 16) my = 63 - 16;
	curz = z;

	if (viewmode == 0){
		endz = curz + 1;
	}

	else{
		endz = Zlevels;
	}
}

/*
	save soldiers coordinates
*/
void BackCoordinates (int xplayer, int zsoldier)
{
	PlayerStartX[zsoldier][xplayer] = manX;
	PlayerStartY[zsoldier][xplayer] = manY;
	PlayerStartZ[zsoldier][xplayer] = manZ;
}

/*
	select current soldier
*/
void SelectSoldier (int xplayer, int zsoldier)
{
	int alive, ac;
	
	if (Object[PlayerStartX[zsoldier][xplayer]]
	[PlayerStartY[zsoldier][xplayer]]
	[PlayerStartZ[zsoldier][xplayer]] == 254){
		sdead = 1;
	}
	
	else sdead = 0;
	
	for (ac = 0; ac < 7; ac++){
		if (SI[xplayer * 8 + zsoldier].HP[ac] <= 
		-SI[xplayer * 8 + zsoldier].OHP[ac]){
			sdead = 1;
		}
	}
	
	manX = PlayerStartX[zsoldier][xplayer];
	manY = PlayerStartY[zsoldier][xplayer];
	manZ = PlayerStartZ[zsoldier][xplayer];
	startX = manX;
	startY = manY;
	startZ = manZ;
}

/*
	calculates how many alive soldiers
	in the current team
*/
int calc_alive (void)
{
	int c;
	int ret = 0;
	int s;
	int os;

	os = soldier;
			
	for (c = 0; c < MAX_START; c++){
		soldier = c;
		s = CheckAliveSoldier ();
		if (s != -1) ret++;
	}
	
	soldier = os;
	return ret;
}

/*	
	returns next alive player (or current player -> end turn)
*/
int NextAlivePlayer (void)
{
	int c, cp;
	int stat;
	
	c = player;
	cp = player + 1;
	if (cp >= default_players) cp = 0;
	
	while (1){
		player = cp;
		
		if (c == player){
			return player;
		}
		
		stat = CheckAlive ();

		if (stat == 1){
			player = c;
			return cp;
		}
		
		else{
			cp++;
			if (cp >= default_players) cp = 0;
		}
	}
}

int AliveSoldier (void)
{
	int c;
	int alive, ac;
	
	for (c = 0; c < TI[player].soldiers; c++){
		alive = 1;
		
		for (ac = 0; ac < 7; ac++){
			if (SI[player * 8 + c].HP[ac] <= 
			-SI[player * 8 + c].OHP[ac]) alive = 0;
		}
		
		if (alive) return c;
	}

	return 0;
}

int CheckAliveCPUSoldier (void)
{
	int ac;
	
	for (ac = 0; ac < 7; ac++){
		if (SI[player * 8 + soldier].HP[ac] <= 
		-SI[player * 8 + soldier].OHP[ac]) return 0;
	}
	
	return 1;
}

/*
	Computer player -> Artificial Intelligency Turn
	
	currently implemented:
	* patrolling
	* firing (spotting)
*/
void Play_AI_Turn (void)
{
	int hit_times = 0;
	int fire_times = 0;
	int current_soldier = 0;
	int CPU_APs;	// will be fixed to moving soon (always door opening)
	int soldier_status;
	int CPU_aframe, CPU_spr_frame;
	int CPU_sprdir, osd;
	int mode;
	int distance, blocked;
	int block, dir;
	int target_soldier, r;
	int index, hitteam, hitsoldier;
	int aim_bonus, temp_aim;
	int spotman, checktimes;
	// new code here...
	long Hit, HitCheck;
	float HitFloat, HitFloat2, HitRange, HitX;
	int HitPR, HitChance, HitBP;
	long HitDamage;
	int StereoVolume;
	long MalFunction;
	
	CalcAPs ();
	
	ClearVB (VB);
	sprintf (output, "Computer %d, playing AI turn, PLEASE WAIT", player + 1);
	ShadeFont (colors[player], 1);
	DisplayString (output, 10, 10);
	RefreshVRAM (VB);
	enemies = 0;
	
	// put here the AI code
	for (current_soldier = 0; current_soldier < MAX_START; current_soldier++){
		soldier = current_soldier;
		soldier_status = CheckAliveCPUSoldier ();
		
		// alive ???
		if (soldier_status == 1){
			// select soldier
			hit_times = fire_times = 0;
			sprintf (output, "soldier %d", soldier + 1);
			DisplayString (output, 10, 20 + soldier * 7);
			RefreshVRAM (VB);
			
			SelectSoldier (player, soldier);
			
			CPU_aframe = AnimFrame[soldier][player];
			CPU_spr_frame = AnimSpr[soldier][player];
			CPU_sprdir = CPU_spr_frame / 7;
			
			// get soldier moving points
			CPU_APs = GetAPs (player, soldier);
			
			// necessary !!!
			Object[manX][manY][manZ] = 255;

			spotman = rand ()% 5;
			
			// is this soldier spotman ???
			if (spotman == 1){
				checktimes = 0;
			}
			
			else checktimes = (rand ()% 5 + 1) * 3;
			
			for (int c = 0; c < checktimes; c++){
				// check if enemies in sight...
				osd = sprdir;
				sprdir = CPU_sprdir;
				CheckVisibleEnemies ();
				sprdir = osd;
			 
				// fire ?
				if (enemies > 0 && SI[player * 8 + current_soldier].Weapon != -1){
				 	CaddWeapon->Select (SI[player * 8 + current_soldier].Weapon);
				 	
					MalFunction = (long) rnd (101);
					
					if (MalFunction > CaddWeapon->WeaponSelected->MalFunction){
						MalFunction = 1;
					}
					
					else MalFunction = 0;
					
				 	// reload weapon ??? -> costs APs...
					if (SI[player * 8 + soldier].Inmag == 0 && SI[player * 8 + soldier].Ammo > 0
					&& MalFunction == 0){
						if (CPU_APs >= CaddWeapon->WeaponSelected->Cost2){
							CPU_APs -= CaddWeapon->WeaponSelected->Cost2;
							SI[player * 8 + soldier].Inmag =
							CaddWeapon->WeaponSelected->MagSize;
							SI[player * 8 + soldier].Ammo--;
						}
					}
				 	
				 	if (CPU_APs >= CaddWeapon->WeaponSelected->Cost1 && MalFunction == 0){
				 		CPU_APs -= CaddWeapon->WeaponSelected->Cost1;
						mode = rand ()% 3;
				
						if (mode == 0){
							target_soldier = rand ()% enemies;
						
							// everything okay ?
							if (SI[player * 8 + soldier].Inmag > 0){
								// first play sample...
								index = player * 8 + soldier;
								
								SI[player * 8 + soldier].Inmag--;
								
								// silent turn?
								if (silent_AI_turn == 0){
									if (scard != 0){
										switch (CaddWeapon->WeaponSelected->WeaponType){
											// pistol / rifle
											case 0: sb_mix_sample (sample[0]); break;
											case 1: sb_mix_sample (sample[0]); break;
											
											// shotgun
											case 2: sb_mix_sample (sample[1]); break; 
								
											// sub mg
											case 3: sb_mix_sample (sample[3]); break; 

											// assault rifle
											case 4: sb_mix_sample (sample[2]); break; 
											
										}
										
										DisplayString ("Shot", 10 + 11 * 6 + 5 * 6 * fire_times + 4 * 6 * hit_times, 20 + soldier * 7);
										fire_times++;
										RefreshVRAM (VB);
									}
								}
							
								// print fire text...
								else{
									DisplayString ("Shot", 10 + 11 * 6 + 5 * 6 * fire_times + 4 * 6 * hit_times, 20 + soldier * 7);
									fire_times++;
									RefreshVRAM (VB);
								}
								
								/*
									calculate will we hit the target...
								*/
								HitRange = (float) (manX - enemyX[target]) * (float) (manX - enemyX[target]);
								HitRange += (float) (manY - enemyY[target]) * (float) (manY - enemyY[target]);
								HitRange += (float) (manZ - enemyZ[target]) * (float) (manZ - enemyZ[target]);
								HitRange = (float) sqrt ((double) HitRange);
						
								HitFloat = (float) CaddWeapon->WeaponSelected->HitAccuracy;
								HitFloat += (float) SI[player * 8 + soldier].FireSkill;
								HitFloat /= 2;
				
								HitX = (float) (CaddWeapon->WeaponSelected->HitAccuracyLoss) / 4096;
					
								if (HitRange < 1) HitRange = 1;
								HitFloat2 = pow (HitX, HitRange - 1);
								HitFloat2 = (float) sqrt ((double) HitFloat2);
								HitFloat2 *= HitFloat;
									
								HitChance = (int) HitFloat2;
								HitPR = rnd (100);
					
								if (HitPR < HitChance) Hit = 1;
								else Hit = 0;
							
								if (Hit){
									DisplayString ("Hit", 10 + 11 * 6 + 4 * 6 * hit_times + 5 * 6 * fire_times, 20 + soldier * 7);
									hit_times++;
									RefreshVRAM (VB);
									
									target = target_soldier;
									
									hitteam = team (enemyX[target], enemyY[target], enemyZ[target]);
									hitsoldier = xsoldier (enemyX[target], enemyY[target], enemyZ[target]);
				
									if (hitteam != 255 && hitsoldier != 255){
										// calculate range damage...
										HitFloat = (float) CaddWeapon->WeaponSelected->Damage;
										HitX = (float) (CaddWeapon->WeaponSelected->DamageLoss) / 4096;
										HitFloat2 = pow (HitX, HitRange - 1);
										HitFloat2 = (float) sqrt ((double) HitFloat2);
										HitFloat2 *= HitFloat;
							
										HitBP = rand ()% (BODYPARTS + 1);
									
										if (HitBP == 0){
											HitFloat2 *= 2;	// double damage :(
										}
							
										else{
											HitBP--;
										}
							
										HitDamage = (int) HitFloat2;
										
										// quickkill ???
										if ((long) rnd (HitDamage) >= HitDamage * 95 / 100){
											// head quickill ?
											if (HitBP == 0){
												if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
													HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
												}
											}
											
											// chest quickill ?
											else if (HitBP == 1){
												if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
													HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
												}
											}
											
											// abdomen quickkill ?
											else if (HitBP == 4){
												if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
													HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
												}
											}
										}
										
										SI[hitteam * 8 + hitsoldier].HP[HitBP] -= HitDamage;
											
										// dead player --> dead frame...
										if (SI[hitteam * 8 + hitsoldier].HP[HitBP] <= 
										-SI[hitteam * 8 + hitsoldier].OHP[HitBP]){
											Object[enemyX[target]][enemyY[target]][enemyZ[target]] = 254;
											
											if (silent_AI_turn == 0){
												if (scard != 0){
													sb_mix_sample (sample[10 + rnd (3)]);
												}
											}
											
											enemies--;
											if (enemies < 0) enemies = 0;
										}
						
										// soldier suffering...
										else{
											if (silent_AI_turn == 0){
												if (scard != 0){
													sb_mix_sample (sample[7 + rnd (3)]);
												}
											}
										}
									}
								}
							}
						}
					}
				}
				
				mode = rand ()% 2;
				
				if (mode == 0){
					// make sure we get a direction which isn't blocked...
					for (int save = 0; save < 5 + rand ()% 6; save++){
						dir = rand ()% 4;
					
						//left
						if (dir == 0){
							blocked = CheckMove (manX - 1, manY, manZ);
							distance = rand ()% 10 + 1;
							CPU_spr_frame = 2 * 7;
						}
							
						// right
						if (dir == 1){
							blocked = CheckMove (manX + 1, manY, manZ);
							distance = rand ()% 10 + 1;
							CPU_spr_frame = 0 * 7;
						}
							
						//up
						if (dir == 2){
							blocked = CheckMove (manX, manY - 1, manZ);
							distance = rand ()% 10 + 1;
							CPU_spr_frame = 3 * 7;
						}
				
						//down	
						if (dir == 3){
							blocked = CheckMove (manX, manY + 1, manZ);
							distance = rand ()% 10 + 1;
							CPU_spr_frame = 1 * 7;
						}
						
						if (blocked == 1) break;
					}
					
					if (blocked == 1){
						for (int dc = 0; dc < distance; dc++){
						
							if (dir == 0 && manX > 0){
								block = CheckMove (manX - 1, manY, manZ);
							
								if (block == 1 && CPU_APs >= MOVE_COST){
									manX--;
									CPU_APs -= MOVE_COST;
								}
							}
						
							if (dir == 1 && manX < 63){
								block = CheckMove (manX + 1, manY, manZ);
						
								if (block == 1 && CPU_APs >= MOVE_COST){
									manX++;
									CPU_APs -= MOVE_COST;
								}
							}
							
							if (dir == 2 && manY > 0){
								block = CheckMove (manX, manY - 1, manZ);
						
								if (block == 1 && CPU_APs >= MOVE_COST){
									manY--;
									CPU_APs -= MOVE_COST;
								}
							}
							
							if (dir == 3 && manY < 63){
								block = CheckMove (manX, manY + 1, manZ);
						
								if (block == 1 && CPU_APs >= MOVE_COST){
									manY++;
									CPU_APs -= MOVE_COST;
								}
							}
						}
					}
				}
			}
			
			Object[manX][manY][manZ] = CPU_spr_frame;
			AnimFrame[soldier][player] = CPU_aframe;
			AnimSpr[soldier][player] = CPU_spr_frame;
			BackCoordinates (player, soldier);
			SaveAPs (player, soldier, CPU_APs);
			delay (200);
		}

		// dead CPU soldier :(		
		else{
			soldier++;
		}
	}
}

int NoHumanPlayers (void)
{
	int plr, cnt;
	
	for (plr = 0; plr < default_players; plr++){
		for (cnt = 0; cnt < MAX_START; cnt++){
			if (health[plr][cnt] > 0 && player_type[plr] == HUMAN){
				return 0;
			}
		}
	}
	
	return 1;
}

void RealPutPixel (int x, int y, char col)
{
	if (x >= 0 && y >= 0 && x <= 319 && y <= 199){
		PutPixel (x, y, col, VB);
	}
}

void DrawMouseCursor (void)
{
		RealPutPixel (mousex - 2, mousey, 64);
		RealPutPixel (mousex - 1, mousey, 64);
				
		RealPutPixel (mousex + 2, mousey, 64);
		RealPutPixel (mousex + 1, mousey, 64);
				
		RealPutPixel (mousex, mousey - 2, 64);
		RealPutPixel (mousex, mousey - 1, 64);
				
		RealPutPixel (mousex, mousey + 2, 64);
		RealPutPixel (mousex, mousey + 1, 64);
}

/*
	makes bleed damage if soldier is wounded and above
	no wound wounded...
*/
void MakeWoundedBleedDamage (void)
{
	long c;
	long xc;
	signed long wt;
	char dead;
		
	for (c = 0; c < TI[player].soldiers; c++){
		dead = 0;
		
		for (xc = 0; xc < 7; xc++){
			if (SI[player * 8 + c].HP[xc] <= -SI[player * 8 + c].OHP[xc]){
				dead = 1;
			}
		}

		// dead soldiers won't yell anything !!
		if (!dead){
			for (xc = 0; xc < 7; xc++){
				wt = ReturnWoundType (SI[player * 8 + c].HP[xc], 
				SI[player * 8 + c].OHP[xc]);
				
				// soldier bleeds...
				if (wt != 0 && dead != 1){
					SI[player * 8 + c].HP[xc] -= wt;
					
					if (SI[player * 8 + c].HP[xc] <= -SI[player * 8 + c].OHP[xc]){
						manX = PlayerStartX[c][player];
						manY = PlayerStartY[c][player];
						manZ = PlayerStartZ[c][player];
						Object[manX][manY][manZ] = 254;
					}
					
					if (player < human_players){
						if (scard != 0){
							sb_mix_sample (sample[7 + rnd (3)]);
						}
					}
					
					else{
						if (silent_AI_turn == 0){
							if (scard != 0){
								sb_mix_sample (sample[7 + rnd (3)]);
							}
						}
					}
				}
			}
		}
	}
}

	
/*
	Game update code
*/
int UpdateGame (void)
{
	char spotquit = 0;
	int CPU_APs;
	int ff;
	int won = 0;
	int act;
	unsigned char kb;
	int close_flag = 0;
	int ptr_dir = 0;
	int op;
	int spr_frame = 0;
	int c = 0;
	int cnt;
	int move;
	int r;
	int index;
	int cm;
	int idle_frames = 0;
	int vision;
	BYTE ol;
	BYTE pressed;
	int alive;
	int hitteam, hitsoldier;
	int hteam, hsoldier, tcnt;
	int stat;
	char demand_path_move = 0, path_moving = 0;
	int demandX, demandY;
	long Hit, HitCheck;
	float HitFloat, HitFloat2, HitRange, HitX;
	int HitPR, HitChance, HitBP;
	long HitDamage;
	int StereoVolume;
	char xreleased;
	long MalFunction;
	
	/*
		below 2 variable init prevents from
		wrong start player / soldier !!!
	*/
	player = 0;
	soldier = 0;
	
	ClearVB (VB);
	Object[manX][manY][manZ] = spr_frame;
	CalcAPs ();
	moving = GetAPs (player, soldier);
	ShadeFont (colors[player], 1);

	SetRepeat (keyfirstdelay, keynextdelay);

	while (1){
		if (!MouseControlFlag){
			while (keytable[pressed] == PRESSED);
		}

		while (1){
			UpdateMapCoordinates ();

			// draw map (blocks & objects) to virtual buffer
			timer_ticks = 0;
			timer_start = 1;
			ShowMap ();
			timer_start = 0;
			refresh_ticks = timer_ticks;
			TopBar (VB);
			
			maxy = 199;
			
			if (health[player][soldier] > 0){
				sprintf (output, "%d APs left, FireSkill %lu", 
				moving, 
				SI[player * 8 + soldier].FireSkill);
				DisplayString (output, 0, 200 - 32);
			}
			
			if (SI[player * 8 + soldier].Weapon != -1){
				CaddWeapon->Select (SI[player * 8 + soldier].Weapon);
				sprintf (output, "Weapon %s, %lu Ammo, %lu Mags", 
				CaddWeapon->WeaponSelected->Name,
				SI[player * 8 + soldier].Inmag,
				SI[player * 8 + soldier].Ammo);
			}
			
			else{
				sprintf (output, "NO WEAPON");
			}
			
			DisplayString (output, 0, 200 - 32 + 16);
			
			if (enemies > 0){
				sprintf (output, "%d enemies  ", enemies);
				DisplayString (output, 0, 200 - 32 + 24);
				
				/*
					loop through all visible possible spotman enemies...
				*/
				for (tcnt = 0; tcnt < enemies; tcnt++){
					// check spotting
					hteam = team (enemyX[tcnt], enemyY[tcnt], enemyZ[tcnt]);
					hsoldier = xsoldier (enemyX[tcnt], enemyY[tcnt], enemyZ[tcnt]);
	
					// CPU fires towards player ?
					if (SI[hteam * 8 + hsoldier].Weapon != -1 && SI[hteam * 8 + hsoldier].Inmag > 0){
						CaddWeapon->Select (SI[hteam * 8 + hsoldier].Weapon);
						
						MalFunction = (long) rnd (101);
					
						if (MalFunction > CaddWeapon->WeaponSelected->MalFunction){
							MalFunction = 1;
						}
					
						else MalFunction = 0;
					
						if (APs[hteam][hsoldier] >= CaddWeapon->WeaponSelected->Cost1 && MalFunction == 0){
							ff = rand ()% 10 + 1;
						
							// fire =)
							if (ff < 8){
								APs[hteam][hsoldier] -= CaddWeapon->WeaponSelected->Cost1;
								TopBar (VB);
								maxy = 199;
								DisplayString ("You are being fired", 160, 200 - 32);
								maxy = 199 - 32;
								RefreshVRAM (VB);
								
								// here (spot doesn't support reloading...)
								if (SI[hteam * 8 + hsoldier].Inmag > 0){
									// first play sample...
									index = hteam * 8 + hsoldier;
								
									// mag ammo--
									SI[hteam * 8 + hsoldier].Inmag--;
									
									// silent turn?
									if (silent_AI_turn == 0){
										if (scard != 0){	
											switch (CaddWeapon->WeaponSelected->WeaponType){
												// pistol / rifle
												case 0: sb_mix_sample (sample[0]); break;
												case 1: sb_mix_sample (sample[0]); break;
												
												// shotgun
												case 2: sb_mix_sample (sample[1]); break; 
									
												// sub mg
												case 3: sb_mix_sample (sample[3]); break; 
	
												// assault rifle
												case 4: sb_mix_sample (sample[2]); break; 
											}
										}
					
									}
									
									else{
										// print fire text...
									}
									
									/*
										calculate will we hit the target...
									*/
									HitRange = (float) (manX - enemyX[target]) * (float) (manX - enemyX[target]);
									HitRange += (float) (manY - enemyY[target]) * (float) (manY - enemyY[target]);
									HitRange += (float) (manZ - enemyZ[target]) * (float) (manZ - enemyZ[target]);
									HitRange = (float) sqrt ((double) HitRange);
					
									HitFloat = (float) CaddWeapon->WeaponSelected->HitAccuracy;
									HitFloat += (float) SI[player * 8 + soldier].FireSkill;
									HitFloat /= 2;
				
									HitX = (float) (CaddWeapon->WeaponSelected->HitAccuracyLoss) / 4096;
					
									if (HitRange < 1) HitRange = 1;
									HitFloat2 = pow (HitX, HitRange - 1);
									HitFloat2 = (float) sqrt ((double) HitFloat2);
									HitFloat2 *= HitFloat;
									
									HitChance = (int) HitFloat2;
									HitPR = rnd (100);
					
									if (HitPR < HitChance) Hit = 1;
									else Hit = 0;
									
									if (Hit){
										hitteam = player;
										hitsoldier = soldier;
					
										if (hitteam != 255 && hitsoldier != 255){
											// calculate range damage...
											HitFloat = (float) CaddWeapon->WeaponSelected->Damage;
											HitX = (float) (CaddWeapon->WeaponSelected->DamageLoss) / 4096;
											HitFloat2 = pow (HitX, HitRange - 1);
											HitFloat2 = (float) sqrt ((double) HitFloat2);
											HitFloat2 *= HitFloat;
							
											HitBP = rand ()% (BODYPARTS + 1);
									
											if (HitBP == 0){
												HitFloat2 *= 2;	// double damage :(
											}
							
											else{
												HitBP--;
											}
											
											HitDamage = (int) HitFloat2;
										
											// quickkill ???
											if ((long) rnd (HitDamage) >= HitDamage * 95 / 100){
												// head quickill ?
												if (HitBP == 0){
													if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
														HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
													}
												}
												
												// chest quickill ?
												else if (HitBP == 1){
													if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
														HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
													}
												}
												
												// abdomen quickkill ?
												else if (HitBP == 4){
													if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
														HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
													}
												}
											}
								
											SI[hitteam * 8 + hitsoldier].HP[HitBP] -= HitDamage;
											
											// dead player --> dead frame...
											if (SI[hitteam * 8 + hitsoldier].HP[HitBP] <= 
											-SI[hitteam * 8 + hitsoldier].OHP[HitBP]){
												Object[manX][manY][manZ] = 254;
												
												if (silent_AI_turn == 0){
													if (scard != 0){
														sb_mix_sample (sample[10 + rnd (3)]);
													}
												}
											
												TopBar (VB);
						
												maxy = 199;
												DisplayString ("You are dead", 0, 200 - 32);
												maxy = 199 - 32;
					
												RefreshVRAM (VB);
												delay (50);
												zgetkey ();
											
												if (CheckAlive() == 1){
													SaveAPs (player, soldier, moving);
													AnimFrame[soldier][player] = aframe;
													AnimSpr[soldier][player] = spr_frame;
													BackCoordinates (player, soldier);
					
													// select until alive soldier found...
													while (1){
														soldier++;
														if (soldier > TI[player].soldiers - 1) soldier = 0;
														alive = CheckAliveSoldier ();
														if (alive != -1) break;
													}
					
													//select soldier
													while (1){
														SelectSoldier (player, soldier);
									
														if (sdead == 1){
															soldier++;
															if (soldier > TI[player].soldiers - 1) soldier = 0;
														}
						
														else break;
													}
					
													moving = GetAPs (player, soldier);
													aframe = AnimFrame[soldier][player];
													spr_frame = AnimSpr[soldier][player];
													sprdir = spr_frame / 7;
													enemies = 0;
													
													demand_path_move = 0;
													path_moving = 0;
													GenX = manX;
													GenY = manY;
													method = -1;
												}
												
												else spotquit = 1;
											}
								
											// soldier suffering...
											else{
												if (silent_AI_turn == 0){
													if (scard != 0){
														sb_mix_sample (sample[7 + rnd (3)]);
													}
												}
											}
										}
									}
								}
							// here end
							}
						}
					}
				}
			}
			
			sprintf (output, "%lu FPS", 1000 / refresh_ticks); //, 1000 % refresh_ticks);
			DisplayString (output, 100, 200 - 32 + 24);
			maxy = 199 - 32;

			// draw cursor at mx, my !
			if (MouseControlFlag){
					UpdateMouse ();
					DrawMouseCursor ();
			}

			stat = GetMapXY (mousex, mousey);

			// debug stuff....
			if (stat != -1){
				maxy = 199;
				sprintf (output, "CX %d CY %d MX %d MY %d", GlobalMapXPosition + 1, GlobalMapYPosition + 1, mx + 1, my + 1);				
				DisplayString (output, 0, 200 - 32 + 8);
				maxy = 199 - 32;
			}
			
			if (MouseControlFlag){
				if (mouseb != 0 && stat != -1 && demand_path_move == 0){
					demand_path_move = 1;
					demandX = GlobalMapXPosition;
					demandY = GlobalMapYPosition;
					path_moving = 1;
					stat = StartWalk (manX, manY, demandX, demandY);
					path_moving = 2;
					GenX = manX;
					GenY = manY;
				}
			}
			
			// refresh VB to VRAM
			RefreshVRAM (VB);

			// increase frames (idle & normal)
			frames++;
			idle_frames++;

			// if idle > idle_limit set start frame
			// idle won't work anymore, why???
			if (idle_frames > 25){
				idle_frames = 0;
				Object[manX][manY][manZ] = spr_frame;
				aframe = 0;
			}
			
			if (no_key () == 0) break;
			if (path_moving != 0) break;
			
			UpdateMouse ();
			if (mouseb != 0) break;
		//}
		}
	
		// reset idle frames
		idle_frames = 0;

		// clear some variables
		act = move = -1;

		// read pressed key fast !, if mouse control Flag true
		if (MouseControlFlag){
			kb = ygetkey();
		}
		
		// else normal key read
		else{
			kb = WaitKB ();
		}

		// hide sprite
		Object[manX][manY][manZ] = 255;

		if (demand_path_move == 1 && moving >= MOVE_COST){
			if (path_moving == 2){
				stat = RealWalk ();
				
				if (stat == 1){
					path_moving = demand_path_move = 0;
				}

				else{
					if (GenX != manX || GenY != manY){
						manX = GenX;
						manY = GenY;
						move = 2;	// this direction should be calculated from x&y ranges !
						
						int xr, yr;
						xr = abs (manX - demandX);
						yr = abs (manY - demandY);
						
						if (xr > yr){
							if (manX < demandX){
								spr_frame = 0 * 7;
								sprdir = 0;
							}
							
							if (manX > demandX){
								spr_frame = 2 * 7;
								sprdir = 2;
							}
						}
						
						if (xr == yr){
							// nothing yet...
						}
						
						if (xr < yr){
							if (manY > demandY){
									spr_frame = 3 * 7;
									sprdir = 3;
							}
							
							if (manY < demandY){
								spr_frame = 1 * 7;
								sprdir = 1;
							}
						}
						
						moving -= MOVE_COST;
					}
				}
			}
		}
		
		// key left
		if (kb == keys[0]){
			demand_path_move = 0;
			path_moving = 0;
			
			act = CheckMove (manX - 1, manY, manZ);

			if (act == 1 && manX > 0 && moving >= MOVE_COST){
				manX--;
				move = 2;
				moving -= MOVE_COST;
				spr_frame = 2 * 7;
				sprdir = 2;
			}

			// traps
			else if (act == 2){
				if (Map[manX - 1][manY][manZ] == 54 && moving >= TRAP_COST){
					manX--;
					move = 2;

					if (manZ == 0){
						act = CheckMove (manX - 2, manY - 1, manZ + 1);

						if (act != 3){
							manX -= 2;
							manY--;
							manZ++;
							moving -= TRAP_COST;
							spr_frame = 2 * 7;
							sprdir = 2;
						}

						else{
							manX++;
							move = -1;
						}
					}

					else{
						if (manZ < Zlevels - 1){
							act = CheckMove (manX - 1, manY, manZ + 1);

							if (act != 3){
								manX--;
								manZ++;
								moving -= TRAP_COST;
								spr_frame = 2 * 7;
								sprdir = 2;
							}

							else{
								manX++;
								move = -1;
							}
						}
					}
				}
			}
		}

		// key right
		if (kb == keys[2]){
			demand_path_move = 0;
			path_moving = 0;
			
			act = CheckMove (manX + 1, manY, manZ);

			if (act == 1 && manX < 63 - 12 && moving >= MOVE_COST){
				manX++;
				move = 0;
				moving -= MOVE_COST;
				spr_frame = 0 * 7;
				sprdir = 0;
			}

			// check if this block is "end of stairs"
			else if (act == 0 && manZ > 0){
				if (manZ > 1){
					act = CheckMove (manX + 2, manY, manZ - 1);

					if (act != 3 && moving >= TRAP_COST){
						if (Map[manX + 1][manY][manZ - 1] == 54){
							manX++;
							move = 0;
							manX++;
							manZ--;
							moving -= TRAP_COST;
							spr_frame = 0 * 7;
							sprdir = 0;
						}
					}
				}

				else{
					act = CheckMove (manX + 3, manY + 1, manZ - 1);

					if (act != 3 && moving >= TRAP_COST){
						if (Map[manX + 2][manY + 1][manZ - 1] == 54){
							manX++;
							manY++;
							move = 0;
							manX += 2;
							manZ--;
							moving -= TRAP_COST;
							spr_frame = 0 * 7;
							sprdir = 0;
						}
					}
				}
			}
		}

		// key up
		if (kb == keys[1]){
			demand_path_move = 0;
			path_moving = 0;
			
			act = CheckMove (manX, manY - 1, manZ);

			if (act == 1 && manY > 0 && moving >= MOVE_COST){
				manY--;
				move = 3;
				moving -= MOVE_COST;
				spr_frame = 3 * 7;
				sprdir = 3;
			}

			// traps
			else if (act == 2){
				if (Map[manX][manY - 1][manZ] == 53 && moving >= TRAP_COST){
					manY--;
					move = 3;

					if (manZ == 0){
						act = CheckMove (manX - 1, manY - 2, manZ + 1);

						if (act != 3){
							manX--;
							manY -= 2;
							manZ++;
							moving -= TRAP_COST;
							spr_frame = 3 * 7;
							sprdir = 3;
						}

						else{
							move = -1;
							manY++;
						}
					}

					else{
						if (manZ < Zlevels - 1){
							act = CheckMove (manX, manY - 1, manZ + 1);

							if (act != 3){
								manY--;
								manZ++;
								moving -= TRAP_COST;
								spr_frame = 3 * 7;
								sprdir = 3;
							}

							else{
								manY++;
								move = -1;
							}
						}
					}
				}
			}
		}

		// key down
		if (kb == keys[3]){
			demand_path_move = 0;
			path_moving = 0;
			
			act = CheckMove (manX, manY + 1, manZ);

			if (act == 1 && manY < 63 - 11 && moving >= MOVE_COST){
				manY++;
				move = 1;
				moving -= MOVE_COST;
				spr_frame = 1 * 7;
				sprdir = 1;
			}

			// check for "end of stairs"
			else if (act == 0 && manZ > 0){
				if (manZ > 1){
					if (Map[manX][manY + 1][manZ - 1] == 53){
						act = CheckMove (manX, manY + 2, manZ - 1);

						if (act != 3 && moving >= TRAP_COST){
							manY++;
							move = 1;
							manY++;
							manZ--;
							moving -= TRAP_COST;
							spr_frame = 1 * 7;
							sprdir = 1;
						}
					}
				}

				else{
					if (Map[manX + 1][manY + 2][manZ - 1] == 53){
						act = CheckMove (manX + 1, manY + 3, manZ - 1);

						if (act != 3 && moving >= TRAP_COST){
							manY++;
							manX++;
							move = 1;
							manY += 2;
							manZ--;
							moving -= TRAP_COST;
							spr_frame = 1 * 7;
							sprdir = 1;
						}
					}
				}
			}
		}

		if (kb == keys[8] && sprdir != 2){
			if (moving >= TURN_COST){
				spr_frame = 2 * 7;
				sprdir = 2;
				moving -= TURN_COST;
			}
		}
		
		if (kb == keys[9] && sprdir != 3){
			if (moving >= TURN_COST){
				spr_frame = 3 * 7;
				sprdir = 3;
				moving -= TURN_COST;
			}
		}
		
		if (kb == keys[10] && sprdir != 0){
			if (moving >= TURN_COST){
				spr_frame = 0 * 7;
				sprdir = 0;
				moving -= TURN_COST;
			}
		}
		
		if (kb == keys[11] && sprdir != 1){
			if (moving >= TURN_COST){
				spr_frame = 1 * 7;
				sprdir = 1;
				moving -= TURN_COST;
			}
		}
		
		/*
			soldier fires... if fires..
		*/
		if (kb == keys[4] && enemies > 0 && SI[player * 8 + soldier].Weapon != -1){
			CaddWeapon->Select (SI[player * 8 + soldier].Weapon);

			MalFunction = (long) rnd (101);
					
			if (MalFunction > CaddWeapon->WeaponSelected->MalFunction){
				MalFunction = 1;
			}
					
			else MalFunction = 0;

			// change clip :)
			if (SI[player * 8 + soldier].Inmag == 0 && SI[player * 8 + soldier].Ammo > 0 && MalFunction == 0){
				if (moving >= CaddWeapon->WeaponSelected->Cost2){
					SI[player * 8 + soldier].Inmag = CaddWeapon->WeaponSelected->MagSize;
					SI[player * 8 + soldier].Ammo--;
					moving -= CaddWeapon->WeaponSelected->Cost2;
				}
			}			
			
			if (moving >= CaddWeapon->WeaponSelected->Cost1 
			&& SI[player * 8 + soldier].Inmag > 0 && MalFunction == 0){
				SI[player * 8 + soldier].Inmag--;
				
				index = player * 8 + soldier;
				SetStereoVolumes (32, 32);
				
				if (scard != 0){	
					switch (CaddWeapon->WeaponSelected->WeaponType){
						// pistol / rifle
						case 0: sb_mix_sample (sample[0]); break;
						case 1: sb_mix_sample (sample[0]); break;
											
						// shotgun
						case 2: sb_mix_sample (sample[1]); break; 
								
						// sub mg
						case 3: sb_mix_sample (sample[3]); break; 

						// assault rifle
						case 4: sb_mix_sample (sample[2]); break; 
					}
				}
				
				act = 1;
				ol = LightLevel[manX][manY][manZ];
				r = rnd (100);
				
				HitRange = (float) (manX - enemyX[target]) * (float) (manX - enemyX[target]);
				HitRange += (float) (manY - enemyY[target]) * (float) (manY - enemyY[target]);
				HitRange += (float) (manZ - enemyZ[target]) * (float) (manZ - enemyZ[target]);
				HitRange = (float) sqrt ((double) HitRange);
				
				HitFloat = (float) CaddWeapon->WeaponSelected->HitAccuracy;
				HitFloat += (float) SI[player * 8 + soldier].FireSkill;
				HitFloat /= 2;
				
				HitX = (float) (CaddWeapon->WeaponSelected->HitAccuracyLoss) / 4096;
				
				if (HitRange < 1) HitRange = 1;
				HitFloat2 = pow (HitX, HitRange - 1);
				HitFloat2 = (float) sqrt ((double) HitFloat2);
				HitFloat2 *= HitFloat;
				
				HitChance = (int) HitFloat2;
				HitPR = rnd (100);
				
				if (HitPR < HitChance) Hit = 1;
				else Hit = 0;
				
				// firing animation
				for (cm = 0; cm < 7; cm++){
					Object[manX][manY][manZ] = spr_frame + 224 + cm;
		
					/*
						update light level under soldier -> weapon fire flame...
					*/
					if (ol > 4){
						if (cm < 3){
							LightLevel[manX][manY][manZ] = ol - 2;
						}
	
						else{
							LightLevel[manX][manY][manZ] = ol - 1;
						}
					}
	
					ShowMap ();
					TopBar (VB);
					
					if (Hit && scard == 0){
						maxy = 199;
						DisplayString ("Hit", 0, 200 - 32);
						maxy = 199 - 32;
					}
					
					RefreshVRAM (VB);
					delay (firedelay);
				}

				LightLevel[manX][manY][manZ] = ol;
				moving -= CaddWeapon->WeaponSelected->Cost1;
			
				if (Hit){
					// this code will be change soon...
					hitteam = team (enemyX[target], enemyY[target], enemyZ[target]);
					hitsoldier = xsoldier (enemyX[target], enemyY[target], enemyZ[target]);

					if (hitteam != 255 && hitsoldier != 255){
						// calculate range damage
						HitFloat = (float) CaddWeapon->WeaponSelected->Damage;
						HitX = (float) (CaddWeapon->WeaponSelected->DamageLoss) / 4096;
						HitFloat2 = pow (HitX, HitRange - 1);
						HitFloat2 = (float) sqrt ((double) HitFloat2);
						HitFloat2 *= HitFloat;
						
						HitBP = rand ()% (BODYPARTS + 1);
						
						if (HitBP == 0){
							HitFloat2 *= 2;	// double damage :(
						}
						
						else{
							HitBP--;
						}
						
						HitDamage = (int) HitFloat2;
										
						// quickkill ???
						if ((long) rnd (HitDamage) >= HitDamage * 95 / 100){
							// head quickill ?
							if (HitBP == 0){
								if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
								HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
							}
								
							// chest quickill ?
							else if (HitBP == 1){
								if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
									HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
								}
							}
											
							// abdomen quickkill ?
							else if (HitBP == 4){
									if (HitDamage < SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2){
										HitDamage = SI[hitteam * 8 + hitsoldier].OHP[HitBP] * 2;
									}
								}
							}
						}
						
						SI[hitteam * 8 + hitsoldier].HP[HitBP] -= HitDamage;
						
						// HitBP support coming soon !!!
						
						// dead player --> dead frame...
						if (SI[hitteam * 8 + hitsoldier].HP[HitBP] <= 
							-SI[hitteam * 8 + hitsoldier].OHP[HitBP]){
							Object[enemyX[target]][enemyY[target]][enemyZ[target]] = 254;
						
							if (scard != 0){
								// distance code here...
								
								StereoVolume = (int) (HitRange * 32 / 91) + 1;
								if (StereoVolume > 32) StereoVolume = 32;
								
								if (enemyX[target] < manX){
									SetStereoVolumes (StereoVolume, 0);
								}
								
								else if (enemyX[target] > manX){
									SetStereoVolumes (0, StereoVolume);
								}
								
								else if (enemyX[target] == manX){
									SetStereoVolumes (StereoVolume, StereoVolume);
								}
								
								sb_mix_sample (sample[10 + rnd (3)]);
							}
							
							/*
								soldier gains kills & experience !
								soon ranks too...
							*/
							SI[player * 8 + soldier].Kills++;
							SI[player * 8 + soldier].Experience +=
							SI[team (enemyX[target], enemyY[target], enemyZ[target]) * 8 +
							xsoldier (enemyX[target], enemyY[target], enemyZ[target])].Cost / 500;
							
							for (signed long rank = 0; rank < RANKS; rank++){
								if (SI[player * 8 + soldier].Experience >= RankLimit[rank]){
									SI[player * 8 + soldier].Rank = rank;
								}
							}
							
							enemies--;
							if (enemies < 0) enemies = 0;
						}
				
						else{
							if (scard != 0){
								sb_mix_sample (sample[7 + rnd (3)]);
							}
						}
					}
				}
			}
		}

		if (kb == keys[12]){
			viewmode = (viewmode + 1) & 1;
		}
		
		// soldier statistics ???
		if (kb == keys[14]){
			LoadPalette ();
			SetPalette (&Palette[0]);
			ClearVB (VB);
			SetWindowColors (162, 174, 168, 170);
			DrawWindow (0, 0, 320, 200, "SOLDIER STATISTICS", 10);
			DisplayString ("PRESS ANY KEY TO EXIT", 20, 180);
		
			// statistics start
			if (SI[player * 8 + soldier].Weapon != -1){
				sprintf (output, "WEAPON %s, %lu Ammo, %lu Clips",
				CaddWeapon->GetName (SI[player * 8 + soldier].Weapon), 
				SI[player * 8 + soldier].Inmag,
				SI[player * 8 + soldier].Ammo);
			}
			
			else{
				sprintf (output, "NO WEAPON");
			}

			DisplayString (output, 20, 20);
			
			sprintf (output, "HIT POINTS");
			DisplayString (output, 20, 35);
			
			for (cnt = 0; cnt < BODYPARTS; cnt++){
				sprintf (output, "%s %ld of %ld, %s wound", BodyParts[cnt],
				SI[player * 8 + soldier].HP[cnt], 
				SI[player * 8 + soldier].OHP[cnt],
				WoundType
				[ReturnWoundType (SI[player * 8 + soldier].HP[cnt], 
				SI[player * 8 + soldier].OHP[cnt])]);
				DisplayString (output, 20, 45 + cnt * 8);
			}
			
			sprintf (output, "Rank %s, %lu experience points, %lu kills",
			Ranks[SI[player * 8 + soldier].Rank], 
			SI[player * 8 + soldier].Experience,
			SI[player * 8 + soldier].Kills);
			DisplayString (output, 20, 55 + (BODYPARTS) * 8);
		
			sprintf (output, "FireSkill %lu, Strength %lu, Constitution %lu APs %lu",
			SI[player * 8 + soldier].FireSkill, SI[player * 8 + soldier].Strength,
			SI[player * 8 + soldier].Constitution, moving);
			DisplayString (output, 20, 70 + (BODYPARTS) * 8);
			
			sprintf (output, "Cost %lu dollars, Load %lu KGs",
			SI[player * 8 + soldier].Cost, SI[player * 8 + soldier].Load);
			DisplayString (output, 20, 85 + (BODYPARTS) * 8);

			sprintf (output, "Armor %ld",
			SI[player * 8 + soldier].Armor);
			DisplayString (output, 20, 100 + (BODYPARTS) * 8);

			RefreshVRAM (VB);
	
			// wait prev pressed key's unpress
			while (keytable[kb] == PRESSED);
			WaitKB ();
			DarkenPalette ();
			SetPalette (&Palette[0]);
		}

		/*
			check was ESC pressed, if was
			then exit to OS
		*/
		if (act == -1){
			act = 0;

			if (kb == ESC){
				act= -1;
			}
		}

		// exit to OS
		if (act == -1) break;
		if (spotquit) break;

		// if sprite is moving then animate sprite
		if (move != -1){
			aframe++;
			if (aframe > 6) aframe = 0;
		}

		//enable sprite
		Object[manX][manY][manZ] = spr_frame + aframe;
		
		/*
			NOTE:
			following code must come after
			previous line that enables sprite !!!
		*/
		
		// prev soldier
		if (kb == keys[6]){
			SaveAPs (player, soldier, moving);
			AnimFrame[soldier][player] = aframe;
			AnimSpr[soldier][player] = spr_frame;
			BackCoordinates (player, soldier);
			
			while (1){
				soldier--;
				if (soldier < 0) soldier = 7;
				alive = CheckAliveSoldier ();
				if (alive != -1) break;
			}
			
			// select soldier
			while (1){
				SelectSoldier (player, soldier);
				
				if (sdead == 1){
					soldier--;
					if (soldier < 0) soldier = 7;
				}
				
				else break;
			}
			
			moving = GetAPs (player, soldier);

			aframe = AnimFrame[soldier][player];
			spr_frame = AnimSpr[soldier][player];
			sprdir = spr_frame / 7;
			enemies = 0;
			
			demand_path_move = 0;
			path_moving = 0;
			GenX = manX;
			GenY = manY;
			method = -1;
		}
		
		// next soldier
		if (kb == keys[5]){
			SaveAPs (player, soldier, moving);
			AnimFrame[soldier][player] = aframe;
			AnimSpr[soldier][player] = spr_frame;
			BackCoordinates (player, soldier);
			
			// select until alive soldier found...
			while (1){
				soldier++;
				if (soldier > TI[player].soldiers - 1) soldier = 0;
				alive = CheckAliveSoldier ();
				if (alive != -1) break;
			}
			

			//select soldier
			while (1){
				SelectSoldier (player, soldier);
				
				if (sdead == 1){
					soldier++;
					if (soldier > TI[player].soldiers - 1) soldier = 0;
				}
				
				else break;
			}
			
			moving = GetAPs (player, soldier);
			aframe = AnimFrame[soldier][player];
			spr_frame = AnimSpr[soldier][player];
			sprdir = spr_frame / 7;
			enemies = 0;
			
			demand_path_move = 0;
			path_moving = 0;
			GenX = manX;
			GenY = manY;
			method = -1;
		}
		
		// next player = end turn :)
 		if (kb == keys[7]){
			AnimFrame[soldier][player] = aframe;
			AnimSpr[soldier][player] = spr_frame;
			BackCoordinates (player, soldier);
			
			if (NoHumanPlayers () == 1){
				won = 1;
			}

			MakeWoundedBleedDamage ();
			
			while (1){
				op = player;
				FindProberPlayer ();
				
				if (player == op){
					won = 1;
				}
					
				if (won == 1) break;
				if (player_type[player] == HUMAN) break;
				
				else{
					Play_AI_Turn ();
				}
			}
						
			// player alive select player
			CalcAPs ();
			SelectSoldier (player, soldier);

			moving = GetAPs (player, soldier);
			aframe = AnimFrame[soldier][player];
			spr_frame = AnimSpr[soldier][player];
			sprdir = spr_frame / 7;
			
			ClearVB (VB);
			sprintf (output, "Player %d, press any key to start your turn", player + 1);
			ShadeFont (colors[player], 1);
			DisplayString (output, 10, 10);
			RefreshVRAM (VB);
			
			while (!no_key ());
			pressed = WaitKB ();
			enemies = 0;
			
			demand_path_move = 0;
			path_moving = 0;
			GenX = manX;
			GenY = manY;
			method = -1;
		}
		
		// select target ...
		if (kb == keys[13]){
			if (enemies > 0){
				UpdateAnyMapCoordinates (enemyX[target], enemyY[target], enemyZ[target]);	
				
				// draw map (blocks & objects) to virtual buffer
				ShowMap ();
				TopBar (VB);
				maxy = 199;
				sprintf (output, "%d APs left  ", moving);
				DisplayString (output, 0, 200 - 32);
				sprintf (output, "%d enemies  ", enemies);
				DisplayString (output, 0, 200 - 32 + 8);
				sprintf (output, "target %d of %d    ", target + 1, enemies);
				DisplayString (output, 0, 200 - 32 + 16);
				maxy = 199 - 32;

				// refresh VB to VRAM
				RefreshVRAM (VB);
				target++;
				
				if (target >= enemies){
					target = 0;
				}
				
				// wait prev pressed key unpress...
				while (keytable[kb] == PRESSED);
				kb = WaitKB ();

			}
		}
		
		if (won == 1) break;
	}

	ClearVB (VB);
	DisplayString ("UPDATING TEAM FILES", 10, 10);
	RefreshVRAM (VB);
	UpdateTeamFile ();
	delay (1000);
		
	if (won == 1){
		ClearVB (VB);
	
		if (player_type[op] == HUMAN){
			sprintf (output, "Player %d you have won this battle", op + 1);
		}
		
		else{
			sprintf (output, "Computer player %d has won this battle", op + 1);
		}
		
		ShadeFont (colors[player], 1);
		DisplayString (output, 10, 10);
		RefreshVRAM (VB);
		pressed = WaitKB ();
	}

	maxy = 199;
	return 0;
}
