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, 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 setsize(self, '-32 -32 -24', '32 32 32');
236 setorigin(self, self.origin + '0 0 20');
242 // player has joined game, get him on a team
244 /*void dom_player_join_team(entity pl)
247 float c1, c2, c3, c4, totalteams, smallestteam, smallestteam_count, selectedteam;
248 float balance_teams, force_balance, balance_type;
250 balance_teams = cvar("g_balance_teams");
251 balance_teams = cvar("g_balance_teams_force");
253 c1 = c2 = c3 = c4 = -1;
256 // first find out what teams are allowed
257 head = find(world, classname, "dom_team");
260 if(head.netname != "")
262 //if(head.team == pl.team)
264 if(head.team == COLOR_TEAM1)
268 if(head.team == COLOR_TEAM2)
272 if(head.team == COLOR_TEAM3)
276 if(head.team == COLOR_TEAM4)
281 head = find(head, classname, "dom_team");
284 // make sure there are at least 2 teams to join
286 totalteams = totalteams + 1;
288 totalteams = totalteams + 1;
290 totalteams = totalteams + 1;
292 totalteams = totalteams + 1;
295 error("dom_player_join_team: Too few teams available for domination\n");
297 // whichever teams that are available are set to 0 instead of -1
299 // if we don't care what team he ends up on, put him on whatever team he entered as.
300 // if he's not on a valid team, then put him on the smallest team
301 if(!balance_teams && !force_balance)
303 if( c1 >= 0 && pl.team == COLOR_TEAM1)
304 selectedteam = pl.team;
305 else if(c2 >= 0 && pl.team == COLOR_TEAM2)
306 selectedteam = pl.team;
307 else if(c3 >= 0 && pl.team == COLOR_TEAM3)
308 selectedteam = pl.team;
309 else if(c4 >= 0 && pl.team == COLOR_TEAM4)
310 selectedteam = pl.team;
315 SetPlayerColors(pl, selectedteam - 1);
318 // otherwise end up on the smallest team (handled below)
321 // now count how many players are on each team already
323 head = find(world, classname, "player");
326 //if(head.netname != "")
328 if(head.team == COLOR_TEAM1)
333 if(head.team == COLOR_TEAM2)
338 if(head.team == COLOR_TEAM3)
343 if(head.team == COLOR_TEAM4)
349 head = find(head, classname, "player");
352 // c1...c4 now have counts of each team
353 // figure out which is smallest, giving priority to the team the player is already on as a tie-breaker
356 smallestteam_count = 999;
358 // 2 gives priority to what team you're already on, 1 goes in order
361 if(balance_type == 1)
363 if(c1 >= 0 && c1 < smallestteam_count)
366 smallestteam_count = c1;
368 if(c2 >= 0 && c2 < smallestteam_count)
371 smallestteam_count = c2;
373 if(c3 >= 0 && c3 < smallestteam_count)
376 smallestteam_count = c3;
378 if(c4 >= 0 && c4 < smallestteam_count)
381 smallestteam_count = c4;
386 if(c1 >= 0 && (c1 < smallestteam_count ||
387 (c1 == smallestteam_count && self.team == COLOR_TEAM1) ) )
390 smallestteam_count = c1;
392 if(c2 >= 0 && c2 < (c2 < smallestteam_count ||
393 (c2 == smallestteam_count && self.team == COLOR_TEAM2) ) )
396 smallestteam_count = c2;
398 if(c3 >= 0 && c3 < (c3 < smallestteam_count ||
399 (c3 == smallestteam_count && self.team == COLOR_TEAM3) ) )
402 smallestteam_count = c3;
404 if(c4 >= 0 && c4 < (c4 < smallestteam_count ||
405 (c4 == smallestteam_count && self.team == COLOR_TEAM4) ) )
408 smallestteam_count = c4;
412 if(smallestteam == 1)
414 selectedteam = COLOR_TEAM1 - 1;
416 if(smallestteam == 2)
418 selectedteam = COLOR_TEAM2 - 1;
420 if(smallestteam == 3)
422 selectedteam = COLOR_TEAM3 - 1;
424 if(smallestteam == 4)
426 selectedteam = COLOR_TEAM4 - 1;
429 SetPlayerColors(pl, selectedteam);
432 /*QUAKED dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
433 Control point for Domination gameplay.
435 void() dom_controlpoint =
437 if(!cvar("g_domination"))
442 self.think = dom_controlpoint_setup;
443 self.nextthink = time + 0.1;
448 //if(!self.glow_size)
449 // self.glow_size = cvar("g_domination_point_glow");
450 self.effects = self.effects | EF_FULLBRIGHT;
453 // code from here on is just to support maps that don't have control point and team entities
454 void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
456 local entity oldself;
459 self.classname = "dom_team";
460 self.netname = teamname;
461 self.cnt = teamcolor;
462 self.model = pointmodel;
463 self.skin = pointskin;
464 self.noise = capsound;
465 self.noise1 = capnarration;
466 self.message = capmessage;
468 // this code is identical to dom_team
469 setmodel(self, self.model);
470 self.mdl = self.model;
471 self.dmg = self.modelindex;
474 // this would have to be changed if used in quakeworld
475 self.team = self.cnt + 1;
481 void(vector org) dom_spawnpoint =
483 local entity oldself;
486 self.classname = "dom_controlpoint";
487 self.think = dom_controlpoint;
488 self.nextthink = time;
494 // spawn some default teams if the map is not set up for domination
495 void() dom_spawnteams =
499 numteams = cvar("g_domination_default_teams");
500 // LordHavoc: edit this if you want to change defaults
501 dom_spawnteam("Red", 4, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
502 dom_spawnteam("Blue", 13, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
504 dom_spawnteam("Green", 3, "models/domination/dom_green.md3", 0, "domination/claim.wav", "", "Green team has captured a control point");
506 dom_spawnteam("Yellow", 12, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
507 dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
510 void() dom_delayedinit =
514 self.think = SUB_Remove;
515 self.nextthink = time;
516 // if no teams are found, spawn defaults
517 if (find(world, classname, "dom_team") == world)
519 // if no control points are found, spawn defaults
520 if (find(world, classname, "dom_controlpoint") == world)
522 // here follow default domination points for each map
524 if (world.model == "maps/e1m1.bsp")
526 dom_spawnpoint('0 0 0');
531 // if no supported map was found, make every deathmatch spawn a point
532 head = find(world, classname, "info_player_deathmatch");
535 dom_spawnpoint(head.origin);
536 head = find(head, classname, "info_player_deathmatch");
545 // we have to precache default models/sounds even if they might not be
546 // used because worldspawn is executed before any other entities are read,
547 // so we don't even know yet if this map is set up for domination...
548 precache_model("models/domination/dom_red.md3");
549 precache_model("models/domination/dom_blue.md3");
550 precache_model("models/domination/dom_green.md3");
551 precache_model("models/domination/dom_yellow.md3");
552 precache_model("models/domination/dom_unclaimed.md3");
553 precache_sound("domination/claim.wav");
555 e.think = dom_delayedinit;
556 e.nextthink = time + 0.1;
558 // teamplay is always on in domination, defaults to hurt self but not teammates
559 //if(!cvar("teamplay"))
560 // cvar_set("teamplay", "3");