]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/gamemodes/gamemode/keyhunt/sv_keyhunt.qc
Nades code: don't use booleans as array indexes for m_projectile, optimize spawn_held...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / gamemodes / gamemode / keyhunt / sv_keyhunt.qc
index 21d9208bf96b74746cbb7f35c074b2a5f228ad27..beb5cd7f40f6d75a459466a132ae27eb571e0a95 100644 (file)
@@ -1,5 +1,11 @@
 #include "sv_keyhunt.qh"
 
+#include <server/command/vote.qh>
+#include <server/gamelog.qh>
+#include <server/damage.qh>
+#include <server/items/items.qh>
+#include <common/mapobjects/triggers.qh>
+
 float autocvar_g_balance_keyhunt_damageforcescale;
 float autocvar_g_balance_keyhunt_delay_collect;
 float autocvar_g_balance_keyhunt_delay_damage_return;
@@ -39,8 +45,8 @@ const float KH_KEY_XYSPEED = 45;
 #endif
 const float KH_KEY_WP_ZSHIFT = 20;
 
-const vector KH_KEY_MIN = '-10 -10 -46';
-const vector KH_KEY_MAX = '10 10 3';
+const vector KH_KEY_MIN = '-25 -25 -46'; // 0.8.6 used '-10 -10 -46' with sv_legacy_bbox_expand 1 and FL_ITEM
+const vector KH_KEY_MAX = '25 25 4';     // 0.8.6 used '10 10 3'     with sv_legacy_bbox_expand 1 and FL_ITEM
 const float KH_KEY_BRIGHTNESS = 2;
 
 bool kh_no_radar_circles;
@@ -84,7 +90,7 @@ void kh_ScoreRules(int teams)
         field_team(ST_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
         field(SP_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
         field(SP_KH_PUSHES, "pushes", 0);
-        field(SP_KH_DESTROYS, "destroyed", SFL_LOWER_IS_BETTER);
+        field(SP_KH_DESTRUCTIONS, "destructions", SFL_LOWER_IS_BETTER);
         field(SP_KH_PICKUPS, "pickups", 0);
         field(SP_KH_KCKILLS, "kckills", 0);
         field(SP_KH_LOSSES, "losses", SFL_LOWER_IS_BETTER);
@@ -125,12 +131,12 @@ void kh_update_state()
                s |= (32 ** key.count) * f;
        }
 
-       FOREACH_CLIENT(true, { STAT(KH_KEYS, it) = s; });
+       FOREACH_CLIENT(true, { STAT(OBJECTIVE_STATUS, it) = s; });
 
        FOR_EACH_KH_KEY(key)
        {
                if(key.owner)
-                       STAT(KH_KEYS, key.owner) |= (32 ** key.count) * 31;
+                       STAT(OBJECTIVE_STATUS, key.owner) |= (32 ** key.count) * 31;
        }
        //print(ftos((nextent(NULL)).kh_state), "\n");
 }
@@ -209,6 +215,7 @@ vector kh_AttachedOrigin(entity e)  // runs when a team captures the flag, it ca
 
 void kh_Key_Attach(entity key)  // runs when a player picks up a key and several times when a key is assigned to a player at the start of a round
 {
+       key.solid = SOLID_NOT; // before setorigin to prevent area grid linking
 #ifdef KH_PLAYER_USE_ATTACHMENT
        entity first = key.owner.kh_next;
        if(key == first)
@@ -242,7 +249,6 @@ void kh_Key_Attach(entity key)  // runs when a player picks up a key and several
        key.flags = 0;
        if(IL_CONTAINS(g_items, key))
                IL_REMOVE(g_items, key);
-       key.solid = SOLID_NOT;
        set_movetype(key, MOVETYPE_NONE);
        key.team = key.owner.team;
        key.nextthink = time;
@@ -254,6 +260,7 @@ void kh_Key_Attach(entity key)  // runs when a player picks up a key and several
 
 void kh_Key_Detach(entity key) // runs every time a key is dropped or lost. Runs several times times when all the keys are captured
 {
+       key.solid = SOLID_TRIGGER; // before setorigin to ensure area grid linking
 #ifdef KH_PLAYER_USE_ATTACHMENT
        entity first = key.owner.kh_next;
        if(key == first)
@@ -283,8 +290,8 @@ void kh_Key_Detach(entity key) // runs every time a key is dropped or lost. Runs
        key.flags = FL_ITEM;
        if(!IL_CONTAINS(g_items, key))
                IL_PUSH(g_items, key);
-       key.solid = SOLID_TRIGGER;
        set_movetype(key, MOVETYPE_TOSS);
+       nudgeoutofsolid(key); // a key has a bigger bbox than a player
        key.pain_finished = time + autocvar_g_balance_keyhunt_delay_return;
        key.damageforcescale = autocvar_g_balance_keyhunt_damageforcescale;
        key.takedamage = DAMAGE_YES;
@@ -541,7 +548,12 @@ void kh_WinnerTeam(int winner_team)  // runs when a team wins
                midpoint += thisorigin;
 
                if(!first)
-                       te_lightning2(NULL, lastorigin, thisorigin);
+               {
+                       // TODO: this effect has been replaced due to a possible crash it causes
+                       // see https://gitlab.com/xonotic/darkplaces/issues/123
+                       //te_lightning2(NULL, lastorigin, thisorigin);
+                       Send_Effect(EFFECT_TR_NEXUIZPLASMA, lastorigin, thisorigin, 1);
+               }
                lastorigin = thisorigin;
                if(first)
                        firstorigin = thisorigin;
@@ -549,7 +561,8 @@ void kh_WinnerTeam(int winner_team)  // runs when a team wins
        }
        if(NumTeams(kh_teams) > 2)
        {
-               te_lightning2(NULL, lastorigin, firstorigin);
+               //te_lightning2(NULL, lastorigin, firstorigin); // TODO see above
+               Send_Effect(EFFECT_TR_NEXUIZPLASMA, lastorigin, firstorigin, 1);
        }
        midpoint = midpoint * (1 / NumTeams(kh_teams));
        te_customflash(midpoint, 1000, 1, Team_ColorRGB(winner_team) * 0.5 + '0.5 0.5 0.5');  // make the color >=0.5 in each component
@@ -571,7 +584,7 @@ void kh_LoserTeam(int loser_team, entity lostkey)  // runs when a player pushes
        {
                if(lostkey.kh_previous_owner)
                        kh_Scores_Event(lostkey.kh_previous_owner, NULL, "pushed", 0, -autocvar_g_balance_keyhunt_score_push);
-                       // don't actually GIVE him the -nn points, just log
+                       // don't actually GIVE them the -nn points, just log
                kh_Scores_Event(attacker, NULL, "push", autocvar_g_balance_keyhunt_score_push, 0);
                GameRules_scoring_add(attacker, KH_PUSHES, 1);
                //centerprint(attacker, "Your push is the best!"); // does this really need to exist?
@@ -591,10 +604,10 @@ void kh_LoserTeam(int loser_team, entity lostkey)  // runs when a player pushes
 
                if(lostkey.kh_previous_owner)
                        kh_Scores_Event(lostkey.kh_previous_owner, NULL, "destroyed", 0, -autocvar_g_balance_keyhunt_score_destroyed);
-                       // don't actually GIVE him the -nn points, just log
+                       // don't actually GIVE them the -nn points, just log
 
                if(lostkey.kh_previous_owner.playerid == lostkey.kh_previous_owner_playerid)
-                       GameRules_scoring_add(lostkey.kh_previous_owner, KH_DESTROYS, 1);
+                       GameRules_scoring_add(lostkey.kh_previous_owner, KH_DESTRUCTIONS, 1);
 
                DistributeEvenly_Init(autocvar_g_balance_keyhunt_score_destroyed, keys * of + players);
 
@@ -705,16 +718,13 @@ void key_reset(entity this)
        kh_Key_Remove(this);
 }
 
-const string STR_ITEM_KH_KEY = "item_kh_key";
 void kh_Key_Spawn(entity initial_owner, float _angle, float i)  // runs every time a new flag is created, ie after all the keys have been collected
 {
-       entity key = spawn();
+       entity key = new(item_kh_key);
        key.count = i;
-       key.classname = STR_ITEM_KH_KEY;
        settouch(key, kh_Key_Touch);
        setthink(key, kh_Key_Think);
        key.nextthink = time;
-       key.items = IT_KEY1 | IT_KEY2;
        key.cnt = _angle;
        key.angles = '0 360 0' * random();
        key.event_damage = kh_Key_Damage;
@@ -845,7 +855,7 @@ int kh_GetMissingTeams()
                                ++players;
                });
                if (!players)
-                       missing_teams |= (2 ** i);
+                       missing_teams |= BIT(i);
        }
        return missing_teams;
 }
@@ -970,27 +980,24 @@ void kh_Initialize()  // sets up th KH environment
                kh_teams = cvar("g_keyhunt_teams"); // read the cvar directly as it gets written earlier in the same frame
        kh_teams = BITS(bound(2, kh_teams, 4));
 
-       // make a KH entity for controlling the game
-       kh_controller = spawn();
-       setthink(kh_controller, kh_Controller_Think);
-       kh_Controller_SetThink(0, kh_WaitForPlayers);
+       // use a temp entity to avoid linking kh_controller to the world with setmodel
+       entity tmp_ent = spawn();
+       setmodel(tmp_ent, MDL_KH_KEY);
+       kh_key_dropped = tmp_ent.modelindex;
 
-       setmodel(kh_controller, MDL_KH_KEY);
-       kh_key_dropped = kh_controller.modelindex;
-       /*
-       dprint(vtos(kh_controller.mins));
-       dprint(vtos(kh_controller.maxs));
-       dprint("\n");
-       */
 #ifdef KH_PLAYER_USE_CARRIEDMODEL
-       setmodel(kh_controller, MDL_KH_KEY_CARRIED);
-       kh_key_carried = kh_controller.modelindex;
+       setmodel(tmp_ent, MDL_KH_KEY_CARRIED);
+       kh_key_carried = tmp_ent.modelindex;
 #else
        kh_key_carried = kh_key_dropped;
 #endif
 
-       kh_controller.model = "";
-       kh_controller.modelindex = 0;
+       delete(tmp_ent);
+
+       // make a KH entity for controlling the game
+       kh_controller = new_pure(kh_controller);
+       setthink(kh_controller, kh_Controller_Think);
+       kh_Controller_SetThink(0, kh_WaitForPlayers);
 
        kh_ScoreRules(kh_teams);
 }
@@ -1037,7 +1044,7 @@ void havocbot_goalrating_kh(entity this, float ratingscale_team, float ratingsca
                        navigation_routerating(this, head.owner, ratingscale_enemy * 10000, 100000);
        }
 
-       havocbot_goalrating_items(this, 1, this.origin, 10000);
+       havocbot_goalrating_items(this, 80000, this.origin, 10000);
 }
 
 void havocbot_role_kh_carrier(entity this)
@@ -1251,14 +1258,6 @@ MUTATOR_HOOKFUNCTION(kh, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(kh, SpectateCopy)
-{
-       entity spectatee = M_ARGV(0, entity);
-       entity client = M_ARGV(1, entity);
-
-       STAT(KH_KEYS, client) = STAT(KH_KEYS, spectatee);
-}
-
 MUTATOR_HOOKFUNCTION(kh, PlayerUseKey)
 {
        entity player = M_ARGV(0, entity);