void Item_Think(entity this)
{
- if (Item_IsLoot(this))
+ if (ITEM_IS_LOOT(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
}
}
- // enable pickup by the player who threw it
- this.owner = NULL;
+ if (this.itemdef.instanceOfPowerup)
+ powerups_DropItem_Think(this);
+
+ // caution: kludge FIXME (with sv_legacy_bbox_expand)
+ // this works around prediction errors caused by bbox discrepancy between SVQC and CSQC
+ if (this.velocity == '0 0 0' && IS_ONGROUND(this))
+ this.gravity = 0; // don't send ISF_DROP anymore
// send slow updates even if the item didn't move
// recovers prediction desyncs where server thinks item stopped, client thinks it didn't
void Item_Touch(entity this, entity toucher)
{
// remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
- if (Item_IsLoot(this))
+ if (ITEM_IS_LOOT(this))
{
if (ITEM_TOUCH_NEEDKILL())
{
+ this.SendFlags |= ISF_REMOVEFX;
RemoveItem(this);
return;
}
toucher = M_ARGV(1, entity);
- if (Item_IsExpiring(this))
+ if (ITEM_IS_EXPIRING(this))
{
this.strength_finished = max(0, this.strength_finished - time);
this.invincible_finished = max(0, this.invincible_finished - time);
bool gave = ITEM_HANDLE(Pickup, this.itemdef, this, toucher);
if (!gave)
{
- if (Item_IsExpiring(this))
+ if (ITEM_IS_EXPIRING(this))
{
// undo what we did above
this.strength_finished += time;
return;
}
- if (Item_IsLoot(this))
+ if (ITEM_IS_LOOT(this))
{
- delete(this);
+ this.SendFlags |= ISF_REMOVEFX;
+ RemoveItem(this);
return;
}
if (!this.spawnshieldtime)
{
Item_Show(this, !this.state);
- if (Item_IsLoot(this))
+ if (ITEM_IS_LOOT(this))
{
return;
}
{
setorigin(to, this.origin);
to.spawnflags = this.spawnflags;
- to.noalign = Item_ShouldKeepPosition(this);
+ to.noalign = ITEM_SHOULD_KEEP_POSITION(this);
to.cnt = this.cnt;
to.team = this.team;
to.spawnfunc_checked = true;
if(wasfreed(this) || !this) { return; }
if(this.waypointsprite_attached)
WaypointSprite_Kill(this.waypointsprite_attached);
- delete(this);
+
+ if (this.SendFlags & ISF_REMOVEFX)
+ {
+ // delay removal until ISF_REMOVEFX has been sent
+ setthink(this, RemoveItem);
+ this.nextthink = time + 2 * autocvar_sys_ticrate; // micro optimisation: next frame will be too soon
+ this.solid = SOLID_NOT; // untouchable
+ }
+ else
+ delete(this);
}
// pickup evaluation functions
// set item size before we spawn a waypoint or droptofloor or MoveOutOfSolid
setsize (this, this.pos1 = def.m_mins, this.pos2 = def.m_maxs);
- if (Item_IsLoot(this))
+ if (ITEM_IS_LOOT(this))
{
this.reset = RemoveItem;
this.nextthink = time + IT_UPDATE_INTERVAL;
this.wait = time + autocvar_g_items_dropped_lifetime;
+ this.owner = NULL; // anyone can pick this up, including the player who threw it
+ this.item_spawnshieldtime = time + 0.5; // but not straight away
+
this.takedamage = DAMAGE_YES;
this.event_damage = Item_Damage;
// enable this to have thrown items burn in lava
//this.damagedbycontents = true;
//IL_PUSH(g_damagedbycontents, this);
- if (Item_IsExpiring(this))
+ if (ITEM_IS_EXPIRING(this))
{
// if item is worthless after a timer, have it expire then
this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
}
else
{
+ this.reset = Item_Reset;
+
// must be done after def.m_iteminit() as that may set ITEM_FLAG_MUTATORBLOCKED
if(!have_pickup_item(this))
{
if(def.instanceOfWeaponPickup)
{
- if (!Item_IsLoot(this)) // if dropped, colormap is already set up nicely
+ if (!ITEM_IS_LOOT(this)) // if dropped, colormap is already set up nicely
this.colormap = 1024; // color shirt=0 pants=0 grey
if (!(this.spawnflags & 1024))
this.ItemStatus |= ITS_ANIMATE1;
this.reset = Item_FindTeam;
}
else
- {
- this.reset = Item_Reset;
Item_Reset(this);
- }
Net_LinkEntity(this, !(def.instanceOfPowerup || def.instanceOfHealth || def.instanceOfArmor), 0, ItemSend);
void setItemGroup(entity this)
{
- if(!IS_SMALL(this.itemdef) || Item_IsLoot(this))
+ if(!IS_SMALL(this.itemdef) || ITEM_IS_LOOT(this))
return;
FOREACH_ENTITY_RADIUS(this.origin, 120, (it != this) && IS_SMALL(it.itemdef),
void target_items_use(entity this, entity actor, entity trigger)
{
- if(Item_IsLoot(actor))
+ if(ITEM_IS_LOOT(actor))
{
EXACTTRIGGER_TOUCH(this, trigger);
delete(actor);
EXACTTRIGGER_TOUCH(this, trigger);
}
- IL_EACH(g_items, it.enemy == actor && Item_IsLoot(it),
+ IL_EACH(g_items, it.enemy == actor && ITEM_IS_LOOT(it),
{
delete(it);
});