]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/server/func_breakable.qc
First part of the predator stomach board; Send the stomach load stat of the predator...
[voretournament/voretournament.git] / data / qcsrc / server / func_breakable.qc
1 .entity sprite;\r
2 \r
3 .float dmg;\r
4 .float dmg_edge;\r
5 .float dmg_radius;\r
6 .float dmg_force;\r
7 .float debrismovetype;\r
8 .float debrissolid;\r
9 .vector debrisvelocity;\r
10 .vector debrisvelocityjitter;\r
11 .vector debrisavelocityjitter;\r
12 .float debristime;\r
13 .float debristimejitter;\r
14 .float debrisfadetime;\r
15 .float debrisdamageforcescale;\r
16 .float debrisskin;\r
17 \r
18 .string mdl_dead; // or "" to hide when broken\r
19 .string debris; // space separated list of debris models\r
20 // other fields:\r
21 //   mdl = particle effect name\r
22 //   count = particle effect multiplier\r
23 //   targetname = target to trigger to unbreak the model\r
24 //   target = targets to trigger when broken\r
25 //   health = amount of damage it can take\r
26 //   spawnflags:\r
27 //     1 = start disabled (needs to be triggered to activate)\r
28 //     2 = indicate damage\r
29 // notes:\r
30 //   for mdl_dead to work, origin must be set (using a common/origin brush).\r
31 //   Otherwise mdl_dead will be displayed at the map origin, and nobody would\r
32 //   want that!\r
33 \r
34 .vector mins_save, maxs_save;\r
35 \r
36 void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);\r
37 \r
38 //\r
39 // func_breakable\r
40 // - basically func_assault_destructible for general gameplay use\r
41 //\r
42 void LaunchDebris (string debrisname, vector force) =\r
43 {\r
44         local   entity dbr;\r
45 \r
46         dbr = spawn();\r
47         setorigin(dbr, self.absmin\r
48                    + '1 0 0' * random() * (self.absmax_x - self.absmin_x)\r
49                    + '0 1 0' * random() * (self.absmax_y - self.absmin_y)\r
50                    + '0 0 1' * random() * (self.absmax_z - self.absmin_z));\r
51         setmodel (dbr, debrisname );\r
52         dbr.skin = self.debrisskin;\r
53         dbr.colormap = self.colormap; // inherit team colors\r
54         dbr.owner = self; // do not be affected by our own explosion\r
55         dbr.movetype = self.debrismovetype;\r
56         dbr.solid = self.debrissolid;\r
57         if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out\r
58                 setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it\r
59         dbr.velocity_x = self.debrisvelocity_x + self.debrisvelocityjitter_x * crandom();\r
60         dbr.velocity_y = self.debrisvelocity_y + self.debrisvelocityjitter_y * crandom();\r
61         dbr.velocity_z = self.debrisvelocity_z + self.debrisvelocityjitter_z * crandom();\r
62         self.velocity = self.velocity + force * self.debrisdamageforcescale;\r
63         dbr.avelocity_x = random()*self.debrisavelocityjitter_x;\r
64         dbr.avelocity_y = random()*self.debrisavelocityjitter_y;\r
65         dbr.avelocity_z = random()*self.debrisavelocityjitter_z;\r
66         dbr.damageforcescale = self.debrisdamageforcescale;\r
67         if(dbr.damageforcescale)\r
68                 dbr.takedamage = DAMAGE_YES;\r
69         SUB_SetFade(dbr, time + self.debristime + crandom() * self.debristimejitter, self.debrisfadetime);\r
70 };\r
71 \r
72 void func_breakable_colormod()\r
73 {\r
74         float h;\r
75         if not(self.spawnflags & 2)\r
76                 return;\r
77         h = self.health / self.max_health;\r
78         if(h < 0.25)\r
79                 self.colormod = '1 0 0';\r
80         else if(h <= 0.75)\r
81                 self.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);\r
82         else\r
83                 self.colormod = '1 1 1';\r
84 }\r
85 \r
86 void func_breakable_look_destroyed()\r
87 {\r
88         local float floor_z;\r
89 \r
90         if(self.mdl_dead == "")\r
91                 self.model = "";\r
92         else {\r
93                 setmodel(self, self.mdl_dead);\r
94                 if (self.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..\r
95                         floor_z = self.absmin_z;\r
96                         setorigin(self,((self.absmax+self.absmin)*.5));\r
97                         self.origin_z = floor_z;\r
98                 }\r
99         }\r
100 \r
101         self.solid = SOLID_NOT;\r
102 }\r
103 \r
104 void func_breakable_look_restore()\r
105 {\r
106         setmodel(self, self.mdl);\r
107         self.solid = SOLID_BSP;\r
108 }\r
109 \r
110 void func_breakable_behave_destroyed()\r
111 {\r
112         self.health = self.max_health;\r
113         self.takedamage = DAMAGE_NO;\r
114         self.event_damage = SUB_Null;\r
115         self.state = 1;\r
116         setsize(self, '0 0 0', '0 0 0');\r
117         func_breakable_colormod();\r
118 }\r
119 \r
120 void func_breakable_behave_restore()\r
121 {\r
122         self.health = self.max_health;\r
123         self.takedamage = DAMAGE_AIM;\r
124         self.event_damage = func_breakable_damage;\r
125         self.state = 0;\r
126         setsize(self, self.mins_save, self.maxs_save);\r
127         func_breakable_colormod();\r
128 }\r
129 \r
130 void func_breakable_destroyed()\r
131 {\r
132         func_breakable_look_destroyed();\r
133         func_breakable_behave_destroyed();\r
134 }\r
135 \r
136 void func_breakable_restore()\r
137 {\r
138         func_breakable_look_restore();\r
139         func_breakable_behave_restore();\r
140 }\r
141 \r
142 vector debrisforce; // global, set before calling this\r
143 void func_breakable_destroy() {\r
144         float n, i;\r
145         string oldmsg;\r
146 \r
147         activator = self.owner;\r
148 \r
149         // now throw around the debris\r
150         n = tokenize_console(self.debris);\r
151         for(i = 0; i < n; ++i)\r
152                 LaunchDebris(argv(i), debrisforce);\r
153 \r
154         func_breakable_destroyed();\r
155 \r
156         if(self.noise)\r
157                 sound (self, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);\r
158 \r
159         if(self.dmg)\r
160                 RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, self.dmg_force, DEATH_HURTTRIGGER, world);\r
161 \r
162         if(self.cnt)\r
163                 pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);\r
164 \r
165         oldmsg = self.message;\r
166         self.message = "";\r
167         SUB_UseTargets();\r
168         self.message = oldmsg;\r
169 }\r
170 \r
171 void func_breakable_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
172 {\r
173         if(self.state == 1)\r
174                 return;\r
175         if(self.spawnflags & DOOR_NOSPLASH)\r
176                 if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))\r
177                         return;\r
178         if(self.team)\r
179                 if(attacker.team == self.team)\r
180                         return;\r
181         if(self.sprite)\r
182                 WaypointSprite_Ping(self.sprite);\r
183         self.health = self.health - damage;\r
184         func_breakable_colormod();\r
185 \r
186         if(self.health <= 0)\r
187         {\r
188                 debrisforce = force;\r
189                 W_PrepareExplosionByDamage(attacker, func_breakable_destroy);\r
190         }\r
191 }\r
192 \r
193 void func_breakable_reset()\r
194 {\r
195         self.team = self.team_saved;\r
196         func_breakable_look_restore();\r
197         if(self.spawnflags & 1)\r
198                 func_breakable_behave_destroyed();\r
199         else\r
200                 func_breakable_behave_restore();\r
201 }\r
202 \r
203 // destructible walls that can be used to trigger target_objective_decrease\r
204 void spawnfunc_func_breakable() {\r
205         float n, i;\r
206         if(!self.health)\r
207                 self.health = 100;\r
208         self.max_health = self.health;\r
209 \r
210         // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway\r
211         if(!self.debrismovetype) self.debrismovetype = MOVETYPE_BOUNCE;\r
212         if(!self.debrissolid) self.debrissolid = SOLID_NOT;\r
213         if(self.debrisvelocity == '0 0 0') self.debrisvelocity = '0 0 140';\r
214         if(self.debrisvelocityjitter == '0 0 0') self.debrisvelocityjitter = '70 70 70';\r
215         if(self.debrisavelocityjitter == '0 0 0') self.debrisavelocityjitter = '600 600 600';\r
216         if(!self.debristime) self.debristime = 3.5;\r
217         if(!self.debristimejitter) self.debristime = 2.5;\r
218 \r
219         if(self.mdl != "")\r
220                 self.cnt = particleeffectnum(self.mdl);\r
221         if(self.count == 0)\r
222                 self.count = 1;\r
223 \r
224         if(!self.message)\r
225                 self.message = "got too close to an explosion";\r
226         if(!self.message2)\r
227                 self.message2 = "was pushed into an explosion by";\r
228         if(!self.dmg_radius)\r
229                 self.dmg_radius = 150;\r
230         if(!self.dmg_force)\r
231                 self.dmg_force = 200;\r
232 \r
233         self.mdl = self.model;\r
234         SetBrushEntityModel();\r
235         self.mins_save = self.mins;\r
236         self.maxs_save = self.maxs;\r
237 \r
238         self.use = func_breakable_restore;\r
239 \r
240         // precache all the models\r
241         if (self.mdl_dead)\r
242                 precache_model(self.mdl_dead);\r
243         n = tokenize_console(self.debris);\r
244         for(i = 0; i < n; ++i)\r
245                 precache_model(argv(i));\r
246         if(self.noise)\r
247                 precache_sound(self.noise);\r
248 \r
249         self.team_saved = self.team;\r
250 \r
251         self.reset = func_breakable_reset;\r
252         func_breakable_reset();\r
253 }\r