From 71e16c6b9353c27bbf97da8797904122cb8c2fd2 Mon Sep 17 00:00:00 2001 From: blub0 Date: Sun, 6 Jul 2008 22:11:59 +0000 Subject: [PATCH] Added the capture-counter and changed the CTF scoreboard to display the caps. Gameplay changes: cvar g_ctf_win_mode: 2 to play as usual, with just a fraglimit 1 use the teamfrags if the team-captures are equal 0 use overtime cvar capturelimit - does it need explanation? g_ctf_flagscore_kill - frags to get when killing the carrier (default 6) g_ctf_flagpenalty_drop - frags to lose when dropping the flag (default 0) git-svn-id: svn://svn.icculus.org/nexuiz/trunk@3780 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/qcsrc/client/Defs.qc | 1 + data/qcsrc/client/Main.qc | 104 ++++++++++++++++++++++------ data/qcsrc/client/View.qc | 4 ++ data/qcsrc/client/csqc_builtins.qc | 1 + data/qcsrc/client/main.qh | 5 +- data/qcsrc/client/ons.qc | 11 +-- data/qcsrc/client/sbar.qc | 75 +++++++++++++++----- data/qcsrc/common/constants.qh | 12 ++-- data/qcsrc/server/cl_client.qc | 37 ++++++++++ data/qcsrc/server/clientcommands.qc | 4 ++ data/qcsrc/server/ctf.qc | 57 ++++++++++++++- data/qcsrc/server/defs.qh | 3 + data/qcsrc/server/ent_cs.qc | 15 ++-- data/qcsrc/server/g_damage.qc | 6 +- data/qcsrc/server/g_world.qc | 25 ++++++- data/qcsrc/server/teamplay.qc | 4 ++ 16 files changed, 300 insertions(+), 64 deletions(-) diff --git a/data/qcsrc/client/Defs.qc b/data/qcsrc/client/Defs.qc index 38cf9db3a..704a52e6b 100644 --- a/data/qcsrc/client/Defs.qc +++ b/data/qcsrc/client/Defs.qc @@ -169,3 +169,4 @@ vector dmg_origin; .float enttype; // entity type sent from server .float sv_entnum; // entity number sent from server float vid_conwidth, vid_conheight; +float caps_team1, caps_team2; diff --git a/data/qcsrc/client/Main.qc b/data/qcsrc/client/Main.qc index 707ed496e..3c3981058 100644 --- a/data/qcsrc/client/Main.qc +++ b/data/qcsrc/client/Main.qc @@ -20,8 +20,6 @@ float using_gps; void CSQC_Init(void) { - float i; - drawfont = 0; menu_visible = FALSE; menu_show = menu_show_error; @@ -39,9 +37,23 @@ void CSQC_Init(void) gps_start = world; + postinit = false; +} + +void PostInit(void) +{ + float i; + entity pl; + + print(strcat("PostInit\n maxclients = ", ftos(maxclients), "\n")); databuf = buf_create(); for(i = 0; i < maxclients; ++i) + { bufstr_set(databuf, DATABUF_PING + i, "N/A"); + bufstr_set(databuf, DATABUF_CAPTURES + i, "0"); + } + + postinit = true; } // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc) void CSQC_Shutdown(void) @@ -95,34 +107,44 @@ float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary) // -------------------------------------------------------------------------- // BEGIN OPTIONAL CSQC FUNCTIONS - -void ReadPings() -{ - float plnum, ping; - for(plnum = ReadByte(); plnum != 0; plnum = ReadByte()) - { - ping = ReadShort(); - bufstr_set(databuf, DATABUF_PING + plnum-1, ftos(ping)); - } -} - -void ReadONS(float bIsNewEntity) +void ReadONS() { + entity gps; using_gps = true; - + self.origin_x = ReadCoord(); self.origin_y = ReadCoord(); self.angles_y = ReadCoord(); self.origin_z = self.angles_x = self.angles_z = 0; - if(bIsNewEntity) + for(gps = gps_start; gps; gps = gps.chain) + { + if(gps == self) + break; + } + if(!gps) { - //print(strcat("Adding entity: ", ftos(self.sv_entnum), "\n")); self.chain = gps_start; gps_start = self; } } +void RemoveONS() +{ + if(gps_start == self) + gps_start = self.chain; + else + { + local entity ent; + ent = gps_start; + + while(ent.chain != self && ent.chain != world) + ent = ent.chain; + if(ent.chain == self) + ent.chain = self.chain; + } +} + // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured. // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS. void(float bIsNewEntity) CSQC_Ent_Update = @@ -137,7 +159,8 @@ void(float bIsNewEntity) CSQC_Ent_Update = { switch(msg) { - case ENTCS_MSG_ONS: ReadONS(bIsNewEntity); break; + case ENTCS_MSG_ONS_GPS: ReadONS(); break; + case ENTCS_MSG_ONS_REMOVE: RemoveONS(); break; default: error("unknown ENTCS_MSG type\n"); } @@ -250,6 +273,37 @@ void CSQC_Parse_CenterPrint(string strMessage) { cprint(strMessage); } + +void ReadInit() +{ + maxclients = ReadByte(); +} + +void ReadPings() +{ + float plnum, ping; + for(plnum = ReadByte(); plnum != 0; plnum = ReadByte()) + { + ping = ReadShort(); + bufstr_set(databuf, DATABUF_PING + plnum-1, ftos(ping)); + } +} + +void ReadCaptures() +{ + float plnum, caps; + entity pl; + caps_team1 = ReadByte(); + caps_team2 = ReadByte(); + for(plnum = ReadByte(); plnum != 0; plnum = ReadByte()) + { + caps = ReadByte(); + //print(strcat("Cap update: ", ftos(plnum), " has ", ftos(caps), " caps\n")); + //print(strcat("Index: ", ftos(DATABUF_CAPTURES + plnum-1), " -- I AM: ", ftos(player_localentnum), "\n")); + bufstr_set(databuf, DATABUF_CAPTURES + plnum-1, ftos(caps)); + } +} + // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer. // You must ALWAYS first acquire the temporary ID, which is sent as a byte. // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event. @@ -263,18 +317,26 @@ float CSQC_Parse_TempEntity() switch(nTEID) { + case TE_CSQC_INIT: + ReadInit(); + bHandled = true; + break; case TE_CSQC_PING: ReadPings(); bHandled = true; break; - //case TE_GUNSHOT: - // Do something cool with TE_GUNSHOT! - // break; + case TE_CSQC_CAPTURES: + ReadCaptures(); + bHandled = true; + break; default: // No special logic for this temporary entity; return 0 so the engine can handle it bHandled = false; break; } + + if(!postinit) + PostInit(); return bHandled; } diff --git a/data/qcsrc/client/View.qc b/data/qcsrc/client/View.qc index f6202fc55..5ca4e81f8 100644 --- a/data/qcsrc/client/View.qc +++ b/data/qcsrc/client/View.qc @@ -14,8 +14,12 @@ void CSQC_common_hud(void); void CSQC_kh_hud(void); void CSQC_ctf_hud(void); +void PostInit(void); void CSQC_UpdateView(void) { + if(!postinit) + PostInit(); + sbar_alpha_fg = cvar("sbar_alpha_fg" ); sbar_hudselector = cvar("sbar_hudselector"); activeweapon = getstati(STAT_ACTIVEWEAPON); diff --git a/data/qcsrc/client/csqc_builtins.qc b/data/qcsrc/client/csqc_builtins.qc index 0fa283d70..1d6ad18c2 100644 --- a/data/qcsrc/client/csqc_builtins.qc +++ b/data/qcsrc/client/csqc_builtins.qc @@ -257,3 +257,4 @@ float(string s1, string s2, float len) strncasecmp = #230; float(string str, string sub, float startoffs) strstrofs = #221; //float(string str, string sub) strstrofs = #221; entity(float num) edict_num = #459; +float(entity ent) num_for_edict = #512; diff --git a/data/qcsrc/client/main.qh b/data/qcsrc/client/main.qh index 0511a1e8d..3291e977b 100644 --- a/data/qcsrc/client/main.qh +++ b/data/qcsrc/client/main.qh @@ -2,7 +2,8 @@ // MENU Functionality #define DATABUF_PING 0 -#define DATABUF_SAMPLE (1*maxclients) +#define DATABUF_CAPTURES (1*maxclients) +#define DATABUF_NEXT (2*maxclients) void() menu_show_error; void() menu_sub_null; @@ -32,7 +33,7 @@ float ons_showmap; // General stuff float drawfont; - +float postinit; float gametype; entity gps_start; diff --git a/data/qcsrc/client/ons.qc b/data/qcsrc/client/ons.qc index 871d28979..3c2ab8580 100644 --- a/data/qcsrc/client/ons.qc +++ b/data/qcsrc/client/ons.qc @@ -39,20 +39,13 @@ void() ons_view = local float color; local vector coord, rgb; - color = stof(getplayerkey(player_localentnum-1, "colors")) & 15; + color = GetPlayerColor(player_localentnum-1); + rgb = GetTeamRGB(color); coord = mapcoords(pmove_org); drawpic('272 50', minimapname, '256 256', '1 1 1', 1, 0); drawpic('257 35', "gfx/ons-frame.tga", '286 286', '1 1 1', 1, 0); - if(color == COLOR_TEAM_RED) - { - rgb = '1 0 0'; - } else if(color == COLOR_TEAM_BLUE) { - rgb = '0 0 1'; - } else { - rgb = '1 1 1'; - } drawpic('257 35', "gfx/ons-frame-team.tga", '286 286', rgb, 1, 0); drawplayer(coord, input_angles, '1 1 1'); diff --git a/data/qcsrc/client/sbar.qc b/data/qcsrc/client/sbar.qc index 4c017ce84..fb313335f 100644 --- a/data/qcsrc/client/sbar.qc +++ b/data/qcsrc/client/sbar.qc @@ -9,6 +9,7 @@ entity sortedTeams; .float sb_frags; .float sb_team; .float sb_player; +.float sb_caps; void Sbar_FinaleOverlay() { @@ -115,10 +116,17 @@ float Sbar_PlayerCmp(entity l, entity r) { if(teamplay) { - if(l.sb_team < r.sb_team) + if(l.sb_team > r.sb_team) return true; else if(l.sb_team > r.sb_team) return false; + if(gametype == GAME_CTF) + { + if(l.sb_caps > r.sb_caps) + return true; + else if(l.sb_caps < r.sb_caps) + return false; + } } if(l.sb_frags > r.sb_frags) return true; @@ -128,6 +136,13 @@ float Sbar_PlayerCmp(entity l, entity r) } float Sbar_TeamCmp(entity l, entity r) { + if(gametype == GAME_CTF) + { + if(l.sb_caps > r.sb_caps) + return true; + else if(l.sb_caps < r.sb_caps) + return false; + } if(l.sb_frags > r.sb_frags) return true; else if(l.sb_frags < r.sb_frags) @@ -163,6 +178,8 @@ void Sbar_SortFrags() t1.sb_player = t2.sb_player = t3.sb_player = t4.sb_player = ts.sb_player = 0; t1.sb_frags = t2.sb_frags = t3.sb_frags = t4.sb_frags = 0; + t1.sb_caps = caps_team1; + t2.sb_caps = caps_team2; sortedTeams = Sort_New(Sbar_TeamCmp); for(i = 0; i < maxclients; ++i) @@ -173,6 +190,8 @@ void Sbar_SortFrags() tmp = spawn(); tmp.sb_player = i; tmp.sb_frags = stof(getplayerkey(i, "frags")); + tmp.sb_caps = stof(bufstr_get(databuf, DATABUF_CAPTURES + tmp.sb_player)); + if(tmp.sb_frags == -666) tmp.sb_team = COLOR_SPECTATOR; else @@ -220,11 +239,12 @@ void Sbar_SortFrags() } } } - +float xmin, xmax, ymin, ymax; void Sbar_PrintScoreboardItem(vector pos, entity pl, float is_self, float mask) { vector tmp; string str; + entity player; tmp_y = tmp_z = 0; pos_x += 56; @@ -233,8 +253,15 @@ void Sbar_PrintScoreboardItem(vector pos, entity pl, float is_self, float mask) tmp_x = 4*8 - strlen(str) * 8 - 56; drawstring(pos + tmp, str, '8 8 0', '0.8 0.8 0.8', 0.8, 0); - if(!(mask & 1)) + if(!(mask & 1)) // not a spectator: { + if(gametype == GAME_CTF) + { + str = bufstr_get(databuf, DATABUF_CAPTURES + pl.sb_player); + tmp_x = xmax - strlen(str)*8 - pos_x; + drawstring(pos + tmp, str, '8 8 0', '1 1 1', 1, 0); + } + str = ftos(pl.sb_frags); tmp_x = 4*8 - strlen(str) * 8; drawstring(pos + tmp, str, '8 8 0', '1 1 1', 1, 0); @@ -266,10 +293,11 @@ void Sbar_PrintScoreboardTeamItem(vector pos, entity tm, vector rgb, string name void Sbar_DrawScoreboard() { // Assume: frags are already sorted - float xmin, xmax, ymin, ymax, plcount; + //float xmin, xmax, ymin, ymax, plcount; + float plcount; vector pos, teammin, teammax, rgb; entity pl, tm; - float specs; + float specs, minoffset; specs = false; xmin = vid_conwidth / 4; @@ -282,7 +310,7 @@ void Sbar_DrawScoreboard() teammin = teammax = '0 0 0'; teammin_x = xmin - 2; - teammax_x = xmax - 2; + teammax_x = xmax + 2; pos_x = 0.5 * (xmin + xmax) - (24*5); drawfont = FONT_USER+0; @@ -294,29 +322,39 @@ void Sbar_DrawScoreboard() drawstring(pos, "ping", '8 8 0', '1 1 1', 1, 0); drawstring(pos + '48 0 0', "frags", '8 8 0', '1 1 1', 1, 0); drawstring(pos + '104 0 0', "name", '8 8 0', '1 1 1', 1, 0); + if(gametype == GAME_CTF) + { + pos_x = xmax - 4*8; + drawstring(pos, "caps", '8 8 0', '1 1 1', 1, 0); + pos_x = xmin; + } + pos_y += 16; if(teamplay) { - /*teampos_z = 0; - teampos_y = pos_y - 40; - teampos_x = (vid_conwidth * 0.5) - (numteams*6*12);*/ for(tm = sortedTeams.sort_next; tm; tm = tm.sort_next) { + minoffset = pos_y + 24; if(!tm.sb_player || tm.sb_team == COLOR_SPECTATOR) // no players in it? continue; - //Sbar_DrawXNum(teampos-sbar, tm.sb_frags, -4, 24, GetTeamRGB(tm.sb_team), 1, DRAWFLAG_NORMAL); - //teampos_x += 6*24; - Sbar_DrawXNum(pos-'106 0 0'-sbar, tm.sb_frags, 4, 24, GetTeamRGB(tm.sb_team), 1, DRAWFLAG_NORMAL); + rgb = GetTeamRGB(tm.sb_team); + if(gametype == GAME_CTF) + { + minoffset = pos_y + 24 + 12; + if(tm.sb_team == COLOR_TEAM1) + Sbar_DrawXNum(pos-'106 0 0'-sbar, caps_team1, 4, 24, rgb, 1, DRAWFLAG_NORMAL); + else if(tm.sb_team == COLOR_TEAM2) + Sbar_DrawXNum(pos-'106 0 0'-sbar, caps_team2, 4, 24, rgb, 1, DRAWFLAG_NORMAL); + Sbar_DrawXNum(pos-'44 -24 0'-sbar, tm.sb_frags, 4, 10, rgb, 1, DRAWFLAG_NORMAL); + } else + Sbar_DrawXNum(pos-'106 0 0'-sbar, tm.sb_frags, 4, 24, rgb, 1, DRAWFLAG_NORMAL); teammin_y = pos_y - 2; teammax_y = pos_y + 2 + 10 * (tm.sb_player); - rgb = GetTeamRGB(tm.sb_team); drawfill(teammin, teammax - teammin, rgb, 0.2, DRAWFLAG_NORMAL); - /*Sbar_PrintScoreboardTeamItem(pos, tm, rgb, GetTeamName(tm.sb_team)); - pos_y += 12;*/ - //for(i = 0; i < maxclients; ++i) + plcount = 0; for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next) { @@ -326,9 +364,10 @@ void Sbar_DrawScoreboard() pos_y += 10; ++plcount; } + pos_y += 12; - if(plcount < 2) - pos_y += 12; + if(pos_y < minoffset) + pos_y = minoffset; } // rgb := tempvector :) diff --git a/data/qcsrc/common/constants.qh b/data/qcsrc/common/constants.qh index dfa600f54..15147aadd 100644 --- a/data/qcsrc/common/constants.qh +++ b/data/qcsrc/common/constants.qh @@ -147,16 +147,20 @@ const float K_MOUSE15 = 528; const float K_MOUSE16 = 529; const float ENTCS_MSG_END = 0; -const float ENTCS_MSG_ONS = 1; +const float ENTCS_MSG_ONS_GPS = 1; +const float ENTCS_MSG_ONS_REMOVE = 2; const float TE_CSQC_START = 100; -const float TE_CSQC_PING = 100; +const float TE_CSQC_INIT = 100; +const float TE_CSQC_PING = 101; +const float TE_CSQC_CAPTURES = 102; -const float TE_CSQC_END = 100; +const float TE_CSQC_END = 101; const float STAT_KH_KEYS = 32; +const float STAT_CTF_CAPTURES = 33; -const float STAT_CTF_STATE = 33; +const float STAT_CTF_STATE = 34; const float CTF_STATE_ATTACK = 1; const float CTF_STATE_DEFEND = 2; const float CTF_STATE_COMMANDER = 3; diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index 53f554702..12da08e1e 100644 --- a/data/qcsrc/server/cl_client.qc +++ b/data/qcsrc/server/cl_client.qc @@ -348,6 +348,7 @@ PutObserverInServer putting a client as observer in the server ============= */ +void ctf_UpdateCaptures(); void PutObserverInServer (void) { entity spot; @@ -372,6 +373,11 @@ void PutObserverInServer (void) WaypointSprite_PlayerDead(); DistributeFragsAmongTeam(self, self.team, 1); + if(g_ctf) + { + self.captures = 0; + ctf_UpdateCaptures(); + } if(self.frags <= 0 && self.frags > -666 && g_lms && self.killcount != -666) bprint ("^4", self.netname, "^4 has no more lives left\n"); @@ -697,6 +703,23 @@ void PutClientInServer (void) // ctf_playerchanged(); } +/* +============= +SendCSQCInfo + +Send whatever CSQC needs NOW and cannot wait for SendServerInfo to happen... +============= +*/ +void SendCSQCInfo(void) +{ + if(clienttype(self) != CLIENTTYPE_REAL) + return; + msg_entity = self; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_INIT); + WriteByte(MSG_ONE, maxclients-1); +} + /* ============= SetNewParms @@ -745,6 +768,11 @@ Called when a client types 'kill' in the console void ClientKill_Now_TeamChange() { + if(g_ctf) + { + self.captures = 0; + ctf_UpdateCaptures(); + } if(self.killindicator_teamchange == -1) { self.team = -1; @@ -941,6 +969,7 @@ Called when a client connects to the server //void ctf_clientconnect(); string ColoredTeamName(float t); void DecodeLevelParms (void); +void ctf_SendCaptures(entity); //void dom_player_join_team(entity pl); void ClientConnect (void) { @@ -1094,6 +1123,9 @@ void ClientConnect (void) self.jointime = time; self.allowedTimeouts = cvar("sv_timeout_number"); + + SendCSQCInfo(); + ctf_SendCaptures(self); } /* @@ -1146,6 +1178,11 @@ void ClientDisconnect (void) DropFlag(self.flagcarried); DistributeFragsAmongTeam(self, self.team, 1); + if(g_ctf) + { + self.captures = 0; + ctf_UpdateCaptures(); + } save = self.flags; self.flags = self.flags - (self.flags & FL_CLIENT); diff --git a/data/qcsrc/server/clientcommands.qc b/data/qcsrc/server/clientcommands.qc index 7d05afbc1..b81b7e1b2 100644 --- a/data/qcsrc/server/clientcommands.qc +++ b/data/qcsrc/server/clientcommands.qc @@ -214,6 +214,8 @@ void SV_ParseClientCommand(string s) { kh_Key_DropAll(self, TRUE); WaypointSprite_PlayerDead(); DistributeFragsAmongTeam(self, self.team, 1.0); + self.captures = 0; + ctf_UpdateCaptures(); self.classname = "observer"; if(blockSpectators) sprint(self, strcat("^7You have to become a player within the next ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n")); @@ -226,6 +228,8 @@ void SV_ParseClientCommand(string s) { if(isJoinAllowed()) { self.classname = "player"; self.frags = 0; + self.captures = 0; + ctf_UpdateCaptures(); bprint ("^4", self.netname, "^4 is playing now\n"); PutClientInServer(); } diff --git a/data/qcsrc/server/ctf.qc b/data/qcsrc/server/ctf.qc index fabe02c0f..efbfd1c12 100644 --- a/data/qcsrc/server/ctf.qc +++ b/data/qcsrc/server/ctf.qc @@ -4,7 +4,6 @@ entity ctf_worldflaglist; // CTF flags in the map .float next_take_time; // the next time a player can pick up a flag (time + blah) /// I used this, in part, to fix the looping score bug. - avirox - //float FLAGSCORE_PICKUP = 1; //float FLAGSCORE_RETURN = 5; // returned by owner team //float FLAGSCORE_RETURNROGUE = 10; // returned by rogue team @@ -130,6 +129,12 @@ void DropFlag(entity e) return; } bprint(p.netname, "^7 lost the ", e.netname, "\n"); + + if(cvar("g_ctf_flagpenalty_drop")) + UpdateFrags(p, -cvar("g_ctf_flagpenalty_drop")); + + //if(e.enemy && e.enemy != e) + //UpdateFrags(e.enemy, cvar("g_ctf_flagscore_kill")); WaypointSprite_DetachCarrier(p); LogCTF("dropped", p.team, p.flagcarried); @@ -225,6 +230,39 @@ void FlagThink() } }; +void ctf_SendCaptures(entity player) +{ + entity p; + if(clienttype(player) != CLIENTTYPE_REAL) + return; + msg_entity = player; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_CAPTURES); + WriteByte(MSG_ONE, caps_team1); + WriteByte(MSG_ONE, caps_team2); + FOR_EACH_CLIENT(p) + { + WriteByte(MSG_ONE, num_for_edict(p)); + WriteByte(MSG_ONE, p.captures); + } + WriteByte(MSG_ONE, 0); +} + +void ctf_UpdateCaptures() +{ + entity p; + WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte(MSG_BROADCAST, TE_CSQC_CAPTURES); + WriteByte(MSG_BROADCAST, caps_team1); + WriteByte(MSG_BROADCAST, caps_team2); + FOR_EACH_REALCLIENT(p) + { + WriteByte(MSG_BROADCAST, num_for_edict(p)); + WriteByte(MSG_BROADCAST, p.captures); + } + WriteByte(MSG_BROADCAST, 0); +} + void FlagTouch() { if(gameover) return; @@ -278,6 +316,16 @@ void FlagTouch() bprint(other.netname, "^7 captured the ", other.flagcarried.netname, " in ", s, ", failing to break ", strcat(h0, " record of ", s0, " seconds\n")); } + other.captures++; + if(other.team == COLOR_TEAM1) + caps_team1++; + else if(other.team == COLOR_TEAM2) + caps_team2++; + else + print("Unknown team captured the flag!\n"); + ctf_UpdateCaptures(); + // FIXME: When counting captures, should the score be updated? + LogCTF("capture", other.flagcarried.team, other); // give credit to the individual player UpdateFrags(other, cvar("g_ctf_flagscore_capture")); @@ -665,6 +713,13 @@ void ctf_init() { local entity e; + caps_team1 = caps_team2 = 0; + registercvar("capturelimit", "8"); + registercvar("g_ctf_win_mode", "0"); + //registercvar("g_overtime", "1"); + registercvar("g_ctf_flagscore_kill", "6"); + registercvar("g_ctf_flagpenalty_drop", "0"); + //addstat(STAT_CTF_CAPTURES, AS_INT, captures); //addstat(STAT_CTF_STATE, AS_FLOAT_TRUNCATED, ctf_state); e = spawn(); e.think = ctf_delayedinit; diff --git a/data/qcsrc/server/defs.qh b/data/qcsrc/server/defs.qh index 1630907a2..e830f9cb4 100644 --- a/data/qcsrc/server/defs.qh +++ b/data/qcsrc/server/defs.qh @@ -436,3 +436,6 @@ float sv_maxidle; float sv_maxidle_spectatorsareidle; float next_pingtime; + +.float captures; +float caps_team1, caps_team2; diff --git a/data/qcsrc/server/ent_cs.qc b/data/qcsrc/server/ent_cs.qc index b914648d3..f2e7f3114 100644 --- a/data/qcsrc/server/ent_cs.qc +++ b/data/qcsrc/server/ent_cs.qc @@ -37,11 +37,13 @@ entity get_entcs_ent(float num) void entcs_ons(entity to) { - if(to == self.owner || self.team != to.team) - return; - if(self.owner.classname == "observer" || to.classname == "observer") + if(to == self.owner || self.team != to.team || + self.owner.classname == "observer" || to.classname == "observer") + { + WriteByte(MSG_ENTITY, ENTCS_MSG_ONS_REMOVE); return; - WriteByte(MSG_ENTITY, ENTCS_MSG_ONS); + } + WriteByte(MSG_ENTITY, ENTCS_MSG_ONS_GPS); WriteCoord(MSG_ENTITY, self.owner.origin_x); WriteCoord(MSG_ENTITY, self.owner.origin_y); WriteCoord(MSG_ENTITY, self.owner.angles_y); @@ -76,7 +78,7 @@ float entcs_send(entity to) entcs_common_self(); } - if(game == GAME_ONSLAUGHT) + if(g_onslaught) entcs_ons(to); WriteByte(MSG_ENTITY, ENTCS_MSG_END); @@ -94,7 +96,7 @@ void entcs_think() self.nextthink = time + 10; // update pings every 10 seconds }; -void attach_entcs() +entity attach_entcs() { local float num; local entity ent; @@ -116,6 +118,7 @@ void attach_entcs() setsize(ent, '0 0 0', '0 0 0'); ent.SendEntity = entcs_send; + return ent; }; void detach_entcs() diff --git a/data/qcsrc/server/g_damage.qc b/data/qcsrc/server/g_damage.qc index b424e1adf..a5ca4032e 100644 --- a/data/qcsrc/server/g_damage.qc +++ b/data/qcsrc/server/g_damage.qc @@ -318,8 +318,10 @@ void Obituary (entity attacker, entity targ, float deathtype) else bprint ("^1",s, "^1 was fragged by ", a, "\n"); } - - GiveFrags(attacker, targ, 1); + if(g_ctf && targ.flagcarried) + GiveFrags(attacker, targ, cvar("g_ctf_flagscore_kill")); + else + GiveFrags(attacker, targ, 1); if (targ.killcount > 2) { if(sv_gentle) bprint ("^1",s,"'s ^1", ftos(targ.killcount), " scoring spree was ended by ", a, "\n"); diff --git a/data/qcsrc/server/g_world.qc b/data/qcsrc/server/g_world.qc index 14d49a00f..2e9bc69c2 100644 --- a/data/qcsrc/server/g_world.qc +++ b/data/qcsrc/server/g_world.qc @@ -1484,7 +1484,7 @@ float WinningConditionBase_Teamplay(float fraglimit) AddWinners(team, COLOR_TEAM4); } - if(!g_runematch && !g_domination) + if(!g_runematch && !g_domination && !g_ctf) if(tdm_max_score != tdm_old_score) { if(tdm_max_score == fraglimit - 1) @@ -1558,6 +1558,23 @@ float WinningCondition_MaxTeamMax(float fraglimit) return WinningConditionBase_Teamplay(fraglimit); } +float WinningCondition_CTF(float capturelimit, float fraglimit) +{ + if(cvar("g_ctf_win_mode") == 2) + return WinningCondition_MaxTeamSum(fraglimit); + + team1_score = caps_team1; + team2_score = caps_team2; + team3_score = team4_score = 0; + + if(team1_score == team2_score && cvar("g_ctf_win_mode")) + { + return WinningCondition_MaxTeamSum(0); + } + + return WinningConditionBase_Teamplay(capturelimit); +} + void print_to(entity e, string s) { if(e) @@ -1758,6 +1775,7 @@ void CheckRules_World() local float status; local float timelimit; local float fraglimit; + local float capturelimit; VoteThink(); MapVote_Think(); @@ -1786,6 +1804,7 @@ void CheckRules_World() timelimit = cvar("timelimit") * 60; fraglimit = cvar("fraglimit"); + capturelimit = cvar("capturelimit"); if(checkrules_overtimeend) { @@ -1831,6 +1850,10 @@ void CheckRules_World() { status = WinningCondition_Onslaught(); } + else if(g_ctf) + { + status = WinningCondition_CTF(capturelimit, fraglimit); + } else { if(teams_matter) diff --git a/data/qcsrc/server/teamplay.qc b/data/qcsrc/server/teamplay.qc index 5c44aee6d..78b0d398e 100644 --- a/data/qcsrc/server/teamplay.qc +++ b/data/qcsrc/server/teamplay.qc @@ -25,6 +25,10 @@ float IsTeamBalanceForced() void TeamchangeFrags(entity e) { + if(g_ctf) + { + e.captures = 0; + } if(e.classname == "player") { // reduce frags during a team change -- 2.17.1