
|
Quake Style - Quake 2
Tutorials |
I was laying in bed the other night and i had a
wonderful idea. I'd been doing lots of mIRC scripting that day and i wondered
how hard it would be to implement some kind of event scripting language in
quake2. Over the next few parts of this tutorial i'm going to try to write a
mini-scripting language using the quake2 console.
This is how it will work:
The user will have 2 .cfg files in a "ev" directory under their mod
dir.
EG:
C:\quake2\mymod\ev\ev_dm.cfg
C:\quake3\mymod\ev\ev_sp.cfg
ev_dm.cfg will contain deathmatch script and ev_sp.cfg will contain
singleplayer script. Adopting this for your mod you could add ev_tp.cfg for
teamplay ev_lms.cfg for last man standing etc, etc.
Right first off, you have to implement Willi's stuffcmd tutorial. It's in the
old tutorial section. Done that? Great. Now open up p_client.c and find the
ClientBeginDeathmatch() function. Now add in this code near the end of the
function:
gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname); ///Vondi Start - exec the clients deathmatch script stuffcmd(ent, "exec ev/ev_dm.cfg\n"); //Vondi End // make sure all view stuff is valid ClientEndServerFrame (ent);}
Still in p_client.c find the ClientBegin() function. Insert this
"curiously similar" code, again near the end.
gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname); ///Vondi Start - exec the clients deathmatch script if (!deathmatch) stuffcmd(ent, "exec ev/ev_dm.cfg\n"); //Vondi End // make sure all view stuff is valid ClientEndServerFrame (ent);}
Now, replace your ClientObituary function in p_client.c with this:
void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker){ int mod; char *message; char *message2; qboolean ff; if (coop->value && attacker->client) meansOfDeath |= MOD_FRIENDLY_FIRE; if (deathmatch->value || coop->value) { ff = meansOfDeath & MOD_FRIENDLY_FIRE; mod = meansOfDeath & ~MOD_FRIENDLY_FIRE; message = NULL; message2 = ""; switch (mod) { case MOD_SUICIDE: message = "suicides"; stuffcmd(attacker, "EV_death_suicide\n"); //Vondi break; case MOD_FALLING: message = "cratered"; stuffcmd(attacker, "EV_death_cratered\n"); //Vondi break; case MOD_CRUSH: message = "was squished"; stuffcmd(attacker, "EV_death_crushed\n"); //Vondi break; case MOD_WATER: message = "sank like a rock"; stuffcmd(attacker, "EV_death_drown\n"); //Vondi break; case MOD_SLIME: message = "melted"; stuffcmd(attacker, "EV_death_slime\n"); //Vondi break; case MOD_LAVA: message = "does a back flip into the lava"; stuffcmd(attacker, "EV_death_lava\n"); //Vondi break; case MOD_EXPLOSIVE: case MOD_BARREL: message = "blew up"; stuffcmd(attacker, "EV_death_explosion\n"); //Vondi break; case MOD_EXIT: message = "found a way out"; break; case MOD_TARGET_LASER: message = "saw the light"; stuffcmd(attacker, "EV_death_laser\n"); //Vondi break; case MOD_TARGET_BLASTER: message = "got blasted"; stuffcmd(attacker, "EV_death_blaster\n"); //Vondi break; case MOD_BOMB: case MOD_SPLASH: case MOD_TRIGGER_HURT: message = "was in the wrong place"; stuffcmd(attacker, "EV_death_explosion\n"); //Vondi break; } if (attacker == self) { switch (mod) { case MOD_HELD_GRENADE: message = "tried to put the pin back in"; stuffcmd(attacker, "EV_suicide_heldgrenade\n"); //Vondi break; case MOD_HG_SPLASH: case MOD_G_SPLASH: if (IsNeutral(self)) message = "tripped on its own grenade"; else if (IsFemale(self)) message = "tripped on her own grenade"; else message = "tripped on his own grenade"; stuffcmd(attacker, "EV_suicide_grenade\n"); //Vondi break; case MOD_R_SPLASH: if (IsNeutral(self)) message = "blew itself up"; else if (IsFemale(self)) message = "blew herself up"; else message = "blew himself up"; stuffcmd(attacker, "EV_suicide_rocketsplash\n"); //Vondi break; case MOD_BFG_BLAST: message = "should have used a smaller gun"; break; default: if (IsNeutral(self)) message = "killed itself"; else if (IsFemale(self)) message = "killed herself"; else message = "killed himself"; stuffcmd(attacker, "EV_suicide_bfg\n"); //Vondi break; } } if (message) { gi.bprintf (PRINT_MEDIUM, "%s %s.\n", self->client->pers.netname, message); if (deathmatch->value) self->client->resp.score--; self->enemy = NULL; return; } self->enemy = attacker; if (attacker && attacker->client) { switch (mod) { case MOD_BLASTER: message = "was blasted by"; stuffcmd(self, "EV_killed_blaster\n"); //Vondi break; case MOD_SHOTGUN: message = "was gunned down by"; stuffcmd(self, "EV_killed_shotgun\n"); //Vondi break; case MOD_SSHOTGUN: message = "was blown away by"; message2 = "'s super shotgun"; stuffcmd(self, "EV_killed_sshotgun\n"); //Vondi break; case MOD_MACHINEGUN: message = "was machinegunned by"; stuffcmd(self, "EV_killed_machinegun\n"); //Vondi break; case MOD_CHAINGUN: message = "was cut in half by"; message2 = "'s chaingun"; stuffcmd(self, "EV_killed_chaingun\n"); //Vondi break; case MOD_GRENADE: message = "was popped by"; message2 = "'s grenade"; stuffcmd(self, "EV_killed_grenade\n"); //Vondi break; case MOD_G_SPLASH: message = "was shredded by"; message2 = "'s shrapnel"; stuffcmd(self, "EV_killed_grenade_splash\n"); //Vondi break; case MOD_ROCKET: message = "ate"; message2 = "'s rocket"; stuffcmd(self, "EV_killed_rocket\n"); //Vondi break; case MOD_R_SPLASH: message = "almost dodged"; message2 = "'s rocket"; stuffcmd(self, "EV_killed_rocket_splash\n"); //Vondi break; case MOD_HYPERBLASTER: message = "was melted by"; message2 = "'s hyperblaster"; stuffcmd(self, "EV_killed_hyperblaster\n"); //Vondi break; case MOD_RAILGUN: message = "was railed by"; stuffcmd(self, "EV_killed_railgun\n"); //Vondi break; case MOD_BFG_LASER: message = "saw the pretty lights from"; message2 = "'s BFG"; stuffcmd(self, "EV_killed_bfglaser\n"); //Vondi break; case MOD_BFG_BLAST: message = "was disintegrated by"; message2 = "'s BFG blast"; stuffcmd(self, "EV_killed_bfg\n"); //Vondi break; case MOD_BFG_EFFECT: message = "couldn't hide from"; message2 = "'s BFG"; stuffcmd(self, "EV_killed_bfg\n"); //Vondi break; case MOD_HANDGRENADE: message = "caught"; message2 = "'s handgrenade"; stuffcmd(self, "EV_killed_hgrenade\n"); //Vondi break; case MOD_HG_SPLASH: message = "didn't see"; message2 = "'s handgrenade"; stuffcmd(self, "EV_killed_hgrenade_splash\n"); //Vondi break; case MOD_HELD_GRENADE: message = "feels"; message2 = "'s pain"; stuffcmd(self, "EV_killed_held_grenade\n"); //Vondi break; case MOD_TELEFRAG: message = "tried to invade"; message2 = "'s personal space"; stuffcmd(self, "EV_killed_telefrag\n"); //Vondi break; } if (message) { gi.bprintf (PRINT_MEDIUM,"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2); if (deathmatch->value) { if (ff) attacker->client->resp.score--; else attacker->client->resp.score++; } return; } } } gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname); if (deathmatch->value) self->client->resp.score--;}
Woah, thats a lot of code. What does it do? Well, the death message code seemed
a good palce to put this since the attacker/victim stuff is all their ready to
be used and im lazy. It's fairly self explanatory, read through it. (It's the
only way your going to learn, *WHIP*)
now create a "EV" dir in your mods directory. In that dir place
ev_dm.cfg and ev_sp.cfg. To bind some commands to an event do this:
alias EV_killed_bfg "say wow, i died;echo I was killed by a bfg"
Yes, they're just alias but you'd be surprised how much fun you can have with
this scripting. There are only two drawbacks.
1. Abuse, spammers can have a field day with this. (I'll be dealing with it
later)
2. Memory, if you use *ALL* of those defined events your going to use a hell of
a lot of memory and may crash quake2. I didn't do it during testing but im sure
its possible. (I'll attempt to fix this later)
-NEXT ISNTALLMENT-
You can expect:
1. More events (item pickups etc)
2. CVAR's to control the language from the server, server admins can
allow/disallow entire blocks of events or individual ones. Oh the power.
As always if you find anything screwed up in this tutorial then _PLEASE_ email
so i can correct it.
--
Credits:
Tutorial by Vondi
QS Tutorials
--
Important:
If you do use something from QuakeStyle in your mod, please give
us credit.
Our code is copyrighted, but we give permission to everyone to use
it in any way they see fit, as long as we are recognized.