Pseudo random monster spawning - Check spawn location.

Discuss programming in the QuakeC language.
Post Reply
Ace12GA
Posts: 56
Joined: Sat Jan 28, 2012 12:08 am

Pseudo random monster spawning - Check spawn location.

Post by Ace12GA »

I am using the existing monster spawn points, and randomly choosing a place around that monster spawn point (within 128 units currently) to randomly spawn between 1 and 4 extra monsters. I have then modified the monster walk code in MONSTER.QC to remove any entity that is stuck in a wall. This works. However it dumps a lot of errors to the console from droptofloor and the actual check if the monster is stuck in a wall.

I am trying to figure out how to check the random spawn location of a monster, prior to spawning it. I want to see if that location (origin plus bounding box extents) is in a wall, or if a monster is already spawned there. droptofloor takes care of some of the cases, and unsticks them for me, however I want to avoid all the errors, and have the monsters spawned in the clear.

Is findradius supposed to return the world?

Like I said, it works as is, but its not clean.

Thanks.
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Pseudo random monster spawning - Check spawn location.

Post by leileilol »

Would using tracebox help?
i should not be here
Ace12GA
Posts: 56
Joined: Sat Jan 28, 2012 12:08 am

Re: Pseudo random monster spawning - Check spawn location.

Post by Ace12GA »

Heh, oddly enough, after I posted this I found tracebox in dpextensions. It does help, and is a great suggestion. It does have limitations, which is it is tracing a volume from a start point (the original spawn) to the proposed new origin. That said, it helps a lot; I get fully 10% of the errors I was getting. Downside, I am running into loop overload initially, and once I expanded the area that a spawn can occur in, it went away, it concerns me. Any suggestions on my math to reduce while loops would be appreciated. As this code is only being run on level load to spawn the monsters, I am not that concerned, but it is potentially a problem.

Here is my new monster_army function.

Code: Select all

void() monster_army =
{
	if (deathmatch)
	{
		remove(self);
		return;
	}
	
	local float rand_x, rand_y, rand_int, spawncount, canspawn;
	local vector neworigin, oldorigin;
	local entity new, tmp;
	
	spawncount = 0;
	rand_int = rint((random() * 4) + 1);
	while (spawncount < rand_int)
	{
		canspawn = 0;
		while (canspawn == 0)
		{
			rand_x = 0;
			rand_y = 0;
			while (rand_x > -18 && rand_x < 18)
			{
				rand_x = -512 + random() * 1024;
			}
			while (rand_y > -18 && rand_y < 18)
			{
				rand_y = -512 + random() * 1024;
			}
			neworigin_x = self.origin_x + rand_x;
			neworigin_y = self.origin_y + rand_y;
			neworigin_z = self.origin_z + 16;
			tracebox(self.origin, '-16 -16 -24', '16 16 40', neworigin, FALSE, self);
			if (trace_fraction == 1)
			{
				canspawn = 1;
			}
		}
		new = spawn();
		new.classname = "monster_army";
		new.angles = self.angles;
		setorigin(new, neworigin);
		tmp = self;
		self = new;
		monster_army_spawn();
		new = self;
		self = tmp;
		spawncount = spawncount + 1;
	}
	// Spawn original monster in intended location still.
	new = spawn();
	new.classname = "monster_army";
	new.angles = self.angles;
	setorigin(new, self.origin);
	tmp = self;
	self = new;
	monster_army_spawn();
	new = self;
	self = tmp;
}
It is reasonably fun to have a whole load of weakened monsters in pseudo random places in the map.

Image
andrewj
Posts: 133
Joined: Mon Aug 30, 2010 3:29 pm
Location: Australia

Re: Pseudo random monster spawning - Check spawn location.

Post by andrewj »

I suggest moving the code to spawn an extra monster into a separate function (will be a lot more readable that way), and limiting the amount of places to try to 16 places (or whatever), the function can just 'return' when you reach the limit.

I also suggest spawning the extra monsters AFTER the original one.
Ace12GA
Posts: 56
Joined: Sat Jan 28, 2012 12:08 am

Re: Pseudo random monster spawning - Check spawn location.

Post by Ace12GA »

Thanks for the tips. The function monster_army is a new function that calls monster_army_spawn, the original function. This was done to allow the original map entities to work, and to make it easier to work with. That said, I am eliminating the monster spawn at the original origin. Its much more interesting when the monsters (soldiers and dogs so far) are not where you remember them, and they move each time. That also eliminates two of the while loops from the code outright.

My next potential hurtle will be not spawning too many monsters... I have crashed darkplaces twice now by trying to spawn too many entities... oops. I have already reduced the maximum possible to spawn, but I think I need a better way.

It looks like this now:

Code: Select all

// The original monster_army function
void() monster_army_spawn =
{
	precache_model ("progs/soldier.mdl");
	precache_model ("progs/h_guard.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;

	setmodel (self, "progs/soldier.mdl");
	setsize (self, '-16 -16 -24', '16 16 40');
	self.health = 10;

	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 ();
};

// My new monster_army function, that calls the old one to actually spawn the monster.
void() monster_army =
{
	if (deathmatch)
	{
		remove(self);
		return;
	}
	
	local float rand_x, rand_y, rand_int, spawncount, canspawn;
	local vector neworigin, oldorigin;
	local entity new, tmp;

	spawncount = 0;
	rand_int = rint((random() * 3) + 1);
	while (spawncount < rand_int)
	{
		canspawn = 0;
		while (canspawn == 0)
		{
			rand_x = -256 + random() * 512;
			rand_y = -256 + random() * 512;
			neworigin_x = self.origin_x + rand_x;
			neworigin_y = self.origin_y + rand_y;
			neworigin_z = self.origin_z + 4;
			tracebox(self.origin, '-16 -16 -24', '16 16 40', neworigin, FALSE, self);
			if (trace_fraction == 1)
			{
				if (neworigin != '0 0 0')
				{
					canspawn = 1;
				}
			}
		}
		new = spawn();
		new.classname = "monster_army";
		new.angles = self.angles;
		setorigin(new, neworigin);
		tmp = self;
		self = new;
		monster_army_spawn();
		new = self;
		self = tmp;
		spawncount = spawncount + 1;
	}
}
Post Reply