Implements a slow update rate for loot items, just enough to correct occasional prediction errors.
Includes SVQC prerequisites for loot item despawn effects
const int ITS_ALLOWFB = BIT(4);
const int ITS_ALLOWSI = BIT(5);
const int ITS_GLOW = BIT(6);
+const int ITS_EXPIRING = BIT(7);
+
+// enough to notice it's about to despawn and circle jump to grab it
+const float IT_DESPAWNFX_TIME = 1.5;
+
+// 2hz probably enough to correct a desync caused by serious lag
+const float IT_UPDATE_INTERVAL = 0.5;
.float fade_start;
.float fade_end;
void Item_Think(entity this)
{
- this.nextthink = time;
- if(this.origin != this.oldorigin)
+ if (Item_IsLoot(this))
+ {
+ if (time < this.wait - IT_DESPAWNFX_TIME)
+ this.nextthink = min(time + IT_UPDATE_INTERVAL, this.wait - IT_DESPAWNFX_TIME); // ensuring full time for effects
+ else
+ {
+ // despawning soon, start effects
+ this.ItemStatus |= ITS_EXPIRING;
+ this.SendFlags |= ISF_STATUS;
+ if (time < this.wait - IT_UPDATE_INTERVAL)
+ this.nextthink = time + IT_UPDATE_INTERVAL;
+ else
+ {
+ setthink(this, RemoveItem);
+ this.nextthink = this.wait;
+ }
+ }
+
+ // enable pickup by the player who threw it
+ this.owner = NULL;
+
+ // send slow updates even if the item didn't move
+ // recovers prediction desyncs where server thinks item stopped, client thinks it didn't
ItemUpdate(this);
+ }
+ else
+ {
+ // bones_was_here: TODO: predict movers, enable client prediction of items with a groundentity,
+ // and then send those less often too (and not all on the same frame)
+ this.nextthink = time;
+
+ if(this.origin != this.oldorigin)
+ ItemUpdate(this);
+ }
}
bool Item_ItemsTime_SpectatorOnly(GameItem it);
this.reset = RemoveItem;
set_movetype(this, MOVETYPE_TOSS);
- // Savage: remove thrown items after a certain period of time ("garbage collection")
- setthink(this, RemoveItem);
- this.nextthink = time + autocvar_g_items_dropped_lifetime;
+ setthink(this, Item_Think);
+ this.nextthink = time + IT_UPDATE_INTERVAL;
+ this.wait = time + autocvar_g_items_dropped_lifetime;
this.takedamage = DAMAGE_YES;
this.event_damage = Item_Damage;
#include <server/weapons/weaponsystem.qh>
#include <server/world.qh>
-void thrown_wep_think(entity this)
-{
- this.nextthink = time;
- if(this.oldorigin != this.origin)
- {
- this.SendFlags |= ISF_LOCATION;
- this.oldorigin = this.origin;
- }
- this.owner = NULL;
- float timeleft = this.savenextthink - time;
- if(timeleft > 1)
- SUB_SetFade(this, this.savenextthink - 1, 1);
- else if(timeleft > 0)
- SUB_SetFade(this, time, timeleft);
- else
- SUB_VanishOrRemove(this);
-}
-
// returns amount of ammo used, or -1 for failure, or 0 for no ammo count
float W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity)
{
weapon_defaultspawnfunc(wep, info);
if(startitem_failed)
return -1;
- setthink(wep, thrown_wep_think);
- wep.savenextthink = wep.nextthink;
- wep.nextthink = min(wep.nextthink, time + 0.5);
+
wep.pickup_anyway = true; // these are ALWAYS pickable
//wa = W_AmmoItemCode(wpn);
bool autocvar_g_weapon_throwable;
-.float savenextthink;
-void thrown_wep_think(entity this);
-
// returns amount of ammo used, or -1 for failure, or 0 for no ammo count
float W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity);