1 void dom_EventLog(string mode, float team_before, entity actor) // use an alias for easy changing and quick editing later
3 if(autocvar_sv_eventlog)
4 GameLogEcho(strcat(":dom:", mode, ":", ftos(team_before), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
7 void set_dom_state(entity e)
9 e.dom_total_pps = total_pps;
10 e.dom_pps_red = pps_red;
11 e.dom_pps_blue = pps_blue;
13 e.dom_pps_yellow = pps_yellow;
15 e.dom_pps_pink = pps_pink;
18 void dompoint_captured ()
21 float old_delay, old_team, real_team;
23 // now that the delay has expired, switch to the latest team to lay claim to this point
29 dom_EventLog("taken", self.team, self.dmg_inflictor);
30 self.dmg_inflictor = world;
32 self.goalentity = head;
33 self.model = head.mdl;
34 self.modelindex = head.dmg;
35 self.skin = head.skin;
37 float points, wait_time;
38 if (autocvar_g_domination_point_amt)
39 points = autocvar_g_domination_point_amt;
42 if (autocvar_g_domination_point_rate)
43 wait_time = autocvar_g_domination_point_rate;
45 wait_time = self.wait;
47 bprint("^3", head.netname, "^3", self.message);
49 bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
51 bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
53 if(self.enemy.playerid == self.enemy_playerid)
54 PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
60 sound(self.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
62 sound(self, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
63 if (head.noise1 != "")
64 play2all(head.noise1);
66 self.delay = time + wait_time;
69 old_delay = self.delay;
71 self.team = real_team;
75 self.delay = old_delay;
78 WaypointSprite_UpdateSprites(self.sprite, strcat("dom-", Team_ColorName_Lower(self.goalentity.team)), "", "");
80 total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
81 for(head = world; (head = find(head, classname, "dom_controlpoint")) != world; )
83 if (autocvar_g_domination_point_amt)
84 points = autocvar_g_domination_point_amt;
87 if (autocvar_g_domination_point_rate)
88 wait_time = autocvar_g_domination_point_rate;
90 wait_time = head.wait;
91 switch(head.goalentity.team)
94 pps_red += points/wait_time;
97 pps_blue += points/wait_time;
100 pps_yellow += points/wait_time;
103 pps_pink += points/wait_time;
105 total_pps += points/wait_time;
108 WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, colormapPaletteColor(self.goalentity.team - 1, 0));
109 WaypointSprite_Ping(self.sprite);
113 FOR_EACH_REALCLIENT(head)
117 void AnimateDomPoint()
119 if(self.pain_finished > time)
121 self.pain_finished = time + self.t_width;
122 if(self.nextthink > self.pain_finished)
123 self.nextthink = self.pain_finished;
125 self.frame = self.frame + 1;
126 if(self.frame > self.t_length)
134 self.nextthink = time + 0.1;
136 //self.frame = self.frame + 1;
137 //if(self.frame > 119)
143 if (gameover || self.delay > time || time < game_starttime) // game has ended, don't keep giving points
146 if(autocvar_g_domination_point_rate)
147 self.delay = time + autocvar_g_domination_point_rate;
149 self.delay = time + self.wait;
151 // give credit to the team
152 // NOTE: this defaults to 0
153 if (self.goalentity.netname != "")
155 if(autocvar_g_domination_point_amt)
156 fragamt = autocvar_g_domination_point_amt;
158 fragamt = self.frags;
159 TeamScore_AddToTeam(self.goalentity.team, ST_SCORE, fragamt);
160 TeamScore_AddToTeam(self.goalentity.team, ST_DOM_TICKS, fragamt);
162 // give credit to the individual player, if he is still there
163 if (self.enemy.playerid == self.enemy_playerid)
165 PlayerScore_Add(self.enemy, SP_SCORE, fragamt);
166 PlayerScore_Add(self.enemy, SP_DOM_TICKS, fragamt);
176 if (other.classname != "player")
178 if (other.health < 1)
181 if(time < self.captime + 0.3)
184 // only valid teams can claim it
185 head = find(world, classname, "dom_team");
186 while (head && head.team != other.team)
187 head = find(head, classname, "dom_team");
188 if (!head || head.netname == "" || head == self.goalentity)
193 self.team = self.goalentity.team; // this stores the PREVIOUS team!
195 self.cnt = other.team;
196 self.owner = head; // team to switch to after the delay
197 self.dmg_inflictor = other;
200 // self.delay = time + cvar("g_domination_point_capturetime");
201 //self.nextthink = time + cvar("g_domination_point_capturetime");
202 //self.think = dompoint_captured;
204 // go to neutral team in the mean time
205 head = find(world, classname, "dom_team");
206 while (head && head.netname != "")
207 head = find(head, classname, "dom_team");
211 WaypointSprite_UpdateSprites(self.sprite, "dom-neut", "", "");
212 WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
213 WaypointSprite_Ping(self.sprite);
215 self.goalentity = head;
216 self.model = head.mdl;
217 self.modelindex = head.dmg;
218 self.skin = head.skin;
220 self.enemy = other; // individual player scoring
221 self.enemy_playerid = other.playerid;
225 void dom_controlpoint_setup()
228 // find the spawnfunc_dom_team representing unclaimed points
229 head = find(world, classname, "dom_team");
230 while(head && head.netname != "")
231 head = find(head, classname, "dom_team");
233 objerror("no spawnfunc_dom_team with netname \"\" found\n");
235 // copy important properties from spawnfunc_dom_team entity
236 self.goalentity = head;
237 setmodel(self, head.mdl); // precision already set
238 self.skin = head.skin;
242 if(self.message == "")
243 self.message = " has captured a control point";
250 float points, waittime;
251 if (autocvar_g_domination_point_amt)
252 points = autocvar_g_domination_point_amt;
255 if (autocvar_g_domination_point_rate)
256 waittime = autocvar_g_domination_point_rate;
258 waittime = self.wait;
260 total_pps += points/waittime;
263 self.t_width = 0.02; // frame animation rate
265 self.t_length = 239; // maximum frame
267 self.think = dompointthink;
268 self.nextthink = time;
269 self.touch = dompointtouch;
270 self.solid = SOLID_TRIGGER;
271 self.flags = FL_ITEM;
272 setsize(self, '-32 -32 -32', '32 32 32');
273 setorigin(self, self.origin + '0 0 20');
276 waypoint_spawnforitem(self);
277 WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT, '0 1 1');
280 //go to best items, or control points you don't own
281 void havocbot_role_dom()
283 if(self.deadflag != DEAD_NO)
286 if (self.bot_strategytime < time)
288 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
289 navigation_goalrating_start();
290 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
291 havocbot_goalrating_items(8000, self.origin, 8000);
292 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
293 //havocbot_goalrating_waypoints(1, self.origin, 1000);
294 navigation_goalrating_end();
298 MUTATOR_HOOKFUNCTION(dom_ClientConnect)
304 MUTATOR_HOOKFUNCTION(dom_BotRoles)
306 self.havocbot_role = havocbot_role_dom;
310 /*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
311 Control point for Domination gameplay.
313 void spawnfunc_dom_controlpoint()
320 self.think = dom_controlpoint_setup;
321 self.nextthink = time + 0.1;
322 self.reset = dom_controlpoint_setup;
327 self.effects = self.effects | EF_LOWPRECISION;
328 if (autocvar_g_domination_point_fullbright)
329 self.effects |= EF_FULLBRIGHT;
332 /*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
333 Team declaration for Domination gameplay, this allows you to decide what team
334 names and control point models are used in your map.
336 Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
337 can have netname set! The nameless team owns all control points at start.
341 Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
343 Scoreboard color of the team (for example 4 is red and 13 is blue)
345 Model to use for control points owned by this team (for example
346 "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
349 Skin of the model to use (for team skins on a single model)
351 Sound to play when this team captures a point.
352 (this is a localized sound, like a small alarm or other effect)
354 Narrator speech to play when this team captures a point.
355 (this is a global sound, like "Red team has captured a control point")
358 void spawnfunc_dom_team()
360 if(!g_domination || autocvar_g_domination_teams_override >= 2)
365 precache_model(self.model);
366 if (self.noise != "")
367 precache_sound(self.noise);
368 if (self.noise1 != "")
369 precache_sound(self.noise1);
370 self.classname = "dom_team";
371 setmodel(self, self.model); // precision not needed
372 self.mdl = self.model;
373 self.dmg = self.modelindex;
376 // this would have to be changed if used in quakeworld
378 self.team = self.cnt + 1; // WHY are these different anyway?
382 void ScoreRules_dom()
384 float sp_domticks, sp_score;
385 sp_score = sp_domticks = 0;
386 if(autocvar_g_domination_disable_frags)
387 sp_domticks = SFL_SORT_PRIO_PRIMARY;
389 sp_score = SFL_SORT_PRIO_PRIMARY;
390 CheckAllowedTeams(world);
391 ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), sp_score, sp_score, TRUE);
392 ScoreInfo_SetLabel_TeamScore (ST_DOM_TICKS, "ticks", sp_domticks);
393 ScoreInfo_SetLabel_PlayerScore(SP_DOM_TICKS, "ticks", sp_domticks);
394 ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES, "takes", 0);
395 ScoreRules_basics_end();
398 // code from here on is just to support maps that don't have control point and team entities
399 void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
404 self.classname = "dom_team";
405 self.netname = teamname;
406 self.cnt = teamcolor;
407 self.model = pointmodel;
408 self.skin = pointskin;
409 self.noise = capsound;
410 self.noise1 = capnarration;
411 self.message = capmessage;
413 // this code is identical to spawnfunc_dom_team
414 setmodel(self, self.model); // precision not needed
415 self.mdl = self.model;
416 self.dmg = self.modelindex;
419 // this would have to be changed if used in quakeworld
420 self.team = self.cnt + 1;
426 void dom_spawnpoint(vector org)
431 self.classname = "dom_controlpoint";
432 self.think = spawnfunc_dom_controlpoint;
433 self.nextthink = time;
434 setorigin(self, org);
435 spawnfunc_dom_controlpoint();
439 // spawn some default teams if the map is not set up for domination
440 void dom_spawnteams()
442 float numteams = ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override);
444 dom_spawnteam("Red", NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
445 dom_spawnteam("Blue", NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
447 dom_spawnteam("Yellow", NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
449 dom_spawnteam("Pink", NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
450 dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
453 void dom_DelayedInit() // Do this check with a delay so we can wait for teams to be set up.
455 // if no teams are found, spawn defaults
456 if(find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
458 print("No ""dom_team"" entities found on this map, creating them anyway.\n");
465 void dom_Initialize()
467 precache_model("models/domination/dom_red.md3");
468 precache_model("models/domination/dom_blue.md3");
469 precache_model("models/domination/dom_yellow.md3");
470 precache_model("models/domination/dom_pink.md3");
471 precache_model("models/domination/dom_unclaimed.md3");
472 precache_sound("domination/claim.wav");
474 addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
475 addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
476 addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
477 if(c3 >= 0) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
478 if(c4 >= 0) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
480 InitializeEntity(world, dom_DelayedInit, INITPRIO_GAMETYPE);
484 MUTATOR_DEFINITION(gamemode_domination)
486 MUTATOR_HOOK(ClientConnect, dom_ClientConnect, CBC_ORDER_ANY);
487 MUTATOR_HOOK(HavocBot_ChooseRule, dom_BotRoles, CBC_ORDER_ANY);
491 if(time > 1) // game loads at time 1
492 error("This is a game type and it cannot be added at runtime.");
498 error("This is a game type and it cannot be removed at runtime.");