1 #include "sv_physical_items.qh"
3 int autocvar_g_physical_items;
4 float autocvar_g_physical_items_damageforcescale;
5 float autocvar_g_physical_items_reset;
7 REGISTER_MUTATOR(physical_items, autocvar_g_physical_items)
9 // check if we have a physics engine
12 if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
14 LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.");
19 MUTATOR_ONROLLBACK_OR_REMOVE
21 // nothing to roll back
26 LOG_INFO("This cannot be removed at runtime");
33 .vector spawn_origin, spawn_angles;
35 void physical_item_think(entity this)
37 this.nextthink = time;
39 this.alpha = this.owner.alpha; // apply fading and ghosting
41 if(!this.cnt) // map item, not dropped
43 // copy ghost item properties
44 this.colormap = this.owner.colormap;
45 this.colormod = this.owner.colormod;
46 this.glowmod = this.owner.glowmod;
48 // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
49 if(autocvar_g_physical_items_reset)
51 if(this.owner.wait > time) // awaiting respawn
53 setorigin(this, this.spawn_origin);
54 this.angles = this.spawn_angles;
55 this.solid = SOLID_NOT;
57 set_movetype(this, MOVETYPE_NONE);
62 this.solid = SOLID_CORPSE;
63 set_movetype(this, MOVETYPE_PHYSICS);
68 if(!this.owner.modelindex)
69 delete(this); // the real item is gone, remove this
72 void physical_item_touch(entity this, entity toucher)
74 if(!this.cnt) // not for dropped items
75 if (ITEM_TOUCH_NEEDKILL())
77 setorigin(this, this.spawn_origin);
78 this.angles = this.spawn_angles;
82 void physical_item_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
84 if(!this.cnt) // not for dropped items
85 if(ITEM_DAMAGE_NEEDKILL(deathtype))
87 setorigin(this, this.spawn_origin);
88 this.angles = this.spawn_angles;
92 MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
94 entity item = M_ARGV(0, entity);
96 if(item.owner == NULL && autocvar_g_physical_items <= 1)
98 if (item.spawnflags & 1) // floating item
101 // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
102 // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
103 entity wep = spawn();
104 _setmodel(wep, item.model);
105 setsize(wep, item.mins, item.maxs);
106 setorigin(wep, item.origin);
107 wep.angles = item.angles;
108 wep.velocity = item.velocity;
111 wep.solid = SOLID_CORPSE;
112 set_movetype(wep, MOVETYPE_PHYSICS);
113 wep.takedamage = DAMAGE_AIM;
114 wep.effects |= EF_NOMODELFLAGS; // disable the spinning
115 wep.colormap = item.owner.colormap;
116 wep.glowmod = item.owner.glowmod;
117 wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
118 wep.dphitcontentsmask = item.dphitcontentsmask;
119 wep.cnt = (item.owner != NULL);
121 setthink(wep, physical_item_think);
122 wep.nextthink = time;
123 settouch(wep, physical_item_touch);
124 wep.event_damage = physical_item_damage;
128 // fix the spawn origin
129 setorigin(wep, wep.origin + '0 0 1');
133 wep.spawn_origin = wep.origin;
134 wep.spawn_angles = item.angles;
136 item.effects |= EF_NODRAW; // hide the original weapon
137 set_movetype(item, MOVETYPE_FOLLOW);
138 item.aiment = wep; // attach the original weapon
139 setSendEntity(item, func_null);