Frikbot Item desirability

Discuss Artificial Intelligence and Bot programming.
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

Ok, I uploaded the source code and waypoints here:
http://fbe.am/uoS
Dr. Shadowborg wrote: Keep in mind I'm only going to impliment the bot fixes, nothing more.
Don't worry, that's all I was hoping you would do. :)
Dr. Shadowborg
InsideQC Staff
Posts: 1120
Joined: Sat Oct 16, 2004 3:34 pm

Re: Frikbot Item desirability

Post by Dr. Shadowborg »

Just started working on it.

Hmmm, there are some fairly glaring flaws / bugs within painkeep's code, not to mention some incompatibilities between frikbot and painkeeps 2dtrain code. (wouldn't even compile on modern fteqcc)

I've adapted the bot to use b_target1-4 instead of the original target1-4, so it compiles, but I haven't installed the botfixes yet.

Question: Would it be okay with you if I fixed the obvious bugs / flaws / inconsistencies within painkeep? Alternately I could just make two or three versions, one with the original buggy painkeep code, one with bugfixes (but leaving everything as is), and one with my personal preferences, enhancements and bugfixes?
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

Dr. Shadowborg wrote: Question: Would it be okay with you if I fixed the obvious bugs / flaws / inconsistencies within painkeep? Alternately I could just make two or three versions, one with the original buggy painkeep code, one with bugfixes (but leaving everything as is), and one with my personal preferences, enhancements and bugfixes?
Of course! You can modify whatever you like with the Painkeep code to make it more compatible with the Frikbots. After all, this version of Painkeep should be geared toward bots anyway.

I just now noticed this new version of Painkeep on the internet, but it appears to be designed for Darkplaces (it doesn't seem to work in Qrack at all). There are all kinds of console error messages in GLquake. The author is not the original, so it appears to be an unofficial update to Painkeep. The version I sent you was the last "official" version to be released by the original author(s). Honestly, the list of "fixes" doesn't seem to be all that impressive anyway. I say continue using version 1.1 that I uploaded, but I just felt I should mention this new version in case you wanted to check it out. The fact that it doesn't even seem to run in Qrack instantly turns me away from it.
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

Hey Shadowborg, I just realized the bots are all messed up on skill 1 (and possibly other skills). Throughout this entire thread, I've been testing them on skill 3 only. In skill 1, they seem to act like all the other bots have the Ring of shadows, and behave strangely when aiming. They also proceed to walk in to walls when other bots are present.
Dr. Shadowborg
InsideQC Staff
Posts: 1120
Joined: Sat Oct 16, 2004 3:34 pm

Re: Frikbot Item desirability

Post by Dr. Shadowborg »

Lightning Hunter wrote:Hey Shadowborg, I just realized the bots are all messed up on skill 1 (and possibly other skills). Throughout this entire thread, I've been testing them on skill 3 only. In skill 1, they seem to act like all the other bots have the Ring of shadows, and behave strangely when aiming. They also proceed to walk in to walls when other bots are present.
In bot_ai.qc, within bot_angle_set, just add this to the top of the else if (self.b_skill < 1) block:

Code: Select all

if (self.b_angle_x < -180)
        self.b_angle_x = self.b_angle_x + 360;
I think they're pretty deadly on any skill now. Guess I did too good of a job on their aimcode. :shock:

Sorry this painkeep adaptation is taking so long, but there are quite a few bugs within painkeeps code (I know this is a very old mod, and team evolve did their best at the time, but I'm amazed that people were actually able to play this over the net :shock: )
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

That didn't seem to fix it. I'll post my bot_ai so you can make sure everything is correct:

Code: Select all

/***********************************************
*                                              *
*            FrikBot General AI                *
*     "The I'd rather be playing Quake AI"     *
*                                              *
***********************************************/

/*

This program is in the Public Domain. My crack legal
team would like to add:

RYAN "FRIKAC" SMITH IS PROVIDING THIS SOFTWARE "AS IS"
AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE
ACCURACY, CAPABILITY, EFFICIENCY, MERCHANTABILITY, OR
FUNCTIONING OF THIS SOFTWARE AND/OR DOCUMENTATION. IN
NO EVENT WILL RYAN "FRIKAC" SMITH BE LIABLE FOR ANY
GENERAL, CONSEQUENTIAL, INDIRECT, INCIDENTAL,
EXEMPLARY, OR SPECIAL DAMAGES, EVEN IF RYAN "FRIKAC"
SMITH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES, IRRESPECTIVE OF THE CAUSE OF SUCH DAMAGES. 

You accept this software on the condition that you
indemnify and hold harmless Ryan "FrikaC" Smith from
any and all liability or damages to third parties,
including attorney fees, court costs, and other
related costs and expenses, arising out of your use
of this software irrespective of the cause of said
liability. 

The export from the United States or the subsequent
reexport of this software is subject to compliance
with United States export control and munitions
control restrictions. You agree that in the event you
seek to export this software, you assume full
responsibility for obtaining all necessary export
licenses and approvals and for assuring compliance
with applicable reexport restrictions. 

Any reproduction of this software must contain
this notice in its entirety. 

*/

/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

target_onstack

checks to see if an entity is on the bot's stack

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/

float(entity scot) target_onstack =
{
	if (scot == world)
		return FALSE;
	else if (self.target1 == scot)
		return 1;
	else if (self.target2 == scot)
		return 2;
	else if (self.target3 == scot)
		return 3;
	else if (self.target4 == scot)
		return 4;
	else
		return FALSE;
};

/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

target_add

adds a new entity to the stack, since it's a
LIFO stack, this will be the bot's new target1

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/

void(entity ent) target_add =
{
	if (ent == world)
		return;
	if (target_onstack(ent))
		return;
	self.target4 = self.target3;
	self.target3 = self.target2;
	self.target2 = self.target1;
	self.target1 = ent;
	self.search_time = time + 5;
};


/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

target_drop

Removes an entity from the bot's target stack.
The stack will empty everything up to the object
So if you have target2 item_health, target1
waypoint, and you drop the health, the waypoint
is gone too.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/

void(entity ent) target_drop =
{
	local float tg;
	
	tg = target_onstack(ent);
	if (tg == 1)
	{
		self.target1 = self.target2;
		self.target2 = self.target3;
		self.target3 = self.target4;
		self.target4 = world;
	}
	else if (tg == 2)
	{
		self.target1 = self.target3;
		self.target2 = self.target4;
		self.target3 = self.target4 = world;
	}
	else if (tg == 3)
	{
		self.target1 = self.target4;
		self.target2 = self.target3 = self.target4 = world;
	}
	else if (tg == 4)
		self.target1 = self.target2 = self.target3 = self.target4 = world;
	self.search_time = time + 5;
};

/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

bot_lost

Bot has lost its target.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/

void(entity targ, float success) bot_lost =
{
	if (!targ)
		return;

	target_drop(targ);
	if (targ.classname == "waypoint")
		targ.b_sound = targ.b_sound - (targ.b_sound & ClientBitFlag(self.b_clientno));

	// find a new route
	if (!success)
	{
		self.target1 = self.target2 = self.target3 = self.target4 = world;
		self.last_way = FindWayPoint(self.current_way);
		ClearMyRoute();
		self.b_aiflags = 0;
	}
        else
        {
		if (targ.classname == "item_artifact_invisibility")
			if (self.items & 524288)
				bot_start_topic(3);
                
                if (targ.flags & FL_ITEM)
                {
                        if (targ.model == string_null)
                                targ._last = world;
                        else
                                targ._last = self;
                }
        }


	if (targ.classname != "player")
		targ.search_time = time + 5;
};

/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

bot_check_lost

decide if my most immediate target should be
removed.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void(entity targ) bot_check_lost =
{
	local vector dist;
	dist = realorigin(targ) - self.origin;
	dist_z = 0;
	if (targ == world)
		return;

	// waypoints and items are lost if you get close enough to them

	else if (targ.flags & FL_ITEM)
	{
		if (vlen(targ.origin - self.origin) < 32)
			bot_lost(targ, TRUE);
		else if (targ.model == string_null)
			bot_lost(targ, TRUE);
	}
	else if (targ.classname == "waypoint")
	{
		if (!(self.b_aiflags & (AI_SNIPER | AI_AMBUSH)))
		{
			if (self.b_aiflags & AI_RIDE_TRAIN)
			{
				if (vlen(targ.origin - self.origin) < 48)
					bot_lost(targ, TRUE);
			}
			else if (self.b_aiflags & AI_PRECISION)
			{
				if (vlen(targ.origin - self.origin) < 24)
					bot_lost(targ, TRUE);
			}
			else if (vlen(targ.origin - self.origin) < 32)
				bot_lost(targ, TRUE);
		}
	}
	else if (targ.classname == "temp_waypoint")
	{
		if (vlen(targ.origin - self.origin) < 32)
			bot_lost(targ, TRUE);
	}
	else if (targ.classname == "player")
	{
		if (targ.health <= 0)
			bot_lost(targ, TRUE);
		else if ((coop) || (teamplay && targ.team == self.team))
		{
			if (targ.target1.classname == "player")
			{
				if (!targ.target1.ishuman)
					bot_lost(targ, TRUE);
			}
			else if (targ.teleport_time > time)
			{
				// try not to telefrag teammates
				self.keys = self.keys & 960;
			}
			else if (vlen(targ.origin - self.origin) < 128)
			{
				if (vlen(targ.origin - self.origin) < 48)
					frik_walkmove(self.origin - targ.origin);
				else
				{
					self.keys = self.keys & 960;
					bot_start_topic(4);
				}
				self.search_time = time + 5; // never time out
			}
			else if (!fisible(targ))
				bot_lost(targ, FALSE);	
		}
		else if (waypoint_mode > WM_LOADED)
		{
			if (vlen(targ.origin - self.origin) < 128)
			{
				bot_lost(targ, TRUE);	
			}
		}
	}

	// buttons are lost of their frame changes
	else if (targ.classname == "func_button")
	{
		if (targ.frame)
		{
			bot_lost(targ, TRUE);
			if (self.enemy == targ)
				self.enemy = world;
			//if (self.target1)
			//	bot_get_path(self.target1, TRUE);
				
		}
	}
	// trigger_multiple style triggers are lost if their thinktime changes
	else if ((targ.movetype == MOVETYPE_NONE) && (targ.solid == SOLID_TRIGGER))
	{
		if (targ.nextthink >= time)
		{
			bot_lost(targ, TRUE);
			//if (self.target1)
			//	bot_get_path(self.target1, TRUE);
		}
	}
   // DRS: Teleporter target fix
   if(targ.classname == "trigger_teleport" && (self.bot_teleport_dest.classname == "info_teleport_destination" && vlen(self.bot_teleport_dest.origin - self.origin) < 32))
   {
    self.bot_teleport_dest = world;
    bot_lost(targ, TRUE);
   }
	// lose any target way above the bot's head
	// FIXME: if the bot can fly in your mod..
	if ((targ.origin_z - self.origin_z) > 64)
	{
		dist = targ.origin - self.origin;
		dist_z = 0;
		if (vlen(dist) < 32)
			if (self.flags & FL_ONGROUND)
				if(!frik_recognize_plat(FALSE))
					bot_lost(targ, FALSE);
	}
	else if (targ.classname == "train")
	{
		if (frik_recognize_plat(FALSE))
			bot_lost(targ, TRUE);
	}
	// targets are lost if the bot's search time has expired
	if (time > self.search_time)
		bot_lost(targ, FALSE);
};


/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

bot_handle_ai

This is a 0.10 addition. Handles any action
based b_aiflags.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/

void() bot_handle_ai =
{
	local entity newt;
	local vector v;

	// handle ai flags -- note, not all aiflags are handled
	// here, just those that perform some sort of action

	// wait is used by the ai to stop the bot until his search time expires / or route changes

	if (self.b_aiflags & AI_WAIT)
		self.keys = self.keys & 960;

	if (self.b_aiflags & AI_DOORFLAG) // was on a door when spawned
	{
		b_temp3 = self;
		self = self.last_way;
		if (!frik_recognize_plat(FALSE)) // if there is nothing there now
		{
			newt = FindThing("door"); // this is likely the door responsible (crossfingers)
			self = b_temp3;

			if (self.b_aiflags & AI_DOOR_NO_OPEN)
			{
				if (newt.nextthink)
					self.keys = self.keys & 960; // wait until it closes
				else
				{
					bot_lost(self.last_way, FALSE);
				}
			}
			else
			{
				if (newt.targetname)
				{
					newt = find(world, target, newt.targetname);
					if (newt.health > 0) 
					{
						self.enemy = newt;
						bot_weapon_switch(1);
					}
					else
					{
					//	target_drop(self.last_way);
						target_add(newt);
					//	bot_get_path(newt, TRUE);
					}
				}
				self.b_aiflags = self.b_aiflags - AI_DOORFLAG;
			}
		}
		else
			self = b_temp3;
	}

	if (self.b_aiflags & AI_JUMP)
	{
		if (self.flags & FL_ONGROUND)
		{
			bot_jump();
			self.b_aiflags = self.b_aiflags - AI_JUMP;
		}
	}
	else if (self.b_aiflags & AI_SUPER_JUMP)
	{
		if (self.weapon != 32)
			self.impulse = 7;
		else if (self.flags & FL_ONGROUND)
		{
			self.b_aiflags = self.b_aiflags - AI_SUPER_JUMP;
			if (bot_can_rj(self))
			{
				bot_jump();
				self.v_angle_x = self.b_angle_x = 80;
				self.button0 = TRUE;
			}
			else
				bot_lost(self.target1, FALSE);
			
		}
	}
	if (self.b_aiflags & AI_SURFACE)
	{
		if (self.waterlevel > 2)
  		{
			self.keys = KEY_MOVEUP;
			self.button2 = TRUE; // swim!
    		}
		else
			self.b_aiflags = self.b_aiflags - AI_SURFACE;
	}
	if (self.b_aiflags & AI_RIDE_TRAIN)
	{
		// simple, but effective
		// this can probably be used for a lot of different
		// things, not just trains (door elevators come to mind)
		b_temp3 = self;
		self = self.last_way;
	
		if (!frik_recognize_plat(FALSE)) // if there is nothing there now
		{
			self = b_temp3;
			self.keys = self.keys & 960;
		}
		else
		{
			self = b_temp3;
			if (frik_recognize_plat(FALSE))
			{
				v = realorigin(trace_ent) + trace_ent.origin - self.origin;
				v_z = 0;
				if (vlen(v) < 24)
					self.keys = self.keys & 960;
				else
				{
					self.b_aiflags = self.b_aiflags | AI_PRECISION;
					self.keys = frik_KeysForDir(v);
				}
			}
		}
	}
	if (self.b_aiflags & AI_PLAT_BOTTOM)
	{
		newt = FindThing("plat");
		if (newt.state != 1)
		{
			v =  self.origin - realorigin(newt);
			v_z = 0;
			if (vlen(v) > 96)
				self.keys = self.keys & 960;
			else
				frik_walkmove(v);
		}
		else
			self.b_aiflags = self.b_aiflags - AI_PLAT_BOTTOM;
	}
	if (self.b_aiflags & AI_DIRECTIONAL)
	{
		if ((normalize(self.last_way.origin - self.origin) * self.b_dir) > 0.4)
		{
			self.b_aiflags = self.b_aiflags - AI_DIRECTIONAL;
			bot_lost(self.target1, TRUE);
		}
	}
	if (self.b_aiflags & AI_SNIPER)
	{
		self.b_aiflags = (self.b_aiflags | AI_WAIT | AI_PRECISION) - AI_SNIPER;
		// FIXME: Add a switch to wep command
		// FIXME: increase delay?
	}
	if (self.b_aiflags & AI_AMBUSH)
	{
		self.b_aiflags = (self.b_aiflags | AI_WAIT) - AI_AMBUSH;
		// FIXME: Add a switch to wep command
		// FIXME: increase delay?
	}

};

/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

bot_path

Bot will follow a route generated by the
begin_route set of functions in bot_way.qc.
This code, while it works pretty well, can get
confused

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/

void() bot_path =
{

	local entity jj, tele;

	bot_check_lost(self.target1);
	if (!self.target1)
	{
		self.keys=0;
		return;
	}
	if (target_onstack(self.last_way))
		return; // old waypoint still being hunted

	jj = FindRoute(self.last_way);
	if (!jj)
	{
		// this is an ugly hack
		if (self.target1.current_way != self.last_way)
		{
			if (self.target1.classname != "temp_waypoint")
				if (self.target1.classname != "player")
					bot_lost(self.target1, FALSE);
		}

		return;
	}

	// update the bot's special ai features

	// Readahed types are AI conditions to perform while heading to a waypoint
	// point types are AI flags that should be executed once reaching a waypoint

	self.b_aiflags = (jj.b_aiflags & AI_READAHEAD_TYPES) | (self.last_way.b_aiflags & AI_POINT_TYPES);
	target_add(jj);
	if (self.last_way)
	{
		if (CheckLinked(self.last_way, jj) == 2) // waypoints are telelinked
		{
			tele = FindThing("trigger_teleport"); // this is probbly the teleport responsible
			target_add(tele);
		}
		traceline(self.last_way.origin, jj.origin, FALSE, self); // check for blockage
   		if (trace_fraction != 1)
		{
			if (trace_ent.classname == "door" && !(self.b_aiflags & AI_DOOR_NO_OPEN)) // a door blocks the way
			{
				// linked doors fix
				if (trace_ent.owner)
					trace_ent = trace_ent.owner;
				if ((trace_ent.health > 0) && (self.enemy == world))
				{
					self.enemy = trace_ent;
					bot_weapon_switch(1);
					self.b_aiflags = self.b_aiflags | AI_BLIND; // nick knack paddy hack
				}
				else if (trace_ent.targetname)
				{
					tele = find(world, target, trace_ent.targetname);
					if (tele.health > 0) 
					{
						self.enemy = tele;
						bot_weapon_switch(1);
					}
					else
					{
					//	target_drop(jj);
						target_add(tele);
					//	bot_get_path(tele, TRUE);
						self.b_aiflags = self.b_aiflags | AI_BLIND; // give a bot a bone	
						return;
					}					
				}		
			}
			else if (trace_ent.classname == "func_wall")
			{
				// give up
				bot_lost(self.target1, FALSE);
				return;
			}
		}
	}
	// this is used for AI_DRIECTIONAL
	self.b_dir = normalize(jj.origin - self.last_way.origin);

	self.last_way = jj;
};


/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Bot Priority Look. What a stupid name. This is where
the bot finds things it wants to kill/grab.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
// priority scale
// 0 - 10 virtually ignore
// 10 - 30 normal item range
// 30 - 50 bot will consider this a target worth changing course for
// 50 - 90 bot will hunt these as vital items

// *!* Make sure you add code to bot_check_lost to remove the target *!*

float(entity thing) priority_for_thing =
{
	local float thisp;
	thisp = 0;
	// This is the most executed function in the bot. Careful what you do here.

	if ((thing.flags & FL_ITEM) && thing.model != string_null && thing.search_time < time)
	{
		// ugly hack
                if (thing._last != self)
                        thisp = 10*(random()) + 20;
		//~ ai fix start
		/* 
		if (thing.classname == "item_artifact_super_damage")
			thisp = 65;
		else if (thing.classname == "item_artifact_invulnerability")
			thisp = 65;
		else if (thing.classname == "item_health")
		{
			if (thing.spawnflags & 2)
				thisp = 55;
			if (self.health < 50)
				thisp = thisp + 115;
		}
		else if (thing.model == "progs/armor.mdl")
		{
			if (self.armorvalue < 200)
			{		
				if (thing.skin == 2)
					thisp = 60;
				else if (self.armorvalue < 100)			
					thisp = thisp + 25;
			}
		}
		else if (thing.classname == "weapon_supershotgun")
		{
			if (!(self.items & 2)) // IT_SUPER_SHOTGUN  
				thisp = 35;
		}
		else if (thing.classname == "weapon_nailgun")
		{
			if (!(self.items & 4)) // IT_NAILGUN 
				thisp = 30;
		}
		else if (thing.classname == "weapon_supernailgun")
		{
			if (!(self.items & 8)) // IT_SUPER_NAILGUN
				thisp = 40;
		}
		else if (thing.classname == "weapon_grenadelauncher")
		{
			if (!(self.items & 16)) // IT_GRENADE_LAUNCHER
				thisp = 45;
		}
		else if (thing.classname == "weapon_rocketlauncher")
		{
			if (!(self.items & 32)) // IT_ROCKET_LAUNCHER
				thisp = 60;
		}
		else if (thing.classname == "weapon_lightning")
		{
			if (!(self.items & 64)) // IT_LIGHTNING
				thisp = 50;
		}
	*/
	if (thing.classname == "item_artifact_super_damage")
			thisp = 19*(random()) + 40;
		else if (thing.classname == "item_artifact_invulnerability")
			thisp = 19*(random()) + 40;
		else if (thing.classname == "item_artifact_invisibility")
			thisp = 19*(random()) + 40;
		else if (thing.classname == "item_health")
		{
			if (self.health <= 50)
				thisp = 50;
			if (self.health > 50)
           		 thisp = 35;
			if (self.health > 80)
           		 thisp = 20;
			if (self.health > 95)
           		 thisp = 0;
			if (thing.spawnflags & 2)
				thisp = 13*(random()) + 37;
		}

		else if (thing.classname == "item_armor1")
		{
			if (self.armorvalue <= 99)
				thisp = 13*(random()) + 26;

			if (self.armorvalue > 99)
           		thisp = 0;
		}

		else if (thing.classname == "item_armor2")
		{
			if (self.armorvalue <= 149)
				thisp = 13*(random()) + 35;

			if (self.armorvalue > 149)
           		thisp = 0;
		}

		else if (thing.classname == "item_armorInv")
		{
			if (self.armorvalue <= 199)
				thisp = 10*(random()) + 45;

			if (self.armorvalue > 199)
           		thisp = 0;
		}


		else if (thing.classname == "weapon_rocketlauncher")
		{
			if (!(self.items & 32)) // IT_ROCKET_LAUNCHER
				thisp = 5*(random()) + 45;
		}
		else if (thing.classname == "weapon_lightning")
		{
			if (!(self.items & 64)) // IT_LIGHTNING
				thisp = 13*(random()) + 37;
		}
		else if (thing.classname == "weapon_grenadelauncher")
		{
			if (!(self.items & 16)) // IT_GRENADE_LAUNCHER
				thisp = 10*(random()) + 30;
		}
		else if (thing.classname == "weapon_supernailgun")
		{
			if (!(self.items & 8)) // IT_SUPER_NAILGUN
				thisp = 8*(random()) + 25;
		}
		else if (thing.classname == "weapon_nailgun")
		{
			if (!(self.items & 4)) // IT_NAILGUN 
				thisp = 8*(random()) + 15;
		}
		else if (thing.classname == "weapon_supershotgun")
		{
			if (!(self.items & 2)) // IT_SUPER_SHOTGUN  
				thisp = 8*(random()) + 20;
		}

		else if (thing.model == "progs/backpack.mdl")
			thisp = 18*(random()) + 20;
		else if (thing.classname == "item_artifact_envirosuit")
			thisp = 15;
	}
	//~ ai fix end
	else if ((thing.flags & FL_MONSTER) && thing.health > 0)
		thisp = 45;
	else if (thing.classname == "player")
	{ 
		if (thing.health > 0)
		{
			if (thing == self)
				return 0;
			else
			{
				if (thing.items & IT_INVISIBILITY) //FIXME
					thisp = 2;
				else if (coop)
				{
					thisp = 200;
					if (thing.target1.classname == "player")
						if (!thing.target1.ishuman)
							return 0;
				}
				else if (teamplay && thing.team == self.team)
				{
					thisp = 100;
					if (thing.target1.classname == "player")
						return 0;
				}
				else thisp = 30;
			}
		}
	}
	else if (thing.classname == "waypoint")
	{
		if (thing.b_aiflags & AI_SNIPER)
			thisp = 30;
		else if (thing.b_aiflags & AI_AMBUSH)
			thisp = 30;
	}
	if (pointcontents(thing.origin) < -3)
		return 0;
	if (thisp)
	{
		if (thing.current_way)
		{
			// check to see if it's unreachable
			if (thing.current_way.items == -1)
				return 0;
			else
				thisp = thisp + (13000 - thing.current_way.items) * 0.05; 
		}
	} 		
	return thisp;
};

void(float scope) bot_look_for_crap =
{
	local entity foe, best;
	local float thatp, bestp, dist;

	if (scope == 1)
		foe = findradius(self.origin, 13000);
	else
		foe = findradius(self.origin, 500);

	bestp = 1;
	while(foe)
	{
		thatp = priority_for_thing(foe);
		if (thatp)
			if (!scope)
				if (!sisible(foe))
					thatp = 0;
		if (thatp > bestp)
		{
			bestp = thatp;
			best = foe;
			dist = vlen(self.origin - foe.origin);
		}
		foe = foe.chain;
	}
	if (best == world)
		return;
	if (!target_onstack(best))
	{	
		target_add(best);
		if (scope)
		{
			bot_get_path(best, FALSE);
			self.b_aiflags = self.b_aiflags | AI_WAIT;
		}
	}
};


/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

bot_angle_set

Sets the bots look keys & b_angle to point at
the target - used for fighting and just
generally making the bot look good.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
float() crandom;
void() bot_angle_set =
{
   local float h;
   local vector view, voffset;
    local vector offset, spot1, oldview;
    local float offset_amt, dist1, dist2;
   
   if (self.enemy)
   {
      if (self.enemy.items & 524288)
         if (random() > 0.01)
            return;
      if (self.missile_speed == 0)
         self.missile_speed = 10000;
      if (self.enemy.solid == SOLID_BSP)
      {
         view = (((self.enemy.absmin + self.enemy.absmax) * 0.5)); // - self.origin
         self.dontshoot = FALSE;
            view = normalize(view - (self.origin + self.view_ofs));
      }
      else
      {
         view = self.enemy.origin;

          // find lead point on target
          // then traceline to it, if blocked before full dist,
          // set targetpoint to stopped origin
          // then trace again to check if there's a clear path to
          // target, if not, just target enemy.origin.
          // also, check to see if trace endpoint is within 140 qu
          // of the bot, if so, aim at the enemy.origin, because
          // we are looking at a wall, and that could hurt if it's a rocketlauncher
            h = vlen(view - self.origin) / self.missile_speed; // need to get the speed of projectile
            if (self.enemy.flags & FL_ONGROUND)
               view = self.enemy.velocity * h; // Aim straight at enemy, not at his feet, that will be handled later
            else
               view = (self.enemy.velocity - (sv_gravity * '0 0 1') * h) * h; // hes in the air, lead accordingly
            view = self.enemy.origin + view; // set our leadpoint
            traceline(self.enemy.origin, view, FALSE, self); // trace from enemy.origin to lead aimpoint
            view = trace_endpos; // set view origin to lead aimpoint
            traceline(self.origin + self.view_ofs, view, FALSE, self); // do a trace to view from self.
            spot1 = trace_endpos; // get trace_endpos
            dist1 = vlen(spot1 - (self.origin + self.view_ofs)); // range from self to trace
            dist2 = vlen(view - (self.origin + self.view_ofs)); // range from self to aimpoint
            if((dist1 < 140) && (dist1 != dist2)) // too close, shoot at enemy.origin
             view = self.enemy.origin;
            else if(vlen(view - spot1) > 32 && trace_ent.takedamage == DAMAGE_NO)
             view = self.enemy.origin; // something that can't be damaged in the way, just shoot at enemy.origin.
             dist2 = vlen(view - (self.origin+self.view_ofs));
            
// DRS: Tweaked Supa Aimcode (wazat inspired) below
// DRS: FIXME: Change this so that it's not so consistent...
            if(self.weapon != IT_GRENADE_LAUNCHER) // Grenade Launcher should not jitter
          {
             if(self.b_skill == 0)
            offset_amt = 55;  //110
             else if (self.b_skill == 1)
                 offset_amt = 45;  //80
             else if (self.b_skill == 2)
            offset_amt = 36; //60
             else if (self.b_skill == 3)
            offset_amt = 15; //0

             offset_x = crandom() * offset_amt;
             offset_y = crandom() * offset_amt;
             offset_z = crandom() * offset_amt;
         }
          if(self.weapon == IT_GRENADE_LAUNCHER) // using grenades? Aim properly then!
            {
            local float realrange, flitime;
            local vector grndir;

            grndir = normalize(view - (self.origin + self.view_ofs));//normalize(self.enemy.origin - self.origin);
            realrange = dist2*mathlib_cos(grndir_x);
            flitime = realrange / self.missile_speed;
          
               view = view + '0 0 -20'; // aim at feet
            grndir = normalize(view - (self.origin + self.view_ofs));//normalize(self.enemy.origin - self.origin);
             grndir = grndir * 600;
            grndir_z = grndir_z + (sv_gravity*flitime) * 0.3;
            view = normalize(grndir);
            self.dontshoot = FALSE;
         }
         if(self.weapon == IT_ROCKET_LAUNCHER && (self.enemy.flags & FL_ONGROUND)) // Rocketlauncher?  Aim at feet if they're on the ground!
         {
          oldview = view;
          view = view + '0 0 -20'; // aim at feet
          traceline(self.origin + self.view_ofs, view, FALSE, self);
           if(vlen(view - trace_endpos) > 32)
            view = oldview;
         }
       // DRS: Do a viability test on whether we actually should shoot or not
         if(self.enemy.solid != SOLID_BSP && self.weapon != IT_GRENADE_LAUNCHER)
         {
         traceline(self.origin+self.view_ofs, view, TRUE, self);
         if(vlen(trace_endpos - (self.origin+self.view_ofs)) < (dist2 - 32))
          self.dontshoot = TRUE;
         else if(vlen(trace_endpos - (self.origin+self.view_ofs)) > (dist2 + 32))
          self.dontshoot = TRUE;
         else self.dontshoot = FALSE;
        }
            
       if(self.weapon != IT_GRENADE_LAUNCHER)
           view = normalize((view + offset) - (self.origin + self.view_ofs));
      }   
      view = vectoangles(view);
      view_x = view_x * -1;
      self.b_angle = view;
   }
   else if (self.target1)
   {
      view = realorigin(self.target1);
      if (self.target1.flags & FL_ITEM)
            view = view + '0 0 48';
      view = view - (self.origin + self.view_ofs);
      view = vectoangles(view);
      view_x = view_x * -1;
      self.b_angle = view;
      self.dontshoot = TRUE;
   }
   else
    {
      self.b_angle_x = 0;
     self.dontshoot = TRUE;
    }

   // HACK HACK HACK HACK
   // The bot falls off ledges a lot because of "turning around"
   // so let the bot use instant turn around when not hunting a player
   if (self.b_skill == 3)
   {
      if (self.b_angle_x < -180)
         self.b_angle_x = self.b_angle_x + 360;
      if (self.b_angle_x > 180)
         self.b_angle_x = self.b_angle_x - 360;
         
      self.keys = self.keys & 63;   
      self.v_angle = self.b_angle;
   }
   else if ((self.enemy == world || self.enemy.movetype == MOVETYPE_PUSH) && self.target1.classname != "player")
   {
      if (self.b_angle_x < -180)
         self.b_angle_x = self.b_angle_x + 360;
      if (self.b_angle_x > 180)
         self.b_angle_x = self.b_angle_x - 360;

      self.keys = self.keys & 63;
      self.v_angle = self.b_angle;
   }
   else if (self.b_skill < 1) // skill 2 handled in bot_phys
   {
      if (self.b_angle_x < -180)
         self.b_angle_x = self.b_angle_x + 360;
      if (self.b_angle_x > 180)
         self.b_angle_x = self.b_angle_x - 360;
      self.keys = self.keys & 63;

      if (angcomp(self.b_angle_y, self.v_angle_y) > 10)
         self.keys = self.keys | KEY_LOOKLEFT;
      else if (angcomp(self.b_angle_y, self.v_angle_y) < -10)
         self.keys = self.keys | KEY_LOOKRIGHT;
      if (angcomp(self.b_angle_x, self.v_angle_x) < -10)
         self.keys = self.keys | KEY_LOOKUP;
      else if (angcomp(self.b_angle_x, self.v_angle_x) > 10)
         self.keys = self.keys | KEY_LOOKDOWN;
   }
};

/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

BotAI

This is the main ai loop. Though called every
frame, the ai_time limits it's actual updating

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
float stagger_think;

void() BotAI =
{
	// am I dead? Fire randomly until I respawn
	// health < 1 is used because fractional healths show up as 0 on normal player
	// status bars, and the mod probably already compensated for that

	if (self.health < 1)
	{ 
		self.button0 = floor(random() * 2);
		self.button2 = 0;
		self.keys = 0;
		self.b_aiflags = 0;
		ClearMyRoute();
		self.target1 = self.target2 = self.target3 = self.target4 = self.enemy = world;
		self.last_way = world;
		return;
	}
		
	// stagger the bot's AI out so they all don't think at the same time, causing game
	// 'spikes'
	if (self.b_skill < 2)
	{
		if (self.ai_time > time)
			return;

		self.ai_time = time + 0.05;
		if (bot_count > 0)
		{
			if ((time - stagger_think) < (0.1 / bot_count))
				self.ai_time = self.ai_time + 0.1 / (2 * bot_count);
		}
		else
			return;
	}
	if (self.view_ofs == '0 0 0')
		bot_start_topic(7);
	stagger_think = time;

	// shut the bot's buttons off, various functions will turn them on by AI end

	self.button2 = 0;
	self.button0 = 0;
	

	// target1 is like goalentity in normal Quake monster AI.
	// it's the bot's most immediate target
	if (route_table == self)
	{
		if (busy_waypoints <= 0)
		{
			if (waypoint_mode < WM_EDITOR)
				bot_look_for_crap(TRUE);
		}
		self.b_aiflags = 0;
		self.keys = 0;
	}
   else if (self.target1)
   {
      frik_movetogoal();
      bot_path();
   }
	else
	{
		if (waypoint_mode < WM_EDITOR)
                {
                	if(self.route_failed)
                	{
                		if (waypoint_mode == WM_DYNAMIC)
                	        	frik_bot_roam();
                	        else
                	        	self.keys = 0;
                		self.route_failed = 0;
                	}
                        else if(!begin_route())
                        {	
                                bot_look_for_crap(FALSE);
                                self.keys = 0;
                        }
			
                }
		else
		{
			self.b_aiflags = AI_WAIT;
			self.keys = 0;
		}
	}

	// bot_angle_set points the bot at it's goal (self.enemy or target1)

	bot_angle_set();

	// fight my enemy. Enemy is probably a field QC coders will most likely use a lot
	// for their own needs, since it's unused on a normal player
	// FIXME
	if (self.enemy)
		bot_fight_style();
	else if (random() < 0.2)
		if (random() < 0.2)
			bot_weapon_switch(-1);
	bot_dodge_stuff();

	// checks to see if bot needs to start going up for air
	if (self.waterlevel > 2)
  	{
		if (time > (self.air_finished - 2))
		{
			traceline (self.origin, self.origin + '0 0 6800', TRUE, self);
			if (trace_inopen)	
			{
				self.keys = KEY_MOVEUP;
				self.button2 = TRUE; // swim!
				return; // skip ai flags for now - this is life or death
			}
		}
    	}

	// b_aiflags handling

	
	if (self.b_aiflags)
		bot_handle_ai(); 
	else
		bot_chat(); // don't want chat to screw him up if he's rjing or something
};

I think they're pretty deadly on any skill now. Guess I did too good of a job on their aimcode. :shock:
Wazat's aim offset code still works though, right? If the bots seem too challenging, I can always just further modify the aim offset. After all, the most challenging aspect of bots in fps games is their aim. Reduce their aim, and they become much easier. I'll do some testing with their aim once this current bug is resolved!
Sorry this painkeep adaptation is taking so long, but there are quite a few bugs within painkeeps code (I know this is a very old mod, and team evolve did their best at the time, but I'm amazed that people were actually able to play this over the net :shock: )
It's all good! I'm glad you are doing this, because I'm getting the urge to waypoint more painkeep maps. I may just do a whole separate release for the painkeep mod, rather than bundling it all together with my other waypoints. Speaking of which, I meant to ask you if you wanted to release all your Frikbot fixes on your own (as a stand-alone release), or if you wanted me to bundle the fixes with my waypoint pack. If you choose the latter, I would of course mention your name multiple times in the readme file and all the web sites that I release the waypoint pack. I have already been documenting all the changes you have made in a readme, so I can mention it in the release. Readme files for my projects always end up being large, because I believe in always mentioning all parties involved who helped with my projects. :mrgreen:
Dr. Shadowborg
InsideQC Staff
Posts: 1120
Joined: Sat Oct 16, 2004 3:34 pm

Re: Frikbot Item desirability

Post by Dr. Shadowborg »

Your code appears to be correct, and I even tested it on the developmental build. You recompiled your code right?

Try this copy of the developmental build if you're still having problems:
http://fbe.am/uuk

That one works fine over here.
Lightning Hunter wrote: Wazat's aim offset code still works though, right? If the bots seem too challenging, I can always just further modify the aim offset. After all, the most challenging aspect of bots in fps games is their aim. Reduce their aim, and they become much easier. I'll do some testing with their aim once this current bug is resolved!
Wazat's aimcode still works, I've just been eating too many rockets to the face during playtesting. (and suffering ego damage from being last in place 20 - 8 frags) Don't worry about it. :wink:
Lightning Hunter wrote: It's all good! I'm glad you are doing this, because I'm getting the urge to waypoint more painkeep maps. I may just do a whole separate release for the painkeep mod, rather than bundling it all together with my other waypoints. Speaking of which, I meant to ask you if you wanted to release all your Frikbot fixes on your own (as a stand-alone release), or if you wanted me to bundle the fixes with my waypoint pack. If you choose the latter, I would of course mention your name multiple times in the readme file and all the web sites that I release the waypoint pack. I have already been documenting all the changes you have made in a readme, so I can mention it in the release. Readme files for my projects always end up being large, because I believe in always mentioning all parties involved who helped with my projects. :mrgreen:
Might actually be better to do painkeeps waypoint package separate, I dunno. In either case, the bugfixed / enhanced version of painkeep will definitely be a step up from the original.

I'm going to release a fixed up Frikbot at some point built into an enhanced / fixed version of GPL v101qc, but it will be a bit off into the future, so feel free to release the current fixes with your pack. :wink:
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

Dr. Shadowborg wrote:Your code appears to be correct, and I even tested it on the developmental build. You recompiled your code right?

Try this copy of the developmental build if you're still having problems:
http://fbe.am/uuk

That one works fine over here.
That code did in fact work. I have no clue what was wrong with my code. Maybe it was something else other than bot_ai. I have made so many changes in my code from your posts that I could have messed up anywhere along the way. Does the developmental code you just uploaded contain all the fixes until now? I think I may scrap all of my modified QC files and just start clean using the one you just uploaded. I did notice that your upload contains a mathlib.qc that mine does NOT contain. What kind of side effects could that have created?
Wazat's aimcode still works, I've just been eating too many rockets to the face during playtesting. (and suffering ego damage from being last in place 20 - 8 frags) Don't worry about it. :wink:
Haha. I know what you mean. I will definitely be testing the bots more thoroughly before a release to see if the skills need more balancing with their aim. I was actually thinking of making a request if it's possible to add maybe 2 more skill levels, but I didn't want to bother you with such a request with so many of my other requests lately. I have no clue how difficult it would be to make the skills go up to 5 instead of 3. If there were two more skills added, they could simply be identical to the skill 3 code in every way, except have different aim offsets using Wazat's code. So something like this:

Code: Select all

// DRS: Tweaked Supa Aimcode (wazat inspired) below
// DRS: FIXME: Change this so that it's not so consistent...
            if(self.weapon != IT_GRENADE_LAUNCHER) // Grenade Launcher should not jitter
          {
             if(self.b_skill == 0)
            offset_amt = 75;
             else if (self.b_skill == 1)
                 offset_amt = 60; 
             else if (self.b_skill == 2)
            offset_amt = 45;
             else if (self.b_skill == 3)
            offset_amt = 30;
             else if (self.b_skill == 4)
            offset_amt = 15;
             else if (self.b_skill == 5)
            offset_amt = 0;

             offset_x = crandom() * offset_amt;
             offset_y = crandom() * offset_amt;
             offset_z = crandom() * offset_amt;
         }
That would give players more options if they were either getting their rear kicked by the bots, or found the bots too easy. The bots could be as difficult as being god-like with their aim, or miss almost every time (and everything in-between).
Might actually be better to do painkeeps waypoint package separate, I dunno. In either case, the bugfixed / enhanced version of painkeep will definitely be a step up from the original.
I'm looking forward to it! And I think I will make a separate release for the Painkeep mod, if not just to keep the filesize down.
I'm going to release a fixed up Frikbot at some point built into an enhanced / fixed version of GPL v101qc, but it will be a bit off into the future, so feel free to release the current fixes with your pack. :wink:
Sounds good. In that case, I will make sure I give you full credit for everything you have done when my next waypoint pack is complete.

Edit: By the way, I am currently doing the waypoints for dm1-6 from scratch. I figured now that I have waypointed 730 custom made maps, it is time to apply all my knowledge and experience of waypointing to the official deathmatch maps. :P I am being extra picky with these waypoints, and will make sure they are pretty much flawless. I will then apply them to the .qc files instead of using waypoint files.
Dr. Shadowborg
InsideQC Staff
Posts: 1120
Joined: Sat Oct 16, 2004 3:34 pm

Re: Frikbot Item desirability

Post by Dr. Shadowborg »

Lightning Hunter wrote: ...Does the developmental code you just uploaded contain all the fixes until now? I think I may scrap all of my modified QC files and just start clean using the one you just uploaded. I did notice that your upload contains a mathlib.qc that mine does NOT contain. What kind of side effects could that have created?
Yes, all fixes until now (including the skill 1 and lower) have been included.

mathlib.qc was created by FrikaC long ago, all it adds is some qc side math / trig functions. Its where mathlib_cos came from which is used in the grenade launcher aimcode. (mathlib.qc also comes with extra stuff that can be used to hook up to builtins if the engine supports them) It shouldn't cause anything wierd to happen otherwise.

The only other things different with the developmental would be faster SNG nails (for lead code testing), and player lifetime messages when players / bots die. Neither of them would cause the problems you mentioned.
Lightning Hunter wrote: Haha. I know what you mean. I will definitely be testing the bots more thoroughly before a release to see if the skills need more balancing with their aim. I was actually thinking of making a request if it's possible to add maybe 2 more skill levels, but I didn't want to bother you with such a request with so many of my other requests lately. I have no clue how difficult it would be to make the skills go up to 5 instead of 3. If there were two more skills added, they could simply be identical to the skill 3 code in every way, except have different aim offsets using Wazat's code. So something like this:

Code: Select all

// DRS: Tweaked Supa Aimcode (wazat inspired) below
// DRS: FIXME: Change this so that it's not so consistent...
            if(self.weapon != IT_GRENADE_LAUNCHER) // Grenade Launcher should not jitter
          {
             if(self.b_skill == 0)
            offset_amt = 75;
             else if (self.b_skill == 1)
                 offset_amt = 60; 
             else if (self.b_skill == 2)
            offset_amt = 45;
             else if (self.b_skill == 3)
            offset_amt = 30;
             else if (self.b_skill == 4)
            offset_amt = 15;
             else if (self.b_skill == 5)
            offset_amt = 0;

             offset_x = crandom() * offset_amt;
             offset_y = crandom() * offset_amt;
             offset_z = crandom() * offset_amt;
         }
That would give players more options if they were either getting their rear kicked by the bots, or found the bots too easy. The bots could be as difficult as being god-like with their aim, or miss almost every time (and everything in-between).
I see no reason why that code wouldn't work, beyond some small tweaks being required to support the higher skill levels. (predominately within the skill == 3 related stuff needing to be set to skill >= 3 instead)
Lightning Hunter wrote: Edit: By the way, I am currently doing the waypoints for dm1-6 from scratch. I figured now that I have waypointed 730 custom made maps, it is time to apply all my knowledge and experience of waypointing to the official deathmatch maps. :P I am being extra picky with these waypoints, and will make sure they are pretty much flawless. I will then apply them to the .qc files instead of using waypoint files.
Sounds good, be sure to send them my way when they're done so I can include them in the later GPL v101qc+FBX package. :wink:
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

Dr. Shadowborg wrote: The only other things different with the developmental would be faster SNG nails (for lead code testing), and player lifetime messages when players / bots die. Neither of them would cause the problems you mentioned.
So the developmental code you sent me has faster nails and such? I was going to use it as my new permanent source code for the Frikbot waypoint pack, but I guess some things would have to be reverted back to the default before I do that. Has anything else besides the nails and lifetime messages changed? If you have modified too much of the code, then maybe I should use my old code and just fix it up.

Sounds good, be sure to send them my way when they're done so I can include them in the later GPL v101qc+FBX package. :wink:
Will do. I completed DM1 and DM2 so far. DM2 was quite a bit easier than I thought it would be to waypoint (many of the custom maps I waypointed had more difficult buttons and traps). The bots will activate all traps, obtain all items, use all the different paths and shortcuts, etc.. They will even obtain the red armor and mega health without extending the bridge (although they will sometimes use the bridge too, just for some randomization). The most difficult part actually ended up being the train that goes to the grenade launcher and mega health. It took about 15 minutes to set that thing up properly, but the bots use it well now.

Edit: I just now saw a bot fire a grenade launcher at a button. I thought that was fixed? I guess you did not apply that fix to the developmental code?

Maybe I should use the code I have been using throughout this thead, and just find the problem that is happening with skill 1. I have uploaded it for you here Shadowborg. Maybe you can find the issue by comparing it to your code?
http://fbe.am/uuA
Dr. Shadowborg
InsideQC Staff
Posts: 1120
Joined: Sat Oct 16, 2004 3:34 pm

Re: Frikbot Item desirability

Post by Dr. Shadowborg »

Lightning Hunter wrote: So the developmental code you sent me has faster nails and such? I was going to use it as my new permanent source code for the Frikbot waypoint pack, but I guess some things would have to be reverted back to the default before I do that. Has anything else besides the nails and lifetime messages changed? If you have modified too much of the code, then maybe I should use my old code and just fix it up.
That's all I remember touching, and both are easily removed.

Just remove the newmis.velocity = newmis.velocity * 2; line from W_FireSuperSpikes, .float deathtime; from bot.qc, and this block from ClientObituary() in client.qc

Code: Select all

bprint(targ.netname);
bprint(" died after ");
bprint(ftos(time - targ.deathtime));
bprint(" seconds\n");
Lightning Hunter wrote: Edit: I just now saw a bot fire a grenade launcher at a button. I thought that was fixed? I guess you did not apply that fix to the developmental code?
The code has been applied to the developmental code. I tried it on ztnbase again, and they are definitely changing their weapon properly for buttons. Maybe he was shooting at another bot that you couldn't see?
Lightning Hunter wrote: Maybe I should use the code I have been using throughout this thead, and just find the problem that is happening with skill 1. I have uploaded it for you here Shadowborg. Maybe you can find the issue by comparing it to your code?
http://fbe.am/uuA
Found the problem, it can be fixed in one of two different ways:
Method #1: In bot_ai.qc, within bot_angle_set, change this

Code: Select all

else if (self.b_skill < 1) // skill 2 handled in bot_phys
to this:

Code: Select all

else if (self.b_skill < 2) // skill 2 handled in bot_phys
This method makes skills 0-1 use bad keyboarder controls.

Method #2:
In bot_phys.qc, within CL_KeyMove and change this:

Code: Select all

if (self.b_skill < 2) // use mouse emulation
to this:

Code: Select all

if (self.b_skill < 1) // use mouse emulation
This method will allow skill 1-2 to use mouse emulation. (but not skill 0) Skill 3 pretty much just uses instalook, so it doesn't really matter.
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

The code has been applied to the developmental code. I tried it on ztnbase again, and they are definitely changing their weapon properly for buttons. Maybe he was shooting at another bot that you couldn't see?
That's possible. The bot was standing against a door that opens using a shootable button, and was firing grenades in the general direction of the button (the bot must have fired 10 grenades or so in that direction). I thought he was aiming at the button, but maybe I missed something else.
Found the problem, it can be fixed in one of two different ways:
Method #1: In bot_ai.qc, within bot_angle_set, change this

Code: Select all

else if (self.b_skill < 1) // skill 2 handled in bot_phys
to this:

Code: Select all

else if (self.b_skill < 2) // skill 2 handled in bot_phys
This method makes skills 0-1 use bad keyboarder controls.

Method #2:
In bot_phys.qc, within CL_KeyMove and change this:

Code: Select all

if (self.b_skill < 2) // use mouse emulation
to this:

Code: Select all

if (self.b_skill < 1) // use mouse emulation
This method will allow skill 1-2 to use mouse emulation. (but not skill 0) Skill 3 pretty much just uses instalook, so it doesn't really matter.
So I'm guessing "bad keyboarder" controls makes the bots play worse than mouse emulation? If so, then skill 0 should be set that way, but skill 1 should use mouse emulation. I guess skill 2 should use mouse emulation as well, although I'm not sure what it currently uses.

Which method(s) are you using in your developmental code? I'm not even sure how the default was set.

Edit: I'm not sure if this topic has anything to with an issue I am noticing with the skill levels or not, but I do think that the bots should navigate the same way in skill 1 as they do in skill 2. I noticed that in DM2 that I just waypointed, skill 2 and 3 bots will succeed in bypassing the extending bridge and jump across the lava gap to the red armor and mega health 100% of the time, unless another bot interrupts them mid-jump. However, in Skill 1, the bots only make the jump maybe 10% of the time. This is not good, because I'm guessing a lot of people will play the bots on skill 1. I think the only difference between skill 1 and 2 should be with the aim. Skill 1 bots currently look pretty sucky with their navigation. I think the current skill 1 navigation should be what skill 0 looks like.

I have uploaded my dm2 waypoints in case you want to take a look for yourself, Shadowborg. If you want to see the difference in navigation between skills, simply spawn a bot and order it to jump across the lava gap to the red armor/mega health using the bot management menu (I have it bound to the home key). Skill 2/3 bots should make it just fine, while skill 1 bots will probably fall right in to the lava.
http://fbe.am/uv6
Dr. Shadowborg
InsideQC Staff
Posts: 1120
Joined: Sat Oct 16, 2004 3:34 pm

Re: Frikbot Item desirability

Post by Dr. Shadowborg »

Lightning Hunter wrote: So I'm guessing "bad keyboarder" controls makes the bots play worse than mouse emulation? If so, then skill 0 should be set that way, but skill 1 should use mouse emulation. I guess skill 2 should use mouse emulation as well, although I'm not sure what it currently uses.

Which method(s) are you using in your developmental code? I'm not even sure how the default was set.
Original FBX behavior was "Bad Keyboarder" for skills 0-1 (skill 0 disables some AI flags), Mouse Emulation for skill 2, and insta-look for skill 3. Developmental code was set for skill 0 = bad keyboarder (with some disabled AI flags), skill 1-2 mouse emulation, skill 3 instalook. (Method #2) Personally, I would just remove the ai flag limiters for skill 0 (retaining "bad keyboarder"), and allow skill 1 to use mouse emulation.
Lightning Hunter wrote: Edit: I'm not sure if this topic has anything to with an issue I am noticing with the skill levels or not, but I do think that the bots should navigate the same way in skill 1 as they do in skill 2. I noticed that in DM2 that I just waypointed, skill 2 and 3 bots will succeed in bypassing the extending bridge and jump across the lava gap to the red armor and mega health 100% of the time, unless another bot interrupts them mid-jump. However, in Skill 1, the bots only make the jump maybe 10% of the time. This is not good, because I'm guessing a lot of people will play the bots on skill 1. I think the only difference between skill 1 and 2 should be with the aim. Skill 1 bots currently look pretty sucky with their navigation. I think the current skill 1 navigation should be what skill 0 looks like.
Agreed.
Lightning Hunter wrote: I have uploaded my dm2 waypoints in case you want to take a look for yourself, Shadowborg. If you want to see the difference in navigation between skills, simply spawn a bot and order it to jump across the lava gap to the red armor/mega health using the bot management menu (I have it bound to the home key). Skill 2/3 bots should make it just fine, while skill 1 bots will probably fall right in to the lava.
http://fbe.am/uv6
Quite helpful, this issue would have driven me up the wall a month or so ago, now it's this easy to fix:

In bot_ai.qc, within the BotAI function, change this:

Code: Select all

if (self.b_skill < 2)
to this:

Code: Select all

if (self.b_skill < 1)
And that should take care of mistakes around certain jumps on skill 1.
Lightning Hunter
Posts: 169
Joined: Wed Nov 28, 2007 6:15 am

Re: Frikbot Item desirability

Post by Lightning Hunter »

I went ahead and set skill 1 to use mouse emulation, and changed the bit of code you mentioned. Indeed, it did fix the navigation issues! How funny that all this time, one line of code could have made waypointing easier for me. It wasn't until the last hundred or so waypointed maps that I started testing the bots on skill 3. I always tested them using skill 1, and it drove me nuts how the bots were not consistent (randomly failing jumps after tweaking the waypoints for hours). If I had realized that they could navigate better, it might have saved me hundreds of hours of headaches. :lol:

By the way, I meant to ask you about this:
Dr. Shadowborg wrote:
Lightning Hunter wrote: I was actually thinking of making a request if it's possible to add maybe 2 more skill levels, but I didn't want to bother you with such a request with so many of my other requests lately. I have no clue how difficult it would be to make the skills go up to 5 instead of 3. If there were two more skills added, they could simply be identical to the skill 3 code in every way, except have different aim offsets using Wazat's code. So something like this:

Code: Select all

// DRS: Tweaked Supa Aimcode (wazat inspired) below
// DRS: FIXME: Change this so that it's not so consistent...
            if(self.weapon != IT_GRENADE_LAUNCHER) // Grenade Launcher should not jitter
          {
             if(self.b_skill == 0)
            offset_amt = 75;
             else if (self.b_skill == 1)
                 offset_amt = 60; 
             else if (self.b_skill == 2)
            offset_amt = 45;
             else if (self.b_skill == 3)
            offset_amt = 30;
             else if (self.b_skill == 4)
            offset_amt = 15;
             else if (self.b_skill == 5)
            offset_amt = 0;

             offset_x = crandom() * offset_amt;
             offset_y = crandom() * offset_amt;
             offset_z = crandom() * offset_amt;
         }
That would give players more options if they were either getting their rear kicked by the bots, or found the bots too easy. The bots could be as difficult as being god-like with their aim, or miss almost every time (and everything in-between).
I see no reason why that code wouldn't work, beyond some small tweaks being required to support the higher skill levels. (predominately within the skill == 3 related stuff needing to be set to skill >= 3 instead)
I had no clue it would be almost as simple as adding the code in the quote. Doesn't more code have to be added for the game to recognize a skill 4 and 5? What else would need to be done? I don't know how many times skill 3 is mentioned.
Dr. Shadowborg
InsideQC Staff
Posts: 1120
Joined: Sat Oct 16, 2004 3:34 pm

Re: Frikbot Item desirability

Post by Dr. Shadowborg »

Lightning Hunter wrote: I went ahead and set skill 1 to use mouse emulation, and changed the bit of code you mentioned. Indeed, it did fix the navigation issues! How funny that all this time, one line of code could have made waypointing easier for me. It wasn't until the last hundred or so waypointed maps that I started testing the bots on skill 3. I always tested them using skill 1, and it drove me nuts how the bots were not consistent (randomly failing jumps after tweaking the waypoints for hours). If I had realized that they could navigate better, it might have saved me hundreds of hours of headaches. :lol:
Probably only existed to help differentiate skill 1 from the other skills as a sort of simulated "reflex" latency to help them screw up more. (e.g. make them more human. Even I occasionally screw up on that jump, which is why I usually jump from the handrail instead.)
Lightning Hunter wrote: By the way, I meant to ask you about this:
Dr. Shadowborg wrote:
Lightning Hunter wrote: I was actually thinking of making a request if it's possible to add maybe 2 more skill levels, but I didn't want to bother you with such a request with so many of my other requests lately. I have no clue how difficult it would be to make the skills go up to 5 instead of 3. If there were two more skills added, they could simply be identical to the skill 3 code in every way, except have different aim offsets using Wazat's code. So something like this:

Code: Select all

// DRS: Tweaked Supa Aimcode (wazat inspired) below
// DRS: FIXME: Change this so that it's not so consistent...
            if(self.weapon != IT_GRENADE_LAUNCHER) // Grenade Launcher should not jitter
          {
             if(self.b_skill == 0)
            offset_amt = 75;
             else if (self.b_skill == 1)
                 offset_amt = 60; 
             else if (self.b_skill == 2)
            offset_amt = 45;
             else if (self.b_skill == 3)
            offset_amt = 30;
             else if (self.b_skill == 4)
            offset_amt = 15;
             else if (self.b_skill == 5)
            offset_amt = 0;

             offset_x = crandom() * offset_amt;
             offset_y = crandom() * offset_amt;
             offset_z = crandom() * offset_amt;
         }
That would give players more options if they were either getting their rear kicked by the bots, or found the bots too easy. The bots could be as difficult as being god-like with their aim, or miss almost every time (and everything in-between).
I just investigated this, while theres nothing stopping you from supporting skills higher than 3 in the code, there appears to be some engine hardcoding that locks skills higher than 3 back down to 3 when switching maps. (at least there is in winquake, other engines may have removed this limitation)

Also, there appears to be some problems in the "auto respawn bots after map change" feature.

That said, theres nothing stopping you from adding support for "elite" bots via a special impulse or something.

For reference, skill related code may be found in combat.qc (nightmare monster painframe ignore), boss.qc (leading players with lavaballs), bot.qc (skill locking stuffs, bot respawning after map change), bot_ai.qc (bot_angle_set), bot_fight.qc (only one b_skill == 3 here, change it to b_skill >= 3 if you're going for higher skills)

At this point, there are enough downsides that I'd suggest maybe just making skill 0 bots easy, skill 1 bots average (good for casual / not-too- stressful to play against), skill 2 bots somewhat elite, and skill 3 bots godlike. Or maybe do what UT does and reserve one skill for "auto adjusting skill"?
Post Reply