From f7271e30cb1d52d41e0e3ee4bebc4e0edf48b830 Mon Sep 17 00:00:00 2001 From: fruitiex Date: Tue, 10 Nov 2009 21:28:20 +0000 Subject: [PATCH] Commit the new clan arena mod, as well as make the unbalanced team nagger optional via a serverside cvar (default on). Also do tiny balance changes to the nexrun balance... again ;) git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8267 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/balanceNexrun.cfg | 4 +- data/defaultNexuiz.cfg | 2 + data/maps/aggressor.mapinfo | 1 + data/maps/aneurysm.mapinfo | 1 + data/maps/basement.mapinfo | 1 + data/maps/bleach.mapinfo | 1 + data/maps/darkzone.mapinfo | 1 + data/maps/desertfactory.mapinfo | 1 + data/maps/dieselpower.mapinfo | 1 + data/maps/downer.mapinfo | 1 + data/maps/eggandbacon.mapinfo | 1 + data/maps/evilspace.mapinfo | 1 + data/maps/farewell.mapinfo | 1 + data/maps/final_rage.mapinfo | 1 + data/maps/reslimed.mapinfo | 1 + data/maps/ruiner.mapinfo | 1 + data/maps/runningman.mapinfo | 1 + data/maps/runningman_1on1remix.mapinfo | 1 + data/maps/skyway.mapinfo | 1 + data/maps/slimepit.mapinfo | 1 + data/maps/soylent.mapinfo | 1 + data/maps/starship.mapinfo | 1 + data/maps/stormkeep.mapinfo | 1 + data/maps/stormkeep2.mapinfo | 1 + data/maps/strength.mapinfo | 1 + data/maps/toxic.mapinfo | 1 + data/maps/warfare.mapinfo | 1 + data/qcsrc/client/Main.qc | 9 + data/qcsrc/client/sbar.qc | 4 +- data/qcsrc/common/constants.qh | 2 + data/qcsrc/common/mapinfo.qc | 10 +- data/qcsrc/common/mapinfo.qh | 3 +- data/qcsrc/common/util.qc | 1 + .../menu/nexuiz/dialog_multiplayer_create.c | 2 + .../dialog_multiplayer_create_mapinfo.c | 4 + data/qcsrc/server/arena.qc | 172 +++++++++++++----- data/qcsrc/server/cl_client.qc | 36 +++- data/qcsrc/server/cl_player.qc | 3 +- data/qcsrc/server/clientcommands.qc | 7 +- data/qcsrc/server/constants.qh | 2 +- data/qcsrc/server/defs.qh | 2 +- data/qcsrc/server/g_damage.qc | 2 +- data/qcsrc/server/g_world.qc | 5 +- data/qcsrc/server/scores.qc | 6 +- data/qcsrc/server/t_items.qc | 6 +- data/qcsrc/server/teamplay.qc | 6 +- 46 files changed, 239 insertions(+), 74 deletions(-) diff --git a/data/balanceNexrun.cfg b/data/balanceNexrun.cfg index f63036677..f50cc722e 100644 --- a/data/balanceNexrun.cfg +++ b/data/balanceNexrun.cfg @@ -159,7 +159,7 @@ set g_balance_fuel_limit 999 // }}} // {{{ misc -set g_balance_selfdamagepercent 1 +set g_balance_selfdamagepercent 0.75 set g_balance_weaponswitchdelay 0.1 set g_weaponspeedfactor 1 "weapon projectile speed multiplier" set g_weaponratefactor 1 "weapon fire rate multiplier" @@ -424,7 +424,7 @@ set g_balance_hagar_secondary_ammo 1 // {{{ rocketlauncher set g_balance_rocketlauncher_damage 90 set g_balance_rocketlauncher_edgedamage 30 -set g_balance_rocketlauncher_force 400 +set g_balance_rocketlauncher_force 350 set g_balance_rocketlauncher_radius 110 set g_balance_rocketlauncher_speed 1000 set g_balance_rocketlauncher_speedaccel 0 diff --git a/data/defaultNexuiz.cfg b/data/defaultNexuiz.cfg index 2b2c1aa39..4864e026d 100644 --- a/data/defaultNexuiz.cfg +++ b/data/defaultNexuiz.cfg @@ -563,6 +563,8 @@ set g_tdm_team_spawns 0 "when 1, a map can define team spawnpoints for TDM" set g_changeteam_banned 0 "not allowed to change team" set g_changeteam_fragtransfer 0 "% of frags you get to keep when you change teams (rounded down)" +set sv_teamnagger 1 "enable a nag message when the teams are unbalanced" + // dm set g_dm 1 "Deathmatch: killing any other player is one frag, player with most frags wins" set gamecfg 1 // "deathmatch" diff --git a/data/maps/aggressor.mapinfo b/data/maps/aggressor.mapinfo index d0dc9c767..3ec63e5e4 100644 --- a/data/maps/aggressor.mapinfo +++ b/data/maps/aggressor.mapinfo @@ -13,3 +13,4 @@ type arena 10 20 type kh 1000 20 3 type rc 20 5 10 20 cdtrack 4 +type ca 10 20 diff --git a/data/maps/aneurysm.mapinfo b/data/maps/aneurysm.mapinfo index f56b6104b..139cc3d1e 100644 --- a/data/maps/aneurysm.mapinfo +++ b/data/maps/aneurysm.mapinfo @@ -12,3 +12,4 @@ type arena 10 20 type kh 1000 30 2 type tdm 50 20 2 cdtrack 6 +type ca 10 20 diff --git a/data/maps/basement.mapinfo b/data/maps/basement.mapinfo index 0d6aec434..6066ff88a 100644 --- a/data/maps/basement.mapinfo +++ b/data/maps/basement.mapinfo @@ -10,3 +10,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 4 +type ca 10 20 diff --git a/data/maps/bleach.mapinfo b/data/maps/bleach.mapinfo index 8c7af8326..a01d0cb88 100644 --- a/data/maps/bleach.mapinfo +++ b/data/maps/bleach.mapinfo @@ -11,3 +11,4 @@ type rune 200 20 type lms 9 20 type kh 1000 20 3 cdtrack 8 +type ca 10 20 diff --git a/data/maps/darkzone.mapinfo b/data/maps/darkzone.mapinfo index d1557633a..286a9f694 100644 --- a/data/maps/darkzone.mapinfo +++ b/data/maps/darkzone.mapinfo @@ -10,3 +10,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 8 +type ca 10 20 diff --git a/data/maps/desertfactory.mapinfo b/data/maps/desertfactory.mapinfo index b95b83f2c..d1bb65803 100644 --- a/data/maps/desertfactory.mapinfo +++ b/data/maps/desertfactory.mapinfo @@ -8,3 +8,4 @@ type tdm 30 20 2 type lms 9 20 type arena 10 20 type kh 1000 20 2 +type ca 10 20 diff --git a/data/maps/dieselpower.mapinfo b/data/maps/dieselpower.mapinfo index 6db25430f..01b833474 100644 --- a/data/maps/dieselpower.mapinfo +++ b/data/maps/dieselpower.mapinfo @@ -11,3 +11,4 @@ type rune 200 20 type lms 9 20 type kh 1000 20 3 cdtrack 15 +type ca 10 20 diff --git a/data/maps/downer.mapinfo b/data/maps/downer.mapinfo index 137b47a35..9f214c017 100644 --- a/data/maps/downer.mapinfo +++ b/data/maps/downer.mapinfo @@ -11,3 +11,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 8 +type ca 10 20 diff --git a/data/maps/eggandbacon.mapinfo b/data/maps/eggandbacon.mapinfo index bf90e014b..f4c6cca61 100644 --- a/data/maps/eggandbacon.mapinfo +++ b/data/maps/eggandbacon.mapinfo @@ -9,3 +9,4 @@ type dm 30 20 type lms 16 20 type arena 10 20 type ctf 300 20 +type ca 10 20 diff --git a/data/maps/evilspace.mapinfo b/data/maps/evilspace.mapinfo index 9953aaffb..376f8b14e 100644 --- a/data/maps/evilspace.mapinfo +++ b/data/maps/evilspace.mapinfo @@ -8,3 +8,4 @@ type dm 30 20 type lms 9 20 type arena 10 20 cdtrack 7 +type ca 10 20 diff --git a/data/maps/farewell.mapinfo b/data/maps/farewell.mapinfo index aae967589..33b9f2b15 100644 --- a/data/maps/farewell.mapinfo +++ b/data/maps/farewell.mapinfo @@ -11,3 +11,4 @@ type lms 9 20 type arena 10 20 cdtrack 5 size -1536 -832 -576 896 1152 768 +type ca 10 20 diff --git a/data/maps/final_rage.mapinfo b/data/maps/final_rage.mapinfo index 8c0a02265..8e513c040 100644 --- a/data/maps/final_rage.mapinfo +++ b/data/maps/final_rage.mapinfo @@ -11,3 +11,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 7 +type ca 10 20 diff --git a/data/maps/reslimed.mapinfo b/data/maps/reslimed.mapinfo index badcf6cde..3093d003f 100644 --- a/data/maps/reslimed.mapinfo +++ b/data/maps/reslimed.mapinfo @@ -10,3 +10,4 @@ type dom 200 20 type rune 200 20 type lms 9 20 cdtrack 4 +type ca 10 20 diff --git a/data/maps/ruiner.mapinfo b/data/maps/ruiner.mapinfo index 43ac8afbb..778116594 100644 --- a/data/maps/ruiner.mapinfo +++ b/data/maps/ruiner.mapinfo @@ -12,3 +12,4 @@ type arena 10 20 cdtrack 11 clientsettemp_for_type all r_shadow_glossexponent 96 clientsettemp_for_type all r_shadow_glossintensity 2 +type ca 10 20 diff --git a/data/maps/runningman.mapinfo b/data/maps/runningman.mapinfo index 9caf57e00..297950176 100644 --- a/data/maps/runningman.mapinfo +++ b/data/maps/runningman.mapinfo @@ -11,3 +11,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 2 +type ca 10 20 diff --git a/data/maps/runningman_1on1remix.mapinfo b/data/maps/runningman_1on1remix.mapinfo index 0dcc54c55..56195c2ca 100644 --- a/data/maps/runningman_1on1remix.mapinfo +++ b/data/maps/runningman_1on1remix.mapinfo @@ -12,3 +12,4 @@ type lms 9 20 type arena 10 20 type kh 1000 20 3 cdtrack 2 +type ca 10 20 diff --git a/data/maps/skyway.mapinfo b/data/maps/skyway.mapinfo index 8d219aed8..20ad5e01b 100644 --- a/data/maps/skyway.mapinfo +++ b/data/maps/skyway.mapinfo @@ -11,3 +11,4 @@ type lms 9 20 type arena 10 20 type kh 1000 20 3 cdtrack 9 +type ca 10 20 diff --git a/data/maps/slimepit.mapinfo b/data/maps/slimepit.mapinfo index 005dab21f..9a0c79644 100644 --- a/data/maps/slimepit.mapinfo +++ b/data/maps/slimepit.mapinfo @@ -10,3 +10,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 4 +type ca 10 20 diff --git a/data/maps/soylent.mapinfo b/data/maps/soylent.mapinfo index d81773cf7..bd588ae9d 100644 --- a/data/maps/soylent.mapinfo +++ b/data/maps/soylent.mapinfo @@ -11,3 +11,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 14 +type ca 10 20 diff --git a/data/maps/starship.mapinfo b/data/maps/starship.mapinfo index ea5e179f2..7c2d2a6d8 100644 --- a/data/maps/starship.mapinfo +++ b/data/maps/starship.mapinfo @@ -10,3 +10,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 16 +type ca 10 20 diff --git a/data/maps/stormkeep.mapinfo b/data/maps/stormkeep.mapinfo index eccf2e4e5..230413335 100644 --- a/data/maps/stormkeep.mapinfo +++ b/data/maps/stormkeep.mapinfo @@ -13,3 +13,4 @@ type arena 10 20 type kh 1000 20 3 type tdm 50 20 2 cdtrack 6 +type ca 10 20 diff --git a/data/maps/stormkeep2.mapinfo b/data/maps/stormkeep2.mapinfo index 3a826dee8..670425c89 100644 --- a/data/maps/stormkeep2.mapinfo +++ b/data/maps/stormkeep2.mapinfo @@ -12,3 +12,4 @@ type arena 10 20 type kh 1000 20 3 type tdm 50 20 2 cdtrack 6 +type ca 10 20 diff --git a/data/maps/strength.mapinfo b/data/maps/strength.mapinfo index cdbae1ec3..6ef14e60e 100644 --- a/data/maps/strength.mapinfo +++ b/data/maps/strength.mapinfo @@ -11,3 +11,4 @@ type lms 9 20 type arena 10 20 type tdm 50 20 2 cdtrack 5 +type ca 10 20 diff --git a/data/maps/toxic.mapinfo b/data/maps/toxic.mapinfo index dedfebae2..3d3b3de5f 100644 --- a/data/maps/toxic.mapinfo +++ b/data/maps/toxic.mapinfo @@ -11,3 +11,4 @@ type rune 200 20 type lms 9 20 type arena 10 20 cdtrack 3 +type ca 10 20 diff --git a/data/maps/warfare.mapinfo b/data/maps/warfare.mapinfo index 8b3668eaf..1cc3ef61d 100644 --- a/data/maps/warfare.mapinfo +++ b/data/maps/warfare.mapinfo @@ -11,3 +11,4 @@ type tdm 50 20 2 type lms 9 20 type arena 10 20 cdtrack 6 +type ca 10 20 diff --git a/data/qcsrc/client/Main.qc b/data/qcsrc/client/Main.qc index a47da340d..e8e141086 100644 --- a/data/qcsrc/client/Main.qc +++ b/data/qcsrc/client/Main.qc @@ -1050,6 +1050,11 @@ void Net_ReadSpawn() current_viewzoom = 0.6; } +void Net_TeamNagger() +{ + teamnagger = 1; +} + // 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. @@ -1088,6 +1093,10 @@ float CSQC_Parse_TempEntity() Net_ReadNexgunBeamParticle(); bHandled = true; break; + case TE_CSQC_TEAMNAGGER: + Net_TeamNagger(); + bHandled = true; + break; case TE_CSQC_LIGHTNINGARC: Net_ReadLightningarc(); bHandled = true; diff --git a/data/qcsrc/client/sbar.qc b/data/qcsrc/client/sbar.qc index 5e4ea2832..83bbe7578 100644 --- a/data/qcsrc/client/sbar.qc +++ b/data/qcsrc/client/sbar.qc @@ -1,6 +1,8 @@ void drawstringright(vector, string, vector, vector, float, float); void drawstringcenter(vector, string, vector, vector, float, float); +float teamnagger; + float weapon_hits[WEP_COUNT]; float weapon_fired[WEP_COUNT]; float weapon_number; @@ -2598,7 +2600,7 @@ void Sbar_Draw (void) o = Sbar_DrawNoteLine(o, s); } } - if(teamplay && !intermission && !spectatee_status) + if(teamplay && !intermission && !spectatee_status && gametype != GAME_CA && teamnagger) { entity tm; float ts_min, ts_max; diff --git a/data/qcsrc/common/constants.qh b/data/qcsrc/common/constants.qh index f4d554c97..4e9fe23a3 100644 --- a/data/qcsrc/common/constants.qh +++ b/data/qcsrc/common/constants.qh @@ -38,6 +38,7 @@ const float GAME_ONSLAUGHT = 10; const float GAME_RACE = 11; const float GAME_NEXBALL = 12; const float GAME_CTS = 13; +const float GAME_CA = 14; const float AS_STRING = 1; const float AS_INT = 2; @@ -50,6 +51,7 @@ const float TE_CSQC_SPAWN = 102; const float TE_CSQC_ZCURVEPARTICLES = 103; const float TE_CSQC_NEXGUNBEAMPARTICLE = 104; const float TE_CSQC_LIGHTNINGARC = 105; +const float TE_CSQC_TEAMNAGGER = 106; const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder const float RACE_NET_CHECKPOINT_CLEAR = 1; diff --git a/data/qcsrc/common/mapinfo.qc b/data/qcsrc/common/mapinfo.qc index c6fa7920c..a438bcf2b 100644 --- a/data/qcsrc/common/mapinfo.qc +++ b/data/qcsrc/common/mapinfo.qc @@ -405,8 +405,10 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH; // Rune always works MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS; // LMS always works - if(spawnpoints >= 8 && diameter > 4096) + if(spawnpoints >= 8 && diameter > 4096) { MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH; + MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CA; + } if( diameter < 4096) MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ARENA; if(spawnpoints >= 12 && diameter > 5120) @@ -525,6 +527,7 @@ float MapInfo_Type_FromString(string t) else if(t == "rune") return MAPINFO_TYPE_RUNEMATCH; else if(t == "lms") return MAPINFO_TYPE_LMS; else if(t == "arena") return MAPINFO_TYPE_ARENA; + else if(t == "ca") return MAPINFO_TYPE_CA; else if(t == "kh") return MAPINFO_TYPE_KEYHUNT; else if(t == "as") return MAPINFO_TYPE_ASSAULT; else if(t == "ons") return MAPINFO_TYPE_ONSLAUGHT; @@ -699,6 +702,7 @@ float MapInfo_Get_ByName(string pFilename, float pAllowGenerate, float pGametype if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RUNEMATCH) fputs(fh, "type rune 200 20\n"); if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_LMS) fputs(fh, "type lms 9 20\n"); if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ARENA) fputs(fh, "type arena 10 20\n"); + if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_CA) fputs(fh, "type ca 10 20\n"); if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_KEYHUNT) fputs(fh, "type kh 1000 20 3\n"); if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ASSAULT) fputs(fh, "type as 20\n"); if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE) fputs(fh, "type rc 20 5 7 15\n"); @@ -966,6 +970,8 @@ float MapInfo_CurrentGametype() return MAPINFO_TYPE_LMS; else if(cvar("g_arena")) return MAPINFO_TYPE_ARENA; + else if(cvar("g_ca")) + return MAPINFO_TYPE_CA; else if(cvar("g_keyhunt")) return MAPINFO_TYPE_KEYHUNT; else if(cvar("g_onslaught")) @@ -1010,6 +1016,7 @@ string MapInfo_GetGameTypeCvar(float t) case MAPINFO_TYPE_RUNEMATCH: return "g_runematch"; case MAPINFO_TYPE_LMS: return "g_lms"; case MAPINFO_TYPE_ARENA: return "g_arena"; + case MAPINFO_TYPE_CA: return "g_ca"; case MAPINFO_TYPE_KEYHUNT: return "g_kh"; case MAPINFO_TYPE_ASSAULT: return "g_assault"; case MAPINFO_TYPE_ONSLAUGHT: return "g_onslaught"; @@ -1030,6 +1037,7 @@ void MapInfo_SwitchGameType(float t) cvar_set("g_runematch", (t == MAPINFO_TYPE_RUNEMATCH) ? "1" : "0"); cvar_set("g_lms", (t == MAPINFO_TYPE_LMS) ? "1" : "0"); cvar_set("g_arena", (t == MAPINFO_TYPE_ARENA) ? "1" : "0"); + cvar_set("g_ca", (t == MAPINFO_TYPE_CA) ? "1" : "0"); cvar_set("g_keyhunt", (t == MAPINFO_TYPE_KEYHUNT) ? "1" : "0"); cvar_set("g_assault", (t == MAPINFO_TYPE_ASSAULT) ? "1" : "0"); cvar_set("g_onslaught", (t == MAPINFO_TYPE_ONSLAUGHT) ? "1" : "0"); diff --git a/data/qcsrc/common/mapinfo.qh b/data/qcsrc/common/mapinfo.qh index 7c06a98da..a8cd7a2b9 100644 --- a/data/qcsrc/common/mapinfo.qh +++ b/data/qcsrc/common/mapinfo.qh @@ -11,7 +11,8 @@ float MAPINFO_TYPE_ARENA = 512; float MAPINFO_TYPE_KEYHUNT = 1024; float MAPINFO_TYPE_NEXBALL = 2048; float MAPINFO_TYPE_CTS = 4096; -float MAPINFO_TYPE_ALL = 65535; // this has to include all above bits +float MAPINFO_TYPE_CA = 8192; +float MAPINFO_TYPE_ALL = 16383; // this has to include all above bits float MAPINFO_FEATURE_WEAPONS = 1; // not defined for minstagib-only maps diff --git a/data/qcsrc/common/util.qc b/data/qcsrc/common/util.qc index dcae85e87..b2ad966ee 100644 --- a/data/qcsrc/common/util.qc +++ b/data/qcsrc/common/util.qc @@ -462,6 +462,7 @@ string GametypeNameFromType(float g) else if (g == GAME_RUNEMATCH) return "rune"; else if (g == GAME_LMS) return "lms"; else if (g == GAME_ARENA) return "arena"; + else if (g == GAME_CA) return "ca"; else if (g == GAME_KEYHUNT) return "kh"; else if (g == GAME_ONSLAUGHT) return "ons"; else if (g == GAME_ASSAULT) return "as"; diff --git a/data/qcsrc/menu/nexuiz/dialog_multiplayer_create.c b/data/qcsrc/menu/nexuiz/dialog_multiplayer_create.c index 768228d05..65f4c1d6d 100644 --- a/data/qcsrc/menu/nexuiz/dialog_multiplayer_create.c +++ b/data/qcsrc/menu/nexuiz/dialog_multiplayer_create.c @@ -51,6 +51,8 @@ void fillNexuizServerCreateTab(entity me) if(e.checked) e0 = NULL; me.TD(me, 1, me.columns / n, e = makeNexuizGametypeButton(1, "g_ctf", "CTF")); if(e.checked) e0 = NULL; + me.TD(me, 1, me.columns / n, e = makeNexuizGametypeButton(1, "g_ca", "CA")); + if(e.checked) e0 = NULL; me.TD(me, 1, me.columns / n, e = makeNexuizGametypeButton(1, "g_domination", "Domination")); if(e.checked) e0 = NULL; me.TD(me, 1, me.columns / n, e = makeNexuizGametypeButton(1, "g_keyhunt", "Key Hunt")); diff --git a/data/qcsrc/menu/nexuiz/dialog_multiplayer_create_mapinfo.c b/data/qcsrc/menu/nexuiz/dialog_multiplayer_create_mapinfo.c index 845962d5a..6f3f50601 100644 --- a/data/qcsrc/menu/nexuiz/dialog_multiplayer_create_mapinfo.c +++ b/data/qcsrc/menu/nexuiz/dialog_multiplayer_create_mapinfo.c @@ -22,6 +22,7 @@ CLASS(NexuizMapInfoDialog) EXTENDS(NexuizDialog) ATTRIB(NexuizMapInfoDialog, typeDominationLabel, entity, NULL) ATTRIB(NexuizMapInfoDialog, typeKeyHuntLabel, entity, NULL) ATTRIB(NexuizMapInfoDialog, typeCTFLabel, entity, NULL) + ATTRIB(NexuizMapInfoDialog, typeCALabel, entity, NULL) ATTRIB(NexuizMapInfoDialog, typeAssaultLabel, entity, NULL) ATTRIB(NexuizMapInfoDialog, typeOnslaughtLabel, entity, NULL) ATTRIB(NexuizMapInfoDialog, typeRaceLabel, entity, NULL) @@ -76,6 +77,7 @@ void loadMapInfoNexuizMapInfoDialog(entity me, float i, entity mlb) me.typeRuneLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RUNEMATCH); me.typeKeyHuntLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_KEYHUNT); me.typeCTFLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_CTF); + me.typeCALabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_CA); me.typeAssaultLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ASSAULT); me.typeOnslaughtLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ONSLAUGHT); me.typeRaceLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE); @@ -132,6 +134,8 @@ void fillNexuizMapInfoDialog(entity me) me.typeKeyHuntLabel = e; me.TD(me, 1, wgt, e = makeNexuizTextLabel(0, "CTF")); me.typeCTFLabel = e; + me.TD(me, 1, wgt, e = makeNexuizTextLabel(0, "CA")); + me.typeCALabel = e; me.TD(me, 1, wgt, e = makeNexuizTextLabel(0, "Assault")); me.typeAssaultLabel = e; me.TD(me, 1, wgt, e = makeNexuizTextLabel(0, "Onslaught")); diff --git a/data/qcsrc/server/arena.qc b/data/qcsrc/server/arena.qc index 9d96a51d6..bdb918c79 100644 --- a/data/qcsrc/server/arena.qc +++ b/data/qcsrc/server/arena.qc @@ -9,6 +9,9 @@ entity spawnqueue_first; entity spawnqueue_last; entity champion; float warmup; +float allowed_to_spawn; +float player_cnt; +.float caplayer; void PutObserverInServer(); void PutClientInServer(); @@ -29,10 +32,13 @@ void reset_map(float dorespawn) entity oldself; oldself = self; - if(g_arena) + if(g_arena || g_ca) if(cvar("g_arena_warmup")) warmup = time + cvar("g_arena_warmup"); + if(g_ca) + allowed_to_spawn = 1; + lms_lowest_lives = 999; lms_next_place = player_count; @@ -81,6 +87,10 @@ void reset_map(float dorespawn) else PutObserverInServer(); } + else if(g_ca && self.caplayer) { + self.classname = "player"; + PutClientInServer(); + } else { /* @@ -111,8 +121,8 @@ void reset_map(float dorespawn) if(g_keyhunt) kh_Controller_SetThink(cvar("g_balance_keyhunt_delay_round")+(game_starttime - time), "", kh_StartRound); - if(g_arena) - if(champion) + if(g_arena || g_ca) + if(champion && champion.classname == "player" && player_cnt > 1) UpdateFrags(champion, +1); self = oldself; @@ -175,50 +185,73 @@ void Spawnqueue_Mark(entity e) * * Called in PlayerPostThink() */ +float roundStartTime_prev; // prevent networkspam void Arena_Warmup() { float f; string msg; - if(!g_arena || !arena_roundbased || (time < game_starttime)) + if((!g_arena && !g_ca) || !arena_roundbased || (time < game_starttime)) return; - f = rint(warmup - time); + f = floor(warmup - time + 1); + + allowed_to_spawn = 0; + + if(g_ca && player_cnt < 2) + allowed_to_spawn = 1; msg = NEWLINES; - if(time < warmup && self.spawned) + if(time < warmup) { - if(champion) - msg = strcat(msg, "The Champion is ", champion.netname, "^7\n"); + if (g_ca) + allowed_to_spawn = 1; + if(champion && !(g_ca)) + centerprint(self, strcat(msg, "The Champion is ", champion.netname, "^7\n")); + + if(f != roundStartTime_prev) { + centerprint(self, strcat("Round will start in ", ftos(f),"\n")); + roundStartTime_prev = f; + if(f == 5) + play2all("announcer/robotic/prepareforbattle.wav"); + else if(f == 3) + play2all("announcer/robotic/3.wav"); + else if(f == 2) + play2all("announcer/robotic/2.wav"); + else if(f == 1) + play2all("announcer/robotic/1.wav"); + } - if(f) - msg = strcat(msg, "Round will start in ", ftos(f),"\n"); - else - { + if (!g_ca) { if(self.spawned) - msg = strcat(msg, "^1Fight!\n"); + self.movetype = MOVETYPE_NONE; + + self.velocity = '0 0 0'; + self.avelocity = '0 0 0'; + self.movement = '0 0 0'; + //self.fixangle = TRUE; } + } - centerprint(self, msg); + else if((!g_ca && self.movetype == MOVETYPE_NONE) || ((g_ca && f > -1 && f != roundStartTime_prev))) + { + if(self.classname == "player") + self.movetype = MOVETYPE_WALK; + centerprint(self, "^1Fight!\n"); + roundStartTime_prev = f; + play2all("announcer/robotic/begin.wav"); - if(self.spawned) - self.movetype = MOVETYPE_NONE; + player_cnt = 0; - self.velocity = '0 0 0'; - self.avelocity = '0 0 0'; - self.movement = '0 0 0'; - //self.fixangle = TRUE; - } - else if(self.movetype == MOVETYPE_NONE) - { - self.movetype = MOVETYPE_WALK; - centerprint(self, "\n"); + FOR_EACH_CLIENT(self) { + if (self.classname == "player") { + player_cnt += 1; + } + } } - } float next_round; - /** * This function finds out whether an arena round is over 1 player is left. * It determines the last player who's still alive and saves it's entity reference @@ -231,34 +264,83 @@ void Spawnqueue_Check() if(time < warmup + 1) return; - //extend next_round if it isn't set yet and only 1 player is spawned - if(!next_round) - if(numspawned < 2) - next_round = time + 3; + if(g_ca) { + // check the amount of spawned players in each team + float redspawned, bluespawned; + FOR_EACH_CLIENT(self) { + if (self.classname == "player") { + if (self.team == COLOR_TEAM1) redspawned += 1; + else if (self.team == COLOR_TEAM2) bluespawned += 1; + } + } - if(!arena_roundbased || (next_round && next_round < time && player_count > 1)) - { - next_round = 0; + if(player_cnt < 2 && (redspawned && bluespawned)) { + reset_map(TRUE); + } + else if(player_cnt < 2) { + FOR_EACH_CLIENT(self) + if(self.classname == "player") + centerprint(self, strcat("^1Need at least 2 players to play CA", "^7\n")); - if(arena_roundbased) + allowed_to_spawn = 1; + return; + } + else if(!next_round) + if((redspawned && bluespawned == 0) || (bluespawned && redspawned == 0)) { + next_round = time + 5; + + champion = find(world, classname, "player"); + string champion_team; + if(champion.team == COLOR_TEAM1) { + champion_team = "^1Red team"; + play2all("ctf/red_capture.wav"); + } + else if(champion.team == COLOR_TEAM2) { + champion_team = "^4Blue team"; + play2all("ctf/blue_capture.wav"); + } + FOR_EACH_CLIENT(self) centerprint(self, strcat(champion_team, "^7 wins the round.", "^7\n")); + else if(!redspawned && !bluespawned) { + FOR_EACH_CLIENT(self) centerprint(self, strcat("^7Round tied.", "^7\n")); + next_round = time + 5; + } + } + + if((next_round && next_round < time)) { - champion = find(world, classname, "player"); - while(champion && champion.deadflag) - champion = find(champion, classname, "player"); + next_round = 0; reset_map(TRUE); } + } else { // arena + //extend next_round if it isn't set yet and only 1 player is spawned + if(!next_round) + if(numspawned < 2) + next_round = time + 3; - while(numspawned < maxspawned && spawnqueue_first) + if(!arena_roundbased || (next_round && next_round < time && player_count > 1)) { - self = spawnqueue_first; + next_round = 0; - bprint ("^4", self.netname, "^4 is the next challenger\n"); + if(arena_roundbased) + { + champion = find(world, classname, "player"); + while(champion && champion.deadflag) + champion = find(champion, classname, "player"); + reset_map(TRUE); + } - Spawnqueue_Remove(self); - Spawnqueue_Mark(self); + while(numspawned < maxspawned && spawnqueue_first) + { + self = spawnqueue_first; - self.classname = "player"; - PutClientInServer(); + bprint ("^4", self.netname, "^4 is the next challenger\n"); + + Spawnqueue_Remove(self); + Spawnqueue_Mark(self); + + self.classname = "player"; + PutClientInServer(); + } } } } diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index 7d9d077ee..da1e834f3 100644 --- a/data/qcsrc/server/cl_client.qc +++ b/data/qcsrc/server/cl_client.qc @@ -1,5 +1,10 @@ void race_send_recordtime(float t, float msg); +void send_CSQC_teamnagger() { + WriteByte(0, SVC_TEMPENTITY); + WriteByte(0, TE_CSQC_TEAMNAGGER); +} + float ClientData_Send(entity to, float sf) { if(to != self.owner) @@ -316,7 +321,7 @@ entity SelectSpawnPoint (float anypoint) // there is 50/50 chance of choosing a random spot or the furthest spot // (this means that roughly every other spawn will be furthest, so you // usually won't get fragged at spawn twice in a row) - if (arena_roundbased) + if (arena_roundbased && !g_ca) { firstspot_new = Spawn_FilterOutBadSpots(firstspot, playerlist, 800, teamcheck); if(firstspot_new) @@ -638,7 +643,11 @@ void PutObserverInServer (void) if(sv_loddistance1) SetCustomizer(self, Client_customizeentityforclient, Client_uncustomizeentityforclient); - self.team = -1; + if(g_ca) { + // do nothing + } + else + self.team = -1; if(g_arena) { @@ -785,14 +794,14 @@ void PutClientInServer (void) self.classname = "observer"; } - if(g_arena) + if(g_arena || (g_ca && !allowed_to_spawn)) if(!self.spawned) self.classname = "observer"; if(gameover) self.classname = "observer"; - if(self.classname == "player") { + if(self.classname == "player" && (!g_ca || (g_ca && allowed_to_spawn))) { entity spot, oldself; float j; @@ -936,6 +945,9 @@ void PutClientInServer (void) Spawnqueue_Mark(self); } + else if(g_ca) + self.caplayer = 1; + self.event_damage = PlayerDamage; self.bot_attack = TRUE; @@ -993,7 +1005,7 @@ void PutClientInServer (void) SUB_UseTargets(); activator = world; self = oldself; - } else if(self.classname == "observer") { + } else if(self.classname == "observer" || (g_ca && !allowed_to_spawn)) { PutObserverInServer (); } @@ -1406,10 +1418,11 @@ void ClientConnect (void) stuffcmd(self, strcat("set gametype ", ftos(game), "\n")); - if(g_arena) + if(g_arena || g_ca) { self.classname = "observer"; - Spawnqueue_Insert(self); + if(g_arena) + Spawnqueue_Insert(self); } /*else if(g_ctf) { @@ -1473,6 +1486,8 @@ void ClientConnect (void) speedaward_alltimebest_holder = db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/netname")); race_send_speedaward_alltimebest(MSG_ONE); } + else if(cvar("sv_teamnagger")) + send_CSQC_teamnagger(); } /* @@ -2140,7 +2155,10 @@ void LeaveSpectatorMode() centerprint(self,""); // clear MOTD return; } else { - stuffcmd(self,"menu_showteamselect\n"); + if (g_ca && self.caplayer) { + } // do nothing + else + stuffcmd(self,"menu_showteamselect\n"); return; } } @@ -2430,7 +2448,7 @@ void PlayerPreThink (void) if(frametime) player_anim(); button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE); - force_respawn = (g_lms || cvar("g_forced_respawn")); + force_respawn = (g_lms || (g_ca) || cvar("g_forced_respawn")); if (self.deadflag == DEAD_DYING) { if(force_respawn) diff --git a/data/qcsrc/server/cl_player.qc b/data/qcsrc/server/cl_player.qc index 5870832e8..457f5da56 100644 --- a/data/qcsrc/server/cl_player.qc +++ b/data/qcsrc/server/cl_player.qc @@ -475,8 +475,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht else Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); - if(g_arena) - if(numspawned < 2) + if(g_arena && numspawned < 2) return; if (!g_minstagib) diff --git a/data/qcsrc/server/clientcommands.qc b/data/qcsrc/server/clientcommands.qc index 3b3eb2edf..5f0bfd1ab 100644 --- a/data/qcsrc/server/clientcommands.qc +++ b/data/qcsrc/server/clientcommands.qc @@ -257,6 +257,8 @@ void SV_ParseClientCommand(string s) { kh_Key_DropAll(self, TRUE); WaypointSprite_PlayerDead(); self.classname = "observer"; + if(g_ca) + self.caplayer = 0; 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")); PutClientInServer(); @@ -269,6 +271,8 @@ void SV_ParseClientCommand(string s) { { if(isJoinAllowed()) { self.classname = "player"; + if(g_ca) + self.caplayer = 1; PlayerScore_Clear(self); bprint ("^4", self.netname, "^4 is playing now\n"); PutClientInServer(); @@ -813,7 +817,8 @@ void ReadyRestartForce() void ReadyRestart() { // no arena, assault support yet... - if(g_arena | g_assault | gameover | intermission_running | race_completing) + // TODO: CA support + if(g_arena | g_ca | g_assault | gameover | intermission_running | race_completing) localcmd("restart\n"); else localcmd("\nsv_hook_gamerestart;"); diff --git a/data/qcsrc/server/constants.qh b/data/qcsrc/server/constants.qh index e1460f8bc..867e3b8c0 100644 --- a/data/qcsrc/server/constants.qh +++ b/data/qcsrc/server/constants.qh @@ -1,4 +1,4 @@ -string CVAR_CHECK_DEFAULT = "9ede7a7edae0b7ae4c8b7e6517293a6a"; +string CVAR_CHECK_DEFAULT = "489314f0011ead8255994194a02ab81a"; string CVAR_CHECK_BALANCE = "729b07b9caa8a86c08841a0f4275e97d"; float FALSE = 0; diff --git a/data/qcsrc/server/defs.qh b/data/qcsrc/server/defs.qh index e4986a6c1..eb1e68238 100644 --- a/data/qcsrc/server/defs.qh +++ b/data/qcsrc/server/defs.qh @@ -17,7 +17,7 @@ float require_spawnfunc_prefix; // if this float exists, only functions with spa float ctf_score_value(string parameter); -float g_dm, g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught, g_assault, g_arena, g_lms, g_runematch, g_race, g_nexball, g_cts; +float g_dm, g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught, g_assault, g_arena, g_ca, g_lms, g_runematch, g_race, g_nexball, g_cts; float g_cloaked, g_footsteps, g_jump_grunt, g_grappling_hook, g_laserguided_missile, g_midair, g_minstagib, g_nixnex, g_nixnex_with_laser, g_pinata, g_norecoil, g_vampire, g_minstagib_invis_alpha, g_bloodloss; float g_warmup_limit; float g_warmup_allguns; diff --git a/data/qcsrc/server/g_damage.qc b/data/qcsrc/server/g_damage.qc index f1d927955..bbbf91417 100644 --- a/data/qcsrc/server/g_damage.qc +++ b/data/qcsrc/server/g_damage.qc @@ -121,7 +121,7 @@ void GiveFrags (entity attacker, entity targ, float f) PlayerScore_Add(targ, SP_DEATHS, 1); - if(g_arena) + if(g_arena || g_ca) if(cvar("g_arena_roundbased")) return; diff --git a/data/qcsrc/server/g_world.qc b/data/qcsrc/server/g_world.qc index 7c4bc39dc..7687b9a90 100644 --- a/data/qcsrc/server/g_world.qc +++ b/data/qcsrc/server/g_world.qc @@ -243,6 +243,7 @@ void cvar_changes_init() BADCVAR("timelimit"); BADCVAR("fraglimit"); BADCVAR("g_arena"); + BADCVAR("g_ca"); BADCVAR("g_assault"); BADCVAR("g_ctf"); BADCVAR("g_dm"); @@ -1205,7 +1206,7 @@ void DumpStats(float final) { s = strcat(":player:see-labels:", GetPlayerScoreString(other, 0), ":"); s = strcat(s, ftos(rint(time - other.jointime)), ":"); - if(other.classname == "player" || g_arena || g_lms) + if(other.classname == "player" || g_arena || g_ca || g_lms) s = strcat(s, ftos(other.team), ":"); else s = strcat(s, "spectator:"); @@ -1702,7 +1703,7 @@ float WinningCondition_Scores(float limit, float leadlimit) if(WinningConditionHelper_zeroisworst) leadlimit = 0; // not supported in this mode - if(g_dm || g_tdm || g_arena || (g_race && !g_race_qualifying) || g_nexball) + if(g_dm || g_tdm || g_arena || g_ca || (g_race && !g_race_qualifying) || g_nexball) // these modes always score in increments of 1, thus this makes sense { if(leaderfrags != WinningConditionHelper_topscore) diff --git a/data/qcsrc/server/scores.qc b/data/qcsrc/server/scores.qc index 90c2f5725..30adf39fb 100644 --- a/data/qcsrc/server/scores.qc +++ b/data/qcsrc/server/scores.qc @@ -246,7 +246,7 @@ void PlayerScore_Clear(entity player) if(teamscores_entities_count) return; if(g_lms) return; - if(g_arena) return; + if(g_arena || g_ca) return; if(g_race && !g_race_qualifying) return; sk = player.scorekeeper; @@ -496,12 +496,12 @@ void WinningConditionHelper() s = strcat(s, ":human"); else s = strcat(s, ":bot"); - if(p.classname != "player" && !g_arena && !g_lms) + if(p.classname != "player" && !g_arena && !g_ca && !g_lms) s = strcat(s, ":spectator"); } else { - if(p.classname == "player" || g_arena || g_lms) + if(p.classname == "player" || g_arena || g_ca || g_lms) s = GetPlayerScoreString(p, 2); else s = "-666"; diff --git a/data/qcsrc/server/t_items.qc b/data/qcsrc/server/t_items.qc index 1f30ca73b..a1b22b2fd 100644 --- a/data/qcsrc/server/t_items.qc +++ b/data/qcsrc/server/t_items.qc @@ -1270,7 +1270,7 @@ void spawnfunc_item_health_mega (void) { if(!cvar("g_powerup_superhealth")) return; - if(g_arena && !cvar("g_arena_powerups")) + if((g_arena || g_ca) && !cvar("g_arena_powerups")) return; if(g_minstagib) { @@ -1295,7 +1295,7 @@ void spawnfunc_item_strength (void) { if(!cvar("g_powerup_strength")) return; - if(g_arena && !cvar("g_arena_powerups")) + if((g_arena || g_ca) && !cvar("g_arena_powerups")) return; if(g_minstagib) { @@ -1311,7 +1311,7 @@ void spawnfunc_item_invincible (void) { if(!cvar("g_powerup_shield")) return; - if(g_arena && !cvar("g_arena_powerups")) + if((g_arena || g_ca) && !cvar("g_arena_powerups")) return; if(g_minstagib) { diff --git a/data/qcsrc/server/teamplay.qc b/data/qcsrc/server/teamplay.qc index 387a6b209..c20e3a414 100644 --- a/data/qcsrc/server/teamplay.qc +++ b/data/qcsrc/server/teamplay.qc @@ -93,6 +93,7 @@ void WriteGameCvars() cvar_set("g_runematch", ftos(g_runematch)); cvar_set("g_lms", ftos(g_lms)); cvar_set("g_arena", ftos(g_arena)); + cvar_set("g_ca", ftos(g_ca)); cvar_set("g_keyhunt", ftos(g_keyhunt)); cvar_set("g_assault", ftos(g_assault)); cvar_set("g_onslaught", ftos(g_onslaught)); @@ -118,6 +119,7 @@ void ReadGameCvars() found += (g_runematch = (!found && (prev != GAME_RUNEMATCH) && cvar("g_runematch"))); found += (g_lms = (!found && (prev != GAME_LMS) && cvar("g_lms"))); found += (g_arena = (!found && (prev != GAME_ARENA) && cvar("g_arena"))); + found += (g_ca = (!found && (prev != GAME_CA) && cvar("g_ca"))); found += (g_keyhunt = (!found && (prev != GAME_KEYHUNT) && cvar("g_keyhunt"))); found += (g_assault = (!found && (prev != GAME_ASSAULT) && cvar("g_assault"))); found += (g_onslaught = (!found && (prev != GAME_ONSLAUGHT) && cvar("g_onslaught"))); @@ -282,10 +284,12 @@ void InitGameplayMode() ScoreRules_lms(); } - if(g_arena) + if(g_arena || g_ca) { game = GAME_ARENA; gamemode_name = "Arena"; + if(g_ca) + ActivateTeamplay(); fraglimit_override = cvar("g_arena_point_limit"); leadlimit_override = cvar("g_arena_point_leadlimit"); maxspawned = cvar("g_arena_maxspawned"); -- 2.39.2