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