From: Samual Lenks Date: Mon, 4 Feb 2013 23:13:07 +0000 (-0500) Subject: Merge remote-tracking branch 'origin/master' into samual/notification_rewrite X-Git-Tag: xonotic-v0.7.0~62^2~23^2~278 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=80ea2c26461cab2b2992f79643eaf59aacb7cda7;p=xonotic%2Fxonotic-data.pk3dir.git Merge remote-tracking branch 'origin/master' into samual/notification_rewrite Conflicts: qcsrc/server/teamplay.qc --- 80ea2c26461cab2b2992f79643eaf59aacb7cda7 diff --cc qcsrc/server/attic/domination.qc index 000000000,6a0dcdf8b..e0bad53d3 mode 000000,100644..100644 --- a/qcsrc/server/attic/domination.qc +++ b/qcsrc/server/attic/domination.qc @@@ -1,0 -1,525 +1,525 @@@ + + /* + 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_TEAM1: ++ case FL_TEAM_1: + WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", ""); + break; - case COLOR_TEAM2: ++ case FL_TEAM_2: + WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", ""); + break; - case COLOR_TEAM3: ++ case FL_TEAM_3: + WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", ""); + break; - case COLOR_TEAM4: ++ 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_TEAM1: ++ case FL_TEAM_1: + pps_red += points/wait_time; + break; - case COLOR_TEAM2: ++ case FL_TEAM_2: + pps_blue += points/wait_time; + break; - case COLOR_TEAM3: ++ case FL_TEAM_3: + pps_yellow += points/wait_time; + break; - case COLOR_TEAM4: ++ 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("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"); ++ 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("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow 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", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point"); ++ 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); + } + diff --cc qcsrc/server/mutators/gamemode_domination.qc index 000000000,852fb90c0..1c2ded2db mode 000000,100644..100644 --- a/qcsrc/server/mutators/gamemode_domination.qc +++ b/qcsrc/server/mutators/gamemode_domination.qc @@@ -1,0 -1,515 +1,502 @@@ + 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; + - 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", "", ""); - } - ++ 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_TEAM1: ++ case FL_TEAM_1: + pps_red += points/wait_time; + break; - case COLOR_TEAM2: ++ case FL_TEAM_2: + pps_blue += points/wait_time; + break; - case COLOR_TEAM3: ++ case FL_TEAM_3: + pps_yellow += points/wait_time; + break; - case COLOR_TEAM4: ++ 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("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"); ++ 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("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow 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", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point"); ++ 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; + } diff --cc qcsrc/server/teamplay.qc index fd7b554ef,1ed2f533b..dddd5f1d4 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@@ -13,7 -13,45 +13,6 @@@ void TeamchangeFrags(entity e 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();