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 dompoint_captured ()
29 self.goalentity = head;
30 self.model = head.mdl;
31 self.modelindex = head.dmg;
32 self.skin = head.skin;
34 //bprint(head.message);
37 //bprint(^3head.netname);
38 //bprint(head.netname);
39 //bprint(self.message);
42 bprint(strcat("^3", head.netname, "^3", self.message, "\n"));
45 sound(self, CHAN_BODY, head.noise, 1, ATTN_NORM);
46 if (head.noise1 != "")
47 sound(self, CHAN_VOICE, head.noise1, 1, ATTN_NONE);
49 //self.nextthink = time + cvar("g_domination_point_rate");
50 //self.think = dompointthink;
51 self.delay = time + cvar("g_domination_point_rate");
54 void AnimateDomPoint()
56 if(self.pain_finished > time)
58 self.pain_finished = time + self.t_width;
59 if(self.nextthink > self.pain_finished)
60 self.nextthink = self.pain_finished;
62 self.frame = self.frame + 1;
63 if(self.frame > self.t_length)
67 void() dompointthink =
73 self.nextthink = time + 0.1;
75 //self.frame = self.frame + 1;
76 //if(self.frame > 119)
82 if (gameover) // game has ended, don't keep giving points
95 waittime = cvar("g_domination_point_rate");
98 self.delay = time + waittime;
100 if (!self.goalentity.netname)
104 fragamt = cvar("g_domination_point_amt");
106 fragamt = self.frags;
108 head = find(head, classname, "player");
111 if (head.team == self.goalentity.team)
112 head.frags = head.frags + fragamt;
113 head = find(head, classname, "player");
115 self.goalentity.frags = self.goalentity.frags + fragamt;
118 void() dompointtouch =
121 if (other.classname != "player")
123 if (other.health < 1)
125 if(self.cnt > 0 && self.cnt == other.team)
128 // only valid teams can claim it
129 head = find(world, classname, "dom_team");
130 while (head && head.team != other.team)
131 head = find(head, classname, "dom_team");
132 if (!head || head.netname == "" || head == self.goalentity)
137 self.cnt = other.team;
141 self.delay = time + cvar("g_domination_point_capturetime");
142 //self.nextthink = time + cvar("g_domination_point_capturetime");
143 //self.think = dompoint_captured;
144 // go to neutral team in the mean time
146 head = find(world, classname, "dom_team");
147 while (head && head.netname != "")
148 head = find(head, classname, "dom_team");
152 self.goalentity = head;
153 self.model = head.mdl;
154 self.modelindex = head.dmg;
155 self.skin = head.skin;
158 /*QUAKED dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
159 Team declaration for Domination gameplay, this allows you to decide what team
160 names and control point models are used in your map.
162 Note: If you use dom_team entities you must define at least 3 and only two
163 can have netname set! The nameless team owns all control points at start.
167 Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
169 Scoreboard color of the team (for example 4 is red and 13 is blue)
171 Model to use for control points owned by this team (for example
172 "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
175 Skin of the model to use (for team skins on a single model)
177 Sound to play when this team captures a point.
178 (this is a localized sound, like a small alarm or other effect)
180 Narrator speech to play when this team captures a point.
181 (this is a global sound, like "Red team has captured a control point")
186 precache_model(self.model);
187 if (self.noise != "")
188 precache_sound(self.noise);
189 if (self.noise1 != "")
190 precache_sound(self.noise1);
191 self.classname = "dom_team";
192 setmodel(self, self.model);
193 self.mdl = self.model;
194 self.dmg = self.modelindex;
197 // this would have to be changed if used in quakeworld
198 self.team = self.cnt + 1;
201 void() dom_controlpoint_setup =
204 // find the dom_team representing unclaimed points
205 head = find(world, classname, "dom_team");
206 while(head && head.netname != "")
207 head = find(head, classname, "dom_team");
209 objerror("no dom_team with netname \"\" found\n");
211 // copy important properties from dom_team entity
212 self.goalentity = head;
213 setmodel(self, head.mdl);
214 self.skin = head.skin;
219 self.message = " has captured a control point";
227 self.t_width = 0.1; // frame animation rate
229 self.t_length = 119; // maximum frame
231 self.think = dompointthink;
232 self.nextthink = time;
233 self.touch = dompointtouch;
234 self.solid = SOLID_TRIGGER;
235 self.flags = FL_ITEM;
236 setsize(self, '-32 -32 -24', '32 32 32');
237 setorigin(self, self.origin + '0 0 20');
243 // player has joined game, get him on a team
245 /*void dom_player_join_team(entity pl)
248 float c1, c2, c3, c4, totalteams, smallestteam, smallestteam_count, selectedteam;
249 float balance_teams, force_balance, balance_type;
251 balance_teams = cvar("g_balance_teams");
252 balance_teams = cvar("g_balance_teams_force");
254 c1 = c2 = c3 = c4 = -1;
257 // first find out what teams are allowed
258 head = find(world, classname, "dom_team");
261 if(head.netname != "")
263 //if(head.team == pl.team)
265 if(head.team == COLOR_TEAM1)
269 if(head.team == COLOR_TEAM2)
273 if(head.team == COLOR_TEAM3)
277 if(head.team == COLOR_TEAM4)
282 head = find(head, classname, "dom_team");
285 // make sure there are at least 2 teams to join
287 totalteams = totalteams + 1;
289 totalteams = totalteams + 1;
291 totalteams = totalteams + 1;
293 totalteams = totalteams + 1;
296 error("dom_player_join_team: Too few teams available for domination\n");
298 // whichever teams that are available are set to 0 instead of -1
300 // if we don't care what team he ends up on, put him on whatever team he entered as.
301 // if he's not on a valid team, then put him on the smallest team
302 if(!balance_teams && !force_balance)
304 if( c1 >= 0 && pl.team == COLOR_TEAM1)
305 selectedteam = pl.team;
306 else if(c2 >= 0 && pl.team == COLOR_TEAM2)
307 selectedteam = pl.team;
308 else if(c3 >= 0 && pl.team == COLOR_TEAM3)
309 selectedteam = pl.team;
310 else if(c4 >= 0 && pl.team == COLOR_TEAM4)
311 selectedteam = pl.team;
316 SetPlayerColors(pl, selectedteam - 1);
319 // otherwise end up on the smallest team (handled below)
322 // now count how many players are on each team already
324 head = find(world, classname, "player");
327 //if(head.netname != "")
329 if(head.team == COLOR_TEAM1)
334 if(head.team == COLOR_TEAM2)
339 if(head.team == COLOR_TEAM3)
344 if(head.team == COLOR_TEAM4)
350 head = find(head, classname, "player");
353 // c1...c4 now have counts of each team
354 // figure out which is smallest, giving priority to the team the player is already on as a tie-breaker
357 smallestteam_count = 999;
359 // 2 gives priority to what team you're already on, 1 goes in order
362 if(balance_type == 1)
364 if(c1 >= 0 && c1 < smallestteam_count)
367 smallestteam_count = c1;
369 if(c2 >= 0 && c2 < smallestteam_count)
372 smallestteam_count = c2;
374 if(c3 >= 0 && c3 < smallestteam_count)
377 smallestteam_count = c3;
379 if(c4 >= 0 && c4 < smallestteam_count)
382 smallestteam_count = c4;
387 if(c1 >= 0 && (c1 < smallestteam_count ||
388 (c1 == smallestteam_count && self.team == COLOR_TEAM1) ) )
391 smallestteam_count = c1;
393 if(c2 >= 0 && c2 < (c2 < smallestteam_count ||
394 (c2 == smallestteam_count && self.team == COLOR_TEAM2) ) )
397 smallestteam_count = c2;
399 if(c3 >= 0 && c3 < (c3 < smallestteam_count ||
400 (c3 == smallestteam_count && self.team == COLOR_TEAM3) ) )
403 smallestteam_count = c3;
405 if(c4 >= 0 && c4 < (c4 < smallestteam_count ||
406 (c4 == smallestteam_count && self.team == COLOR_TEAM4) ) )
409 smallestteam_count = c4;
413 if(smallestteam == 1)
415 selectedteam = COLOR_TEAM1 - 1;
417 if(smallestteam == 2)
419 selectedteam = COLOR_TEAM2 - 1;
421 if(smallestteam == 3)
423 selectedteam = COLOR_TEAM3 - 1;
425 if(smallestteam == 4)
427 selectedteam = COLOR_TEAM4 - 1;
430 SetPlayerColors(pl, selectedteam);
433 /*QUAKED dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
434 Control point for Domination gameplay.
436 void() dom_controlpoint =
438 if(!cvar("g_domination"))
443 self.think = dom_controlpoint_setup;
444 self.nextthink = time + 0.1;
449 //if(!self.glow_size)
450 // self.glow_size = cvar("g_domination_point_glow");
451 self.effects = self.effects | EF_FULLBRIGHT;
454 // code from here on is just to support maps that don't have control point and team entities
455 void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
457 local entity oldself;
460 self.classname = "dom_team";
461 self.netname = teamname;
462 self.cnt = teamcolor;
463 self.model = pointmodel;
464 self.skin = pointskin;
465 self.noise = capsound;
466 self.noise1 = capnarration;
467 self.message = capmessage;
469 // this code is identical to dom_team
470 setmodel(self, self.model);
471 self.mdl = self.model;
472 self.dmg = self.modelindex;
475 // this would have to be changed if used in quakeworld
476 self.team = self.cnt + 1;
482 void(vector org) dom_spawnpoint =
484 local entity oldself;
487 self.classname = "dom_controlpoint";
488 self.think = dom_controlpoint;
489 self.nextthink = time;
495 // spawn some default teams if the map is not set up for domination
496 void() dom_spawnteams =
500 numteams = cvar("g_domination_default_teams");
501 // LordHavoc: edit this if you want to change defaults
502 dom_spawnteam("Red", 4, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
503 dom_spawnteam("Blue", 13, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
505 dom_spawnteam("Pink", 9, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
507 dom_spawnteam("Yellow", 12, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
508 dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
511 void() dom_delayedinit =
515 self.think = SUB_Remove;
516 self.nextthink = time;
517 // if no teams are found, spawn defaults
518 if (find(world, classname, "dom_team") == world)
520 // if no control points are found, spawn defaults
521 if (find(world, classname, "dom_controlpoint") == world)
523 // here follow default domination points for each map
525 if (world.model == "maps/e1m1.bsp")
527 dom_spawnpoint('0 0 0');
532 // if no supported map was found, make every deathmatch spawn a point
533 head = find(world, classname, "info_player_deathmatch");
536 dom_spawnpoint(head.origin);
537 head = find(head, classname, "info_player_deathmatch");
546 // we have to precache default models/sounds even if they might not be
547 // used because worldspawn is executed before any other entities are read,
548 // so we don't even know yet if this map is set up for domination...
549 precache_model("models/domination/dom_red.md3");
550 precache_model("models/domination/dom_blue.md3");
551 precache_model("models/domination/dom_pink.md3");
552 precache_model("models/domination/dom_yellow.md3");
553 precache_model("models/domination/dom_unclaimed.md3");
554 precache_sound("domination/claim.wav");
556 e.think = dom_delayedinit;
557 e.nextthink = time + 0.1;
559 // teamplay is always on in domination, defaults to hurt self but not teammates
560 //if(!cvar("teamplay"))
561 // cvar_set("teamplay", "3");