]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Some cleanup of the buff code revolving around timers (and supporting them on legacy...
authorMario <mario@smbclan.net>
Fri, 9 Aug 2019 19:46:54 +0000 (05:46 +1000)
committerMario <mario@smbclan.net>
Fri, 9 Aug 2019 19:46:54 +0000 (05:46 +1000)
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/t_items.qc
qcsrc/server/client.qc
qcsrc/server/compat/quake3.qc
ruleset-XDF.cfg

index 58663be1ac72aafd49268046138727770b250871..97df48106dcbc935fa4e38c0720f42b8cc3a0854 100644 (file)
@@ -180,9 +180,11 @@ void buff_Touch(entity this, entity toucher)
        {
                if (CS(toucher).cvar_cl_buffs_autoreplace && STAT(BUFFS, toucher) != STAT(BUFFS, this))
                {
+                       // TODO: lost-gained notification for this case
                        int buffid = buff_FirstFromFlags(STAT(BUFFS, toucher)).m_id;
-                       //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, STAT(BUFFS, toucher));
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
+                       Send_Notification(NOTIF_ONE, toucher, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
+                       if(!IS_INDEPENDENT_PLAYER(toucher))
+                               Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
 
                        STAT(BUFFS, toucher) = 0;
                        //sound(toucher, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
@@ -193,13 +195,17 @@ void buff_Touch(entity this, entity toucher)
        this.owner = toucher;
        this.buff_active = false;
        this.lifetime = 0;
-       int buffid = buff_FirstFromFlags(STAT(BUFFS, this)).m_id;
-       Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, buffid);
-       Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, buffid);
+       entity thebuff = buff_FirstFromFlags(STAT(BUFFS, this));
+       Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, thebuff.m_id);
+       if(!IS_INDEPENDENT_PLAYER(toucher))
+               Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, thebuff.m_id);
 
        Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
        sound(toucher, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
        STAT(BUFFS, toucher) |= (STAT(BUFFS, this));
+       float bufftime = ((this.count) ? this.count : thebuff.m_time(thebuff));
+       if(bufftime)
+               STAT(BUFF_TIME, toucher) = min(time + bufftime, max(STAT(BUFF_TIME, toucher), time) + bufftime);
 }
 
 float buff_Available(entity buff)
@@ -339,6 +345,12 @@ bool buff_Customize(entity this, entity client)
        return true;
 }
 
+void buff_Delete(entity this)
+{
+       WaypointSprite_Kill(this.buff_waypoint);
+       delete_fn(this);
+}
+
 void buff_Init(entity this)
 {
        if(!cvar("g_buffs")) { delete(this); return; }
@@ -374,6 +386,7 @@ void buff_Init(entity this)
        buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate + max(0, game_starttime - time));
        this.buff_active = !this.buff_activetime;
        this.pflags = PFLAGS_FULLDYNAMIC;
+       this.dtor = buff_Delete;
 
        if(this.spawnflags & 1)
                this.noalign = true;
@@ -562,8 +575,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
 {
        entity player = M_ARGV(0, entity);
 
-       STAT(BUFFS, player) = 0;
-       STAT(BUFF_TIME, player) = 0;
+       player.oldbuffs = 0;
        PS(player).buff_shield = time + 0.5; // prevent picking up buffs immediately
        // reset timers here to prevent them continuing after re-spawn
        player.buff_disability_time = 0;
@@ -609,8 +621,10 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
        if(STAT(BUFFS, frag_target))
        {
                int buffid = buff_FirstFromFlags(STAT(BUFFS, frag_target)).m_id;
-               Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
+               if(!IS_INDEPENDENT_PLAYER(frag_target))
+                       Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
                STAT(BUFFS, frag_target) = 0;
+               STAT(BUFF_TIME, frag_target) = 0;
 
                if(frag_target.buff_model)
                {
@@ -630,11 +644,12 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
        {
                int buffid = buff_FirstFromFlags(STAT(BUFFS, player)).m_id;
                Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid);
-               Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
+               if(!IS_INDEPENDENT_PLAYER(player))
+                       Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
 
                STAT(BUFFS, player) = 0;
+               STAT(BUFF_TIME, player) = 0;
                PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay);
-               //STAT(BUFF_TIME, player) = 0; // already notified
                sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
                return true;
        }
@@ -846,7 +861,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
                                Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
                                sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
                        }
-                       else
+                       else if(!IS_INDEPENDENT_PLAYER(player))
                                Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
                        STAT(BUFFS, player) = 0;
                        PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay); // always put in a delay, even if small
@@ -898,7 +913,8 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
        {
                entity buff = buff_FirstFromFlags(STAT(BUFFS, player));
                float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
-               STAT(BUFF_TIME, player) = (bufftime) ? time + bufftime : 0;
+               if(STAT(BUFF_TIME, player) <= time) // if the player still has a buff countdown, don't reset it!
+                       STAT(BUFF_TIME, player) = (bufftime) ? time + bufftime : 0;
 
                BUFF_ONADD(BUFF_AMMO)
                {
index 466b38311214c20d0aa66baefa1a7d35fcf93c98..6b04c98b069044428af14c76b7b316b6692198ab 100644 (file)
@@ -1503,9 +1503,11 @@ spawnfunc(target_items)
                                FOREACH(Buffs, it != BUFF_Null,
                                {
                                        s = Buff_UndeprecateName(argv(j));
-                                       if(s == it.m_name)
+                                       if(s == it.netname)
                                        {
                                                STAT(BUFFS, this) |= (it.m_itemid);
+                                               if(!STAT(BUFF_TIME, this))
+                                                       STAT(BUFF_TIME, this) = it.m_time(it);
                                                break;
                                        }
                                });
@@ -1565,7 +1567,7 @@ spawnfunc(target_items)
                if(GetResource(this, RES_FUEL) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_FUEL)), "fuel");
                if(GetResource(this, RES_HEALTH) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_HEALTH)), "health");
                if(GetResource(this, RES_ARMOR) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_ARMOR)), "armor");
-               FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
+               FOREACH(Buffs, it != BUFF_Null && (STAT(BUFFS, this) & it.m_itemid), this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, STAT(BUFF_TIME, this)), it.netname));
                FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
        }
        this.netname = strzone(this.netname);
@@ -1615,28 +1617,28 @@ float GiveWeapon(entity e, float wpn, float op, float val)
 bool GiveBuff(entity e, Buff thebuff, int op, int val)
 {
        bool had_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
-       switch(op)
+       switch (op)
        {
                case OP_SET:
-                       if(val > 0)
-                               STAT(BUFFS, e) |= thebuff.m_itemid;
-                       else
-                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) = val;
                        break;
                case OP_MIN:
-               case OP_PLUS:
-                       if(val > 0)
-                               STAT(BUFFS, e) |= thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) = max(STAT(BUFF_TIME, e), val);
                        break;
                case OP_MAX:
-                       if(val <= 0)
-                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) = min(STAT(BUFF_TIME, e), val);
+                       break;
+               case OP_PLUS:
+                       STAT(BUFF_TIME, e) += val;
                        break;
                case OP_MINUS:
-                       if(val > 0)
-                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) -= val;
                        break;
        }
+       if(STAT(BUFF_TIME, e) <= 0)
+               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+       else
+               STAT(BUFFS, e) = thebuff.m_itemid; // NOTE: replaces any existing buffs on the player!
        bool have_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
        return (had_buff != have_buff);
 }
@@ -1706,6 +1708,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        e.strength_finished = max(0, e.strength_finished - time);
        e.invincible_finished = max(0, e.invincible_finished - time);
        e.superweapons_finished = max(0, e.superweapons_finished - time);
+       STAT(BUFF_TIME, e) = max(0, STAT(BUFF_TIME, e) - time);
 
        PREGIVE(e, items);
        PREGIVE_WEAPONS(e);
@@ -1820,7 +1823,7 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveResourceValue(e, RES_FUEL, op, val);
                                break;
                        default:
-                               FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
+                               FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.netname,
                                {
                                        got += GiveBuff(e, it, op, val);
                                        break;
@@ -1858,7 +1861,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        POSTGIVE_RES_ROT(e, RES_HEALTH, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
 
        if(e.superweapons_finished <= 0)
-               if(!g_weaponarena && STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
+               if(!g_weaponarena && (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                        e.superweapons_finished = autocvar_g_balance_superweapons_time;
 
        if(e.strength_finished <= 0)
@@ -1873,6 +1876,10 @@ float GiveItems(entity e, float beginarg, float endarg)
                e.superweapons_finished = 0;
        else
                e.superweapons_finished += time;
+       if(STAT(BUFF_TIME, e) <= 0)
+               STAT(BUFF_TIME, e) = 0;
+       else
+               STAT(BUFF_TIME, e) += time;
 
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
index f43785bbb2fce697784fb80c1511541d6466fa56..7e2f0cf02ab878525ac6e50dae2b285cb90febd9 100644 (file)
@@ -640,6 +640,10 @@ void PutPlayerInServer(entity this)
        STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
 
+       // TODO: we can't set these in the PlayerSpawn hook since the target code is called before it!
+       STAT(BUFFS, this) = 0;
+       STAT(BUFF_TIME, this) = 0;
+
        this.air_finished = time + 12;
        this.waterlevel = WATERLEVEL_NONE;
        this.watertype = CONTENT_EMPTY;
index 112a7f039d95cee3c5ab34820011a0a1a7dd20d4..f96825132f12ef1ba0973b6b6a9296abae4bf54b 100644 (file)
@@ -119,7 +119,16 @@ void target_init_use(entity this, entity actor, entity trigger)
        {
                actor.strength_finished = 0;
                actor.invincible_finished = 0;
-               STAT(BUFFS, actor) = 0;
+               if(STAT(BUFFS, actor)) // TODO: make a dropbuffs function to handle this
+               {
+                       int buffid = buff_FirstFromFlags(STAT(BUFFS, actor)).m_id;
+                       Send_Notification(NOTIF_ONE, actor, MSG_MULTI, ITEM_BUFF_DROP, buffid);
+                       sound(actor, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+                       if(!IS_INDEPENDENT_PLAYER(actor))
+                               Send_Notification(NOTIF_ALL_EXCEPT, actor, MSG_INFO, INFO_ITEM_BUFF_LOST, actor.netname, buffid);
+                       STAT(BUFFS, actor) = 0;
+                       STAT(BUFF_TIME, actor) = 0;
+               }
        }
 
        if (!(this.spawnflags & 16))
@@ -169,6 +178,12 @@ void target_give_init(entity this)
                        SetResourceExplicit(this, RES_ARMOR, 100);
                else if (it.classname == "item_health_mega")
                        SetResourceExplicit(this, RES_HEALTH, 200);
+               else if (it.classname == "item_buff") {
+                       entity buff = buff_FirstFromFlags(STAT(BUFFS, it));
+                       this.netname = cons(this.netname, buff.netname);
+                       STAT(BUFF_TIME, this) = it.count;
+               }
+
                //remove(it); // removing ents in init functions causes havoc, workaround:
         setthink(it, SUB_Remove);
         it.nextthink = time;
index 20740d9a86482beef2dfb4c14e375453ffc71ec0..16cdd100a8fb7b89c7389c6d360f53c0e8f2ba7f 100644 (file)
@@ -21,6 +21,7 @@ set teamplay_mode 2 // friendly fire and self damage
 set sv_vote_nospectators 1
 set timelimit_override 20
 set g_buffs_cooldown_respawn 0.1
+set g_buffs_randomize 0
 
 // game mode settings
 set g_cts_finish_kill_delay 2