2 int autocvar_g_physical_items;
3 float autocvar_g_physical_items_damageforcescale;
4 float autocvar_g_physical_items_reset;
6 REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
8 // check if we have a physics engine
11 if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
13 LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
18 MUTATOR_ONROLLBACK_OR_REMOVE
20 // nothing to roll back
25 LOG_INFO("This cannot be removed at runtime\n");
32 .vector spawn_origin, spawn_angles;
34 void physical_item_think(entity this)
36 self.nextthink = time;
38 self.alpha = self.owner.alpha; // apply fading and ghosting
40 if(!self.cnt) // map item, not dropped
42 // copy ghost item properties
43 self.colormap = self.owner.colormap;
44 self.colormod = self.owner.colormod;
45 self.glowmod = self.owner.glowmod;
47 // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
48 if(autocvar_g_physical_items_reset)
50 if(self.owner.wait > time) // awaiting respawn
52 setorigin(self, self.spawn_origin);
53 self.angles = self.spawn_angles;
54 self.solid = SOLID_NOT;
56 self.movetype = MOVETYPE_NONE;
61 self.solid = SOLID_CORPSE;
62 self.movetype = MOVETYPE_PHYSICS;
67 if(!self.owner.modelindex)
68 remove(self); // the real item is gone, remove this
71 void physical_item_touch(entity this)
73 if(!self.cnt) // not for dropped items
74 if (ITEM_TOUCH_NEEDKILL())
76 setorigin(self, self.spawn_origin);
77 self.angles = self.spawn_angles;
81 void physical_item_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
83 if(!this.cnt) // not for dropped items
84 if(ITEM_DAMAGE_NEEDKILL(deathtype))
86 setorigin(this, this.spawn_origin);
87 this.angles = this.spawn_angles;
91 MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
93 if(self.owner == world && autocvar_g_physical_items <= 1)
95 if (self.spawnflags & 1) // floating item
98 // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
99 // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
102 _setmodel(wep, self.model);
103 setsize(wep, self.mins, self.maxs);
104 setorigin(wep, self.origin);
105 wep.angles = self.angles;
106 wep.velocity = self.velocity;
109 wep.solid = SOLID_CORPSE;
110 wep.movetype = MOVETYPE_PHYSICS;
111 wep.takedamage = DAMAGE_AIM;
112 wep.effects |= EF_NOMODELFLAGS; // disable the spinning
113 wep.colormap = self.owner.colormap;
114 wep.glowmod = self.owner.glowmod;
115 wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
116 wep.dphitcontentsmask = self.dphitcontentsmask;
117 wep.cnt = (self.owner != world);
119 setthink(wep, physical_item_think);
120 wep.nextthink = time;
121 settouch(wep, physical_item_touch);
122 wep.event_damage = physical_item_damage;
126 // fix the spawn origin
127 setorigin(wep, wep.origin + '0 0 1');
130 WITHSELF(wep, builtin_droptofloor());
133 wep.spawn_origin = wep.origin;
134 wep.spawn_angles = self.angles;
136 self.effects |= EF_NODRAW; // hide the original weapon
137 self.movetype = MOVETYPE_FOLLOW;
138 self.aiment = wep; // attach the original weapon
139 self.SendEntity3 = func_null;