Enemy not attacking?

Discuss programming in the QuakeC language.
ScatterBox
Posts: 50
Joined: Sun Oct 13, 2013 7:53 pm

Enemy not attacking?

Post by ScatterBox »

So as some of you might know I've been coding in a new enemy bot for my mod. Well, it's more or less a bot. I'm trying to make it more of a "Stay still" bot, so instead of it roaming the level it stays still until it notices the player..

Well, I deleted all of the old monsters from Quake since they weren't needed, and then got to work. First I made the bot base. I wrote a completely new spawn function to where the bot doesn't spawn until the player walks into a trigger tied to the bot entity. Really my reason for doing this is to save ram since my mod is for the PSP. So instead of the bots just standing around the level waiting for the player, they spawn when the player walks into the trigger. so they don't take up as much memory usage. Anyways, my spawn function *sort of* works. But really my main problem right now is that when the bot sees a player, he runs up to them and does nothing. Now, he's based off the soldier code, so what he should do is start shooting/running towards the player. So my main problem here is that the bot doesn't want to attack the player...

Now I have thought of the number of reasons as to why this doesn't work, as well as re-went through all of the forum pages looking for similar problems. The one thing that I could come up with is that the players hitbox/size has changed. I heard this makes the monsters not want to attack the player, but I looked through all of my code and compared it to fresh QC and all of the view off sets and hitbox sizes are the same.. :? I also completely removed crouching from the code as well. (partially because I don't feel like there's a use for it in my mod anyways) so that couldn't be the problem either..

So if anyone could think of a reason as to why this isn't working it would be great! I've been in the IRC getting help for a couple says now getting help for all of this. Thanks to everyone who has helped me so far! :D
ceriux
Posts: 2230
Joined: Sat Sep 06, 2008 3:30 pm
Location: Indiana, USA

Re: Enemy not attacking?

Post by ceriux »

its hard to tell with no code preview.
ScatterBox
Posts: 50
Joined: Sun Oct 13, 2013 7:53 pm

Re: Enemy not attacking?

Post by ScatterBox »

ceriux wrote:its hard to tell with no code preview.
Didn't really think I needed one since it's just as simple as default Quake, but here you go!

Code: Select all

void() spawn_a_enemy =
    {
   precache_model ("progs/enemy.mdl");
	precache_model ("progs/gib1.mdl");
	precache_model ("progs/gib2.mdl");
	precache_model ("progs/gib3.mdl");

	precache_sound ("soldier/death1.wav");
	precache_sound ("soldier/idle.wav");
	precache_sound ("soldier/pain1.wav");
	precache_sound ("soldier/pain2.wav");
	precache_sound ("soldier/sattck1.wav");
	precache_sound ("soldier/sight1.wav");

	precache_sound ("player/udeath.wav");		// gib death


	self.solid = SOLID_SLIDEBOX;
	self.movetype = MOVETYPE_STEP;
	self.flags = FL_MONSTER;

	setmodel (self, "progs/enemy.mdl");

	setsize (self, '-16 -16 -24', '16 16 40');
	self.health = 50;

	self.th_stand = army_stand1;
	self.th_walk = army_walk1;
	self.th_run = army_run1;
	self.th_missile = army_atk1;
	self.th_pain = army_pain;
	self.th_die = army_die;

	walkmonster_start ();
}
Seven
Posts: 301
Joined: Sat Oct 06, 2007 8:49 pm
Location: Germany

Re: Enemy not attacking?

Post by Seven »

Hello ScatterBox,

it worries me a little that you deleted all the monsters code, as you say.
Do you also mean the monsters code inside ai.qc and fight.qc ?

Your new monster is hunting the player.
That means that you left this function chain intact:
from FindTarget() until HuntTarget(), which will make use of self.th_run

But if your new monster does not shoot at the player, you seem to lost the call for: self.th_missile
The first important function for it is: CheckAnyAttack() (comparable with FindTarget() )
The soldiers classname is monster_army, i do not see a specific classname for your new monster.
Be sure to check for its classname inside CheckAnyAttack(), otherwise the standard function will be used: CheckAttack()
CheckAttack() is declared inside fight.qc
This function will then start your desired self.th_missile :)

You also didnt post your function: army_atk1(), which will be used then for your new monster.
You only posted the spawn functon of the new monster. Be sure to have army_atk1() in your code.

I am not sure if this is the problem, but I hope it helps a tiny little bit to find it.

Best wishes,
Seven
ScatterBox
Posts: 50
Joined: Sun Oct 13, 2013 7:53 pm

Re: Enemy not attacking?

Post by ScatterBox »

Seven wrote:Hello ScatterBox,

it worries me a little that you deleted all the monsters code, as you say.
Do you also mean the monsters code inside ai.qc and fight.qc ?

Your new monster is hunting the player.
That means that you left this function chain intact:
from FindTarget() until HuntTarget(), which will make use of self.th_run

But if your new monster does not shoot at the player, you seem to lost the call for: self.th_missile
The first important function for it is: CheckAnyAttack() (comparable with FindTarget() )
The soldiers classname is monster_army, i do not see a specific classname for your new monster.
Be sure to check for its classname inside CheckAnyAttack(), otherwise the standard function will be used: CheckAttack()
CheckAttack() is declared inside fight.qc
This function will then start your desired self.th_missile :)

You also didnt post your function: army_atk1(), which will be used then for your new monster.
You only posted the spawn functon of the new monster. Be sure to have army_atk1() in your code.

I am not sure if this is the problem, but I hope it helps a tiny little bit to find it.

Best wishes,
Seven
Thanks! The reason it didn't work was because I didn't have a classname set for the enemy. When I said I removed the monsters I meant just the qc files, not their base code. :) I hope this helps someone else who might have this problem! :)
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Enemy not attacking?

Post by frag.machine »

Glad you managed to find by yourself the fix. Just a small correction: unless PSP ports of the engine works in a radically different way from standard Quake, there's no "memory allocation" when spawning a new entity. All entities live in a preallocated static (DP and I think FTE uses heap memory, but still preallocated) array, and the spawn() builtin just finds an empty slot in this array.

In other words, deferring entities allocation won't save a single byte, and even may turn the game choppy if a great number of them are spawned at the same time.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: Enemy not attacking?

Post by Cobalt »

That was and still is a problem as far back as 1.06 .....even DP on a quad core will bog down with a few thousand or so dynamic ents created. I found this trick in the original Frogbot mod from 1998. Its a decent way of hijacking the spawn with a warning if you approach the recommended 6K (as per Lord Havoc) total number / max edicts with a float. Not that any mod really intends to have nearly 6K editcs intentionally, its just if you mess with code alot, you will eventually forget a SUB_Remove or to add a nextthink and wind up with a routine somewhare thats not removing or is creating too many.

Code: Select all

// in Defs.qc
entity () spawn_apply = #14; 
entity () spawn =
{
	if ((TOTAL_EDICTS >= 6000))
	{
	localcmd ("echo WARNING: HIgh edict count, 6000. ");
localcmd ("\n");	

		return (world);
	}

TOTAL_EDICTS = (TOTAL_EDICTS + 1);
	return (spawn_apply ());
}; 





frag.machine wrote:Glad you managed to find by yourself the fix. Just a small correction: unless PSP ports of the engine works in a radically different way from standard Quake, there's no "memory allocation" when spawning a new entity. All entities live in a preallocated static (DP and I think FTE uses heap memory, but still preallocated) array, and the spawn() builtin just finds an empty slot in this array.

In other words, deferring entities allocation won't save a single byte, and even may turn the game choppy if a great number of them are spawned at the same time.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Enemy not attacking?

Post by Spike »

you're brave if you're willing to let spawn return world. no code checks its return value. expect explosions.

if it helps, I've seen a mod intentionally and without bugs use about 200,000 entities, flood-filling a map with waypoints. Making them all visible did indeed slow things down somewhat...
certainly mods can recycle through a whole boatload of ents. especially ones that spawn worker entities for traceline contexts or whatever.

FTE uses preallocated address space, but not preallocated memory for entities, as part of its VM sandbox.
DP uses heap memory for entities. Nothing is allocated in advance.
Neither engine frees the memory until the map is changed.

Actually, memory allocation is generally regarded as faster than memory freeing. Allocation can just split blocks, while freeing requires merging things and mutex issues etc.

spawning an entity in qc involves looping through all the previously allocated entities to check to see if there are any gaps. if that wasn't enough, each one calling find or findradius or checkclient+a traceline every frame is a performance nightmare.
if they're nonsolid, invisible, and inactive they all get culled away and you won't notice.

quad-core won't help you. quake is mostly single threaded.
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Enemy not attacking?

Post by frag.machine »

@Spike: I stand corrected. Just checked DP source (function PRVM_ED_Alloc () in prvm_edict.c if anyone is interested) and indeed, it allocs additional memory space for edicts on the fly if required.

That said, most of less sophisticated Quake engines (FitzQuake and PSPQuake included) just use a preallocated array (sv_main.c, function SV_SpawnServer()):

Code: Select all

// allocate the memory	
	sv.edicts = Hunk_AllocName (sv.max_edicts * pr_edict_size, "edicts");
Therefore, my advice stills valid. ;)

EDIT: @Cobalt: I once wrote a small QC mod with similar wrappers to spawn() and remove (). It was a bit more complex though.
I changed spawn() to receive the classname of the new entity, and in my code I checked for temporary entities names like "gib", "spike", etc. to put it on a "short lived stuff" linked list. Once allocated an entity, a global counter was incremented.
In remove (), I checked again the classname to eventually remove the entity from the linked list so it always had only valid entries. Once removed the entity, the global counter was decremented.
If the global counter was too close to the engine limit I made the spawn() wrapper just grab the head entity from the linked list and remove() it before trying to call the actual spawn() builtin. Since the head was the older entity on the linked list, it was the more likely candidate to disappear and make room for another.

I didn't tested it for too long, but the code worked fine in a test map with a dozen of gib fountains (similar the ones you find in the Extras R4 mod) running FitzQuake.
Last edited by frag.machine on Mon Dec 02, 2013 4:02 am, edited 1 time in total.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
ScatterBox
Posts: 50
Joined: Sun Oct 13, 2013 7:53 pm

Re: Enemy not attacking?

Post by ScatterBox »

Hm, well after seeing all of this I'm quite surprised! Even if this doesn't help to much with performance it would still look nicer. Instead of seeing the bots just standing around the map, maybe you could walk into a trigger and one spawn behind you to add some more challenge. :)
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Enemy not attacking?

Post by frag.machine »

It's OK if it's a gameplay mechanism. But if the intention was to do premature optmization, think again. ;)
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
ScatterBox
Posts: 50
Joined: Sun Oct 13, 2013 7:53 pm

Re: Enemy not attacking?

Post by ScatterBox »

frag.machine wrote:It's OK if it's a gameplay mechanism. But if the intention was to do premature optmization, think again. ;)
It was intended to be both. :) While were on the subject though.. would there be a way I could optimize spawning to make AI hit less on the system? :)
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Enemy not attacking?

Post by Spike »

if you just want to reduce the cpu load on the server, one trick is to just stagger the nextthinks slightly, so the monsters don't all think at once. this reduces the spikes and leaves everything much smoother, despite actually increasing cpu load slightly (due to the extra calls to random() ).
you can also switch monsters to use a framegroup for at least their idle animation, which a) reduces network traffic. b) allows you to reduce the interval at which they check for players without making them jerky if there's a player sneaking up behind them.
also, make sure your map is vised. the ai will use tracelines if it thinks a player is in range and in pvs. these will hurt if you have a lot of monsters.
also, don't use gyro or equivelents, at least if the monster is still idle.
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Enemy not attacking?

Post by frag.machine »

^^^ what Spike said. :)

@Spike: do you think moving some of the builtins (specially traceline() ) to run in separated threads would improve the responsiveness ?
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Enemy not attacking?

Post by Spike »

you mean like a dedicated server?.. try it.
by the time you get the result of your traceline back, you're likely to have forgotten why you wanted it anyway.
if its specific to idle monsters, then 'meh' is my answer.
if its instead some routing algorithm to get from a to b, then threading that might help, but it would still have to cope with other changes happening while its running, which might be messy (especially as linked lists are generally involved, take a snapshot of all position state perhaps?). that would be a proper workload for a thread.
the easier solution is to just use a dedicated server.
Post Reply