--- /dev/null
- case COLOR_TEAM1:
+
+ /*
+ Domination as a plugin for netquake mods
+ by LordHavoc (lordhavoc@ghdigital.com)
+
+ How to add domination points to a mod:
+ 1. Add this line to progs.src above world.qc:
+ domination.qc
+ 2. Comment out all lines in ClientObituary in client.qc that begin with targ.frags or attacker.frags.
+ 3. Add this above spawnfunc_worldspawn in world.qc:
+ void() dom_init;
+ 4. Add this line to the end of spawnfunc_worldspawn in world.qc:
+ dom_init();
+
+ Note: The only teams who can use dom control points are identified by spawnfunc_dom_team entities (if none exist these default to red and blue and use only quake models/sounds).
+ */
+
+ #define DOMPOINTFRAGS frags
+
+ .float enemy_playerid;
+ .entity sprite;
+ .float captime;
+
+ // pps: points per second
+ .float dom_total_pps;
+ .float dom_pps_red;
+ .float dom_pps_blue;
+ .float dom_pps_yellow;
+ .float dom_pps_pink;
+ float total_pps;
+ float pps_red;
+ float pps_blue;
+ float pps_yellow;
+ float pps_pink;
+ void set_dom_state(entity e)
+ {
+ e.dom_total_pps = total_pps;
+ e.dom_pps_red = pps_red;
+ e.dom_pps_blue = pps_blue;
+ if(c3 >= 0)
+ e.dom_pps_yellow = pps_yellow;
+ if(c4 >= 0)
+ e.dom_pps_pink = pps_pink;
+ }
+
+ void() dom_controlpoint_setup;
+
+ void LogDom(string mode, float team_before, entity actor)
+ {
+ string s;
+ if(!autocvar_sv_eventlog)
+ return;
+ s = strcat(":dom:", mode);
+ s = strcat(s, ":", ftos(team_before));
+ s = strcat(s, ":", ftos(actor.playerid));
+ GameLogEcho(s);
+ }
+
+ void() dom_spawnteams;
+
+ void dompoint_captured ()
+ {
+ entity head;
+ float old_delay, old_team, real_team;
+
+ // now that the delay has expired, switch to the latest team to lay claim to this point
+ head = self.owner;
+
+ real_team = self.cnt;
+ self.cnt = -1;
+
+ LogDom("taken", self.team, self.dmg_inflictor);
+ self.dmg_inflictor = world;
+
+ self.goalentity = head;
+ self.model = head.mdl;
+ self.modelindex = head.dmg;
+ self.skin = head.skin;
+
+ //bprint(head.message);
+ //bprint("\n");
+
+ //bprint(^3head.netname);
+ //bprint(head.netname);
+ //bprint(self.message);
+ //bprint("\n");
+
+ float points, wait_time;
+ if (autocvar_g_domination_point_amt)
+ points = autocvar_g_domination_point_amt;
+ else
+ points = self.frags;
+ if (autocvar_g_domination_point_rate)
+ wait_time = autocvar_g_domination_point_rate;
+ else
+ wait_time = self.wait;
+
+ bprint("^3", head.netname, "^3", self.message);
+ if (points != 1)
+ bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
+ else
+ bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
+
+ if(self.enemy.playerid == self.enemy_playerid)
+ PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
+ else
+ self.enemy = world;
+
+ if (head.noise != "")
+ if(self.enemy)
+ sound(self.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+ else
+ sound(self, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+ if (head.noise1 != "")
+ play2all(head.noise1);
+
+ //self.nextthink = time + autocvar_g_domination_point_rate;
+ //self.think = dompointthink;
+
+ self.delay = time + wait_time;
+
+ // do trigger work
+ old_delay = self.delay;
+ old_team = self.team;
+ self.team = real_team;
+ self.delay = 0;
+ activator = self;
+ SUB_UseTargets ();
+ self.delay = old_delay;
+ self.team = old_team;
+
+ switch(self.goalentity.team)
+ {
- case COLOR_TEAM2:
++ case FL_TEAM_1:
+ WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", "");
+ break;
- case COLOR_TEAM3:
++ case FL_TEAM_2:
+ WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", "");
+ break;
- case COLOR_TEAM4:
++ case FL_TEAM_3:
+ WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", "");
+ break;
- case COLOR_TEAM1:
++ case FL_TEAM_4:
+ WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", "");
+ }
+
+ total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+ for(head = world; (head = find(head, classname, "dom_controlpoint")) != world; )
+ {
+ if (autocvar_g_domination_point_amt)
+ points = autocvar_g_domination_point_amt;
+ else
+ points = head.frags;
+ if (autocvar_g_domination_point_rate)
+ wait_time = autocvar_g_domination_point_rate;
+ else
+ wait_time = head.wait;
+ switch(head.goalentity.team)
+ {
- case COLOR_TEAM2:
++ case FL_TEAM_1:
+ pps_red += points/wait_time;
+ break;
- case COLOR_TEAM3:
++ case FL_TEAM_2:
+ pps_blue += points/wait_time;
+ break;
- case COLOR_TEAM4:
++ case FL_TEAM_3:
+ pps_yellow += points/wait_time;
+ break;
- dom_spawnteam("Red", COLOR_TEAM1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
- dom_spawnteam("Blue", COLOR_TEAM2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
++ case FL_TEAM_4:
+ pps_pink += points/wait_time;
+ }
+ total_pps += points/wait_time;
+ }
+
+ WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, colormapPaletteColor(self.goalentity.team - 1, 0));
+ WaypointSprite_Ping(self.sprite);
+
+ self.captime = time;
+
+ FOR_EACH_REALCLIENT(head)
+ set_dom_state(head);
+ }
+
+ void AnimateDomPoint()
+ {
+ if(self.pain_finished > time)
+ return;
+ self.pain_finished = time + self.t_width;
+ if(self.nextthink > self.pain_finished)
+ self.nextthink = self.pain_finished;
+
+ self.frame = self.frame + 1;
+ if(self.frame > self.t_length)
+ self.frame = 0;
+ }
+
+ void dompointthink()
+ {
+ float fragamt;
+
+ self.nextthink = time + 0.1;
+
+ //self.frame = self.frame + 1;
+ //if(self.frame > 119)
+ // self.frame = 0;
+ AnimateDomPoint();
+
+ // give points
+
+ if (gameover || self.delay > time || time < game_starttime) // game has ended, don't keep giving points
+ return;
+
+ if(autocvar_g_domination_point_rate)
+ self.delay = time + autocvar_g_domination_point_rate;
+ else
+ self.delay = time + self.wait;
+
+ // give credit to the team
+ // NOTE: this defaults to 0
+ if (self.goalentity.netname != "")
+ {
+ if(autocvar_g_domination_point_amt)
+ fragamt = autocvar_g_domination_point_amt;
+ else
+ fragamt = self.DOMPOINTFRAGS;
+ TeamScore_AddToTeam(self.goalentity.team, ST_SCORE, fragamt);
+ TeamScore_AddToTeam(self.goalentity.team, ST_DOM_TICKS, fragamt);
+
+ // give credit to the individual player, if he is still there
+ if (self.enemy.playerid == self.enemy_playerid)
+ {
+ PlayerScore_Add(self.enemy, SP_SCORE, fragamt);
+ PlayerScore_Add(self.enemy, SP_DOM_TICKS, fragamt);
+ }
+ else
+ self.enemy = world;
+ }
+ }
+
+ void dompointtouch()
+ {
+ entity head;
+ if (other.classname != "player")
+ return;
+ if (other.health < 1)
+ return;
+
+ if(time < self.captime + 0.3)
+ return;
+
+ // only valid teams can claim it
+ head = find(world, classname, "dom_team");
+ while (head && head.team != other.team)
+ head = find(head, classname, "dom_team");
+ if (!head || head.netname == "" || head == self.goalentity)
+ return;
+
+ // delay capture
+
+ self.team = self.goalentity.team; // this stores the PREVIOUS team!
+
+ self.cnt = other.team;
+ self.owner = head; // team to switch to after the delay
+ self.dmg_inflictor = other;
+
+ // self.state = 1;
+ // self.delay = time + cvar("g_domination_point_capturetime");
+ //self.nextthink = time + cvar("g_domination_point_capturetime");
+ //self.think = dompoint_captured;
+
+ // go to neutral team in the mean time
+ head = find(world, classname, "dom_team");
+ while (head && head.netname != "")
+ head = find(head, classname, "dom_team");
+ if(head == world)
+ return;
+
+ WaypointSprite_UpdateSprites(self.sprite, "dom-neut", "", "");
+ WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
+ WaypointSprite_Ping(self.sprite);
+
+ self.goalentity = head;
+ self.model = head.mdl;
+ self.modelindex = head.dmg;
+ self.skin = head.skin;
+
+ self.enemy = other; // individual player scoring
+ self.enemy_playerid = other.playerid;
+ dompoint_captured();
+ }
+
+ /*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
+ Team declaration for Domination gameplay, this allows you to decide what team
+ names and control point models are used in your map.
+
+ Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
+ can have netname set! The nameless team owns all control points at start.
+
+ Keys:
+ "netname"
+ Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
+ "cnt"
+ Scoreboard color of the team (for example 4 is red and 13 is blue)
+ "model"
+ Model to use for control points owned by this team (for example
+ "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
+ keycard)
+ "skin"
+ Skin of the model to use (for team skins on a single model)
+ "noise"
+ Sound to play when this team captures a point.
+ (this is a localized sound, like a small alarm or other effect)
+ "noise1"
+ Narrator speech to play when this team captures a point.
+ (this is a global sound, like "Red team has captured a control point")
+ */
+
+ void spawnfunc_dom_team()
+ {
+ if(!g_domination || autocvar_g_domination_teams_override >= 2)
+ {
+ remove(self);
+ return;
+ }
+ precache_model(self.model);
+ if (self.noise != "")
+ precache_sound(self.noise);
+ if (self.noise1 != "")
+ precache_sound(self.noise1);
+ self.classname = "dom_team";
+ setmodel(self, self.model); // precision not needed
+ self.mdl = self.model;
+ self.dmg = self.modelindex;
+ self.model = "";
+ self.modelindex = 0;
+ // this would have to be changed if used in quakeworld
+ if(self.cnt)
+ self.team = self.cnt + 1; // WHY are these different anyway?
+ }
+
+ void dom_controlpoint_setup()
+ {
+ entity head;
+ // find the spawnfunc_dom_team representing unclaimed points
+ head = find(world, classname, "dom_team");
+ while(head && head.netname != "")
+ head = find(head, classname, "dom_team");
+ if (!head)
+ objerror("no spawnfunc_dom_team with netname \"\" found\n");
+
+ // copy important properties from spawnfunc_dom_team entity
+ self.goalentity = head;
+ setmodel(self, head.mdl); // precision already set
+ self.skin = head.skin;
+
+ self.cnt = -1;
+
+ if(self.message == "")
+ self.message = " has captured a control point";
+
+ if(self.DOMPOINTFRAGS <= 0)
+ self.DOMPOINTFRAGS = 1;
+ if(self.wait <= 0)
+ self.wait = 5;
+
+ float points, waittime;
+ if (autocvar_g_domination_point_amt)
+ points = autocvar_g_domination_point_amt;
+ else
+ points = self.frags;
+ if (autocvar_g_domination_point_rate)
+ waittime = autocvar_g_domination_point_rate;
+ else
+ waittime = self.wait;
+
+ total_pps += points/waittime;
+
+ if(!self.t_width)
+ self.t_width = 0.02; // frame animation rate
+ if(!self.t_length)
+ self.t_length = 239; // maximum frame
+
+ self.think = dompointthink;
+ self.nextthink = time;
+ self.touch = dompointtouch;
+ self.solid = SOLID_TRIGGER;
+ self.flags = FL_ITEM;
+ setsize(self, '-32 -32 -32', '32 32 32');
+ setorigin(self, self.origin + '0 0 20');
+ droptofloor();
+
+ waypoint_spawnforitem(self);
+ WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT, '0 1 1');
+ }
+
+
+
+ /*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
+ Control point for Domination gameplay.
+ */
+ void spawnfunc_dom_controlpoint()
+ {
+ if(!g_domination)
+ {
+ remove(self);
+ return;
+ }
+ self.think = dom_controlpoint_setup;
+ self.nextthink = time + 0.1;
+ self.reset = dom_controlpoint_setup;
+
+ if(!self.scale)
+ self.scale = 0.6;
+
+ //if(!self.glow_size)
+ // self.glow_size = cvar("g_domination_point_glow");
+ self.effects = self.effects | EF_LOWPRECISION;
+ if (autocvar_g_domination_point_fullbright)
+ self.effects |= EF_FULLBRIGHT;
+ }
+
+ // code from here on is just to support maps that don't have control point and team entities
+ void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
+ {
+ entity oldself;
+ oldself = self;
+ self = spawn();
+ self.classname = "dom_team";
+ self.netname = teamname;
+ self.cnt = teamcolor;
+ self.model = pointmodel;
+ self.skin = pointskin;
+ self.noise = capsound;
+ self.noise1 = capnarration;
+ self.message = capmessage;
+
+ // this code is identical to spawnfunc_dom_team
+ setmodel(self, self.model); // precision not needed
+ self.mdl = self.model;
+ self.dmg = self.modelindex;
+ self.model = "";
+ self.modelindex = 0;
+ // this would have to be changed if used in quakeworld
+ self.team = self.cnt + 1;
+
+ //eprint(self);
+ self = oldself;
+ }
+
+ void dom_spawnpoint(vector org)
+ {
+ entity oldself;
+ oldself = self;
+ self = spawn();
+ self.classname = "dom_controlpoint";
+ self.think = spawnfunc_dom_controlpoint;
+ self.nextthink = time;
+ setorigin(self, org);
+ spawnfunc_dom_controlpoint();
+ self = oldself;
+ }
+
+ // spawn some default teams if the map is not set up for domination
+ void dom_spawnteams()
+ {
+ float numteams;
+ if(autocvar_g_domination_teams_override < 2)
+ numteams = autocvar_g_domination_default_teams;
+ else
+ numteams = autocvar_g_domination_teams_override;
+ // LordHavoc: edit this if you want to change defaults
- dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
++ dom_spawnteam("Red", FL_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
++ dom_spawnteam("Blue", FL_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
+ if(numteams > 2)
- dom_spawnteam("Pink", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
++ dom_spawnteam("Yellow", FL_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
+ if(numteams > 3)
++ dom_spawnteam("Pink", FL_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
+ dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
+ }
+
+ void dom_delayedinit()
+ {
+ entity head;
+
+ // if no teams are found, spawn defaults, if custom teams are set, use them
+ if (find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
+ dom_spawnteams();
+ // if no control points are found, spawn defaults
+ if (find(world, classname, "dom_controlpoint") == world)
+ {
+ // TODO in a few months (maybe 2011/08): change this into error() and remove this very poor dom point selection
+ backtrace("This map contains no dom_controlpoint entities. A very poor dom point placement will be chosen. Please fix the map.");
+
+ // if no supported map was found, make every deathmatch spawn a point
+ head = find(world, classname, "info_player_deathmatch");
+ while (head)
+ {
+ dom_spawnpoint(head.origin);
+ head = find(head, classname, "info_player_deathmatch");
+ }
+ }
+
+ ScoreRules_dom();
+ }
+
+ void dom_init()
+ {
+ // we have to precache default models/sounds even if they might not be
+ // used because spawnfunc_worldspawn is executed before any other entities are read,
+ // so we don't even know yet if this map is set up for domination...
+ precache_model("models/domination/dom_red.md3");
+ precache_model("models/domination/dom_blue.md3");
+ precache_model("models/domination/dom_yellow.md3");
+ precache_model("models/domination/dom_pink.md3");
+ precache_model("models/domination/dom_unclaimed.md3");
+ precache_sound("domination/claim.wav");
+ InitializeEntity(world, dom_delayedinit, INITPRIO_GAMETYPE);
+
+ addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
+ addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
+ addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
+ if(c3 >= 0) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
+ if(c4 >= 0) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
+ }
+
--- /dev/null
- switch(self.goalentity.team)
- {
- case COLOR_TEAM1:
- WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", "");
- break;
- case COLOR_TEAM2:
- WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", "");
- break;
- case COLOR_TEAM3:
- WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", "");
- break;
- case COLOR_TEAM4:
- WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", "");
- }
-
+ void dom_EventLog(string mode, float team_before, entity actor) // use an alias for easy changing and quick editing later
+ {
+ if(autocvar_sv_eventlog)
+ GameLogEcho(strcat(":dom:", mode, ":", ftos(team_before), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
+ }
+
+ void set_dom_state(entity e)
+ {
+ e.dom_total_pps = total_pps;
+ e.dom_pps_red = pps_red;
+ e.dom_pps_blue = pps_blue;
+ if(c3 >= 0)
+ e.dom_pps_yellow = pps_yellow;
+ if(c4 >= 0)
+ e.dom_pps_pink = pps_pink;
+ }
+
+ void dompoint_captured ()
+ {
+ entity head;
+ float old_delay, old_team, real_team;
+
+ // now that the delay has expired, switch to the latest team to lay claim to this point
+ head = self.owner;
+
+ real_team = self.cnt;
+ self.cnt = -1;
+
+ dom_EventLog("taken", self.team, self.dmg_inflictor);
+ self.dmg_inflictor = world;
+
+ self.goalentity = head;
+ self.model = head.mdl;
+ self.modelindex = head.dmg;
+ self.skin = head.skin;
+
+ float points, wait_time;
+ if (autocvar_g_domination_point_amt)
+ points = autocvar_g_domination_point_amt;
+ else
+ points = self.frags;
+ if (autocvar_g_domination_point_rate)
+ wait_time = autocvar_g_domination_point_rate;
+ else
+ wait_time = self.wait;
+
+ bprint("^3", head.netname, "^3", self.message);
+ if (points != 1)
+ bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
+ else
+ bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
+
+ if(self.enemy.playerid == self.enemy_playerid)
+ PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
+ else
+ self.enemy = world;
+
+ if (head.noise != "")
+ if(self.enemy)
+ sound(self.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+ else
+ sound(self, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+ if (head.noise1 != "")
+ play2all(head.noise1);
+
+ self.delay = time + wait_time;
+
+ // do trigger work
+ old_delay = self.delay;
+ old_team = self.team;
+ self.team = real_team;
+ self.delay = 0;
+ activator = self;
+ SUB_UseTargets ();
+ self.delay = old_delay;
+ self.team = old_team;
+
- case COLOR_TEAM1:
++ WaypointSprite_UpdateSprites(self.sprite, strcat("dom-", Team_ColorName_Lower(self.goalentity.team)), "", "");
++
+ total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+ for(head = world; (head = find(head, classname, "dom_controlpoint")) != world; )
+ {
+ if (autocvar_g_domination_point_amt)
+ points = autocvar_g_domination_point_amt;
+ else
+ points = head.frags;
+ if (autocvar_g_domination_point_rate)
+ wait_time = autocvar_g_domination_point_rate;
+ else
+ wait_time = head.wait;
+ switch(head.goalentity.team)
+ {
- case COLOR_TEAM2:
++ case FL_TEAM_1:
+ pps_red += points/wait_time;
+ break;
- case COLOR_TEAM3:
++ case FL_TEAM_2:
+ pps_blue += points/wait_time;
+ break;
- case COLOR_TEAM4:
++ case FL_TEAM_3:
+ pps_yellow += points/wait_time;
+ break;
- dom_spawnteam("Red", COLOR_TEAM1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
- dom_spawnteam("Blue", COLOR_TEAM2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
++ case FL_TEAM_4:
+ pps_pink += points/wait_time;
+ }
+ total_pps += points/wait_time;
+ }
+
+ WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, colormapPaletteColor(self.goalentity.team - 1, 0));
+ WaypointSprite_Ping(self.sprite);
+
+ self.captime = time;
+
+ FOR_EACH_REALCLIENT(head)
+ set_dom_state(head);
+ }
+
+ void AnimateDomPoint()
+ {
+ if(self.pain_finished > time)
+ return;
+ self.pain_finished = time + self.t_width;
+ if(self.nextthink > self.pain_finished)
+ self.nextthink = self.pain_finished;
+
+ self.frame = self.frame + 1;
+ if(self.frame > self.t_length)
+ self.frame = 0;
+ }
+
+ void dompointthink()
+ {
+ float fragamt;
+
+ self.nextthink = time + 0.1;
+
+ //self.frame = self.frame + 1;
+ //if(self.frame > 119)
+ // self.frame = 0;
+ AnimateDomPoint();
+
+ // give points
+
+ if (gameover || self.delay > time || time < game_starttime) // game has ended, don't keep giving points
+ return;
+
+ if(autocvar_g_domination_point_rate)
+ self.delay = time + autocvar_g_domination_point_rate;
+ else
+ self.delay = time + self.wait;
+
+ // give credit to the team
+ // NOTE: this defaults to 0
+ if (self.goalentity.netname != "")
+ {
+ if(autocvar_g_domination_point_amt)
+ fragamt = autocvar_g_domination_point_amt;
+ else
+ fragamt = self.frags;
+ TeamScore_AddToTeam(self.goalentity.team, ST_SCORE, fragamt);
+ TeamScore_AddToTeam(self.goalentity.team, ST_DOM_TICKS, fragamt);
+
+ // give credit to the individual player, if he is still there
+ if (self.enemy.playerid == self.enemy_playerid)
+ {
+ PlayerScore_Add(self.enemy, SP_SCORE, fragamt);
+ PlayerScore_Add(self.enemy, SP_DOM_TICKS, fragamt);
+ }
+ else
+ self.enemy = world;
+ }
+ }
+
+ void dompointtouch()
+ {
+ entity head;
+ if (other.classname != "player")
+ return;
+ if (other.health < 1)
+ return;
+
+ if(time < self.captime + 0.3)
+ return;
+
+ // only valid teams can claim it
+ head = find(world, classname, "dom_team");
+ while (head && head.team != other.team)
+ head = find(head, classname, "dom_team");
+ if (!head || head.netname == "" || head == self.goalentity)
+ return;
+
+ // delay capture
+
+ self.team = self.goalentity.team; // this stores the PREVIOUS team!
+
+ self.cnt = other.team;
+ self.owner = head; // team to switch to after the delay
+ self.dmg_inflictor = other;
+
+ // self.state = 1;
+ // self.delay = time + cvar("g_domination_point_capturetime");
+ //self.nextthink = time + cvar("g_domination_point_capturetime");
+ //self.think = dompoint_captured;
+
+ // go to neutral team in the mean time
+ head = find(world, classname, "dom_team");
+ while (head && head.netname != "")
+ head = find(head, classname, "dom_team");
+ if(head == world)
+ return;
+
+ WaypointSprite_UpdateSprites(self.sprite, "dom-neut", "", "");
+ WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
+ WaypointSprite_Ping(self.sprite);
+
+ self.goalentity = head;
+ self.model = head.mdl;
+ self.modelindex = head.dmg;
+ self.skin = head.skin;
+
+ self.enemy = other; // individual player scoring
+ self.enemy_playerid = other.playerid;
+ dompoint_captured();
+ }
+
+ void dom_controlpoint_setup()
+ {
+ entity head;
+ // find the spawnfunc_dom_team representing unclaimed points
+ head = find(world, classname, "dom_team");
+ while(head && head.netname != "")
+ head = find(head, classname, "dom_team");
+ if (!head)
+ objerror("no spawnfunc_dom_team with netname \"\" found\n");
+
+ // copy important properties from spawnfunc_dom_team entity
+ self.goalentity = head;
+ setmodel(self, head.mdl); // precision already set
+ self.skin = head.skin;
+
+ self.cnt = -1;
+
+ if(self.message == "")
+ self.message = " has captured a control point";
+
+ if(self.frags <= 0)
+ self.frags = 1;
+ if(self.wait <= 0)
+ self.wait = 5;
+
+ float points, waittime;
+ if (autocvar_g_domination_point_amt)
+ points = autocvar_g_domination_point_amt;
+ else
+ points = self.frags;
+ if (autocvar_g_domination_point_rate)
+ waittime = autocvar_g_domination_point_rate;
+ else
+ waittime = self.wait;
+
+ total_pps += points/waittime;
+
+ if(!self.t_width)
+ self.t_width = 0.02; // frame animation rate
+ if(!self.t_length)
+ self.t_length = 239; // maximum frame
+
+ self.think = dompointthink;
+ self.nextthink = time;
+ self.touch = dompointtouch;
+ self.solid = SOLID_TRIGGER;
+ self.flags = FL_ITEM;
+ setsize(self, '-32 -32 -32', '32 32 32');
+ setorigin(self, self.origin + '0 0 20');
+ droptofloor();
+
+ waypoint_spawnforitem(self);
+ WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT, '0 1 1');
+ }
+
+ //go to best items, or control points you don't own
+ void havocbot_role_dom()
+ {
+ if(self.deadflag != DEAD_NO)
+ return;
+
+ if (self.bot_strategytime < time)
+ {
+ self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+ navigation_goalrating_start();
+ havocbot_goalrating_controlpoints(10000, self.origin, 15000);
+ havocbot_goalrating_items(8000, self.origin, 8000);
+ //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
+ //havocbot_goalrating_waypoints(1, self.origin, 1000);
+ navigation_goalrating_end();
+ }
+ }
+
+ MUTATOR_HOOKFUNCTION(dom_ClientConnect)
+ {
+ set_dom_state(self);
+ return FALSE;
+ }
+
+ MUTATOR_HOOKFUNCTION(dom_BotRoles)
+ {
+ self.havocbot_role = havocbot_role_dom;
+ return TRUE;
+ }
+
+ /*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
+ Control point for Domination gameplay.
+ */
+ void spawnfunc_dom_controlpoint()
+ {
+ if(!g_domination)
+ {
+ remove(self);
+ return;
+ }
+ self.think = dom_controlpoint_setup;
+ self.nextthink = time + 0.1;
+ self.reset = dom_controlpoint_setup;
+
+ if(!self.scale)
+ self.scale = 0.6;
+
+ self.effects = self.effects | EF_LOWPRECISION;
+ if (autocvar_g_domination_point_fullbright)
+ self.effects |= EF_FULLBRIGHT;
+ }
+
+ /*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
+ Team declaration for Domination gameplay, this allows you to decide what team
+ names and control point models are used in your map.
+
+ Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
+ can have netname set! The nameless team owns all control points at start.
+
+ Keys:
+ "netname"
+ Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
+ "cnt"
+ Scoreboard color of the team (for example 4 is red and 13 is blue)
+ "model"
+ Model to use for control points owned by this team (for example
+ "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
+ keycard)
+ "skin"
+ Skin of the model to use (for team skins on a single model)
+ "noise"
+ Sound to play when this team captures a point.
+ (this is a localized sound, like a small alarm or other effect)
+ "noise1"
+ Narrator speech to play when this team captures a point.
+ (this is a global sound, like "Red team has captured a control point")
+ */
+
+ void spawnfunc_dom_team()
+ {
+ if(!g_domination || autocvar_g_domination_teams_override >= 2)
+ {
+ remove(self);
+ return;
+ }
+ precache_model(self.model);
+ if (self.noise != "")
+ precache_sound(self.noise);
+ if (self.noise1 != "")
+ precache_sound(self.noise1);
+ self.classname = "dom_team";
+ setmodel(self, self.model); // precision not needed
+ self.mdl = self.model;
+ self.dmg = self.modelindex;
+ self.model = "";
+ self.modelindex = 0;
+ // this would have to be changed if used in quakeworld
+ if(self.cnt)
+ self.team = self.cnt + 1; // WHY are these different anyway?
+ }
+
+ // scoreboard setup
+ void ScoreRules_dom()
+ {
+ float sp_domticks, sp_score;
+ sp_score = sp_domticks = 0;
+ if(autocvar_g_domination_disable_frags)
+ sp_domticks = SFL_SORT_PRIO_PRIMARY;
+ else
+ sp_score = SFL_SORT_PRIO_PRIMARY;
+ CheckAllowedTeams(world);
+ ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), sp_score, sp_score, TRUE);
+ ScoreInfo_SetLabel_TeamScore (ST_DOM_TICKS, "ticks", sp_domticks);
+ ScoreInfo_SetLabel_PlayerScore(SP_DOM_TICKS, "ticks", sp_domticks);
+ ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES, "takes", 0);
+ ScoreRules_basics_end();
+ }
+
+ // code from here on is just to support maps that don't have control point and team entities
+ void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
+ {
+ entity oldself;
+ oldself = self;
+ self = spawn();
+ self.classname = "dom_team";
+ self.netname = teamname;
+ self.cnt = teamcolor;
+ self.model = pointmodel;
+ self.skin = pointskin;
+ self.noise = capsound;
+ self.noise1 = capnarration;
+ self.message = capmessage;
+
+ // this code is identical to spawnfunc_dom_team
+ setmodel(self, self.model); // precision not needed
+ self.mdl = self.model;
+ self.dmg = self.modelindex;
+ self.model = "";
+ self.modelindex = 0;
+ // this would have to be changed if used in quakeworld
+ self.team = self.cnt + 1;
+
+ //eprint(self);
+ self = oldself;
+ }
+
+ void dom_spawnpoint(vector org)
+ {
+ entity oldself;
+ oldself = self;
+ self = spawn();
+ self.classname = "dom_controlpoint";
+ self.think = spawnfunc_dom_controlpoint;
+ self.nextthink = time;
+ setorigin(self, org);
+ spawnfunc_dom_controlpoint();
+ self = oldself;
+ }
+
+ // spawn some default teams if the map is not set up for domination
+ void dom_spawnteams()
+ {
+ float numteams = ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override);
+
- dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
++ dom_spawnteam("Red", FL_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
++ dom_spawnteam("Blue", FL_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
+ if(numteams > 2)
- dom_spawnteam("Pink", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
++ dom_spawnteam("Yellow", FL_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
+ if(numteams > 3)
++ dom_spawnteam("Pink", FL_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
+ dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
+ }
+
+ void dom_DelayedInit() // Do this check with a delay so we can wait for teams to be set up.
+ {
+ // if no teams are found, spawn defaults
+ if(find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
+ {
+ print("No ""dom_team"" entities found on this map, creating them anyway.\n");
+ dom_spawnteams();
+ }
+
+ ScoreRules_dom();
+ }
+
+ void dom_Initialize()
+ {
+ precache_model("models/domination/dom_red.md3");
+ precache_model("models/domination/dom_blue.md3");
+ precache_model("models/domination/dom_yellow.md3");
+ precache_model("models/domination/dom_pink.md3");
+ precache_model("models/domination/dom_unclaimed.md3");
+ precache_sound("domination/claim.wav");
+
+ addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
+ addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
+ addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
+ if(c3 >= 0) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
+ if(c4 >= 0) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
+
+ InitializeEntity(world, dom_DelayedInit, INITPRIO_GAMETYPE);
+ }
+
+
+ MUTATOR_DEFINITION(gamemode_domination)
+ {
+ MUTATOR_HOOK(ClientConnect, dom_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(HavocBot_ChooseRule, dom_BotRoles, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ dom_Initialize();
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ error("This is a game type and it cannot be removed at runtime.");
+ }
+
+ return 0;
+ }
PlayerScore_Clear(e);
}
- void dom_init();
-vector TeamColor(float teem)
-{
- switch(teem)
- {
- case COLOR_TEAM1:
- return '1 0.0625 0.0625';
- case COLOR_TEAM2:
- return '0.0625 0.0625 1';
- case COLOR_TEAM3:
- return '1 1 0.0625';
- case COLOR_TEAM4:
- return '1 0.0625 1';
- default:
- return '1 1 1';
- }
-}
-
-string TeamName(float t)
-{
- return strcat(Team_ColorName(t), " Team");
-}
-string ColoredTeamName(float t)
-{
- return strcat(Team_ColorCode(t), Team_ColorName(t), " Team^7");
-}
-string TeamNoName(float t)
-{
- // fixme: Search for team entities and get their .netname's!
- if(t == 1)
- return "Red Team";
- if(t == 2)
- return "Blue Team";
- if(t == 3)
- return "Yellow Team";
- if(t == 4)
- return "Pink Team";
- return "Neutral Team";
-}
-
void runematch_init();
void tdm_init();
void entcs_init();