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