# Rbot AI Cog - Alpha 0.32
# Server side - unsynch
#
# Created by Raynar
# Additional code by Hell Raiser

flags=0x280

symbols

message		startup
message		trigger
message		pulse
message		timer

int			botid=0
thing		rbot		local
int			team		local
int			gamemode	local
int			botmode		local
int			botname		local
int			difficulty	local
int			forcemode	local

# Item templates
template	tmp_energycell=ENERGYCELL	local
template	tmp_powercell=POWERCELL		local
template	tmp_raildets=RAILCHARGES	local
template	tmp_bacta=BACTATANK			local
template	tmp_health=HEALTHPACK		local
template	tmp_shields=SHIELDRECHARGE	local
template	tmp_supershield=SUPERSHIELD	local
template	tmp_fullshield=FULLSHIELD	local
template	tmp_mana=MANABOOST			local
template	tmp_powerboost=POWERBOOST	local
template	tmp_revivepack=REVIVEPACK	local
template	tmp_lightside=LIGHTSIDE		local
template	tmp_darkside=DARKSIDE		local
template	tmp_backpack=+backpack		local
template	tmp_weap3=STRIFLE			local
template	tmp_weap4=DETONATOR			local
template	tmp_weap5=CROSSBOW			local
template	tmp_weap6=REPEATERGUN		local
template	tmp_weap7=RAILGUN			local
template	tmp_weap8=SEQCHARGE			local
template	tmp_weap9=CONCRIFLE			local

# Inventory items - other weapons added later
int			shields			local
int			energy			local
int			power			local
int			inv_bacta		local
int			inv_raildets	local
int			inv_weap0		local	desc=saber unlit
int			inv_weap1		local	desc=fists
int			inv_weap2		local	desc=bryar
int			inv_weap3		local	desc=st rifle
int			inv_weap4		local	desc=therm det
int			inv_weap5		local	desc=crossbow
int			inv_weap6		local	desc=repeater
int			inv_weap7		local	desc=railgun
int			inv_weap8		local	desc=seq charges
int			inv_weap9		local	desc=conc rifle
int			inv_weap10		local	desc=saber lit

# Misc
thing		potential	local
thing		target		local
thing		newtarget	local
flex		dot			local
flex		maxdot		local
flex		dist		local
flex		mindist		local
int			targetok	local
int			targetmode	local
int			curweap		local
int			maxthings	local
thing		item		local
flex		disttotarg		local
vector		relpos			local
flex		firedelay		local
flex		minrange		local
flex		maxrange		local
flex		firedelay2		local
flex		minrange2		local
flex		maxrange2		local
int			nextanim=0		local
vector		rvec			local
flex		extra			local
int			slash			local
int			bin				local
int			rank			local
thing		enemy			local
int			health			local
int			damage			local
int			targweap		local
int			powerboost		local
thing		damager			local
thing		highscorer		local
int			captured_red	local
int			captured_gold	local
int			redflag_taken	local
int			goldflag_taken	local
int			targetpriority		local
int			newtargetpriority	local

end

# Code Section

code

startup:
	maxthings = GetThingCount(); // work out how many objects in the level
	return;

trigger:
	if (getsourceref() == 800) // game setup options
	{
		gamemode=getparam(0);
		difficulty=getparam(1);
	}
	if (getsourceref() == 12210) // updated CTF info
	{
		captured_red=GetParam(0);
		captured_gold=GetParam(1);
		redflag_taken=GetParam(2);
		goldflag_taken=GetParam(3);
	}
	if (getparam(0) != botid) return;

	// Bot specific triggers
	if (getsourceref() == 950) // New bot respawned
	{
		rbot=getparam(1);
		team=getparam(3);
		botname=getparam(2);
		botmode=0; // reset botmode
		botmode=BitSet(botmode,0x10000); // bot alive
		botmode=BitSet(botmode,0x200000); // bot is able to block with saber
		inv_weap0=1; // saber unlit
		inv_weap1=1; // fists
		inv_weap2=1; // bryar
		inv_weap3=0;
		inv_weap4=0;
		inv_weap5=0;
		inv_weap6=0;
		inv_weap7=0;
		inv_weap8=0;
		inv_weap9=0;
		inv_weap10=1; // saber lit
		shields=100;
		energy=50;
		power=0;
		inv_bacta=0;
		inv_raildets=0;
		powerboost=1; // normal fire rate
		SetThingHealth(rbot,100);
		SetThingUserData(rbot,team);
		ClearActorFlags(rbot, 8); // remove invulnerable
		ClearThingFlags(rbot, 4); // remove mag sealed
		SetTimerEx(5.0, 160, -1, -1); // ask for high scorer every 5 secs
		curweap=0;
		damager=-1;
		highscorer=-1;
  		setpulse(0.5);
	}
	else if (getsourceref() == 1000) // Bot killed - stop checking
	{
		setpulse(0);
		botmode=BitClear(botmode,0x10000);
		item=CreateThingNr(tmp_backpack,rbot); // create backpack and send info to backpack cog
		SendTrigger(-1, 12010, item, energy, power, inv_weap8); 
		SendTrigger(-1, 12011, item, inv_raildets, inv_weap4, -1); 
		SendTrigger(-1, 12012, item, inv_weap2, inv_weap3, inv_weap5); 
		SendTrigger(-1, 12013, item, inv_weap6, inv_weap7, inv_weap9);   
	}
	else if (getsourceref() == 11020) // Received special info <- current work here!!!
	{
		special=getparam(1);
		if (BitTest(special,0x02)) // tell bot to slow down
		{
			botmode=BitSet(botmode, 0x100000);
			SetTimerEx(3.0, 130, -1, -1); // allow bot to run at full speed again after 5 secs
		}
		if (BitTest(special,0x10) && inv_weap8 > 0 && !BitTest(botmode, 0x4000)) // lay mine & bot has mines & bot does not have a target
		{
			call select_weap8;
			SendTrigger(-1,101020,botid,8,1,-1); // lay a mine (secondary fire)
			inv_weap8 = inv_weap8-1;
			if (inv_weap8 > 0)
			{
				SendTrigger(-1,101020,botid,8,1,-1); // lay another mine (secondary fire)
				inv_weap8 = inv_weap8-1;
			}
		}
		if (BitTest(special,0x20) && !BitTest(botmode, 0x1000)) // send activate to other cogs if running forwards
		//if (BitTest(special,0x20)) // send activate to other cogs if running forwards
		{
			SendTrigger(-1, 11030, botid, rbot, -1, -1);
		}
		if (BitTest(special,0x40) && BitTest(botmode, 0x1000)) // send activate to other cogs if running backwards
		{
			//print("activate back");
			SendTrigger(-1, 11030, botid, rbot, -1, -1);
		}
		if (BitTest(special,0x80)) // wait for arrival
		{
			botmode=BitSet(botmode,0x80000); // tell bot to wait
		}
	}
	else if (getsourceref() == 12001) // get inventory items from backpack
	{
		energy=energy+getparam(1);
		if (energy>500) energy=500;
		power=power+getparam(2);
		if (power>500) power=500;
		inv_weap8=inv_weap8+getparam(3);
		if (inv_weap8>30) inv_weap8=30;
	}
	else if (getsourceref() == 12002) // get inventory items from backpack
	{
		inv_raildets=inv_raildets+getparam(1);
		if (inv_raildets>30) inv_raildets=30;
		inv_weap4=inv_weap4+getparam(2);
		if (inv_weap4>30) inv_weap4=30;
	}
	else if (getsourceref() == 12003) // get inventory items from backpack
	{
		if (getparam(1)) inv_weap2=1;
		if (getparam(2)) inv_weap3=1;
		if (getparam(3)) inv_weap5=1;
	}
	else if (getsourceref() == 12004) // get inventory items from backpack
	{
		if (getparam(1)) inv_weap6=1;
		if (getparam(2)) inv_weap7=1;
		if (getparam(3)) inv_weap9=1;
	}
	else if (getsourceref() == 100000) // Request update
	{
		forcemode=GetParam(2);
		SendTrigger(-1,100001,botid,target,botmode,curweap); // return current info
		SendTrigger(-1,100002,botid,shields,-1,-1); // return current info
	}
	else if (getsourceref() == 100003) // Update after damage
	{
		damage=GetParam(1);
		damager=GetParam(2);

		botmode=BitSet(botmode, 0x8000); // botmode -> under attack
		potential=getthingparent(damager); // who did the damage
		if (BitTest(gamemode,0x8)) // team play - check if target is on our team
		{
			if (GetThingType(potential) == 2 && GetThingUserData(potential) == team) potential=-1; // target is an actor and is on our team - don't target
			if (GetThingType(potential) == 10 && GetPlayerTeam(potential) == team) targetok=-1;   // target is a player and is on our team - don't target
		}
		if (potential != -1)
		{
			target=potential;
			AiSetFireTarget(rbot,target);
			botmode=BitSet(botmode,0x4000); // bot has target
		}

		KillTimerEx(170);
		SetTimerEx(2.0, 170, -1, -1); // forget who damaged the bot after 2.0 secs if no further damage

		if (shields > 0)  // if shields present - take damage from shields
		{
			shields=shields-damage;
			if (shields < 0) shields=0;
			return;
		}
	}
	else if (getsourceref() == 100010) // Turn on stats display
	{
		KillTimerEx(400);
		SetTimerEx(1.0,400,-1,-1); // display stats every 1.0 sec
	}
	else if (getsourceref() == 100011) // Turn off stats display
	{
		KillTimerEx(400);
	}
	else if (getsourceref() == 101030) // Force used against bot
	{
		enemy=GetParam(1);
		bin=GetParam(2);
		rank=GetParam(3);
		if (bin == 24) // Force Pull
		{
			if (curweap > 1 && curweap != 10) // don't force pull fists or saber
			{
				// Remove the weapon from the player
				if (curweap==4)
				{
					inv_weap4=inv_weap4-1;
					if (inv_weap4<0) inv_weap4=0;
				}
				else if (curweap==8)
				{
					inv_weap08=inv_weap8-1;
					if (inv_weap8<0) inv_weap8=0;
				}
				else inv_weap0[curweap]=0;
				call bestweapon; // Select next best weapon
			}
		}
		else if (bin == 31) // Force Grip
		{
			botmode=BitSet(botmode,0x400000); // bot is now 'gripped'
			KillTimerEx(31);
			SetTimerEx(0.8, 31, 0, 0);
		}
	}
	else if (getsourceref() == 101051) // returned highscorer
	{
		highscorer=GetParam(1);
	}
	return;

pulse:
	setpulse(0);
	call findpowerups;
	call findtarget;
	call bestweapon;
	call startfire;
	call setbotmode;
	setpulse(0.25);
	return;

findtarget:
	newtarget=-1;
	maxdot=-1;
	mindist=100;
	targetpriority=0;
	newtargetpriority=-1;

	potential = FirstThingInView(rbot, 270, 8.0, 0x404);  // find (0x404 - player or actor)
	while(potential != -1) // valid target
	{
		targetok=1;
		if (BitTest(gamemode,0x8)) // team play - check if target is on our team
		{
			if (GetThingType(potential) == 2 && GetThingUserData(potential) == team) targetok=0; // target is an actor and is on our team
			if (GetThingType(potential) == 10 && GetPlayerTeam(potential) == team) targetok=0;   // target is a player and is on our team
		}
		if (GetThingFlags(potential) & 0x200) targetok=0; // target is dead
		if (BitTest(GetSectorFlags(GetThingSector(potential)), 0x40)) targetok=0; // target in pit
		if ((GetActorFlags(potential) & 0x80) && !BitTest(forcemode,0x08) && difficulty<4) targetok=0; // target is invisible & force seeing is not enabled - except for high difficulty

		if (targetok && potential!=rbot && HasLOS(rbot,potential)) // target is still ok, is not itself and bot can see it
		{
			// Work out target priority

			dist=VectorDist(GetThingPos(rbot), GetThingPos(potential));
			if (dist > 0 && dist < 1) targetpriority=6; else targetpriority=3; // closer targets get higher priority

			if (damager != -1 && GetThingParent(damager) == potential) targetpriority=7; // whoever hurt the bot last
			
			if (BitTest(gamemode,0x8) && team==1 && captured_red==2 && redflag_taken==potential) targetpriority=10; // teamplay - bot on red team - red flag has been taken and potential has it
			if (BitTest(gamemode,0x8) && team==2 && captured_gold==2 && goldflag_taken==potential) targetpriority=10; // teamplay - bot on gold team - gold flag has been taken and potential has it


			if (targetpriority > newtargetpriority)
			{
				newtarget = potential;
				newtargetpriority=targetpriority;
			}

		}
		potential = NextThingInView();
	}

	target=newtarget;
	if (target == -1) // bot doesn't have a target
	{
		botmode=BitClear(botmode,0x4000);
	}
	else // bot has a target
	{
		AiSetFireTarget(rbot,target);
		botmode=BitSet(botmode,0x4000); 
	}
	return;

findpowerups:
	for (item=1;item<=maxthings;item=item+1) // check every item
	{
		// If bot is close to item and it is available
		if ((VectorDist(GetThingPos(rbot), GetThingPos(item)) < 0.3) && !(getthingflags(item) & 0x80000))
		{
			if (HasLOS(rbot, item))
			{
				SendTrigger(-1,12200,botid,item,rbot,-1); // send info to ctf_main cog
				call pickupitem; // bot can see item - pick it up
			}
		}
	}
	return;

pickupitem:
	if (getthingtemplate(item) == tmp_energycell)
	{
		if (energy<500)
		{
			energy=energy+20;
			if (energy>500) energy=500;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_powercell)
	{
		if (power<500)
		{
			power=power+25;
			if (power>500) power=500;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_weap4)
	{
		if (inv_weap4<30)
		{
			inv_weap4=inv_weap4+3;
			if (inv_weap4>30) inv_weap4=30;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_weap8)
	{
		if (inv_weap8<30);
		{
			inv_weap8=inv_weap8+5;
			if (inv_weap8>30) inv_weap8=30;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_raildets)
	{
		if (inv_raildets<30);
		{
			inv_raildets=inv_raildets+3;
			if (inv_raildets>30) inv_raildets=30;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_bacta)
	{
		if (inv_bacta<5);
		{
			inv_bacta=inv_bacta+1;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_health)
	{
		if (GetThingHealth(rbot)<100)
		{
			extra=GetThingHealth(rbot)+20;
			if (extra > 100) extra=100;
			SetThingHealth(rbot,extra);
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_shields)
	{
		if (shields<200)
		{
			shields=shields+20;
			if (shields>200) shields=100;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_supershield)
	{
		SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		SetActorFlags(rbot, 8); // invulnerable
		SetThingFlags(rbot, 4); // mag sealed
		SetTimerEx(30, 140, -1, -1); // switch off in 30 secs
	}
	else if (getthingtemplate(item) == tmp_powerboost)
	{
		SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		powerboost=2;
		SetTimerEx(30, 150, -1, -1); // switch off in 30 secs
	}
	else if (getthingtemplate(item) == tmp_revivepack)
	{
		if (shields<200 || GetThingHealth(rbot)<100)
		{
			shields=200;
			SetThingHealth(rbot,100);
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_fullshield)
	{
		if (shields<200)
		{
			shields=200;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_mana)
	{
		SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		SendTrigger(-1,101040,botid,100,0,-1); // tell srv to increase mana
	}
	else if (getthingtemplate(item) == tmp_lightside)
	{
		SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		SendTrigger(-1,101040,botid,400,1,-1); // tell srv to increase mana
	}
	else if (getthingtemplate(item) == tmp_darkside)
	{
		SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		SendTrigger(-1,101040,botid,400,2,-1); // tell srv to increase mana
	}
	else if (getthingtemplate(item) == tmp_weap3)
	{
		if (inv_weap3 == 0 || energy < 500)
		{
			inv_weap3=1;
			energy=energy+24;
			if (energy>500) energy=500;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_weap5)
	{
		if (inv_weap5 ==0 || power < 500)
		{
			inv_weap5=1;
			power=power+16;
			if (power>500) power=500;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_weap6)
	{
		if (inv_weap6 ==0 || power < 500)
		{
			inv_weap6=1;
			power=power+24;
			if (power>500) power=500;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}  
	}
	else if (getthingtemplate(item) == tmp_weap7)
	{
		if (inv_weap7 ==0 || inv_raildets < 30)
		{
			inv_weap7=1;
			inv_raildets=inv_raildets+6;
			if (inv_raildets>30) inv_raildets=30;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_weap9)
	{
		if (inv_weap9 ==0 || power < 500)
		{
			inv_weap9=1;
			power=power+32;
			if (power>500) power=500;
			SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
		}
	}
	else if (getthingtemplate(item) == tmp_backpack)
	{
		SendTrigger(-1, 12000, botid, item, -1, -1); // send info to backpack cog
		SendTrigger(-1,101010,botid,item,rbot,-1); // get client to pickup item
	}
	return;

bestweapon:
	if (!BitTest(gamemode,0x01) && BitTest(gamemode,0x02)) // no guns - sabers only
	{
		call select_weap10; // saber
		return;
	}
	else if (!BitTest(gamemode,0x01) && !BitTest(gamemode,0x02)) // no guns - no sabers
	{
		call select_weap1; // fists
		return;
	}

	if (BitTest(botmode,0x40000)) return; // don't select new weapon until old weapon mounted

	// Select best weapon based on difficulty
	if (difficulty < 3 || !Bittest(botmode,0x4000)) // always just use the biggest gun or just use sabers for saber only game - or bot has no target
	{
		if (inv_weap9==1 && power > 7)
		{
			call select_weap9;
		}
		else if (inv_weap7==1 && inv_raildets > 0)
		{
			call select_weap7;
		}
		else if (inv_weap6==1 && power > 0)
		{
			call select_weap6;
		}
		else if (inv_weap5==1 && power > 1)
		{
			call select_weap5;
		}
		else if (inv_weap3==1 && energy > 1)
		{
		call select_weap3;
		}
		else if (inv_weap2==1 && energy > 0)
		{
			call select_weap2;
		}
		else if (BitTest(gamemode,0x02)) call select_weap10; else call select_weap1; // if sabers allowed - select it otherwise select fists
	}
	else
	{		
		disttotarg=VectorDist(GetThingPos(rbot), GetThingPos(target));

		//Get the current weapon of our target
		if (GetThingType(target) == 2) // target is another bot
		{
			targweap=SendMessageEx(GetThingCaptureCog(target), user1, -1, -1, -1, -1);
		}
		else // target is a player
		{
			targweap=GetCurWeapon(target);
			if (targweap==11) targweap=10; // if player has saber, set it to 10 for simplicity
		}

		if (disttotarg <= 0.4) // very close range
		{
			if (targweap == 10) call select_weap10; // target has saber - switch to saber
			else if (inv_weap6==1 && power > 0)
			{
				call select_weap6;
			}
			else if (inv_weap5==1 && power > 1)
			{
				call select_weap5;
			}
			else if (inv_weap3==1 && energy > 1)
			{
			call select_weap3;
			}
			else if (inv_weap2==1 && energy > 0)
			{
				call select_weap2;
			}
		}
		else if (disttotarg > 0.4 && disttotarg < 0.9) // close range
		{
			if (targweap == 10) // target has saber
			{
				if (curweap == 2 || curweap == 3 || curweap ==5 || curweap ==6) // energy weapons
				{
					call select_weap10;
				}
			}
			else if (inv_weap9==1 && power > 7)
			{
				call select_weap9;
			}
			else if (inv_weap7==1 && inv_raildets > 0)
			{
				call select_weap7;
			}
			else if (inv_weap6==1 && power > 0)
			{
				call select_weap6;
			}
			else if (inv_weap5==1 && power > 1)
			{
				call select_weap5;
			}
			else if (inv_weap3==1 && energy > 1)
			{
			call select_weap3;
			}
			else if (inv_weap2==1 && energy > 0)
			{
				call select_weap2;
			}
			else if (BitTest(gamemode,0x02)) call select_weap10; else call select_weap1; // if sabers allowed - select it otherwise select fists
		}
		else // far range
		{
			if (inv_weap9==1 && power > 7)
			{
				call select_weap9;
			}
			else if (inv_weap7==1 && inv_raildets > 0)
			{
				call select_weap7;
			}
			else if (inv_weap6==1 && power > 0)
			{
				call select_weap6;
			}
			else if (inv_weap5==1 && power > 1)
			{
				call select_weap5;
			}
			else if (inv_weap3==1 && energy > 1)
			{
			call select_weap3;
			}
			else if (inv_weap2==1 && energy > 0)
			{
				call select_weap2;
			}
			else if (BitTest(gamemode,0x02)) call select_weap10; else call select_weap1; // if sabers allowed - select it otherwise select fists
		}
	}
	return;

select_weap1: // Fists
	if (curweap==1) return;
	curweap=1;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,3); else setarmedmode(rbot,0);
	firedelay=0.5;
	minrange=0;
	maxrange=0.3;
	return;

select_weap2: // Bryar Pistol
	firedelay=0.6/powerboost;
	if (curweap==2) return;
	curweap=2;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,4); else setarmedmode(rbot,1);
	minrange=0;
	maxrange=8.0;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	KillTimerEx(120); // failsafe
	SetTimerEx(0.5, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap3: // Stormtrooper Rifle
	firedelay=0.2/powerboost;
	if (curweap==3) return;
	curweap=3;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,4); else setarmedmode(rbot,1);
	minrange=0;
	maxrange=8.0;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	//KillTimerEx(120); // failsafe
	SetTimerEx(0.2, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap4: // Thermal Detonators
	if (curweap==4) return;
	curweap=4;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,3); else setarmedmode(rbot,0);
	firedelay=0.8;
	minrange=0.3;
	maxrange=2.0;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	KillTimerEx(120); // failsafe
	SetTimerEx(0.1, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap5: // Crossbow
	firedelay=0.6/powerboost;
	if (curweap==5) return;
	curweap=5;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,4); else setarmedmode(rbot,1);
	minrange=0;
	maxrange=8.0;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	KillTimerEx(120); // failsafe
	SetTimerEx(0.2, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap6: // Repeater
	firedelay=0.1/powerboost;
	if (curweap==6) return;
	curweap=6;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,4); else setarmedmode(rbot,1);
	minrange=0;
	maxrange=8.0;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	KillTimerEx(120); // failsafe
	SetTimerEx(0.2, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap7: // Railgun
	firedelay=1.0/powerboost;
	firedelay2=1.0/powerboost;
	if (curweap==7) return;
	curweap=7;
	if (difficulty > 2) ParseArg(rbot,"eyeoffset=(0.032/0.0/0.0)"); else ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // Set LOS from weapon's height
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,4); else setarmedmode(rbot,1);
	minrange=0.8;
	maxrange=8.0;
	//2nd fire vars [HR]
	minrange2=0.0;
	maxrange2=0.8;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	KillTimerEx(120); // failsafe
	SetTimerEx(0.6, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap8: // Sequencer Mines
	if (curweap==8) return;
	curweap=8;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,3); else setarmedmode(rbot,0);
	firedelay=0.8;
	minrange=0;
	maxrange=0;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	KillTimerEx(120); // failsafe
	SetTimerEx(0.1, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap9: // Concussion Rifle
	firedelay=1.2/powerboost;
	firedelay2=1.2/powerboost;
	if (curweap==9) return;
	curweap=9;
	if (difficulty > 2) ParseArg(rbot,"eyeoffset=(0.032/0.0/0.0)"); else ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // // Set LOS from weapon's height
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,4); else setarmedmode(rbot,1);
	minrange=0.8;
	maxrange=8.0;
	//2nd fire vars [HR]
	minrange2=0.0;
	maxrange2=0.8;
	botmode=BitSet(botmode,0x40000); // weapon not mounted
	KillTimerEx(120); // failsafe
	SetTimerEx(0.5, 120, -1, -1); // allow bot to fire after weapon is mounted
	return;

select_weap10: // Lightsaber
	if (curweap==10) return;
	curweap=10;
	ParseArg(rbot,"eyeoffset=(0.0/0.0/0.037)"); // set normal LOS
	SendTrigger(-1,101000,botid,curweap,rbot,-1); // tell client to change weapon
	if (getmajormode(rbot)>2) setarmedmode(rbot,5); else setarmedmode(rbot,2);
	firedelay=0.5;
	minrange=0;
	maxrange=0.4;
	return;

startfire:
	if (BitTest(botmode,0x40000) || !Bittest(botmode,0x4000) || !BitTest(botmode,0x10000)) return; // weapon not mounted or no target or bot has died
	if (BitTest(botmode,0x20000)) return; // bot is already attacking
	call firetarget;
	return;

firetarget:
//return; // hack to stop bots firing - testing only
	KillTimerEx(300); // make sure no other 'fire' target is active
	if (!BitTest(botmode,0x10000) || !Bittest(botmode,0x4000)) // bot dead or no target
	{
		botmode=BitClear(botmode,0x20000);
		return;
	}
	botmode=BitSet(botmode,0x20000); // bot is now attacking
	disttotarg=VectorDist(GetThingPos(rbot), GetThingPos(target));
	relpos=VectorSet("0.0","0.0", VectorZ(GetThingPos(target))-VectorZ(GetThingPos(rbot))); // work out relative position of target to bot
	if (disttotarg > minrange && disttotarg < maxrange && HasLOS(rbot,target)) // target within range & bot can see it
	{
		if (curweap == 1) // fists
		{
			SendTrigger(-1,101020,botid,1,0,nextanim); // tell client weapon fired - Alternate fists. (use '0' as primary - '1' as secondary fire option)
			nextanim = 1-nextanim;
		}
		else if (curweap == 2)
		{
			SendTrigger(-1,101020,botid,2,0,-1); // tell client weapon fired
			energy=energy-1;
		}
		else if (curweap == 3)
		{
			SendTrigger(-1,101020,botid,3,0,-1); // tell client weapon fired
			energy=energy-2;
		}
		else if (curweap == 4)
		{
			SendTrigger(-1,101020,botid,4,0,-1); // tell client weapon fired
			inv_weap4=inv_weap4-1;
		}
		else if (curweap == 5)
		{
			SendTrigger(-1,101020,botid,5,0,-1); // tell client weapon fired
			power=power-2;
		}
		else if (curweap == 6)
		{
			SendTrigger(-1,101020,botid,6,0,nextanim); // tell client weapon fired
			nextanim=1-nextanim;
			power=power-1;
		}
		else if (curweap == 7)
		{
			SendTrigger(-1,101020,botid,7,0,-1); // tell client weapon fired
			inv_raildets=inv_raildets-1;
		}
		else if (curweap == 9)
		{
			SendTrigger(-1,101020,botid,9,0,-1); // tell client weapon fired
			power=power-8;
		}
		else if (curweap == 10)
		{
			SendTrigger(-1, 2101, botid, rbot, -1, -1); // stop saber block animations
			botmode=BitSet(botmode,0x200000); // Fired saber, NOT ok to block
			SetTimerEx(0.5, 450, 0, 0); //In .5 secs, it's ok to block again

			if (GetMajorMode(rbot) == 5) // Underwater saber attacks
			{
				SendTrigger(-1, 101020, botid, 10, 0, nextanim);
				nextanim=0-nextanim;
				firedelay=1.0;
			}
			else // Land based saber attacks
			{
				dot=ThingViewDot(rbot,target);
				relpos=VectorSet(VectorX(GetThingPos(target))-VectorX(GetThingPos(rbot)),VectorY(GetThingPos(target))-VectorY(GetThingPos(rbot)),"0.0"); // work out relative position of target to bot
				if (dot > 0.4) // target is front of bot
				{
					maxdot=rand()*3;
					if (maxdot > 2)
					{
						SendTrigger(-1, 101020, botid,10, 6, -1);
						firedelay=2.0;
					}
					else if (maxdot > 1)
					{
						SendTrigger(-1, 101020, botid, 10, 4, nextanim);
						nextanim=0-nextanim;
						firedelay=0.8;
					}
					else
					{
						SendTrigger(-1, 101020, botid, 10, 5, slash);
						if (slash == 2) firedelay=0.25; else firedelay=1.0;
						slash=slash+1;
						if (slash > 2) slash=0;
					}
				}
				else if (VectorX(relpos) < 0) // target to the left
				{
					SendTrigger(-1, 101020, botid, 10, 2, -1);
					firedelay=0.8;
				}
				else // target to the right
				{
					SendTrigger(-1, 101020, botid, 10, 1, -1);
					firedelay=0.8;
				}
			}

		}
		SetTimerEx(firedelay, 300, -1, -1); // wait for a short time before firing again
	}
	else if ((curweap == 7 || curweap == 9) && disttotarg < maxrange && HasLOS(rbot,target)) // bot has either raildet or conc and target is too close for regular fire
	{
		if (curweap == 7) // raildet
		{
			if (difficulty < 1) SendTrigger(-1,101020,botid,7,0,-1); else SendTrigger(-1,101020,botid,7,1,-1); // if newbie only use regular fire else use secondary fire
			inv_raildets=inv_raildets-1;
		}
		else if (curweap == 9) // conc rifle
		{
			if (difficulty < 1) SendTrigger(-1,101020,botid,9,0,-1); else SendTrigger(-1,101020,botid,9,1,-1); // if newbie only use regular fire else use secondary fire
			power=power-8;
		}
		SetTimerEx(firedelay, 300, -1, -1); // wait for a short time before firing again
	}
	else
	{
		botmode=BitClear(botmode,0x20000); // bot is no longer attacking
		KillTimerEx(300); // make sure no other 'fire' target is active
	}
	return;

setbotmode:
	// Set botmode
	if (BitTest(gamemode, 0x01)) // allow guns
	{
		if (energy < 100) botmode=BitSet(botmode, 0x20); else botmode=BitClear(botmode, 0x20); // check energy cells
		if (power < 100) botmode=BitSet(botmode, 0x40); else botmode=BitClear(botmode, 0x40);  // check power cells
		if (inv_raildets < 10) botmode=BitSet(botmode, 0x80); else botmode=BitClear(botmode, 0x80);  // check rail dets
		if (inv_weap4 < 6) botmode=BitSet(botmode, 0x100); else botmode=BitClear(botmode, 0x100);  // check thrm dets
		if (inv_weap8 < 5) botmode=BitSet(botmode, 0x200); else botmode=BitClear(botmode, 0x200);  // check seq mines
		if (inv_weap5 !=1) botmode=BitSet(botmode, 0x10); else botmode=BitClear(botmode, 0x10); // check if bot has gun 4 (crossbow)
		if (inv_weap3 !=1) botmode=BitSet(botmode, 0x8); else botmode=BitClear(botmode, 0x8); // check if bot has gun 3 (st rifle)
		if (inv_weap6 !=1) botmode=BitSet(botmode, 0x4); else botmode=BitClear(botmode, 0x4); // check if bot has gun 2 (repeater)
		if (inv_weap7 !=1) botmode=BitSet(botmode, 0x2); else botmode=BitClear(botmode, 0x2); // check if bot has gun 1 (railgun)
		if (inv_weap9 !=1) botmode=BitSet(botmode, 0x1); else botmode=BitClear(botmode, 0x1); // check if bot has gun 0 (conc rifle)
	}
	else // clear all guns related seek flags
	{
		botmode=BitClear(botmode, 0x20); // energy cells
		botmode=BitClear(botmode, 0x40);  // power cells
		botmode=BitClear(botmode, 0x80);  // rail dets
		botmode=BitClear(botmode, 0x100);  // thrm dets
		botmode=BitClear(botmode, 0x200);  // seq mines
		botmode=BitClear(botmode, 0x10); // gun 4 (crossbow)
		botmode=BitClear(botmode, 0x8); // gun 3 (st rifle)
		botmode=BitClear(botmode, 0x4); // gun 2 (repeater)
		botmode=BitClear(botmode, 0x2); // gun 1 (railgun)
		botmode=BitClear(botmode, 0x1); // gun 0 (conc rifle)
	}
	if (GetThingHealth(rbot) < 50) botmode=BitSet(botmode, 0x400); else botmode=BitClear(botmode, 0x400); // check health
	if (shields < 70) botmode=BitSet(botmode, 0x800); else botmode=BitClear(botmode, 0x800); // check shields

	return;


timer:
	if(GetSenderId() == 31) // after force grip
	{
		botmode=BitSet(botmode,0x400000); // bot is not longer 'gripped'
	}
	if (GetSenderId() == 120) // allow fire after weapon is mounted
	{
		botmode=BitClear(botmode,0x40000);
	}
	if (GetSenderId() == 130) // allow bot to run full speed again after slowdown
	{
		botmode=BitClear(botmode, 0x100000); 
	}
	else if (GetSenderId() == 140) // after supershield
	{
		ClearActorFlags(rbot, 8); // remove invulnerable
		ClearThingFlags(rbot, 4); // remove mag sealed
	}
	else if (GetSenderId() == 150) // after powerboost
	{
		powerboost=1;
	}
	else if (GetSenderId() == 160) // ask for high score
	{
		SendTrigger(-1,101050,botid,-1,-1,-1); // ask for high scorer
		SetTimerEx(5.0, 160, -1, -1); // ask for high scorer every 5 secs
	}
	else if (GetSenderId() == 170) // Forget who damaged bot
	{
		damager=-1;
	}
	else if (GetSenderId() == 300) // fire again at target
	{
		call firetarget;
	}
	else if (GetSenderId() == 400) // display stats
	{
		return; // hack
		jkstringclear();
		jkStringConcatUNIString(-1, 1000+botname);
		jkStringConcatAsciiString(": health: ");
		jkStringConcatInt(GetThingHealth(rbot));  
		jkStringConcatAsciiString(" shields: ");
		jkStringConcatInt(shields);
		jkStringConcatAsciiString(" energy: ");
		jkStringConcatInt(energy);
		jkStringConcatAsciiString(" power: ");
		jkStringConcatInt(power);
		jkStringConcatAsciiString(" raildets: ");
		jkStringConcatInt(inv_raildets);
		jkStringConcatAsciiString(" weapon: ");
		jkStringConcatInt(curweap);
		//jkStringConcatAsciiString(" target: ");
		//if (BitTest(botmode,0x4000))
		//{
		//	jkStringConcatInt(target);
		//}
		//else jkStringConcatAsciiString(" none ");
		//if (BitTest(botmode,0x20000)) jkStringConcatAsciiString(" attacking ");
		//if (BitTest(botmode,0x40000)) jkStringConcatAsciiString(" weapon not mounted ");
		jkStringOutput();

		//jkstringclear();
		//jkStringConcatUNIString(-1, 1000+botname);
		//jkStringConcatAsciiString(" has available: ");
		//if (inv_weap9) jkStringConcatAsciiString("conc_rifle ");
		//if (inv_weap7) jkStringConcatAsciiString("railgun ");
		//if (inv_weap6) jkStringConcatAsciiString("repeater ");
		//if (inv_weap5) jkStringConcatAsciiString("bowcaster ");
		//if (inv_weap3) jkStringConcatAsciiString("st_rifle ");
		//if (inv_weap2) jkStringConcatAsciiString("bryar ");
		//jkStringOutput();

		//jkstringclear();
		//jkStringConcatUNIString(-1, 1000+botname);
		//jkStringConcatAsciiString(" needs: ");
		//if (BitTest(botmode, 0x400)) jkStringConcatAsciiString("health ");
		//if (BitTest(botmode, 0x800)) jkStringConcatAsciiString("shields ");
		//if (BitTest(botmode, 0x20)) jkStringConcatAsciiString("energy ");
		//if (BitTest(botmode, 0x40)) jkStringConcatAsciiString("power ");
		//if (BitTest(botmode, 0x80)) jkStringConcatAsciiString("raildets ");
		//if (BitTest(botmode, 0x100)) jkStringConcatAsciiString("thrmdets ");
		//if (BitTest(botmode, 0x200)) jkStringConcatAsciiString("seqmines ");
		//if (BitTest(botmode, 0x10)) jkStringConcatAsciiString("crossbow ");
		//if (BitTest(botmode, 0x8)) jkStringConcatAsciiString("strifle ");
		//if (BitTest(botmode, 0x4)) jkStringConcatAsciiString("repeater ");
		//if (BitTest(botmode, 0x2)) jkStringConcatAsciiString("railgun ");
		//if (BitTest(botmode, 0x1)) jkStringConcatAsciiString("concrifle ");
		//jkStringOutput();

		SetTimerEx(1.0,400,-1,-1); // display stats every 1.0 sec
	}
	else if (GetSenderId() == 450) // Allow bot to block again
	{
		botmode=BitClear(botmode,0x200000);
	}
	return;

end


