]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
items: fix animation interference with physics and reset animation properly if disabled
authorbones_was_here <bones_was_here@xonotic.au>
Sun, 11 Jun 2023 17:52:25 +0000 (03:52 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Thu, 15 Jun 2023 20:36:23 +0000 (06:36 +1000)
Spawns item at the sine wave midpoint instead of "fading in".

qcsrc/client/items/items.qc
qcsrc/client/items/items.qh
xonotic-client.cfg

index a10ac41e490a93ce9c832845dee618797e1dc42f..740294b2c1795d4020bed21dce372a1114bd5f25 100644 (file)
 .bool item_simple; // probably not really needed, but better safe than sorry
 .float alpha;
 .bool pushable;
+.float anim_start_time; // reusing for bob waveform synchronisation
+.vector angles_held; // reusing for (re)storing original angles
 
 void ItemDraw(entity this)
 {
-       if(this.gravity)
+       // no bobbing applied to simple items, for consistency's sake (no visual difference between ammo and weapons)
+       bool animate = autocvar_cl_items_animate & 1 && this.item_simple <= 0 && (this.ItemStatus & ITS_ANIMATE1 || this.ItemStatus & ITS_ANIMATE2);
+
+       // rotation must be set before running physics
+       if(!animate)
        {
-               Movetype_Physics_MatchServer(this, false);
-               if(IS_ONGROUND(this))
-               { // For some reason avelocity gets set to '0 0 0' here ...
-                       this.oldorigin = this.origin;
-                       this.gravity = 0;
+               this.avelocity_y = 0;
+               this.angles = this.angles_held; // restore angles sent from server
+       }
+       else if(!this.avelocity_y) // unset by MOVETYPE_TOSS or animation was disabled previously
+       {
+               if(this.ItemStatus & ITS_ANIMATE1)
+                       this.avelocity_y = 180;
+               else if(this.ItemStatus & ITS_ANIMATE2)
+                       this.avelocity_y = -90;
+       }
 
-                       if(autocvar_cl_animate_items)
-                       { // ... so reset it if animations are requested.
+       // CSQC physics OR bobbing (both would look weird)
+       float bobheight = 0; // reset bob offset if animations are disabled
+       if(this.move_movetype && (!IS_ONGROUND(this) || this.velocity != '0 0 0'))
+       {
+               // this isn't equivalent to player prediction but allows smooth motion with very low ISF_LOCATION rate
+               // which requires running this even if the item is just outside visible range (it could be moving into range)
+               if(animate)
+                       bobheight = this.origin_z - this.oldorigin_z;
+               Movetype_Physics_MatchServer(this, false);
+               this.oldorigin = this.origin; // update real (SVQC equivalent) origin
+               if(animate)
+               {
+                       if(bobheight)
+                       {
+                               this.anim_start_time += frametime; // bobbing is paused this frame
+                               this.oldorigin_z -= bobheight; // restore bob offset (CSQC physics uses the offset bbox)
+                       }
+                       else
+                       {
+                               this.anim_start_time = time; // starting our bob animation from NOW
                                if(this.ItemStatus & ITS_ANIMATE1)
-                                       this.avelocity = '0 180 0';
-
-                               if(this.ItemStatus & ITS_ANIMATE2)
-                                       this.avelocity = '0 -90 0';
+                                       bobheight = 10; // height of wave at 0 time
+                               else if(this.ItemStatus & ITS_ANIMATE2)
+                                       bobheight = 8; // height of wave at 0 time
                        }
-
-                       // delay is for blocking item's position for a while;
-                       // it's a workaround for dropped weapons that receive the position
-                       // another time right after they spawn overriding animation position
-                       this.onground_time = time + 0.5;
                }
        }
-       else if (autocvar_cl_animate_items && !this.item_simple) // no bobbing applied to simple items, for consistency's sake (no visual difference between ammo and weapons)
+       else if(animate)
        {
+               this.angles += this.avelocity * frametime; // MOVETYPE_TOSS does this while it's moving
+
                if(this.ItemStatus & ITS_ANIMATE1)
-               {
-                       this.angles += this.avelocity * frametime;
-                       float fade_in = bound(0, time - this.onground_time, 1);
-                       setorigin(this, this.oldorigin + fade_in * ('0 0 10' + '0 0 8' * sin((time - this.onground_time) * 2)));
-               }
+                       bobheight = 10 + 8 * sin((time - this.anim_start_time) * 2);
+               else if(this.ItemStatus & ITS_ANIMATE2)
+                       bobheight = 8 + 4 * sin((time - this.anim_start_time) * 3);
+       }
 
-               if(this.ItemStatus & ITS_ANIMATE2)
-               {
-                       this.angles += this.avelocity * frametime;
-                       float fade_in = bound(0, time - this.onground_time, 1);
-                       setorigin(this, this.oldorigin + fade_in * ('0 0 8' + '0 0 4' * sin((time - this.onground_time) * 3)));
-               }
+       // apply new bob offset
+       if (bobheight != this.origin_z - this.oldorigin_z)
+       {
+               this.origin_z = this.oldorigin_z + bobheight;
+               this.mins_z = 0 - bobheight; // don't want the absmin and absmax to bob
+               this.maxs_z = 48 - bobheight;
+               // bones_was_here TODO: network proper box size for sv_legacy_bbox_expand 0
        }
 
        // set alpha based on distance
@@ -123,14 +148,15 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
 
        if(sf & ISF_LOCATION)
        {
-               vector org = ReadVector();
-               setorigin(this, org);
-               this.oldorigin = org;
+               float bobheight = this.origin_z - this.oldorigin_z;
+               this.origin = this.oldorigin = ReadVector();
+               this.origin_z += bobheight; // restore animation offset (SVQC physics is unaware of CSQC bbox offset)
+               setorigin(this, this.origin); // link
        }
 
        if(sf & ISF_ANGLES)
        {
-               this.angles = ReadAngleVector();
+               this.angles = this.angles_held = ReadAngleVector();
        }
 
        if(sf & ISF_SIZE)
@@ -158,7 +184,6 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
 
        if(sf & ISF_MODEL)
        {
-               set_movetype(this, MOVETYPE_TOSS);
                if (isnew) IL_PUSH(g_drawables, this);
                this.draw = ItemDraw;
                this.solid = SOLID_TRIGGER;
@@ -231,7 +256,6 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
                //this.angles = '0 0 0';
                set_movetype(this, MOVETYPE_TOSS);
                this.velocity = ReadVector();
-               setorigin(this, this.oldorigin);
 
                if(!this.move_time)
                {
@@ -242,15 +266,6 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
                        this.move_time = max(this.move_time, time);
        }
 
-       if(autocvar_cl_animate_items)
-       {
-               if(this.ItemStatus & ITS_ANIMATE1)
-                       this.avelocity = '0 180 0';
-
-               if(this.ItemStatus & ITS_ANIMATE2)
-                       this.avelocity = '0 -90 0';
-       }
-
        this.entremove = ItemRemove;
 
        return true;
index aa8122697e060deb455cabcaa6a44aa7bfa443ae..03ba02e37813e771e517c4bf4bda627864b63e07 100644 (file)
@@ -2,12 +2,10 @@
 
 const int AMMO_COUNT = 4; // amount of ammo types to show in the ammo panel
 
-.float onground_time;
-
+float  autocvar_cl_items_animate = 7;
 float  autocvar_cl_items_fadedist = 500;
 float  autocvar_cl_items_vehicle_alpha = 0.75;
 vector autocvar_cl_items_vehicle_color = '2 0.5 0.5';
-float  autocvar_cl_animate_items = 1;
 float  autocvar_cl_ghost_items = 0.45;
 vector autocvar_cl_ghost_items_color = '-1 -1 -1';
 vector autocvar_cl_weapon_stay_color = '2 0.5 0.5';
index 5cce2678371ab4eb31b8666751e5932902622743..691ab3a979a2c1299aca7d28da003c717d9c9569 100644 (file)
@@ -905,10 +905,10 @@ exec hud_luma.cfg
 // enable menu syncing - must be after files that call menu_sync on startup - see alias menu_sync ""
 alias menu_sync "menu_cmd sync"
 
+seta cl_items_animate 7 "1 enables bobbing and spinning of 3d items, 2 enables fading out of despawning loot items, 4 enables glowing particles for despawning loot items; add the numbers together to enable that combination."
 seta cl_items_fadedist 500 "distance, relative to the server's g_items_maxdist, at which far away items will start to fade out; 0 disables fading effect"
 seta cl_items_vehicle_alpha 0.75 "Alpha of items seen from inside a vehicle"
 seta cl_items_vehicle_color "2 0.5 0.5" "Colour of items seen from inside a vehicle"
-seta cl_animate_items 1
 seta cl_ghost_items 0.45 "enable ghosted items (when between 0 and 1, overrides the alpha value)"
 seta cl_ghost_items_color "-1 -1 -1" "color of ghosted items (colormod format: 0 0 0 leaves the color unchanged, negative values allowed)"
 seta cl_simple_items 0 "enable simple items (if server allows)"