else
sf &= ~ISF_DROP;
+ // if this item is being spawned (in CSQC's perspective)
+ // reuse ISF_SIZE and ISF_SIZE2 to also tell CSQC its bbox size
+ if(sf & ISF_SIZE)
+ {
+ if(this.maxs == ITEM_S_MAXS) // Small
+ {
+ sf |= ISF_SIZE;
+ sf &= ~ISF_SIZE2;
+ }
+ else if(this.maxs == ITEM_L_MAXS) // Large
+ {
+ sf &= ~ISF_SIZE;
+ sf |= ISF_SIZE2;
+ }
+ else // Default
+ sf |= ISF_SIZE | ISF_SIZE2;
+ }
+
WriteHeader(MSG_ENTITY, ENT_CLIENT_ITEM);
WriteByte(MSG_ENTITY, sf);
WriteAngleVector(MSG_ENTITY, this.angles);
}
- // sets size on the client, unused on server
- //if(sf & ISF_SIZE)
-
if(sf & ISF_STATUS)
WriteByte(MSG_ENTITY, this.ItemStatus);
- if(sf & ISF_MODEL)
+ if(sf & ISF_SIZE || sf & ISF_SIZE2) // always true when it's spawned (in CSQC's perspective)
{
WriteShort(MSG_ENTITY, bound(0, this.fade_end, 32767));
if (this.itemdef.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
return false;
- if(this.itemdef.instanceOfPowerup)
- {
- if(autocvar_g_powerups > 0)
- return true;
- if(autocvar_g_powerups == 0)
- return false;
- }
- else
+ if(!this.itemdef.instanceOfPowerup)
{
if(autocvar_g_pickup_items > 0)
return true;
Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ITEM_JETPACK_GOT);
}
- int its;
- if((its = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
+ int its = (item.items - (item.items & player.items)) & IT_PICKUPMASK;
+ if (its)
{
pickedup = true;
player.items |= its;
{
if (ITEM_TOUCH_NEEDKILL())
{
+ this.SendFlags |= ISF_REMOVEFX;
RemoveItem(this);
return;
}
if (ITEM_IS_LOOT(this))
{
- delete(this);
+ this.SendFlags |= ISF_REMOVEFX;
+ RemoveItem(this);
return;
}
if (!this.spawnshieldtime)
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
this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
}
+ // most loot items have a bigger horizontal size than a player
+ nudgeoutofsolid(this);
+
// don't drop if in a NODROP zone (such as lava)
traceline(this.origin, this.origin, MOVE_NORMAL, this);
if (trace_dpstartcontents & DPCONTENTS_NODROP)
if(this.angles != '0 0 0')
this.SendFlags |= ISF_ANGLES;
- if(q3compat && !this.team)
+ if(q3compat)
{
- string t = GetField_fullspawndata(this, "team");
- // bones_was_here: this hack is cheaper than changing to a .string strcmp()
- if(t) this.team = crc16(false, t);
+ if (!this.team)
+ {
+ string t = GetField_fullspawndata(this, "team");
+ // bones_was_here: this hack is cheaper than changing to a .string strcmp()
+ if(t) this.team = crc16(false, t);
+ }
+
+ // In Q3 the origin is in the middle of the bbox ("radius" 15), in Xon it's at the bottom
+ // so we need to offset vertically (only for items placed by the mapper).
+ this.origin.z += -15 - this.mins.z;
+ setorigin(this, this.origin);
}
// it's a level item
// do item filtering according to game mode and other things
if (this.noalign <= 0)
{
- // first nudge it off the floor a little bit to avoid math errors
- setorigin(this, this.origin + '0 0 1');
// note droptofloor returns false if stuck/or would fall too far
if (!this.noalign)
droptofloor(this);