retarded bots(oh noes new problemz)

Topics regarding Scripting with Reality Factory
Post Reply
User avatar
darksmaster923
Posts: 1857
Joined: Wed Jan 03, 2007 10:32 pm
Location: Huntington Beach, California, USA

retarded bots(oh noes new problemz)

Post by darksmaster923 »

hello, since my other bots have....problems per say i modded genericmissile monster so it is awesome. when i changed my allies to that script they pwned the old buggy script enemies
BUT!!!!!! when i changed the enemies to that script, the enemies attacked and destroyed my allies and they did nothing! plus my allies were just going to their path with messed up anims! the run anim would sometimes freeze! noooooooooooo

Ally script

Code: Select all

{

	// Allied Bot Script
	// Made from Generic missile monster 

	GROUP				[Allies]	// name of monster group
	BOXWIDTH			[40]		// width and depth of bounding box
	HOSTILEPLAYER			[false]		// hostile to player
	HOSTILEDIFFERENT		[true]		// hostile to different Pawn group
	HOSTILESAME			[false]		// hostile to same Pawn group
	HOSTILETOGROUP			[enemy]		// hostile to this group
	HEALTHATTRIBUTE			[playerhealth]	// name of health attribute
	HEALTH				[50]		// initial amount of health
	SIGHTDIST			[500]		// max distance monster can see at idle
	ALERTSIGHTDIST			[600]		// max distance monster can see when alert
	FOV				[180]		// field of view in degrees
	YAWSPEED			[120]		// speed of rotation in deg/sec
	DAMAGEATTRIBUTE			[enemy_health]	// attribute damaged by attack
	ALERTTRIGGER			[AlertG]	// name of alert trigger
	SCALE				[1.4]		// amount to scale actor by
	
	SPAWNPOINT			[spawn_good]	// spawnpoint no 1
	SPAWNPOINT2			[spawn_good2]	// spawnpoint no 2
	FIRSTPOINT			[null]

	STAND				[idle]		// idle animation
	TURNL				[idle]		// turn left animation
	TURNR				[idle]		// turn right animation

	PAIN				[pain]		// pain animations
	PAIN1				[pain]
	PAIN2				[pain]
	PAIN3				[pain]
	PAINPERCENT			[0]		// percentage of time pain is shown

	DIE				[die]		// dying animations
	DIE1				[die2]
	DIE2				[die]
	DIE3				[die2]
	DIEHOLD				[5]		// time corpse still appears
	DIEFADE				[10]		// fadeout time of corpse
	KILLERX				[0]		// X pos of enemy before death
	KILLERY				[0]		// Y pos of enemy before death
	KILLERZ				[0]		// Z pos of enemy before death
	KILLER				[null]		// name o killer

	RUN				[run]		// running animation
	RUNSPEED			[300]		// average run speed
	RUNSOUND			[breath.wav]	

	WALK				[walk]		// walking animation
	WALKSPEED			[200]		// average walk speed

	WEAPON1				[M16_bot]
	WEAP1MAG			[30]
	WEAPON2				[FAMAS_bot]
	WEAP2MAG			[25]
	WEAPON3				[AWP_BOT]	// Sniper Weapon
	WEAP3MAG			[10]
	WEAPON4				[MP7_BOT]
	WEAP4MAG			[40]
	WEAPON5				[ump_bot]
	WEAP5MAG			[25]
	CURRENTWEAPAMMO			[0]
	ATTACKRANGE			[3000]
	SIGHTRANGE			[3400]
	RELOADTIME			[2]
	CLIPSIZE			[0]
	BULLET				[bad_shell]
	FIREBONE			[BIP01]
	WEAPON				[0]

	MISSILEATTACK			[shoot]		// missile attacking animation
	SHOOTUP				[shoot1]
	SHOOTDOWN			[shoot2]
	STRAFE				[strafe]	// strafeing animation
	RELOAD				[reload]	// reload animation
	SNIPERRANGE			[5000]		// distance for sniper rifle
	MISSILERANGE			[3400]		// max distance to start missile attack
	PROJECTILE			[rifle_shell]		// projectile name
	FIREBONE			[BIP01 R HAND]	// projectile launch bone
	OFFSETX				[0]		// launch offsets
	OFFSETY				[0]
	OFFSETZ				[0]
	ATTACKDELAY			[1]		// time between shots
	FIREDELAY			[0.8]		// delay after animation starts before projectile launch
	SKILL				[0]		// skill level 1 to 10

	LOSTTIME			[15]		// time to search for enemy before giving up
	POINTRADIUS			[20]		// radius from point when considered there


	// local variables - do not change

	
	RUNFUNC				[monster_run_start]		// monster run to attack function
	MISSILEFUNC			[monster_missile_start]		// monster missile function
	LOSTFUNC			[monster_lost_target_start]	// monster lost target function

	AS_NONE				[0]
	AS_MISSILE			[2]
	AS_STRAIGHT			[3]
	attack_delay			[0]
	lost_time			[0]
	back_up				[false]
	back_time			[0]
	left_time			[0]
	back_flag			[false]
	fire_delay			[0]
	skill_time			[0]
	attack_state			[0]
	lastorder			[null]
	lastanim			[null]
	killed				[false]

	// spawn pawn and do setup work

	Spawn[ ()
	{
		Console(true);
		BoxWidth(BOXWIDTH);						// set bounding box width/depth
		Scale(SCALE);							// scale actor
		AttributeOrder(HEALTHATTRIBUTE, HEALTH, "Death");		// give monster health
		HostilePlayer(HOSTILEPLAYER);					// set who monster is hostile to
		HostileSame(HOSTILESAME);
		HostileDifferent(HOSTILEDIFFERENT);
		TargetGroup(HOSTILETOGROUP);
		AvoidOrder("Avoidance");
		switch(random(1,5))		// lets bot choose between 5 weapons
		{
			case 1
			{
				SetWeapon("M16_bot");
				WEAPON = 1;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP1MAG + 0;
			}
			case 2
			{
				SetWeapon("FAMAS_bot");
				WEAPON = 2;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP2MAG + 0;
			}
			case 3
			{
				SetWeapon("AWP_BOT");		// Sets Sniping Weapon
				WEAPON = 3;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP3MAG + 0;
			}
			case 4
			{
				SetWeapon("MP7_BOT");
				WEAPON = 4;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP4MAG + 0;
			}
			case 5
			{
				SetWeapon("ump_bot");
				WEAPON = 5;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP5MAG + 0;
			}
		}
		CLIPSIZE = CURRENTWEAPAMMO + 0;
		FIRSTPOINT = self.point_name;
		SetFOV(FOV);							// set field of view
		SetGroup(GROUP);						// assign a group to belong to
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// seen a target to chase
		AddPainOrder("IdlePain", 100);					// show pain and trigger alert
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered 
		NewOrder("Patrol");
	} ]

	DieSpawn[ ()
	{
		Console(true);
		BoxWidth(BOXWIDTH);						// set bounding box width/depth
		HostilePlayer(HOSTILEPLAYER);					// set who monster is hostile to
		HostileSame(HOSTILESAME);
		HostileDifferent(HOSTILEDIFFERENT);
		TargetGroup(HOSTILETOGROUP);
		AvoidOrder("Avoidance");
		CURRENTWEAPAMMO = CLIPSIZE + 0;
		NewPoint(FIRSTPOINT);
		SetFOV(FOV);							// set field of view
		SetGroup(GROUP);						// assign a group to belong to
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// seen a target to chase
		AddPainOrder("IdlePain", 100);					// show pain and trigger alert
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered 
		if(random(1,10) < 6)
		{
			NewOrder("Patrol");
		}
		else
		{
			FindPointOrder("Patrol");
		}
	} ]

	Patrol[ ()
	{
		RotateMoveToPoint(RUN, YAWSPEED, RUNSPEED*SCALE, false, RUNSOUND);
		MoveToPoint(RUN, RUNSPEED*SCALE, RUNSOUND);
		FindTargetOrder(4000, "FoundTarget", "enemy_health" );
		AvoidOrder("Avoidance");
		AddPainOrder("IdlePain", 100);
		NextPoint();
		RestartOrder();
	} ]

	Avoidance[ ()
	{
		if(random(1,10) < 5)
		{
			MoveForward(RUN, RUNSPEED, 100, RUNSOUND);		// Runs forward
			MoveRight(RUN, RUNSPEED, 100, RUNSOUND );
			Jump(RUN, RUNSPEED, true, RUNSOUND );
			AddTimerOrder(1, 10, "CheckForPoints" );
		}
		else
		{
			MoveForward(RUN, RUNSPEED, 100, RUNSOUND);		// Run forward
			MoveLeft(RUN, RUNSPEED, 100, RUNSOUND );
			AddTimerOrder(1, 10, "CheckForPoints" );
		}
		Return();
	} ]

	CheckForPoints[ ()
	{
		if(self.point_vis)
		{
			NewOrder("Patrol");
		}
		else
		{
			FindPointOrder("Patrol");
		}
	} ]		

	// show pain at idle then trigger to alert

	IdlePain[ ()
	{
		switch(random(1,4)) // chose between 4 animations
		{
			case 1
			{
				PlayAnimation(PAIN, true, "");
			}
			case 2
			{
				PlayAnimation(PAIN1, true, "");
			}
			case 3
			{
				PlayAnimation(PAIN2, true, "");
			}
			case 4
			{
				PlayAnimation(PAIN3, true, "");
			}
		}
		NewOrder("FoundTarget");
	} ]	

	// start shifting from idle to alert

	IdleToAlert[ ()
	{
		FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// increase viewing distance
		AddPainOrder("AlertPain", PAINPERCENT);					// show pain
		AddTimerOrder(1, 10, "AlertToIdle");					// go to idle after 10 secs
		SetEventState(ALERTTRIGGER, false);					// turn off alert trigger
		NewOrder("Patrol");
	} ]

	// look around at alert looking for enemy

	Alert[ ()
	{
		FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);
		PlayAnimation(STAND, true, "");
		if(random(1,10)>3) // turn around once in awhile
		{
			if(random(1,10)>5)
			{
				Rotate(TURNL, 102, 0, 90, 0, "");
				Rotate(TURNL, 102, 0, 90, 0, "");
				Rotate(TURNL, 102, 0, 90, 0, "");
				Rotate(TURNL, 102, 0, 90, 0, "");
			}
			else
			{
				Rotate(TURNR, 108, 0, -90, 0, "");
				Rotate(TURNR, 108, 0, -90, 0, "");
				Rotate(TURNR, 108, 0, -90, 0, "");
				Rotate(TURNR, 108, 0, -90, 0, "");
			}
		}
		RestartOrder();
	} ]	

	// show pain at alert

	AlertPain[ ()
	{
		switch(random(1,4)) // play on of 4 animations
		{
			case 1
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				PlayAnimation(PAIN, true, "");
			}
			case 2
			{
				AddExplosion("blood2",FIREBONE,0,0,0);
				PlayAnimation(PAIN1, true, "");
			}
			case 3
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,0,0);
				PlayAnimation(PAIN2, true, "");
			}
			case 4
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,50,0);
				PlayAnimation(PAIN3, true, "");
			}
		}
		Return();
	} ]	

	// timed out at alert so go to idle

	AlertToIdle[ ()
	{
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// decrease viewing distance
		AddPainOrder("IdlePain", 100);					// show pain 
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered
		NewOrder("Patrol");
	} ]

	// found a target to attack

	FoundTarget[ ()
	{
		DelTimerOrder(1);	// get rid of alert timer
		LowLevel(RUNFUNC);	// attack functions are low level
	} ]

	// lost target while attacking so go back to idle again

	LostTarget[ ()
	{
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// seen a target to chase
		AddPainOrder("IdlePain", 100);					// show pain and trigger alert
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered
		NewOrder("Patrol");
	} ]

	// you died

	Death[ ()
	{
		KILLERX = self.enemy_X;
		KILLERY = self.enemy_Y;
		KILLERZ = self.enemy_Z;
		KILLER = self.target_name;
		killed = true;
		AddExplosion("blood",FIREBONE,0,0,0);
		AddExplosion("blood2",FIREBONE,0,50,0);
		if(random(1,10) < 6)
		{
			AnimateStop(DIE,DIEHOLD, "speak/imdieing.wav");
		}
		else
		{
			AnimateStop(DIE1,DIEHOLD, "die.wav");
		}
		ModifyAttribute("terr", 1, "Player");
		if(random(1,10) < 6)
		{			
                	TeleportToPoint(SPAWNPOINT,0,0,0);
		}
		else
		{			
                	TeleportToPoint(SPAWNPOINT2,0,0,0);
		}
        	SetAttribute(HEALTHATTRIBUTE,HEALTH); 
		NewOrder("DieSpawn");
	} ]

	// Low level attack routines

	// Start of run to attack

	monster_run_start[ ()
	{
		Animate(RUN);					// play run animation
		self.ThinkTime = 0;				// start thinking on next frame
		self.think = "monster_run";			// go to run attack routine
		self.ideal_yaw = enemy_yaw;			// set direction to run
		self.yaw_speed = YAWSPEED;			// set rotation speed
		back_up = false;				// initialize obsticle avoidance
		attack_state = AS_NONE;				// not attacking yet
	} ]

	// run to enemy to attack

	monster_run[ ()
	{
		self.ThinkTime = 0.1;
		if(self.health<=0)
		{
			drop();
			HighLevel("Death"); // dead
			return 0;
		}
		if(EnemyExist(DAMAGEATTRIBUTE) < 3)
		{
			HighLevel("LostTarget"); // enemy is gone or dead
			return 0;
		}
		if(enemy_vis = false)
		{
			self.think = LOSTFUNC; // lost sight of enemy
			lost_time = time + LOSTTIME;
			return 0;
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "run_reload";
		}
		if(random(1,10) < 2)
		{
			PlaySound("speak/wehavehostiles.wav",1000);
		}
		ai_run(random(RUNSPEED-2,RUNSPEED+2)); // run toward enemy
	} ]

	run_reload[ ()
	{
		ai_face();
		SetHoldAtEnd(true);
		if(self.animate_at_end)
		{
			CURRENTWEAPAMMO = CLIPSIZE + 0;
			self.think = "monster_run";
		}		
	} ]

	// start of lost sight of enemy routine

	monster_lost_target_start[ ()
	{
		Animate(RUN); // play run animation
		self.ThinkTime = 0;					// start thinking on next frame
		self.think = "monster_lost_target";
	} ]

	// go to last known location of enemy

	monster_lost_target[ ()
	{
		self.ThinkTime = 0.1;
		if(lost_time<time)
		{
			HighLevel("LostTarget"); // timed out while looking
			return 0;
		}
		if(self.health<=0)
		{
			drop();
			HighLevel("Death"); // died
			return 0;
		}
		if(self.in_pain = true and (random(1,10) < 1))
		{
			if(random(1,10) < 2)
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,50,0);
				PlaySound("speak/backup.wav", 1000);
			}
		}
		if(EnemyExist(DAMAGEATTRIBUTE) < 3)
		{
			HighLevel("LostTarget"); // enemy died or was removed
			return 0;
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "lost_reload";
		}
		if(enemy_vis = true)
		{
			if(random(1,10)>5)
			{
				PlaySound("speak/attack.wav", 1000);
			}
			else
			{
				PlaySound("speak/wehavehostiles.wav", 1000);
			}
			self.think = "monster_run_start"; // seen again so run to attack
			self.ThinkTime = 0;
			return 0;
		} 
		if(enemy_range>POINTRADIUS) // get close to last known location
		{
			walk_movetogoal(random(RUNSPEED-2,RUNSPEED+2));
		} 
		else
		{
			HighLevel("LostTarget"); // can't find at last known location
			return 0;
		}
	} ]

	// Reload the weapon

	lost_reload[ ()
	{
		ai_face();
		SetHoldAtEnd(true);
		if(self.animate_at_end)
		{
			CURRENTWEAPAMMO = CLIPSIZE + 0;
			self.think = "monster_lost_target_start";
		}		
	} ]

	// start of missile attack

	monster_missile_start[ ()
	{
		if(WEAPON = 3)
		{
			Animate(MISSILEATTACK); // play missile attack animation
			SetHoldAtEnd(true);
			self.ThinkTime = 0;
			self.think = "sniper_shoot";
			fire_delay = time + FIREDELAY; // set firing delay
			UpdateTarget();					// update target location
			skill_time = time + (SKILL*0.1);		// calculate next update time
			attack_delay = time + ATTACKDELAY;		// delay until next shot
		}
		else
		{	
			Animate(MISSILEATTACK); // play missile attack animation
			SetHoldAtEnd(true);
			self.ThinkTime = 0;
			self.think = "monster_missile";
			fire_delay = time + FIREDELAY; // set firing delay
			UpdateTarget();					// update target location
			skill_time = time + (SKILL*0.1);		// calculate next update time
			attack_delay = time + ATTACKDELAY;		// delay until next shot
		}
	} ]

	sniper_shoot[ ()
	{
		self.ThinkTime = 0.1;		
		if(self.health<=0)
		{
			SetHoldAtEnd(false);
			drop();
			HighLevel("Death"); 	// dead
			return 0;
		}
		exist = EnemyExist(DAMAGEATTRIBUTE);
		if(exist < 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead and gone
			return 0;
		}
		if(exist = 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead but body remains
			return 0;
		}
		if(self.enemy_vis = false)
		{
			self.think = LOSTFUNC; 	// lost sight of enemy
			lost_time = self.time + LOSTTIME;
			SetHoldAtEnd(false);
			return 0;
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "shoot_reload";
		}
		if(self.enemy_range>SNIPERRANGE)
		{
			self.think = RUNFUNC; 	// too far away so run toward
			SetHoldAtEnd(false);
			return 0;
		}		
		if(skill_time<self.time) 	// update according to skill level
		{
			UpdateTarget();		// update target location
			skill_time = self.time + (SKILL*0.1);
			ai_face();		// face enemy while attacking
		}
		if(fire_delay<self.time) 	// delay after animation starts before firing
		{
			FireProjectile("sniper_shell", FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav", 500);
			SetHoldAtEnd(false);
			fire_delay = self.time + 1000; 	// set delay well ahead so it is ignored
		}

		if(self.animate_at_end = true)
		{
			if(attack_delay < self.time)
			{
				self.think = "shoot_start"; 	// go back to missile attack
				SetHoldAtEnd(false);
				self.ThinkTime = 0.1;
			}
		} 
	} ]

	// attack target with projectile

	monster_missile[ ()
	{
		self.ThinkTime = 0.2;
		debug(CURRENTWEAPAMMO);
		if(self.health<=0)
		{
			drop();
			SetHoldAtEnd(false);
			HighLevel("Death"); // dead
			return 0;
		}
		if(self.in_pain = true and (random(1,10) < 1))
		{
			if(random(1,10) < 2)
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,50,0);
			}
		}
		exist = EnemyExist(DAMAGEATTRIBUTE);
		if(exist < 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead and gone
			return 0;
		}
		if(exist = 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead but body remains
			return 0;
		}
		if(enemy_vis = false)
		{
			self.think = LOSTFUNC; // lost sight of enemy
			lost_time = time + LOSTTIME;
			SetHoldAtEnd(false);
			return 0;
		}
		if(enemy_range>MISSILERANGE)
		{
			self.think = RUNFUNC; // too far away so run toward
			SetHoldAtEnd(false);
			return 0;
		}
		if(skill_time < time) // update according to skill level
		{
			UpdateTarget();		// update target location
			skill_time = time + (SKILL*0.1);
			ai_face();	// face enemy while attacking
		}
		if(enemy_range<MISSILERANGE) // delay after animation starts before firing
		{
			UpdateTarget();		// update target location
			Animate(MISSILEATTACK);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			SetTargetPoint(random(-20,20),1000*sin(-self.enemy_pitch) + random(-20,20) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
			FireProjectile(PROJECTILE,"BIP01",0,0,0,"enemy_health");
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav");
		}
		if(self.enemy_Y > Integer(self.current_Y + 100))
		{
			UpdateTarget();		// update target location
			Animate(SHOOTUP);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			FireProjectile("bad_shell", "BIP 01", 0, 0, 25, "enemy_health");
			AddExplosion("Muzzleflash2","BIP 01 R HAND",0,0,0);
			PlaySound("good.wav", 500);
			SetHoldAtEnd(false);
		}
		if(self.enemy_Y < Integer(self.current_Y - 100))
		{
			UpdateTarget();		// update target location
			Animate(SHOOTDOWN);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, "enemy_health");
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav", 500);
			SetHoldAtEnd(false);
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "shoot_reload";
		}
		if(random(1,10) <2)
		{
			Animate(STRAFE);
			if(random(1,10) < 6)
			{
				ForceLeft(30);
				return 0;
			}
			else
			{
				ForceRight(30);
				return 0;
			}
		}
		if(fire_delay<time) 				// delay after animation starts before firing
		{
			if(random(1,10) < 5)
			{
				Animate(STRAFE);
				ForceRight(10);
				return 0;
			}
			else
			{
				Animate(STRAFE);
				ForceLeft(10);
				return 0;
			}
			UpdateTarget();		// update target location
			Animate(MISSILEATTACK);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			SetTargetPoint(random(-20,20),1000*sin(-self.enemy_pitch) + random(-20,20) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
			FireProjectile(PROJECTILE,"BIP01",0,0,0,"enemy_health");
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav");
		}
		if(self.animate_at_end = true)
		{
			if(attack_delay < time)
			{
				self.think = "monster_missile_start"; // go back to missile attack
				SetHoldAtEnd(false);
				self.ThinkTime = 0.1;
			}
		} 
	} ]

	// Reload the weapon

	shoot_reload[ ()
	{
		ai_face();
		SetHoldAtEnd(true);
		if(self.animate_at_end)
		{
			CURRENTWEAPAMMO = CLIPSIZE + 0;
			self.think = "monster_missile_start";
		}		
	} ]

	// Drop that gun soldier
	drop[ ()
	{
		if(WEAPON = 1)
		{
			SetPosition("m16", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 2)
		{
			SetPosition("famas", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 3)
		{
			SetPosition("awp", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 4)
		{
			SetPosition("mp7", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 5)
		{
			SetPosition("ump", self.current_X, self.current_Y, self.current_Z);
		}
	} ]

	// basic AI routines

	// run toward enemy and see if you are ready to attack

	ai_run[ (dist)
	{
		if (attack_state = AS_MISSILE) // do missile attack
		{
			ai_run_missile();
			return 0;
		}
		if (CheckAnyAttack()) // check if you can start the actual attack
		{
			return 0;
		}
		walk_movetogoal(dist); // else move toward the enemy
	} ]

	// missile attack setup

	ai_run_missile[ ()
	{
		ai_face();
		if(FacingIdeal()) // got close enough
		{
			self.think = MISSILEFUNC;	// start missile attack
			attack_state = AS_STRAIGHT;
			UpdateTarget();
			skill_time = time + (SKILL*0.1);
		}
	} ]

	// face enemy

	ai_face[ ()
	{
		self.ideal_yaw = enemy_yaw;
		ChangeYaw(); // rotate to face enemy
	} ]

	// use walkmove to naviagte to enemy

	walk_movetogoal[ (dist)
	{
		if(IsFalling = true)
		{
			return 0;	// don't move while falling
		} 
		if(back_up = false)
		{
			ai_face();	// turn to face enemy
			if(FacingIdeal())
			{
				if(walkmove(self.current_yaw, dist) = true)
				{
					return 0;	// can move in current direction
				}
				else
				{
					if(random(1,10)<3)	// backup and move sideways
					{
						back_up = true;
						back_time = time + 0.5;
						back_flag = false;
						return 0;
					}
					else 
					{ 
						ForceUp(30);	// jump up, forward and to side
						ForceForward(30);
						if(random(1,10)<6)
						{
							ForceRight(30);
						}
						else
						{
							ForceLeft(30);
						} 
					} 
				} 
			}
		}
		else
		{
			if(back_flag = false) // go backward 1/2 sec
			{
				if(back_time > time)
				{
					walkmove((self.current_yaw-(180*0.0174532925199433)), dist);
					return 0;
				}
				else
				{
					back_time = time + 0.5;
					back_flag = true;
				}
			}
			if(back_time > time) // go sideways 1/2 sec
			{
				walkmove((self.current_yaw-(90*0.0174532925199433)), dist);
				return 0;
			}
			back_up = false;
		}
	} ]


	// check if nearly facing enemy

	FacingIdeal[ ()
	{
		selfangle = self.current_yaw/0.0174532925199433; // your direction in degrees
		idealangle = self.ideal_yaw/0.0174532925199433;	// his direction in degrees
		delta = selfangle - idealangle; // difference in directions
		if (delta > -20 and delta < 20) // within 20 degrees is close enough
		{
			return true;
		}
		return false;
	} ]

	// check if ready to do actual attacking

	CheckAnyAttack[ ()
	{
		if(attack_delay>time)
		{
			return false;
		}
		if(enemy_range<MISSILERANGE) // inside missile range
		{
			attack_state = AS_MISSILE; // do a missile attack
			return true;
		}
		return false;
	} ]
}

enemy script
{

Code: Select all

	// Enemy Bot Script
	// Made from Generic missile monster 

	GROUP				[Enemy]	// name of monster group
	BOXWIDTH			[40]		// width and depth of bounding box
	HOSTILEPLAYER			[true]		// hostile to player
	HOSTILEDIFFERENT		[true]		// hostile to different Pawn group
	HOSTILESAME			[false]		// hostile to same Pawn group
	HOSTILETOGROUP			[enemy]		// hostile to this group
	HEALTHATTRIBUTE			[enemy_health]	// name of health attribute
	HEALTH				[50]		// initial amount of health
	SIGHTDIST			[500]		// max distance monster can see at idle
	ALERTSIGHTDIST			[600]		// max distance monster can see when alert
	FOV				[180]		// field of view in degrees
	YAWSPEED			[120]		// speed of rotation in deg/sec
	DAMAGEATTRIBUTE			[playerhealth]	// attribute damaged by attack
	ALERTTRIGGER			[AlertG]	// name of alert trigger
	SCALE				[1.4]		// amount to scale actor by
	
	SPAWNPOINT			[spawn_enemy]	// spawnpoint no 1
	SPAWNPOINT2			[spawn_enemy2]	// spawnpoint no 2
	FIRSTPOINT			[null]

	STAND				[idle]		// idle animation
	TURNL				[idle]		// turn left animation
	TURNR				[idle]		// turn right animation

	PAIN				[pain]		// pain animations
	PAIN1				[pain]
	PAIN2				[pain]
	PAIN3				[pain]
	PAINPERCENT			[0]		// percentage of time pain is shown

	DIE				[die]		// dying animations
	DIE1				[die2]
	DIE2				[die]
	DIE3				[die2]
	DIEHOLD				[5]		// time corpse still appears
	DIEFADE				[10]		// fadeout time of corpse
	KILLERX				[0]		// X pos of enemy before death
	KILLERY				[0]		// Y pos of enemy before death
	KILLERZ				[0]		// Z pos of enemy before death
	KILLER				[null]		// name o killer

	RUN				[run]		// running animation
	RUNSPEED			[300]		// average run speed
	RUNSOUND			[breath.wav]	

	WALK				[walk]		// walking animation
	WALKSPEED			[200]		// average walk speed

	WEAPON1				[M16_bot]
	WEAP1MAG			[30]
	WEAPON2				[FAMAS_bot]
	WEAP2MAG			[25]
	WEAPON3				[AWP_BOT]	// Sniper Weapon
	WEAP3MAG			[10]
	WEAPON4				[MP7_BOT]
	WEAP4MAG			[40]
	WEAPON5				[ump_bot]
	WEAP5MAG			[25]
	CURRENTWEAPAMMO			[0]
	ATTACKRANGE			[3000]
	SIGHTRANGE			[3400]
	RELOADTIME			[2]
	CLIPSIZE			[0]
	BULLET				[bad_shell]
	FIREBONE			[BIP01]
	WEAPON				[0]

	MISSILEATTACK			[shoot]		// missile attacking animation
	SHOOTUP				[shoot1]
	SHOOTDOWN			[shoot2]
	STRAFE				[strafe]	// strafeing animation
	RELOAD				[reload]	// reload animation
	SNIPERRANGE			[5000]		// distance for sniper rifle
	MISSILERANGE			[3400]		// max distance to start missile attack
	PROJECTILE			[bad_shell]		// projectile name
	FIREBONE			[BIP01 R HAND]	// projectile launch bone
	OFFSETX				[0]		// launch offsets
	OFFSETY				[0]
	OFFSETZ				[0]
	ATTACKDELAY			[1]		// time between shots
	FIREDELAY			[0.8]		// delay after animation starts before projectile launch
	SKILL				[0]		// skill level 1 to 10

	LOSTTIME			[15]		// time to search for enemy before giving up
	POINTRADIUS			[20]		// radius from point when considered there


	// local variables - do not change

	
	RUNFUNC				[monster_run_start]		// monster run to attack function
	MISSILEFUNC			[monster_missile_start]		// monster missile function
	LOSTFUNC			[monster_lost_target_start]	// monster lost target function

	AS_NONE				[0]
	AS_MISSILE			[2]
	AS_STRAIGHT			[3]
	attack_delay			[0]
	lost_time			[0]
	back_up				[false]
	back_time			[0]
	left_time			[0]
	back_flag			[false]
	fire_delay			[0]
	skill_time			[0]
	attack_state			[0]
	lastorder			[null]
	lastanim			[null]
	killed				[false]

	// spawn pawn and do setup work

	Spawn[ ()
	{
		Console(true);
		BoxWidth(BOXWIDTH);						// set bounding box width/depth
		Scale(SCALE);							// scale actor
		AttributeOrder(HEALTHATTRIBUTE, HEALTH, "Death");		// give monster health
		HostilePlayer(HOSTILEPLAYER);					// set who monster is hostile to
		HostileSame(HOSTILESAME);
		HostileDifferent(HOSTILEDIFFERENT);
		TargetGroup(HOSTILETOGROUP);
		AvoidOrder("Avoidance");
		switch(random(1,5))		// lets bot choose between 5 weapons
		{
			case 1
			{
				SetWeapon("M16_bot");
				WEAPON = 1;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP1MAG + 0;
			}
			case 2
			{
				SetWeapon("FAMAS_bot");
				WEAPON = 2;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP2MAG + 0;
			}
			case 3
			{
				SetWeapon("AWP_BOT");		// Sets Sniping Weapon
				WEAPON = 3;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP3MAG + 0;
			}
			case 4
			{
				SetWeapon("MP7_BOT");
				WEAPON = 4;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP4MAG + 0;
			}
			case 5
			{
				SetWeapon("ump_bot");
				WEAPON = 5;			// Weapon Number. Used in Attack cmds.
				CURRENTWEAPAMMO = WEAP5MAG + 0;
			}
		}
		CLIPSIZE = CURRENTWEAPAMMO + 0;
		FIRSTPOINT = self.point_name;
		SetFOV(FOV);							// set field of view
		SetGroup(GROUP);						// assign a group to belong to
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// seen a target to chase
		AddPainOrder("IdlePain", 100);					// show pain and trigger alert
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered 
		NewOrder("Patrol");
	} ]

	DieSpawn[ ()
	{
		Console(true);
		BoxWidth(BOXWIDTH);						// set bounding box width/depth
		HostilePlayer(HOSTILEPLAYER);					// set who monster is hostile to
		HostileSame(HOSTILESAME);
		HostileDifferent(HOSTILEDIFFERENT);
		TargetGroup(HOSTILETOGROUP);
		AvoidOrder("Avoidance");
		CURRENTWEAPAMMO = CLIPSIZE + 0;
		NewPoint(FIRSTPOINT);
		SetFOV(FOV);							// set field of view
		SetGroup(GROUP);						// assign a group to belong to
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// seen a target to chase
		AddPainOrder("IdlePain", 100);					// show pain and trigger alert
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered 
		if(random(1,10) < 6)
		{
			NewOrder("Patrol");
		}
		else
		{
			FindPointOrder("Patrol");
		}
	} ]

	Patrol[ ()
	{
		RotateMoveToPoint(RUN, YAWSPEED, RUNSPEED*SCALE, false, RUNSOUND);
		MoveToPoint(RUN, RUNSPEED*SCALE, RUNSOUND);
		FindTargetOrder(4000, "FoundTarget", "playerhealth" );
		AvoidOrder("Avoidance");
		AddPainOrder("IdlePain", 100);
		NextPoint();
		RestartOrder();
	} ]

	Avoidance[ ()
	{
		if(random(1,10) < 5)
		{
			MoveForward(RUN, RUNSPEED, 100, RUNSOUND);		// Runs forward
			MoveRight(RUN, RUNSPEED, 100, RUNSOUND );
			Jump(RUN, RUNSPEED, true, RUNSOUND );
			AddTimerOrder(1, 10, "CheckForPoints" );
		}
		else
		{
			MoveForward(RUN, RUNSPEED, 100, RUNSOUND);		// Run forward
			MoveLeft(RUN, RUNSPEED, 100, RUNSOUND );
			AddTimerOrder(1, 10, "CheckForPoints" );
		}
		Return();
	} ]

	CheckForPoints[ ()
	{
		if(self.point_vis)
		{
			NewOrder("Patrol");
		}
		else
		{
			FindPointOrder("Patrol");
		}
	} ]		

	// show pain at idle then trigger to alert

	IdlePain[ ()
	{
		switch(random(1,4)) // chose between 4 animations
		{
			case 1
			{
				PlayAnimation(PAIN, true, "");
			}
			case 2
			{
				PlayAnimation(PAIN1, true, "");
			}
			case 3
			{
				PlayAnimation(PAIN2, true, "");
			}
			case 4
			{
				PlayAnimation(PAIN3, true, "");
			}
		}
		NewOrder("FoundTarget");
	} ]	

	// start shifting from idle to alert

	IdleToAlert[ ()
	{
		FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// increase viewing distance
		AddPainOrder("AlertPain", PAINPERCENT);					// show pain
		AddTimerOrder(1, 10, "AlertToIdle");					// go to idle after 10 secs
		SetEventState(ALERTTRIGGER, false);					// turn off alert trigger
		NewOrder("Patrol");
	} ]

	// look around at alert looking for enemy

	Alert[ ()
	{
		FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);
		PlayAnimation(STAND, true, "");
		if(random(1,10)>3) // turn around once in awhile
		{
			if(random(1,10)>5)
			{
				Rotate(TURNL, 102, 0, 90, 0, "");
				Rotate(TURNL, 102, 0, 90, 0, "");
				Rotate(TURNL, 102, 0, 90, 0, "");
				Rotate(TURNL, 102, 0, 90, 0, "");
			}
			else
			{
				Rotate(TURNR, 108, 0, -90, 0, "");
				Rotate(TURNR, 108, 0, -90, 0, "");
				Rotate(TURNR, 108, 0, -90, 0, "");
				Rotate(TURNR, 108, 0, -90, 0, "");
			}
		}
		RestartOrder();
	} ]	

	// show pain at alert

	AlertPain[ ()
	{
		switch(random(1,4)) // play on of 4 animations
		{
			case 1
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				PlayAnimation(PAIN, true, "");
			}
			case 2
			{
				AddExplosion("blood2",FIREBONE,0,0,0);
				PlayAnimation(PAIN1, true, "");
			}
			case 3
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,0,0);
				PlayAnimation(PAIN2, true, "");
			}
			case 4
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,50,0);
				PlayAnimation(PAIN3, true, "");
			}
		}
		Return();
	} ]	

	// timed out at alert so go to idle

	AlertToIdle[ ()
	{
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// decrease viewing distance
		AddPainOrder("IdlePain", 100);					// show pain 
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered
		NewOrder("Patrol");
	} ]

	// found a target to attack

	FoundTarget[ ()
	{
		DelTimerOrder(1);	// get rid of alert timer
		LowLevel(RUNFUNC);	// attack functions are low level
	} ]

	// lost target while attacking so go back to idle again

	LostTarget[ ()
	{
		FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);	// seen a target to chase
		AddPainOrder("IdlePain", 100);					// show pain and trigger alert
		AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0);		// go to alert when triggered
		NewOrder("Patrol");
	} ]

	// you died

	Death[ ()
	{
		KILLERX = self.enemy_X;
		KILLERY = self.enemy_Y;
		KILLERZ = self.enemy_Z;
		KILLER = self.target_name;
		killed = true;
		AddExplosion("blood",FIREBONE,0,0,0);
		AddExplosion("blood2",FIREBONE,0,50,0);
		if(random(1,10) < 6)
		{
			AnimateStop(DIE,DIEHOLD, "speak/imdieing.wav");
		}
		else
		{
			AnimateStop(DIE1,DIEHOLD, "die.wav");
		}
		ModifyAttribute("terr", 1, "Player");
		if(random(1,10) < 6)
		{			
                	TeleportToPoint(SPAWNPOINT,0,0,0);
		}
		else
		{			
                	TeleportToPoint(SPAWNPOINT2,0,0,0);
		}
        	SetAttribute(HEALTHATTRIBUTE,HEALTH); 
		NewOrder("DieSpawn");
	} ]

	// Low level attack routines

	// Start of run to attack

	monster_run_start[ ()
	{
		Animate(RUN);					// play run animation
		self.ThinkTime = 0;				// start thinking on next frame
		self.think = "monster_run";			// go to run attack routine
		self.ideal_yaw = enemy_yaw;			// set direction to run
		self.yaw_speed = YAWSPEED;			// set rotation speed
		back_up = false;				// initialize obsticle avoidance
		attack_state = AS_NONE;				// not attacking yet
	} ]

	// run to enemy to attack

	monster_run[ ()
	{
		self.ThinkTime = 0.1;
		if(self.health<=0)
		{
			drop();
			HighLevel("Death"); // dead
			return 0;
		}
		if(EnemyExist(DAMAGEATTRIBUTE) < 3)
		{
			HighLevel("LostTarget"); // enemy is gone or dead
			return 0;
		}
		if(enemy_vis = false)
		{
			self.think = LOSTFUNC; // lost sight of enemy
			lost_time = time + LOSTTIME;
			return 0;
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "run_reload";
		}
		if(random(1,10) < 2)
		{
			PlaySound("speak/wehavehostiles.wav",1000);
		}
		ai_run(random(RUNSPEED-2,RUNSPEED+2)); // run toward enemy
	} ]

	run_reload[ ()
	{
		ai_face();
		SetHoldAtEnd(true);
		if(self.animate_at_end)
		{
			CURRENTWEAPAMMO = CLIPSIZE + 0;
			self.think = "monster_run";
		}		
	} ]

	// start of lost sight of enemy routine

	monster_lost_target_start[ ()
	{
		Animate(RUN); // play run animation
		self.ThinkTime = 0;					// start thinking on next frame
		self.think = "monster_lost_target";
	} ]

	// go to last known location of enemy

	monster_lost_target[ ()
	{
		self.ThinkTime = 0.1;
		if(lost_time<time)
		{
			HighLevel("LostTarget"); // timed out while looking
			return 0;
		}
		if(self.health<=0)
		{
			drop();
			HighLevel("Death"); // died
			return 0;
		}
		if(self.in_pain = true and (random(1,10) < 1))
		{
			if(random(1,10) < 2)
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,50,0);
				PlaySound("speak/backup.wav", 1000);
			}
		}
		if(EnemyExist(DAMAGEATTRIBUTE) < 3)
		{
			HighLevel("LostTarget"); // enemy died or was removed
			return 0;
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "lost_reload";
		}
		if(enemy_vis = true)
		{
			if(random(1,10)>5)
			{
				PlaySound("speak/attack.wav", 1000);
			}
			else
			{
				PlaySound("speak/wehavehostiles.wav", 1000);
			}
			self.think = "monster_run_start"; // seen again so run to attack
			self.ThinkTime = 0;
			return 0;
		} 
		if(enemy_range>POINTRADIUS) // get close to last known location
		{
			walk_movetogoal(random(RUNSPEED-2,RUNSPEED+2));
		} 
		else
		{
			HighLevel("LostTarget"); // can't find at last known location
			return 0;
		}
	} ]

	// Reload the weapon

	lost_reload[ ()
	{
		ai_face();
		SetHoldAtEnd(true);
		if(self.animate_at_end)
		{
			CURRENTWEAPAMMO = CLIPSIZE + 0;
			self.think = "monster_lost_target_start";
		}		
	} ]

	// start of missile attack

	monster_missile_start[ ()
	{
		if(WEAPON = 3)
		{
			Animate(MISSILEATTACK); // play missile attack animation
			SetHoldAtEnd(true);
			self.ThinkTime = 0;
			self.think = "sniper_shoot";
			fire_delay = time + FIREDELAY; // set firing delay
			UpdateTarget();					// update target location
			skill_time = time + (SKILL*0.1);		// calculate next update time
			attack_delay = time + ATTACKDELAY;		// delay until next shot
		}
		else
		{	
			Animate(MISSILEATTACK); // play missile attack animation
			SetHoldAtEnd(true);
			self.ThinkTime = 0;
			self.think = "monster_missile";
			fire_delay = time + FIREDELAY; // set firing delay
			UpdateTarget();					// update target location
			skill_time = time + (SKILL*0.1);		// calculate next update time
			attack_delay = time + ATTACKDELAY;		// delay until next shot
		}
	} ]

	sniper_shoot[ ()
	{
		self.ThinkTime = 0.1;		
		if(self.health<=0)
		{
			SetHoldAtEnd(false);
			drop();
			HighLevel("Death"); 	// dead
			return 0;
		}
		exist = EnemyExist(DAMAGEATTRIBUTE);
		if(exist < 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead and gone
			return 0;
		}
		if(exist = 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead but body remains
			return 0;
		}
		if(self.enemy_vis = false)
		{
			self.think = LOSTFUNC; 	// lost sight of enemy
			lost_time = self.time + LOSTTIME;
			SetHoldAtEnd(false);
			return 0;
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "shoot_reload";
		}
		if(self.enemy_range>SNIPERRANGE)
		{
			self.think = RUNFUNC; 	// too far away so run toward
			SetHoldAtEnd(false);
			return 0;
		}		
		if(skill_time<self.time) 	// update according to skill level
		{
			UpdateTarget();		// update target location
			skill_time = self.time + (SKILL*0.1);
			ai_face();		// face enemy while attacking
		}
		if(fire_delay<self.time) 	// delay after animation starts before firing
		{
			FireProjectile("sniper_shell", FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav", 500);
			SetHoldAtEnd(false);
			fire_delay = self.time + 1000; 	// set delay well ahead so it is ignored
		}

		if(self.animate_at_end = true)
		{
			if(attack_delay < self.time)
			{
				self.think = "shoot_start"; 	// go back to missile attack
				SetHoldAtEnd(false);
				self.ThinkTime = 0.1;
			}
		} 
	} ]

	// attack target with projectile

	monster_missile[ ()
	{
		self.ThinkTime = 0.2;
		debug(CURRENTWEAPAMMO);
		if(self.health<=0)
		{
			drop();
			SetHoldAtEnd(false);
			HighLevel("Death"); // dead
			return 0;
		}
		if(self.in_pain = true and (random(1,10) < 1))
		{
			if(random(1,10) < 2)
			{
				AddExplosion("blood",FIREBONE,0,0,0);
				AddExplosion("blood2",FIREBONE,0,50,0);
			}
		}
		exist = EnemyExist(DAMAGEATTRIBUTE);
		if(exist < 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead and gone
			return 0;
		}
		if(exist = 2)
		{
			SetHoldAtEnd(false);
			HighLevel("LostTarget"); // enemy is dead but body remains
			return 0;
		}
		if(enemy_vis = false)
		{
			self.think = LOSTFUNC; // lost sight of enemy
			lost_time = time + LOSTTIME;
			SetHoldAtEnd(false);
			return 0;
		}
		if(enemy_range>MISSILERANGE)
		{
			self.think = RUNFUNC; // too far away so run toward
			SetHoldAtEnd(false);
			return 0;
		}
		if(skill_time < time) // update according to skill level
		{
			UpdateTarget();		// update target location
			skill_time = time + (SKILL*0.1);
			ai_face();	// face enemy while attacking
		}
		if(enemy_range<MISSILERANGE) // delay after animation starts before firing
		{
			UpdateTarget();		// update target location
			Animate(MISSILEATTACK);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			SetTargetPoint(random(-20,20),1000*sin(-self.enemy_pitch) + random(-20,20) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
			FireProjectile(PROJECTILE,"BIP01",0,0,0,"playerhealth");
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav");
		}
		if(self.enemy_Y > Integer(self.current_Y + 100))
		{
			UpdateTarget();		// update target location
			Animate(SHOOTUP);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			FireProjectile("bad_shell", "BIP 01", 0, 0, 25, "playerhealth");
			AddExplosion("Muzzleflash2","BIP 01 R HAND",0,0,0);
			PlaySound("good.wav", 500);
			SetHoldAtEnd(false);
		}
		if(self.enemy_Y < Integer(self.current_Y - 100))
		{
			UpdateTarget();		// update target location
			Animate(SHOOTDOWN);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, "playerhealth");
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav", 500);
			SetHoldAtEnd(false);
		}
		if(CURRENTWEAPAMMO < 1)
		{
			Animate(RELOAD);
			self.think = "shoot_reload";
		}
		if(random(1,10) <2)
		{
			Animate(STRAFE);
			if(random(1,10) < 6)
			{
				ForceLeft(30);
				return 0;
			}
			else
			{
				ForceRight(30);
				return 0;
			}
		}
		if(fire_delay<time) 				// delay after animation starts before firing
		{
			if(random(1,10) < 5)
			{
				Animate(STRAFE);
				ForceRight(10);
				return 0;
			}
			else
			{
				Animate(STRAFE);
				ForceLeft(10);
				return 0;
			}
			UpdateTarget();		// update target location
			Animate(MISSILEATTACK);
			CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
			SetTargetPoint(random(-20,20),1000*sin(-self.enemy_pitch) + random(-20,20) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
			FireProjectile(PROJECTILE,"BIP01",0,0,0,"playerhealth");
			AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
			PlaySound("good.wav");
		}
		if(self.animate_at_end = true)
		{
			if(attack_delay < time)
			{
				self.think = "monster_missile_start"; // go back to missile attack
				SetHoldAtEnd(false);
				self.ThinkTime = 0.1;
			}
		} 
	} ]

	// Reload the weapon

	shoot_reload[ ()
	{
		ai_face();
		SetHoldAtEnd(true);
		if(self.animate_at_end)
		{
			CURRENTWEAPAMMO = CLIPSIZE + 0;
			self.think = "monster_missile_start";
		}		
	} ]

	// Drop that gun soldier
	drop[ ()
	{
		if(WEAPON = 1)
		{
			SetPosition("m16", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 2)
		{
			SetPosition("famas", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 3)
		{
			SetPosition("awp", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 4)
		{
			SetPosition("mp7", self.current_X, self.current_Y, self.current_Z);
		}
		if(WEAPON = 5)
		{
			SetPosition("ump", self.current_X, self.current_Y, self.current_Z);
		}
	} ]

	// basic AI routines

	// run toward enemy and see if you are ready to attack

	ai_run[ (dist)
	{
		if (attack_state = AS_MISSILE) // do missile attack
		{
			ai_run_missile();
			return 0;
		}
		if (CheckAnyAttack()) // check if you can start the actual attack
		{
			return 0;
		}
		walk_movetogoal(dist); // else move toward the enemy
	} ]

	// missile attack setup

	ai_run_missile[ ()
	{
		ai_face();
		if(FacingIdeal()) // got close enough
		{
			self.think = MISSILEFUNC;	// start missile attack
			attack_state = AS_STRAIGHT;
			UpdateTarget();
			skill_time = time + (SKILL*0.1);
		}
	} ]

	// face enemy

	ai_face[ ()
	{
		self.ideal_yaw = enemy_yaw;
		ChangeYaw(); // rotate to face enemy
	} ]

	// use walkmove to naviagte to enemy

	walk_movetogoal[ (dist)
	{
		if(IsFalling = true)
		{
			return 0;	// don't move while falling
		} 
		if(back_up = false)
		{
			ai_face();	// turn to face enemy
			if(FacingIdeal())
			{
				if(walkmove(self.current_yaw, dist) = true)
				{
					return 0;	// can move in current direction
				}
				else
				{
					if(random(1,10)<3)	// backup and move sideways
					{
						back_up = true;
						back_time = time + 0.5;
						back_flag = false;
						return 0;
					}
					else 
					{ 
						ForceUp(30);	// jump up, forward and to side
						ForceForward(30);
						if(random(1,10)<6)
						{
							ForceRight(30);
						}
						else
						{
							ForceLeft(30);
						} 
					} 
				} 
			}
		}
		else
		{
			if(back_flag = false) // go backward 1/2 sec
			{
				if(back_time > time)
				{
					walkmove((self.current_yaw-(180*0.0174532925199433)), dist);
					return 0;
				}
				else
				{
					back_time = time + 0.5;
					back_flag = true;
				}
			}
			if(back_time > time) // go sideways 1/2 sec
			{
				walkmove((self.current_yaw-(90*0.0174532925199433)), dist);
				return 0;
			}
			back_up = false;
		}
	} ]


	// check if nearly facing enemy

	FacingIdeal[ ()
	{
		selfangle = self.current_yaw/0.0174532925199433; // your direction in degrees
		idealangle = self.ideal_yaw/0.0174532925199433;	// his direction in degrees
		delta = selfangle - idealangle; // difference in directions
		if (delta > -20 and delta < 20) // within 20 degrees is close enough
		{
			return true;
		}
		return false;
	} ]

	// check if ready to do actual attacking

	CheckAnyAttack[ ()
	{
		if(attack_delay>time)
		{
			return false;
		}
		if(enemy_range<MISSILERANGE) // inside missile range
		{
			attack_state = AS_MISSILE; // do a missile attack
			return true;
		}
		return false;
	} ]
}

Herp derp.
Post Reply