]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/mutator_physical_items.qc
Fix another function full of gamemode specific blocks
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator_physical_items.qc
1
2 #include "mutator.qh"
3
4 .vector spawn_origin, spawn_angles;
5
6 void physical_item_think()
7 {SELFPARAM();
8         self.nextthink = time;
9
10         self.alpha = self.owner.alpha; // apply fading and ghosting
11
12         if(!self.cnt) // map item, not dropped
13         {
14                 // copy ghost item properties
15                 self.colormap = self.owner.colormap;
16                 self.colormod = self.owner.colormod;
17                 self.glowmod = self.owner.glowmod;
18
19                 // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
20                 if(autocvar_g_physical_items_reset)
21                 {
22                         if(self.owner.wait > time) // awaiting respawn
23                         {
24                                 setorigin(self, self.spawn_origin);
25                                 self.angles = self.spawn_angles;
26                                 self.solid = SOLID_NOT;
27                                 self.alpha = -1;
28                                 self.movetype = MOVETYPE_NONE;
29                         }
30                         else
31                         {
32                                 self.alpha = 1;
33                                 self.solid = SOLID_CORPSE;
34                                 self.movetype = MOVETYPE_PHYSICS;
35                         }
36                 }
37         }
38
39         if(!self.owner.modelindex)
40                 remove(self); // the real item is gone, remove this
41 }
42
43 void physical_item_touch()
44 {SELFPARAM();
45         if(!self.cnt) // not for dropped items
46         if (ITEM_TOUCH_NEEDKILL())
47         {
48                 setorigin(self, self.spawn_origin);
49                 self.angles = self.spawn_angles;
50         }
51 }
52
53 void physical_item_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
54 {SELFPARAM();
55         if(!self.cnt) // not for dropped items
56         if(ITEM_DAMAGE_NEEDKILL(deathtype))
57         {
58                 setorigin(self, self.spawn_origin);
59                 self.angles = self.spawn_angles;
60         }
61 }
62
63 MUTATOR_HOOKFUNCTION(item_spawning)
64 {SELFPARAM();
65         if(self.owner == world && autocvar_g_physical_items <= 1)
66                 return false;
67         if (self.spawnflags & 1) // floating item
68                 return false;
69
70         // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
71         // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
72         entity wep;
73         wep = spawn();
74         _setmodel(wep, self.model);
75         setsize(wep, self.mins, self.maxs);
76         setorigin(wep, self.origin);
77         wep.angles = self.angles;
78         wep.velocity = self.velocity;
79
80         wep.owner = self;
81         wep.solid = SOLID_CORPSE;
82         wep.movetype = MOVETYPE_PHYSICS;
83         wep.takedamage = DAMAGE_AIM;
84         wep.effects |= EF_NOMODELFLAGS; // disable the spinning
85         wep.colormap = self.owner.colormap;
86         wep.glowmod = self.owner.glowmod;
87         wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
88         wep.dphitcontentsmask = self.dphitcontentsmask;
89         wep.cnt = (self.owner != world);
90
91         wep.think = physical_item_think;
92         wep.nextthink = time;
93         wep.touch = physical_item_touch;
94         wep.event_damage = physical_item_damage;
95
96         if(!wep.cnt)
97         {
98                 // fix the spawn origin
99                 setorigin(wep, wep.origin + '0 0 1');
100                 entity oldself;
101                 oldself = self;
102                 WITH(entity, self, wep, builtin_droptofloor());
103         }
104
105         wep.spawn_origin = wep.origin;
106         wep.spawn_angles = self.angles;
107
108         self.effects |= EF_NODRAW; // hide the original weapon
109         self.movetype = MOVETYPE_FOLLOW;
110         self.aiment = wep; // attach the original weapon
111         self.SendEntity = func_null;
112
113         return false;
114 }
115
116 MUTATOR_DEFINITION(mutator_physical_items)
117 {
118         MUTATOR_HOOK(Item_Spawn, item_spawning, CBC_ORDER_ANY);
119
120         // check if we have a physics engine
121         MUTATOR_ONADD
122         {
123                 if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
124                 {
125                         LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
126                         return -1;
127                 }
128         }
129
130         MUTATOR_ONROLLBACK_OR_REMOVE
131         {
132                 // nothing to roll back
133         }
134
135         MUTATOR_ONREMOVE
136         {
137                 LOG_INFO("This cannot be removed at runtime\n");
138                 return -1;
139         }
140
141         return 0;
142 }