TUTORIAL 7 - Cloaking

von AssKicka


Dieses mal ärgern wir die Bots ein wenig, so wie es der Predator tut. Wir bauen ein nettes Unsichtbarkeits-Feature ein, das allerdings während der Benutzung dem Spieler Health abzieht.

1. NEUES ENTITY FLAG HINZUFÜGEN
Als erstes werden wir ein neues Entity Flag names FL_CLOAK hinzufügen, mit dem wir jeweils unsere Unsichtbarkeit ein- und ausschalten können. Öffne die Datei g_local.h, und füge folgende Zeile zu den gentity->flags hinzu:

#define FL_CLOAK 0x00020000 // health cloaking

(Eventuell müsst ihr einen anderen Wert als 0x00020000 nehmen, falls ihr den schon für andere Zwecke verwendet.)

2. NEUEN CONSOLENBEFEHL EINFÜHREN
Öffne die Datei g_cmds.c und füge vor den ClientCommands folgende Funktion ein:

/*
=================
Cmd_Cloak_f
=================
*/

void Cmd_Cloak_f( gentity_t *ent ) {

char *msg; // message to player
ent->flags ^= FL_CLOAK;
if (!(ent->flags & FL_CLOAK)) {
msg = "Cloaking OFF\n";
ent->client->ps.powerups[PW_INVIS] = level.time;
// Removes the invisible powerup from the player
} else {
msg = "Cloaking ON\n";
ent->client->ps.powerups[PW_INVIS] = level.time + 1000000000;
// Gives the invisible powerup to the player
}
trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg));

}


Hier haben wir eine Funktion erstellt, die durch das \cloak Kommando über die Konsole aufgerufen wird. Die Implementierung zum Erkennen der Eingabe in der Konsole folgt gleich. Die obige Funktion ändert den Status des Flags FL_CLOAK durch die XOR Verknüpfung, schaltet die Unsichtbarkeit an oder aus, und schreibt eine entsprechende "an" oder "aus" Meldung an den Spieler.

Aber was zum Teufel soll das "level.time + 1000000000"? Damit setzen wir die theoretische Dauer des Unsichtbarkeits-Powerups auf eine Zeit von 1666 Minuten. Wir werden dieses Powerup nicht wirklich so lange aktiviert haben, denn wir werden die Health des Spielers kontinuierlich vermindern, und ab nur noch 10 Health automatisch die Unsichtbarkeit deaktivieren.

Jetzt implementieren wir das Erkennen des Aufrufes "cloak" in der Konsole. Wir fügen weiter unten in g_cmds.c, ein weiteres else if an:


else if (Q_stricmp (cmd, "cloak") == 0)

Cmd_Cloak_f( ent );


3. HEALTH DES SPIELERS WÄHREND DER UNSICHTBARKEIT VERMINDERN
Solange das Unsichtbarkeits-Powerup aktiviert ist, wollen wir jede Sekunde die Health des Players vermindern. Öffne dazu g_active.c und gehe in den Bereich "ClientTimerActions". Die Funktion ClientTimerActions() wird genau einmal in der Sekunde aufgerufen, eignet sich also perfekt für unsere Zwecke.

Wir suchen folgenden Abschnitt:

// count down health when over max
if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {

ent->health--;

}


und ändern diesen in den Folgenden um:

if (!(ent->flags & FL_CLOAK)) {


// count down health when over max and not cloaked.

if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) {

ent->health--;

}

}

else {

// count down health when cloaked.
ent->health--;
if ( ent->health < 11) {

ent->flags ^= FL_CLOAK;
ent->client->ps.powerups[PW_INVIS] = level.time;

}

}


Schauen wir uns näher an, was wir hier getan haben. Als erstes überprüfen wir, ob FL_CLOAK aktiviert (also das Flag gesetzt) ist, wenn es NICHT gesetzt ist, überprüfen wir, ob die Health des Spielers größer als 100 (STAT_MAX_HEALTH) ist. Tritt dieser Fall ein, so vermindern wir die Health des Spielers, wie vom Original gewohnt. Wenn der Player unsichtbar ist (also FL_CLOAK gesetzt), so wird der else Teil ausgeführt, wodurch auch die Health des Spielers vermindert wird. Der Grund für diese etwas umständlichere Abfrage ist, dass wir nicht wollen, das dem Spieler gleich 2 Health Punkte pro Sekunde abgezogen werden, falls er unsichtbar ist UND über 100 Health hat. Zudem haben wir die automatische Abfrage eingebaut, die bei weniger als 11 Health die Unsichtbarkeit deaktiviert.

4. KEINE POWER-UPS WEGWERFEN WENN MAN GEFRAGGT WIRD
Der nächste Schritt ist es, das Unsichtbarkeits-Powerup zu entfernen, kurz bevor die normalen Powerups vom Spieler weggeschmissen werden, wenn er stirbt. Das brauchen wir, denn würde der Spieler sterben, während er unsichtbar ist, so würde er das Invisible-Powerup neben sich liegen lassen, und der nächste könnte dieses unendlich lange ohne Verminderung der Health benutzen (was doch ein wenig unfair wäre).

Also gehen wir nun in g_combat.c in den Bereich TossClientItems. Dort gibt es den Unterbereich markiert mit:

// drop all the powerups if not in teamplay

In den Block der darunterliegenden if-Abfrage fügen wir gleich am Anfang folgendes ein:

if (self->flags & FL_CLOAK) {

// remove the invisible powerup if the player is cloaked.
self->client->ps.powerups[PW_INVIS] = level.time;

}

Das wars auch schon, nun einfach kompilieren und die Änderungen an den ahnungslosen Bots ausprobieren :-).