3 Domination as a plugin for netquake mods
4 by LordHavoc (lordhavoc@ghdigital.com)
6 How to add domination points to a mod:
7 1. Add this line to progs.src above world.qc:
9 2. Comment out all lines in ClientObituary in client.qc that begin with targ.frags or attacker.frags.
10 3. Add this above worldspawn in world.qc:
12 4. Add this line to the end of worldspawn in world.qc:
15 Note: The only teams who can use dom control points are identified by dom_team entities (if none exist these default to red and blue and use only quake models/sounds).
19 void() dom_spawnteams;
21 void() dompointthink =
26 if (gameover) // game has ended, don't keep giving points
29 waittime = cvar("g_domination_point_rate");
32 self.nextthink = time + waittime;
34 if (!self.goalentity.netname)
38 fragamt = cvar("g_domination_point_amt");
42 head = find(head, classname, "player");
45 if (head.team == self.goalentity.team)
46 head.frags = head.frags + fragamt;
47 head = find(head, classname, "player");
49 self.goalentity.frags = self.goalentity.frags + fragamt;
52 void dompoint_captured ()
60 self.goalentity = head;
61 self.model = head.mdl;
62 self.modelindex = head.dmg;
63 self.skin = head.skin;
65 //bprint(head.message);
68 //bprint(^3head.netname);
69 //bprint(head.netname);
70 //bprint(self.message);
73 bprint(strcat("^3", head.netname, self.message, "\n"));
76 sound(self, CHAN_BODY, head.noise, 1, ATTN_NORM);
77 if (head.noise1 != "")
78 sound(self, CHAN_VOICE, head.noise1, 1, ATTN_NONE);
80 self.nextthink = time + cvar("g_domination_point_rate");
81 self.think = dompointthink;
84 void() dompointtouch =
87 if (other.classname != "player")
91 if(self.cnt > 0 && self.cnt == other.team)
94 // only valid teams can claim it
95 head = find(world, classname, "dom_team");
96 while (head && head.team != other.team)
97 head = find(head, classname, "dom_team");
98 if (!head || head.netname == "" || head == self.goalentity)
103 self.cnt = other.team;
105 self.nextthink = time + cvar("g_domination_point_capturetime");
106 self.think = dompoint_captured;
108 // go to neutral team in the mean time
110 head = find(world, classname, "dom_team");
111 while (head && head.netname != "")
112 head = find(head, classname, "dom_team");
116 self.goalentity = head;
117 self.model = head.mdl;
118 self.modelindex = head.dmg;
119 self.skin = head.skin;
122 /*QUAKED dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
123 Team declaration for Domination gameplay, this allows you to decide what team
124 names and control point models are used in your map.
126 Note: If you use dom_team entities you must define at least 3 and only two
127 can have netname set! The nameless team owns all control points at start.
131 Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
133 Scoreboard color of the team (for example 4 is red and 13 is blue)
135 Model to use for control points owned by this team (for example
136 "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
139 Skin of the model to use (for team skins on a single model)
141 Sound to play when this team captures a point.
142 (this is a localized sound, like a small alarm or other effect)
144 Narrator speech to play when this team captures a point.
145 (this is a global sound, like "Red team has captured a control point")
150 precache_model(self.model);
151 if (self.noise != "")
152 precache_sound(self.noise);
153 if (self.noise1 != "")
154 precache_sound(self.noise1);
155 self.classname = "dom_team";
156 setmodel(self, self.model);
157 self.mdl = self.model;
158 self.dmg = self.modelindex;
161 // this would have to be changed if used in quakeworld
162 self.team = self.cnt + 1;
165 void() dom_controlpoint_setup =
168 // find the dom_team representing unclaimed points
169 head = find(world, classname, "dom_team");
170 while(head && head.netname != "")
171 head = find(head, classname, "dom_team");
173 objerror("no dom_team with netname \"\" found\n");
175 // copy important properties from dom_team entity
176 self.goalentity = head;
177 setmodel(self, head.mdl);
178 self.skin = head.skin;
183 self.message = " has captured a control point";
190 self.think = dompointthink;
191 self.nextthink = time;
192 self.touch = dompointtouch;
193 self.solid = SOLID_TRIGGER;
194 setsize(self, '-32 -32 -24', '32 32 32');
195 setorigin(self, self.origin);
201 // player has joined game, get him on a team
203 /*void dom_player_join_team(entity pl)
206 float c1, c2, c3, c4, totalteams, smallestteam, smallestteam_count, selectedteam;
207 float balance_teams, force_balance, balance_type;
209 balance_teams = cvar("g_balance_teams");
210 balance_teams = cvar("g_balance_teams_force");
212 c1 = c2 = c3 = c4 = -1;
215 // first find out what teams are allowed
216 head = find(world, classname, "dom_team");
219 if(head.netname != "")
221 //if(head.team == pl.team)
223 if(head.team == COLOR_TEAM1)
227 if(head.team == COLOR_TEAM2)
231 if(head.team == COLOR_TEAM3)
235 if(head.team == COLOR_TEAM4)
240 head = find(head, classname, "dom_team");
243 // make sure there are at least 2 teams to join
245 totalteams = totalteams + 1;
247 totalteams = totalteams + 1;
249 totalteams = totalteams + 1;
251 totalteams = totalteams + 1;
254 error("dom_player_join_team: Too few teams available for domination\n");
256 // whichever teams that are available are set to 0 instead of -1
258 // if we don't care what team he ends up on, put him on whatever team he entered as.
259 // if he's not on a valid team, then put him on the smallest team
260 if(!balance_teams && !force_balance)
262 if( c1 >= 0 && pl.team == COLOR_TEAM1)
263 selectedteam = pl.team;
264 else if(c2 >= 0 && pl.team == COLOR_TEAM2)
265 selectedteam = pl.team;
266 else if(c3 >= 0 && pl.team == COLOR_TEAM3)
267 selectedteam = pl.team;
268 else if(c4 >= 0 && pl.team == COLOR_TEAM4)
269 selectedteam = pl.team;
274 SetPlayerColors(pl, selectedteam - 1);
277 // otherwise end up on the smallest team (handled below)
280 // now count how many players are on each team already
282 head = find(world, classname, "player");
285 //if(head.netname != "")
287 if(head.team == COLOR_TEAM1)
292 if(head.team == COLOR_TEAM2)
297 if(head.team == COLOR_TEAM3)
302 if(head.team == COLOR_TEAM4)
308 head = find(head, classname, "player");
311 // c1...c4 now have counts of each team
312 // figure out which is smallest, giving priority to the team the player is already on as a tie-breaker
315 smallestteam_count = 999;
317 // 2 gives priority to what team you're already on, 1 goes in order
320 if(balance_type == 1)
322 if(c1 >= 0 && c1 < smallestteam_count)
325 smallestteam_count = c1;
327 if(c2 >= 0 && c2 < smallestteam_count)
330 smallestteam_count = c2;
332 if(c3 >= 0 && c3 < smallestteam_count)
335 smallestteam_count = c3;
337 if(c4 >= 0 && c4 < smallestteam_count)
340 smallestteam_count = c4;
345 if(c1 >= 0 && (c1 < smallestteam_count ||
346 (c1 == smallestteam_count && self.team == COLOR_TEAM1) ) )
349 smallestteam_count = c1;
351 if(c2 >= 0 && c2 < (c2 < smallestteam_count ||
352 (c2 == smallestteam_count && self.team == COLOR_TEAM2) ) )
355 smallestteam_count = c2;
357 if(c3 >= 0 && c3 < (c3 < smallestteam_count ||
358 (c3 == smallestteam_count && self.team == COLOR_TEAM3) ) )
361 smallestteam_count = c3;
363 if(c4 >= 0 && c4 < (c4 < smallestteam_count ||
364 (c4 == smallestteam_count && self.team == COLOR_TEAM4) ) )
367 smallestteam_count = c4;
371 if(smallestteam == 1)
373 selectedteam = COLOR_TEAM1 - 1;
375 if(smallestteam == 2)
377 selectedteam = COLOR_TEAM2 - 1;
379 if(smallestteam == 3)
381 selectedteam = COLOR_TEAM3 - 1;
383 if(smallestteam == 4)
385 selectedteam = COLOR_TEAM4 - 1;
388 SetPlayerColors(pl, selectedteam);
391 /*QUAKED dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
392 Control point for Domination gameplay.
394 void() dom_controlpoint =
396 if(!cvar("g_domination"))
401 self.think = dom_controlpoint_setup;
402 self.nextthink = time + 0.1;
408 self.glow_size = cvar("g_domination_point_glow");
411 // code from here on is just to support maps that don't have control point and team entities
412 void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
414 local entity oldself;
417 self.classname = "dom_team";
418 self.netname = teamname;
419 self.cnt = teamcolor;
420 self.model = pointmodel;
421 self.skin = pointskin;
422 self.noise = capsound;
423 self.noise1 = capnarration;
424 self.message = capmessage;
426 // this code is identical to dom_team
427 setmodel(self, self.model);
428 self.mdl = self.model;
429 self.dmg = self.modelindex;
432 // this would have to be changed if used in quakeworld
433 self.team = self.cnt + 1;
439 void(vector org) dom_spawnpoint =
441 local entity oldself;
444 self.classname = "dom_controlpoint";
445 self.think = dom_controlpoint;
446 self.nextthink = time;
452 // spawn some default teams if the map is not set up for domination
453 void() dom_spawnteams =
457 numteams = cvar("g_domination_default_teams");
458 // LordHavoc: edit this if you want to change defaults
459 dom_spawnteam("Red", 4, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
460 dom_spawnteam("Blue", 13, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
462 dom_spawnteam("Green", 3, "models/domination/dom_green.md3", 0, "domination/claim.wav", "", "Green team has captured a control point");
464 dom_spawnteam("Yellow", 12, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
465 dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
468 void() dom_delayedinit =
472 self.think = SUB_Remove;
473 self.nextthink = time;
474 // if no teams are found, spawn defaults
475 if (find(world, classname, "dom_team") == world)
477 // if no control points are found, spawn defaults
478 if (find(world, classname, "dom_controlpoint") == world)
480 // here follow default domination points for each map
482 if (world.model == "maps/e1m1.bsp")
484 dom_spawnpoint('0 0 0');
489 // if no supported map was found, make every deathmatch spawn a point
490 head = find(world, classname, "info_player_deathmatch");
493 dom_spawnpoint(head.origin);
494 head = find(head, classname, "info_player_deathmatch");
503 // we have to precache default models/sounds even if they might not be
504 // used because worldspawn is executed before any other entities are read,
505 // so we don't even know yet if this map is set up for domination...
506 precache_model("models/domination/dom_red.md3");
507 precache_model("models/domination/dom_blue.md3");
508 precache_model("models/domination/dom_green.md3");
509 precache_model("models/domination/dom_yellow.md3");
510 precache_model("models/domination/dom_unclaimed.md3");
511 precache_sound("domination/claim.wav");
513 e.think = dom_delayedinit;
514 e.nextthink = time + 0.1;
516 // teamplay is always on in domination, defaults to hurt self but not teammates
517 //if(!cvar("teamplay"))
518 // cvar_set("teamplay", "3");