]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Lyberta/StandaloneOverkillWeapons
authorLyberta <lyberta@lyberta.net>
Sat, 2 Dec 2017 15:55:11 +0000 (18:55 +0300)
committerLyberta <lyberta@lyberta.net>
Sat, 2 Dec 2017 15:55:11 +0000 (18:55 +0300)
34 files changed:
.gitlab-ci.yml
mutators.cfg
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/client/view.qc
qcsrc/common/mutators/mutator/_mod.inc
qcsrc/common/mutators/mutator/_mod.qh
qcsrc/common/mutators/mutator/kick_teamkiller/_mod.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/kick_teamkiller/_mod.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/mutators/mutator/random_items/sv_random_items.qc
qcsrc/common/notifications/all.inc
qcsrc/common/physics/movetypes/movetypes.qc
qcsrc/common/scores.qh
qcsrc/common/triggers/misc/teleport_dest.qc
qcsrc/common/triggers/teleporters.qc
qcsrc/common/triggers/trigger/teleport.qc
qcsrc/common/weapons/weapon/shockwave.qc
qcsrc/lib/warpzone/common.qc
qcsrc/server/antilag.qc
qcsrc/server/antilag.qh
qcsrc/server/client.qc
qcsrc/server/client.qh
qcsrc/server/compat/quake3.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_subs.qc
qcsrc/server/g_world.qc
qcsrc/server/items.qc
qcsrc/server/items.qh
qcsrc/server/scores.qc
qcsrc/server/scores.qh
qcsrc/server/scores_rules.qc
qcsrc/server/weapons/tracing.qc

index 9305f527cd3abc9640d17bff880e021b854d7b17..9e6a7b6cda7cbe603a22e16bd0631195160c6168 100644 (file)
@@ -29,7 +29,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
     - make
-    - EXPECT=ed9be8d1b1a544f89bcdd7d36876fede
+    - EXPECT=3fb0c7a99263dd44e026804c12da2fa2
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index e37c190902d4901aa02ee2e5abbd86188c6f4489..79ac41791ade308fde3b9371f47757b23b2656b0 100644 (file)
@@ -480,6 +480,12 @@ set g_dynamic_handicap_exponent 1 "The exponent used to calculate handicap. 1 me
 set g_dynamic_handicap_min 0 "The minimum value of the handicap."
 set g_dynamic_handicap_max 0 "The maximum value of the handicap."
 
+// ===============
+// kick teamkiller
+// ===============
+set g_kick_teamkiller_rate 0 "Limit for teamkills per minute before the client gets dropped. 0 means that the teamkillers don't get kicked automatically"
+set g_kick_teamkiller_lower_limit 5 "Minimum number of teamkills before the teamkill rate is considered"
+
 // =====================
 //  stale-move negation
 // =====================
index 8e0d0f057695d8e237fbcbe2816b11298c6fce89..063cb887f92d51a734ff4d3d740ce09fca7bece6 100644 (file)
@@ -96,6 +96,7 @@ string TranslateScoresLabel(string l)
                case "kd": return CTX(_("SCO^k/d"));
                case "kdr": return CTX(_("SCO^kdr"));
                case "kills": return CTX(_("SCO^kills"));
+               case "teamkills": return CTX(_("SCO^teamkills"));
                case "laps": return CTX(_("SCO^laps"));
                case "lives": return CTX(_("SCO^lives"));
                case "losses": return CTX(_("SCO^losses"));
@@ -312,6 +313,7 @@ void Cmd_Scoreboard_Help()
        LOG_INFO(_("^3deaths^7                   Number of deaths"));
        LOG_INFO(_("^3suicides^7                 Number of suicides"));
        LOG_INFO(_("^3frags^7                    kills - suicides"));
+       LOG_INFO(_("^3teamkills^7                Number of teamkills"));
        LOG_INFO(_("^3kd^7                       The kill-death ratio"));
        LOG_INFO(_("^3dmg^7                      The total damage done"));
        LOG_INFO(_("^3dmgtaken^7                 The total damage taken"));
@@ -361,6 +363,7 @@ void Cmd_Scoreboard_Help()
 " -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
 " -teams,lms/deaths +ft,tdm/deaths" \
 " -teams,lms,rc,cts,inv,ka/suicides +ft,tdm/suicides ?+rc,inv/suicides" \
+" +teams/teamkills"\
 " -cts,dm,tdm,ka,ft/frags" /* tdm already has this in "score" */ \
 " -rc,cts,nb/dmg -rc,cts,nb/dmgtaken" \
 " +ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes" \
index e2aadf18d7808a6313771cbaccd8dba08dc63074..d3c1314cd671fdea4bcfa936e26dc9487f0e9b8a 100644 (file)
@@ -12,6 +12,7 @@
 #include "mutators/events.qh"
 
 #include <common/animdecide.qh>
+#include <common/deathtypes/all.qh>
 #include <common/ent_cs.qh>
 #include <common/anim.qh>
 #include <common/constants.qh>
@@ -912,7 +913,8 @@ vector crosshair_getcolor(entity this, float health_stat)
 
                case 2: // crosshair_color_by_health
                {
-                       float hp = health_stat;
+                       vector v = healtharmor_maxdamage(health_stat, STAT(ARMOR), armorblockpercent, DEATH_WEAPON.m_id);
+                       float hp = floor(v.x + 1);
 
                        //x = red
                        //y = green
index d1a6acfc91c0988929456b8eecbf7abc1354f70f..9d52fa20c44af25537d2b11bf68b04b2020cac0c 100644 (file)
@@ -15,6 +15,7 @@
 #include <common/mutators/mutator/instagib/_mod.inc>
 #include <common/mutators/mutator/invincibleproj/_mod.inc>
 #include <common/mutators/mutator/itemstime/_mod.inc>
+#include <common/mutators/mutator/kick_teamkiller/_mod.inc>
 #include <common/mutators/mutator/melee_only/_mod.inc>
 #include <common/mutators/mutator/midair/_mod.inc>
 #include <common/mutators/mutator/multijump/_mod.inc>
index a865d1922d9b0844ec65a711006f1cc3bf6ae679..f9edf4c56c47868e01161b34793a5c05e33f64d9 100644 (file)
@@ -15,6 +15,7 @@
 #include <common/mutators/mutator/instagib/_mod.qh>
 #include <common/mutators/mutator/invincibleproj/_mod.qh>
 #include <common/mutators/mutator/itemstime/_mod.qh>
+#include <common/mutators/mutator/kick_teamkiller/_mod.qh>
 #include <common/mutators/mutator/melee_only/_mod.qh>
 #include <common/mutators/mutator/midair/_mod.qh>
 #include <common/mutators/mutator/multijump/_mod.qh>
diff --git a/qcsrc/common/mutators/mutator/kick_teamkiller/_mod.inc b/qcsrc/common/mutators/mutator/kick_teamkiller/_mod.inc
new file mode 100644 (file)
index 0000000..a374a0e
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qc>
+#endif
diff --git a/qcsrc/common/mutators/mutator/kick_teamkiller/_mod.qh b/qcsrc/common/mutators/mutator/kick_teamkiller/_mod.qh
new file mode 100644 (file)
index 0000000..98fb481
--- /dev/null
@@ -0,0 +1 @@
+// generated file; do not modify
diff --git a/qcsrc/common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qc b/qcsrc/common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qc
new file mode 100644 (file)
index 0000000..a3b028f
--- /dev/null
@@ -0,0 +1,33 @@
+
+float autocvar_g_kick_teamkiller_rate;
+float autocvar_g_kick_teamkiller_lower_limit;
+
+REGISTER_MUTATOR(kick_teamkiller, (autocvar_g_kick_teamkiller_rate > 0));
+
+MUTATOR_HOOKFUNCTION(kick_teamkiller, PlayerDies)
+{
+       if (!teamplay)
+       {
+               return;
+       }
+       if (warmup_stage)
+       {
+               return;
+       }
+       entity attacker = M_ARGV(1, entity);
+       if (!IS_REAL_CLIENT(attacker))
+       {
+               return;
+       }
+
+       int teamkills = PlayerScore_Get(attacker, SP_TEAMKILLS);
+       // use the players actual playtime
+       float playtime = time - CS(attacker).startplaytime;
+       // rate is in teamkills/minutes, playtime in seconds
+       if (teamkills >= autocvar_g_kick_teamkiller_lower_limit && 
+           teamkills >= autocvar_g_kick_teamkiller_rate*playtime/60.0)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK_TEAMKILL, attacker.netname);
+               dropclient(attacker);
+       }
+}
index 4ba441be9df4ae898f1624cbd912048da8ae1909..371d1640d2762a183d4ee6e1865cbdda1b4ba350 100644 (file)
@@ -158,7 +158,7 @@ MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
                        setorigin(wep, ent.origin);
                        setmodel(wep, MDL_OK_HMG);
                        wep.ok_item = true;
-                       wep.noalign = ent.noalign;
+                       wep.noalign = Item_ShouldKeepPosition(ent);
                        wep.cnt = ent.cnt;
                        wep.team = ent.team;
                        wep.respawntime = g_pickup_respawntime_superweapon;
@@ -174,7 +174,7 @@ MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
                        setorigin(wep, ent.origin);
                        setmodel(wep, MDL_OK_RPC);
                        wep.ok_item = true;
-                       wep.noalign = ent.noalign;
+                       wep.noalign = Item_ShouldKeepPosition(ent);
                        wep.cnt = ent.cnt;
                        wep.team = ent.team;
                        wep.respawntime = g_pickup_respawntime_superweapon;
index 47234be290531e7d8a4966e313ac0f2bdb1acde7..3d305746269e1a29cbfb718ceb536175d04693af 100644 (file)
@@ -299,7 +299,7 @@ entity RandomItems_ReplaceMapItem(entity item)
        if (!expr_evaluate(autocvar_g_overkill))
        {
                new_item = Item_Create(strzone(new_classname), item.origin,
-                       item.noalign);
+                       Item_ShouldKeepPosition(item));
                random_items_is_spawning = false;
                if (new_item == NULL)
                {
@@ -311,7 +311,7 @@ entity RandomItems_ReplaceMapItem(entity item)
                new_item = spawn();
                new_item.classname = strzone(new_classname);
                new_item.spawnfunc_checked = true;
-               new_item.noalign = item.noalign;
+               new_item.noalign = Item_ShouldKeepPosition(item);
                new_item.ok_item = true;
                Item_Initialize(new_item, new_classname);
                random_items_is_spawning = false;
index 3b5492ac2d0adab12235d3512c13177e179b412b..b4c6146bb6662535e983df75a4e73962e6289636 100644 (file)
     MSG_INFO_NOTIF(QUIT_DISCONNECT,                         N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 disconnected"), "")
     MSG_INFO_NOTIF(QUIT_KICK_IDLING,                        N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked for idling"), "")
     MSG_INFO_NOTIF(QUIT_KICK_SPECTATING,                    N_CONSOLE,  0, 0, "", "",           "",             _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment."), "")
+    MSG_INFO_NOTIF(QUIT_KICK_TEAMKILL,                      N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked for excessive teamkilling"), "")
     MSG_INFO_NOTIF(QUIT_SPECTATE,                           N_CONSOLE,  1, 0, "s1", "",         "",             _("^BG%s^F3 is now spectating"), "")
 
     MSG_INFO_NOTIF(RACE_ABANDONED,                          N_CONSOLE,  1, 0, "s1", "",                                                                     "",                         _("^BG%s^BG has abandoned the race"), "")
index 995c65b4d322061a7f00d0b5f0899a4480af02a4..3fe2808583b94254d580b3c3960b2610c9192e6f 100644 (file)
@@ -544,7 +544,6 @@ void _Movetype_Physics_ClientFrame(entity this, float movedt)
                        _Movetype_CheckWater(this);
                        this.origin = this.origin + movedt * this.velocity;
                        this.angles = this.angles + movedt * this.avelocity;
-                       _Movetype_LinkEdict(this, false);
                        break;
                case MOVETYPE_STEP:
                        _Movetype_Physics_Step(this, movedt);
@@ -563,6 +562,12 @@ void _Movetype_Physics_ClientFrame(entity this, float movedt)
                case MOVETYPE_PHYSICS:
                        break;
        }
+
+       //_Movetype_CheckVelocity(this);
+
+       _Movetype_LinkEdict(this, true);
+
+       //_Movetype_CheckVelocity(this);
 }
 
 void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient)  // to be run every move frame
index 646638a80ca704778f8628513a6225021c154566..476d0dbbaa612445241bd1450c48642a7f78f347 100644 (file)
@@ -34,6 +34,7 @@ REGISTER_SP(DMGTAKEN);
 REGISTER_SP(KILLS);
 REGISTER_SP(DEATHS);
 REGISTER_SP(SUICIDES);
+REGISTER_SP(TEAMKILLS);
 REGISTER_SP(FRAGS);
 
 REGISTER_SP(ELO);
index fc3cec863a26920d0547df1143e75af283631f88..3f5203806964b64988426406eef59eda544ec899 100644 (file)
@@ -55,11 +55,6 @@ spawnfunc(misc_teleporter_dest)
        spawnfunc_info_teleport_destination(this);
 }
 
-spawnfunc(target_teleporter)
-{
-       spawnfunc_info_teleport_destination(this);
-}
-
 #elif defined(CSQC)
 
 void teleport_dest_remove(entity this)
index 8e9936b2ea2980586e44844ccb66b27f92801670..e1cd95058dbb7b597f174614c8b203be1674e05d 100644 (file)
@@ -228,9 +228,10 @@ entity Simple_TeleportPlayer(entity teleporter, entity player)
 
 void teleport_findtarget(entity this)
 {
+       bool istrigger = (this.solid == SOLID_TRIGGER);
+
        int n = 0;
-       entity e;
-       for(e = NULL; (e = find(e, targetname, this.target)); )
+       for(entity e = NULL; (e = find(e, targetname, this.target)); )
        {
                ++n;
 #ifdef SVQC
@@ -250,7 +251,7 @@ void teleport_findtarget(entity this)
        else if(n == 1)
        {
                // exactly one dest - bots love that
-               this.enemy = find(e, targetname, this.target);
+               this.enemy = find(NULL, targetname, this.target);
        }
        else
        {
@@ -259,9 +260,11 @@ void teleport_findtarget(entity this)
        }
 
        // now enable touch
-       settouch(this, Teleport_Touch);
+       if(istrigger)
+               settouch(this, Teleport_Touch);
 #ifdef SVQC
-       trigger_teleport_link(this);
+       if(istrigger)
+               trigger_teleport_link(this);
 #endif
 }
 
index 5f545f01418488f4375c229715a06040e3fb2c87..0330ce8d8cc46b1e9065ff29065ff51f233dadfd 100644 (file)
@@ -12,52 +12,83 @@ void trigger_teleport_use(entity this, entity actor, entity trigger)
 }
 #endif
 
-void Teleport_Touch(entity this, entity toucher)
+bool Teleport_Active(entity this, entity player)
 {
        if (this.active != ACTIVE_ACTIVE)
-               return;
+               return false;
 
 #ifdef SVQC
-       if (!toucher.teleportable)
-               return;
+       if (!player.teleportable)
+               return false;
 
-       if(toucher.vehicle)
-       if(!toucher.vehicle.teleportable)
-               return;
+       if(player.vehicle)
+       if(!player.vehicle.teleportable)
+               return false;
 
-       if(IS_TURRET(toucher))
-               return;
+       if(IS_TURRET(player))
+               return false;
 #elif defined(CSQC)
-       if(!IS_PLAYER(toucher))
-               return;
+       if(!IS_PLAYER(player))
+               return false;
 #endif
 
-       if(IS_DEAD(toucher))
-               return;
+       if(IS_DEAD(player))
+               return false;
 
        if(this.team)
-               if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
-                       return;
+               if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, player)))
+                       return false;
 
-       EXACTTRIGGER_TOUCH(this, toucher);
+       return true;
+}
+
+void Teleport_Touch(entity this, entity toucher)
+{
+       entity player = toucher;
+
+       if(!Teleport_Active(this, player))
+               return;
+
+       EXACTTRIGGER_TOUCH(this, player);
 
 #ifdef SVQC
-       if(IS_PLAYER(toucher))
-               RemoveGrapplingHooks(toucher);
+       if(IS_PLAYER(player))
+               RemoveGrapplingHooks(player);
 #endif
 
        entity e;
-       e = Simple_TeleportPlayer(this, toucher);
+       e = Simple_TeleportPlayer(this, player);
 
 #ifdef SVQC
        string s = this.target; this.target = string_null;
-       SUB_UseTargets(this, toucher, toucher); // TODO: should we be using toucher for trigger too?
+       SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
        if (!this.target) this.target = s;
 
-       SUB_UseTargets(e, toucher, toucher);
+       SUB_UseTargets(e, player, player);
 #endif
 }
 
+#ifdef SVQC
+void target_teleport_use(entity this, entity actor, entity trigger)
+{
+       entity player = actor;
+
+       if(!Teleport_Active(this, player))
+               return;
+
+       if(IS_PLAYER(player))
+               RemoveGrapplingHooks(player);
+
+       entity e = Simple_TeleportPlayer(this, player);
+
+       string s = this.target; this.target = string_null;
+       SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
+       if (!this.target) this.target = s;
+
+       SUB_UseTargets(e, player, player);
+}
+#endif
+
 #ifdef SVQC
 float trigger_teleport_send(entity this, entity to, float sf)
 {
@@ -101,6 +132,25 @@ spawnfunc(trigger_teleport)
 
        IL_PUSH(g_teleporters, this);
 }
+
+spawnfunc(target_teleporter)
+{
+       if(this.target == "")
+       {
+               // actually a destination!
+               spawnfunc_info_teleport_destination(this);
+               return;
+       }
+
+       this.active = ACTIVE_ACTIVE;
+
+       this.use = target_teleport_use;
+
+       if(this.noise != "")
+               FOREACH_WORD(this.noise, true, precache_sound(it));
+
+       InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
+}
 #elif defined(CSQC)
 NET_HANDLE(ENT_CLIENT_TRIGGER_TELEPORT, bool isnew)
 {
index 990bc29ee3d0da5c55087578aad7a0160e18b604..0ca4d528fe62ea550776a9d6ee1c9ad56dc6a526 100644 (file)
@@ -316,13 +316,7 @@ void W_Shockwave_Attack(entity actor, .entity weaponentity)
        if(autocvar_g_antilag == 0 || noantilag)
                lag = 0; // only do hitscan, but no antilag
        if(lag)
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != actor, antilag_takeback(it, CS(it), time - lag));
-               IL_EACH(g_monsters, it != actor,
-               {
-                       antilag_takeback(it, it, time - lag);
-               });
-       }
+               antilag_takeback_all(actor, lag);
 
        while(head)
        {
@@ -596,13 +590,7 @@ void W_Shockwave_Attack(entity actor, .entity weaponentity)
        }
 
        if(lag)
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != actor, antilag_restore(it, CS(it)));
-               IL_EACH(g_monsters, it != actor,
-               {
-                       antilag_restore(it, it);
-               });
-       }
+               antilag_restore_all(actor);
 }
 
 METHOD(Shockwave, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
index 65b1a7f6416485d2777926c3c86e1aae006a9a02..82d3a50719356083ae96fbb18d691dfc2b9f83df 100644 (file)
@@ -819,12 +819,12 @@ bool WarpZoneLib_MoveOutOfSolid(entity e)
        vector m1 = e.maxs;
        e.mins = '0 0 0';
        e.maxs = '0 0 0';
-       WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m0.x); e.mins.x = m0.x;
-       WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m1.x); e.maxs.x = m1.x;
-       WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m0.y); e.mins.y = m0.y;
-       WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m1.y); e.maxs.y = m1.y;
-       WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m0.z); e.mins.z = m0.z;
-       WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m1.z); e.maxs.z = m1.z;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m0.x); e.mins_x = m0.x;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m1.x); e.maxs_x = m1.x;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m0.y); e.mins_y = m0.y;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m1.y); e.maxs_y = m1.y;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m0.z); e.mins_z = m0.z;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m1.z); e.maxs_z = m1.z;
        setorigin(e, e.origin);
 
        tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
index 46c871876108005a0a69978681454bf1a9446f09..4062f7f660df2d15dfb01ea48bdf822a81599995 100644 (file)
@@ -119,3 +119,30 @@ void antilag_clear(entity e, entity store)
        }
        store.antilag_index = ANTILAG_MAX_ORIGINS - 1; // next one is 0
 }
+
+// TODO: use a single intrusive list across all antilagged entities
+void antilag_takeback_all(entity ignore, float lag)
+{
+       FOREACH_CLIENT(IS_PLAYER(it) && it != ignore, antilag_takeback(it, CS(it), time - lag));
+       IL_EACH(g_monsters, it != ignore,
+       {
+               antilag_takeback(it, it, time - lag);
+       });
+       IL_EACH(g_projectiles, it != ignore && it.classname == "nade",
+       {
+               antilag_takeback(it, it, time - lag);
+       });
+}
+
+void antilag_restore_all(entity ignore)
+{
+       FOREACH_CLIENT(IS_PLAYER(it) && it != ignore, antilag_restore(it, CS(it)));
+       IL_EACH(g_monsters, it != ignore,
+       {
+               antilag_restore(it, it);
+       });
+       IL_EACH(g_projectiles, it != ignore && it.classname == "nade",
+       {
+               antilag_restore(it, it);
+       });
+}
index 6cf392eed5ae1e8bd2bc125b3a19aa5b9e70d6dd..d57762ccd3899ef8588a560229b39e25ac89210e 100644 (file)
@@ -6,6 +6,9 @@ void antilag_takeback(entity e, entity store, float t);
 void antilag_restore(entity e, entity store);
 void antilag_clear(entity e, entity store);
 
+void antilag_takeback_all(entity ignore, float lag);
+void antilag_restore_all(entity ignore);
+
 .float antilag_debug;
 
 #define ANTILAG_LATENCY(e) min(0.4, CS(e).ping * 0.001)
index 2e2116c3496a40e1cafdf39e97918ef79f3b4569..856783df0dedd28ebf0599cadb057a2fcb7ec28d 100644 (file)
@@ -656,9 +656,11 @@ void PutPlayerInServer(entity this)
 
        PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
 
+       // player was spectator
        if (CS(this).killcount == FRAGS_SPECTATOR) {
                PlayerScore_Clear(this);
                CS(this).killcount = 0;
+               CS(this).startplaytime = time;
        }
 
        for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
index af81535a7a231bbd66f34bc0612d40caaf567999..42d7d9560b4e92359242e19428f242d146cbff0a 100644 (file)
@@ -85,6 +85,7 @@ CLASS(Client, Object)
     ATTRIB(Client, motd_actived_time, float, this.motd_actived_time);
     ATTRIB(Client, jointime, float, this.jointime);
     ATTRIB(Client, spectatortime, float, this.spectatortime);
+    ATTRIB(Client, startplaytime, float, this.startplaytime);
     ATTRIB(Client, version_nagtime, float, this.version_nagtime);
     ATTRIB(Client, netname_previous, string, this.netname_previous);
     ATTRIB(Client, allowed_timeouts, int, this.allowed_timeouts);
index a85f4cca6429d8a84af6f287d50366009832aedc..6a7f21aa674d319bad7ece6abeb908b28b764d60 100644 (file)
@@ -95,31 +95,31 @@ void target_give_init(entity this)
 {
        IL_EACH(g_items, it.targetname == this.target,
        {
-               if (it.classname == "weapon_rocketlauncher" || it.classname == "weapon_devastator") {
+               if (it.classname == "weapon_devastator") {
                        this.ammo_rockets += it.count * WEP_CVAR(devastator, ammo);
                        this.netname = cons(this.netname, "devastator");
                }
-               else if (it.classname == "weapon_railgun") {
+               else if (it.classname == "weapon_vortex") {
                        this.ammo_cells += it.count * WEP_CVAR_PRI(vortex, ammo); // WEAPONTODO
                        this.netname = cons(this.netname, "vortex");
                }
-               else if (it.classname == "weapon_lightning") {
+               else if (it.classname == "weapon_electro") {
                        this.ammo_cells += it.count * WEP_CVAR_PRI(electro, ammo); // WEAPONTODO
                        this.netname = cons(this.netname, "electro");
                }
-               else if (it.classname == "weapon_plasmagun") {
+               else if (it.classname == "weapon_hagar") {
                        this.ammo_rockets += it.count * WEP_CVAR_PRI(hagar, ammo); // WEAPONTODO
                        this.netname = cons(this.netname, "hagar");
                }
-               else if (it.classname == "weapon_bfg") {
+               else if (it.classname == "weapon_crylink") {
                        this.ammo_cells += it.count * WEP_CVAR_PRI(crylink, ammo);
                        this.netname = cons(this.netname, "crylink");
                }
-               else if (it.classname == "weapon_grenadelauncher" || it.classname == "weapon_mortar") {
+               else if (it.classname == "weapon_mortar") {
                        this.ammo_rockets += it.count * WEP_CVAR_PRI(mortar, ammo); // WEAPONTODO
                        this.netname = cons(this.netname, "mortar");
                }
-               else if (it.classname == "item_armor_body")
+               else if (it.classname == "item_armor_mega")
                        this.armorvalue = 100;
                else if (it.classname == "item_health_mega")
                        this.health = 200;
index b63b68e8f1db7c4277b84f160fa41bd8bc448da0..3034961c423acce70b57e2682b51f1f323843291 100644 (file)
@@ -138,7 +138,8 @@ void checkSpectatorBlock(entity this);
 
 float game_completion_ratio; // 0 at start, 1 near end
 .float winning;
-.float jointime; // time of joining
+.float jointime; // time of connecting
+.float startplaytime; // time of switching from spectator to player
 .float alivetime; // time of being alive
 .float motd_actived_time; // used for both motd and campaign_message
 
index afe018c08bc0198c2240c99e44f7dea7e75295fd..c0ff6b3f4ebd6c1a833f45c3b2f880ff06f1f442 100644 (file)
@@ -47,7 +47,7 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype)
                else
                {
                        // teamkill
-                       GameRules_scoring_add(attacker, KILLS, -1); // or maybe add a teamkills field?
+                       GameRules_scoring_add(attacker, TEAMKILLS, 1);
                }
        }
        else
index 713577fad17beb0c5d46932b7d845cea4b18cd7e..d9372e0aa561ea44f4d57850db09a656ef18e070 100644 (file)
@@ -50,14 +50,7 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma,
                source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
 
        if (lag)
-       {
-               // take players back into the past
-               FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_takeback(it, CS(it), time - lag));
-               IL_EACH(g_monsters, it != forent,
-               {
-                       antilag_takeback(it, it, time - lag);
-               });
-       }
+               antilag_takeback_all(forent, lag);
 
        // do the trace
        if(wz)
@@ -67,13 +60,7 @@ void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma,
 
        // restore players to current positions
        if (lag)
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != forent, antilag_restore(it, CS(it)));
-               IL_EACH(g_monsters, it != forent,
-               {
-                       antilag_restore(it, it);
-               });
-       }
+               antilag_restore_all(forent);
 
        // restore shooter solid type
        if(source)
index ce25dfa522772b08e3f1dfb41dcc2a536a2f4902..2eda8584ef5d82eeb9f346cb131aa9a049a58488 100644 (file)
@@ -2093,6 +2093,10 @@ void EndFrame()
        {
                antilag_record(it, it, altime);
        });
+       IL_EACH(g_projectiles, it.classname == "nade",
+       {
+               antilag_record(it, it, altime);
+       });
        systems_update();
        IL_ENDFRAME();
 }
index 29a8609bc628530049fb3b11677599529d320b5b..7d248834f72566af97313317a42a3a50c226f637 100644 (file)
@@ -84,6 +84,11 @@ void Item_SetLoot(entity item, bool loot)
        item.m_isloot = loot;
 }
 
+bool Item_ShouldKeepPosition(entity item)
+{
+       return item.noalign || (item.spawnflags & 1);
+}
+
 bool Item_IsExpiring(entity item)
 {
        return item.m_isexpiring;
index af55eebd4d60e42c34505515b42d3fd85dd1b689..1abcf64e0879442a3b8ade446bc724ca8250e503 100644 (file)
@@ -51,6 +51,13 @@ bool Item_IsLoot(entity item);
 /// \return No return.
 void Item_SetLoot(entity item, bool loot);
 
+/// \brief Returns whether item should keep its position or be dropped to the
+/// ground.
+/// \param[in] item Item to check.
+/// \return True if item should keep its position or false if it should be
+/// dropped to the ground.
+bool Item_ShouldKeepPosition(entity item);
+
 /// \brief Returns whether the item is expiring (i.e. its strength, shield and
 /// superweapon timers expire while it is on the ground).
 /// \param[in] item Item to check.
index 32fe3c6aaa2dd178f3af6cff5d89606688e3209f..c9948660efe1165c7ed8654dac1ba770e6763277 100644 (file)
@@ -96,7 +96,7 @@ void TeamScore_Spawn(float t, string name)
        PlayerStats_GameReport_AddTeam(t);
 }
 
-float TeamScore_AddToTeam(float t, float scorefield, float score)
+float TeamScore_AddToTeam(int t, float scorefield, float score)
 {
        entity s;
 
index 79b65299f41e1bfa2c01d5a09e528011d5a560cd..e2a57f43fb4a3ffaf36b6a5d33f1d475d793e9db 100644 (file)
@@ -52,7 +52,7 @@ float TeamScore_Add(entity player, float scorefield, float score);
  * NEVER call this if team has not been set yet!
  * Returns the new score.
  */
-float TeamScore_AddToTeam(float t, float scorefield, float score);
+float TeamScore_AddToTeam(int t, float scorefield, float score);
 
 /**
  * Returns a value indicating the team score (and higher is better).
index d46d95bd1c6114ee5138527c74cb726afc8a7dab..8d87407e64ebd3bc165efe3e27b53c6ceef25f0b 100644 (file)
@@ -44,7 +44,10 @@ void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled
        ScoreInfo_SetLabel_PlayerScore(SP_DEATHS,       "deaths",    SFL_LOWER_IS_BETTER);
 
        if (!INDEPENDENT_PLAYERS)
+       {
                ScoreInfo_SetLabel_PlayerScore(SP_SUICIDES,     "suicides",  SFL_LOWER_IS_BETTER);
+               ScoreInfo_SetLabel_PlayerScore(SP_TEAMKILLS,     "teamkills", SFL_LOWER_IS_BETTER);
+       }
 
        if(score_enabled)
                ScoreInfo_SetLabel_PlayerScore(SP_SCORE,        "score",     sprio);
index bf272a01a94e02d75041436a36b2c7ce1846ddad..157adb5d399c976dca3da949c257c272c3b182d3 100644 (file)
@@ -357,13 +357,7 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo
        if(autocvar_g_antilag == 0 || noantilag)
                lag = 0; // only do hitscan, but no antilag
        if(lag)
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_takeback(it, CS(it), time - lag));
-               IL_EACH(g_monsters, it != this,
-               {
-                       antilag_takeback(it, it, time - lag);
-               });
-       }
+               antilag_takeback_all(this, lag);
 
        // change shooter to SOLID_BBOX so the shot can hit corpses
        int oldsolid = this.dphitcontentsmask;
@@ -480,13 +474,7 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo
        }
 
        if(lag)
-       {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != this, antilag_restore(it, CS(it)));
-               IL_EACH(g_monsters, it != this,
-               {
-                       antilag_restore(it, it);
-               });
-       }
+               antilag_restore_all(this);
 
        // restore shooter solid type
        if(this)