< Quake 3 Code 3 Arena



TUTORIAL 11 - Vortex Grenades

von AssKicka


Dieses mal werden wir die normalen grenades in vortex grenades verwandeln. Hä, wie was vortex ? Die grenade wird den Spieler quasi einsaugen, oder zumindest eine Anziehungskraft auf ihn auswirken. Wenn der Spieler sie dann berührt, explodiert sie.

1. Der Spion

Zuerst benötigen wir eine Hilfsfunktion, um den Umkreis der grenade nach potentiellen Opfern abzusuchen. Füge folgende Funktion ans Ende der Datei g_utils.c:


/*
================
findradius
================
*/
gentity_t *findradius (gentity_t *ent, vec3_t org, float rad) {

	vec3_t eorg;
	int j;

	if (!ent)
		ent = g_entities;
	else
		ent++;

	for (; ent < &g_entities[level.num_entities]; ent++)
	{
		if (!ent->inuse)
			continue;

		for (j=0; j<3; j++)
			eorg[j] = org[j] - (ent->r.currentOrigin[j] + 
			(ent->r.mins[j] + ent->r.maxs[j])*0.5);
		if (VectorLength(eorg) > rad)
			continue;
		return ent;
	}
	return NULL;
} 

Ich habe diese Funktion nicht geschrieben, sie stammt noch aus Q2 Zeiten und wurde im Laufe ihres Lebens oft überarbeitet. Was tut sie genau ? Sie iteriert über alle Entities (sofern kein Anfangswert übergeben wird), und ermittelt die Distanz zwischen der Entity und dem übergebenen Ortsvektor. Ist die Distanz kleiner als der übergebene Radius wird die Schleife verlassen und die ermittelte Entity zurückgegeben.
Der Prototyp für findradius gehört in g_local.h am besten in Nähe der restlichen utils-funktionen (Z 475):


void AddRemap(const char *oldShader, const char *newShader, float timeOffset);
const char *BuildShaderStateConfig();
gentity_t *findradius (gentity_t *ent, vec3_t org, float rad);

2. Der Staubsauger

Jetzt folgt der schwierige Teil, die think Funktion der grenade. Öffne g_missile.c und füge oberhalb von fire_plasma folgende Funktion ein(Z 490):

		  
/*
=================
G_Suck
=================
*/
static void G_Suck( gentity_t *self ) {
	gentity_t *target;
	vec3_t start,dir,end;

	target = NULL;

	// für alle Entitys innerhalb des Radius 500
	while ((target = findradius(target, self->r.currentOrigin, 500)) != NULL)
	{
		// die grenade selbst zählt nicht
		if (target == self) 
			continue;

		// Entity muss ein Client sein
		if (!target->client) 
			continue;

		// Entity darf nicht der Spieler sein, der die gren erzeugt hat 
		if (target == self->parent) 
			continue;

		// Entity muss Schaden nehmen können
		if (!target->takedamage) 
			continue;

		VectorCopy(target->r.currentOrigin, start);
		VectorCopy(self->r.currentOrigin, end); 
		// Vektor zwischen grenade und ermittelter Entity (ziel) in dir speichern
		VectorSubtract(end, start, dir); 
		VectorNormalize(dir); 
		// den Vektor auf 200 Einheiten skalieren und der Geschwindigkeit des Ziels zufügen
		VectorScale(dir,200, target->client->ps.velocity);    
	}

	self->nextthink = level.time + 40; 

	// nach x Millisek. explodieren (wir werden wait auf 20 sek setzen)
	if (level.time > self->wait) 
		G_ExplodeMissile( self);
}

Kurz gesagt: diese Funktion holt sich alle Entities innerhalb des Radius 500, siebt diejenigen aus, die sie verschonen will, und saugt alle anderen langsam aber stetig ein. Um das Testen zu erleichtern, solltest du die Anweisung
if (target == self->parent)
continue;
auskommentieren. Dadurch wirken deine grenades auch auf dich. Da sie aber bei deiner Berührung nicht explodieren, solltest du dir den Befehl "kill" auf eine Taste binden.

3. Der Mann am Hebel

Fehlt nur noch jemand, der unsere schöne Funktion aufruft. fire_grenade hat das Zeug dazu. Fast am Anfang dieser Funktion findest du folgende Zeilen(Z 675):

 
	bolt = G_Spawn();
	bolt->classname = "grenade";
	bolt->nextthink = level.time + 2500;
	bolt->think = G_ExplodeMissile;
		  

Ersetze die letzen beiden Zeilen durch folgende drei:


	bolt = G_Spawn();
	bolt->classname = "grenade";
	bolt->nextthink = level.time + 1000; // ruft G_Suck in 1 sekunde
	bolt->think = G_Suck;					// setzt unsere G_Suck als think Funtion
	bolt->wait = level.time + 20000; // Lebensdauer der grenade == 20 sek

Das war schon alles. Beim testen wird dir auffallen, dass der Ansaugeffekt nicht sehr ausgereift ist. Um eine bessere Version zu erstellen, solltest du das Tutorial Vortex Grenades II durcharbeiten.

<< Tutorial 10 | | Tutorial 12 >>