]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qc
Merge branch 'master' into terencehill/hud_updates
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / physical_items / sv_physical_items.qc
1 #include "sv_physical_items.qh"
2
3 int autocvar_g_physical_items;
4 float autocvar_g_physical_items_damageforcescale;
5 float autocvar_g_physical_items_reset;
6
7 REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
8 {
9         // check if we have a physics engine
10         MUTATOR_ONADD
11         {
12                 if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
13                 {
14                         LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.");
15                         return -1;
16                 }
17         }
18
19         MUTATOR_ONROLLBACK_OR_REMOVE
20         {
21                 // nothing to roll back
22         }
23
24         MUTATOR_ONREMOVE
25         {
26                 LOG_INFO("This cannot be removed at runtime\n");
27                 return -1;
28         }
29
30         return 0;
31 }
32
33 .vector spawn_origin, spawn_angles;
34
35 void physical_item_think(entity this)
36 {
37         this.nextthink = time;
38
39         this.alpha = this.owner.alpha; // apply fading and ghosting
40
41         if(!this.cnt) // map item, not dropped
42         {
43                 // copy ghost item properties
44                 this.colormap = this.owner.colormap;
45                 this.colormod = this.owner.colormod;
46                 this.glowmod = this.owner.glowmod;
47
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)
50                 {
51                         if(this.owner.wait > time) // awaiting respawn
52                         {
53                                 setorigin(this, this.spawn_origin);
54                                 this.angles = this.spawn_angles;
55                                 this.solid = SOLID_NOT;
56                                 this.alpha = -1;
57                                 set_movetype(this, MOVETYPE_NONE);
58                         }
59                         else
60                         {
61                                 this.alpha = 1;
62                                 this.solid = SOLID_CORPSE;
63                                 set_movetype(this, MOVETYPE_PHYSICS);
64                         }
65                 }
66         }
67
68         if(!this.owner.modelindex)
69                 delete(this); // the real item is gone, remove this
70 }
71
72 void physical_item_touch(entity this, entity toucher)
73 {
74         if(!this.cnt) // not for dropped items
75         if (ITEM_TOUCH_NEEDKILL())
76         {
77                 setorigin(this, this.spawn_origin);
78                 this.angles = this.spawn_angles;
79         }
80 }
81
82 void physical_item_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
83 {
84         if(!this.cnt) // not for dropped items
85         if(ITEM_DAMAGE_NEEDKILL(deathtype))
86         {
87                 setorigin(this, this.spawn_origin);
88                 this.angles = this.spawn_angles;
89         }
90 }
91
92 MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
93 {
94         entity item = M_ARGV(0, entity);
95
96         if(item.owner == NULL && autocvar_g_physical_items <= 1)
97                 return;
98         if (item.spawnflags & 1) // floating item
99                 return;
100
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;
104         wep = spawn();
105         _setmodel(wep, item.model);
106         setsize(wep, item.mins, item.maxs);
107         setorigin(wep, item.origin);
108         wep.angles = item.angles;
109         wep.velocity = item.velocity;
110
111         wep.owner = item;
112         wep.solid = SOLID_CORPSE;
113         set_movetype(wep, MOVETYPE_PHYSICS);
114         wep.takedamage = DAMAGE_AIM;
115         wep.effects |= EF_NOMODELFLAGS; // disable the spinning
116         wep.colormap = item.owner.colormap;
117         wep.glowmod = item.owner.glowmod;
118         wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
119         wep.dphitcontentsmask = item.dphitcontentsmask;
120         wep.cnt = (item.owner != NULL);
121
122         setthink(wep, physical_item_think);
123         wep.nextthink = time;
124         settouch(wep, physical_item_touch);
125         wep.event_damage = physical_item_damage;
126
127         if(!wep.cnt)
128         {
129                 // fix the spawn origin
130                 setorigin(wep, wep.origin + '0 0 1');
131                 droptofloor(wep);
132         }
133
134         wep.spawn_origin = wep.origin;
135         wep.spawn_angles = item.angles;
136
137         item.effects |= EF_NODRAW; // hide the original weapon
138         set_movetype(item, MOVETYPE_FOLLOW);
139         item.aiment = wep; // attach the original weapon
140         setSendEntity(item, func_null);
141 }