QuakeZone
MOD Coding Tutorials
Quake II Coding Tutorials!

Introduction
Pre-requisites
Code
Notes
Exercises
Quake II Coding Tutorials

17 Creating Random Spawn Points #2

Introduction Introduction
Related Links

13 Original Spawn Points Tutorial
14 Tech Pick-ups Tutorial

This tutorial describe show to generate a table of random spawn points, useful when spawning pick-up items, such as Tech pick-ups (cf).

These spawn points are not strictly random as they are merely the spawn points of already existing items. In the case of this tutorial, they are those items that are not allowed to spawn (in Team Rocket, no weapons or ammo items are spawned, so their spawn points are used to build our table).

This tutorial is an improvement over the original spawn points tutorial, #13. In this tutorial, the items will merely drop at the point they are spawned. In the original, they are tossed, sometime causing them to be half-embedded in walls. Also in this tutorial, the next spawn point will be used for a new item spawning rather than a random point, thus avoiding the embarrassing situation of 2 items spawning in the same place.

Pre-requisites Pre-requisites

  • None.
Code Code


g_local.h

At the end of structure level_locals_t, add the following 2 lines:

	vec3_t		spawn_points[100];	// random spawn points
	int		num_spawn_points;	// number of spawn points	
		

g_spawn.c

In procedure InitGame, add the following line at the indicated position:

	skill = gi.cvar ("skill", "1", CVAR_LATCH);
	maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);

	level.num_spawn_points = 0;		// PJT - spawn points	
		

g_items.c

In procedure SpawnItem, add the following lines at the start of the procedure:

	// PJT - spawn points
	// create spawn points for disallowed items
	// only spawn armour and health (but may still get disallowed by dm flags)
	if (!(item->pickup == Pickup_Health || item->pickup == Pickup_Adrenaline ||
		  item->pickup == Pickup_AncientHead || item->pickup == Pickup_Armor ||
	  	  item->pickup == Pickup_PowerArmor))
	{
		// PJT - spawn rockets
		if (level.num_spawn_points < 101)
		{
			level.num_spawn_points++;
			VectorCopy(ent->s.origin, level.spawn_points[level.num_spawn_points - 1]);
		}
		// PJT
		G_FreeEdict (ent);
		return;
	}
	// PJT
		
Then add in the following new procedures near the end of the code:
// PJT - spawn rockets

edict_t *SelectRandomSpawnPoint(void)
{
	edict_t *dest;
	vec3_t	rvect;

	dest = SelectRandomDeathmatchSpawnPoint();

	if (level.num_spawn_points)
	{
		VectorCopy(level.spawn_points[(int)(random()*level.num_spawn_points-1)] , rvect);
		VectorCopy(rvect, dest->s.origin);
	}

	return dest;
}

// PJT - spawn points - overflow fix

int NextSpawnPoint(void)
{
	level.next_spawn_point++;
	if (level.next_spawn_point > level.num_spawn_points)
	{
		level.next_spawn_point = 1;
	}
	return level.next_spawn_point;
}

void RemoveSpawnPoint(void)
{

	if (level.next_spawn_point < level.num_spawn_points)
		VectorCopy(level.spawn_points[level.num_spawn_points], level.spawn_points[level.next_spawn_point]);
	level.num_spawn_points--;
}

// PJT
		
Then, in your new "spawn_your_item" procedure, add the following code:

		firstly, at top ......

int 		flag=1;		// PJT <-- add these lines at start of your procedure
trace_t		tr;		// PJT
vec3_t		dest1;		// PJT
float		*v;		// PJT

		then further down in code ........		

  // PJT - drop to floor code (overflow fix)
  while (!flag == 0)
  {

    VectorCopy(level.spawn_points[NextSpawnPoint()] , rocket->s.origin);	// PJT - overflow fix
  	v = tv(0,0,-128);
	VectorAdd (rocket->s.origin, v, dest1);

	tr = gi.trace (rocket->s.origin, rocket->mins, rocket->maxs, dest1, rocket, MASK_SOLID);
	if (tr.startsolid) // PJT <-- shouldnt get on standard maps??
	{
		flag++;
		if (flag > 10)
		{
			gi.dprintf ("droptofloor: %s startsolid at %s\n", rocket->classname, vtos(rocket->s.origin));
			// RemoveSpawnPoint();	// PJT <-- remove duff start point	..or fix point somehow?
			G_FreeEdict (rocket);
			return;
		}
	}
	else
		flag = 0;
 }

	VectorCopy (tr.endpos, rocket->s.origin);
  // PJT
		
Notes Notes to code


g_local.h
  • the level structure is amended to hold a table for the spawn points, and a counter for the number of used spawn points

g_spawn.c
  • InitGame has been amended so that, at the start of every game, the spawn point count is reset

g_items.c
  • SpawnItem has been amended to store the spawn co-ordinates of any item that is not spawned in the mod. This was particularly suited to Team Rocket as all weapons and ammo items are disallowed.
  • SelectRandomSpawnPoint does what it says on the label. However avoid using this because it won't guarantee 2 items not trying to spawn at the same point
  • NextSpawnPoint returns a vector of the next available spawn point. Provided the number of items being spawned using this routine does not exceed the number of spawn points, this will guarantee unique spawning points.
  • RemoveSpawnPoint again does precisely that. To be used by your routine that spawns item, if your routine determines that the spawn point is inappropriate (e.g. too close to wall?)
  • the final section of code is an example of how your spawning procedure would call the above procedures. In the example "rocket" is the name of the entity you are trying to spawn.
Exercises Exercises

  • I noticed that sometimes when items spawn using this code they drop through the floor and disappear from sight. I think the way round this is to use the cide that ID use for spawning items - use the item's think function to call DropToFloor on the next game frame.


Page last updated 31st March 2001