]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/server/vore.qc
Finalize the effect. Not really what I wanted but it's good for now
[voretournament/voretournament.git] / data / qcsrc / server / vore.qc
1 .float regurgitate_prepare;\r
2 .float system_delay, swallow_delay, digest_button_delay, regurgitate_button_delay;\r
3 .float complain_swallow;\r
4 const float complain_delay = 1;\r
5 const float button_delay = 0.5;\r
6 const float steptime = 0.1;\r
7 const float system_delay_time = 0.1;\r
8 \r
9 .float vore_oldmovetype, vore_oldsolid, vore_oldstomachload, vore_oldview_ofs_z;\r
10 \r
11 entity Swallow_distance_check()\r
12 {\r
13         // check if we can swallow a player instead of firing our weapon\r
14         vector w_shotorg, w_shotdir;\r
15         w_shotorg = self.origin + self.view_ofs;\r
16         w_shotdir = v_forward;\r
17 \r
18         WarpZone_traceline_antilag(self, w_shotorg, w_shotorg + w_shotdir * cvar("g_balance_vore_swallow_range"), FALSE, self, ANTILAG_LATENCY(self));\r
19         if(trace_fraction < 1)\r
20         if(trace_ent.classname == "player")\r
21                 return trace_ent;\r
22         return world;\r
23 }\r
24 \r
25 float Swallow_condition_check(entity prey)\r
26 {\r
27         // checks the necessary conditions for swallowing another player\r
28         if(prey.classname == "player" && prey.eater.classname != "player" && prey.deadflag == DEAD_NO) // we can't swallow someone who's already in someone else's stomach\r
29         if(self.classname == "player" && self.eater.classname != "player" && self.deadflag == DEAD_NO) // we can't swallow players while inside someone's stomach ourselves\r
30         if not(vlen(self.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit"))\r
31         {\r
32                 if(self.stomach_load >= cvar("g_balance_vore_swallow_limit"))\r
33                 {\r
34                         if(time > self.complain_swallow)\r
35                         {\r
36                                 play2(self, "weapons/unavailable.wav");\r
37                                 sprint(self, strcat("You cannot swallow more than ^2", cvar_string("g_balance_vore_swallow_limit"), "^7 players at a time\n"));\r
38                                 self.complain_swallow = time + complain_delay;\r
39                         }\r
40                         return FALSE;\r
41                 }\r
42 \r
43                 if(cvar("g_vore_biggergut"))\r
44                 if(prey.stomach_load > self.stomach_load)\r
45                 {\r
46                         if(time > self.complain_swallow)\r
47                         {\r
48                                 play2(self, "weapons/unavailable.wav");\r
49                                 sprint(self, "You cannot swallow someone with a bigger stomach than yours\n");\r
50                                 self.complain_swallow = time + complain_delay;\r
51                         }\r
52                         return FALSE;\r
53                 }\r
54                 return TRUE;\r
55         }\r
56         return FALSE;\r
57 }\r
58 \r
59 // make the camera smoothly lower itself when we get swallowed\r
60 // the target we are going for is from normal view offset to half of the view offset (because half is the best positioning of the view for the stomach model)\r
61 .float cameraeffect_current, cameraeffect_target;\r
62 void Vore_CameraEffect_Set(entity e)\r
63 {\r
64         e.cameraeffect_current = 1;\r
65         e.cameraeffect_target = 2;\r
66 }\r
67 void Vore_CameraEffect_Apply()\r
68 {\r
69         if(self.eater.classname != "player")\r
70                 return;\r
71 \r
72         if(self.cvar_cl_vore_cameraspeed)\r
73         {\r
74                 local float step;\r
75                 step = self.cvar_cl_vore_cameraspeed * frametime;\r
76 \r
77                 if(self.cameraeffect_current >= self.cameraeffect_target + step)\r
78                         self.cameraeffect_current -= step;\r
79                 else if(self.cameraeffect_current <= self.cameraeffect_target - step)\r
80                         self.cameraeffect_current += step;\r
81         }\r
82         else\r
83                 self.cameraeffect_current = self.cameraeffect_target;\r
84 \r
85         self.view_ofs_z = self.vore_oldview_ofs_z / self.cameraeffect_current;\r
86 }\r
87 \r
88 void Vore_Weight_apply(entity e)\r
89 {\r
90         // apply stomach weight that makes you heavier the more you eat\r
91         // slowing the player is applied in cl_physics.qc\r
92         if(e.stomach_load != e.vore_oldstomachload)\r
93                 e.gravity += 1 + (e.stomach_load * cvar("g_balance_vore_weight_gravity") - e.vore_oldstomachload);\r
94         if(e.gravity == 0)\r
95                 e.gravity = 0.00001; // 0 becomes 1 for .gravity, so do this to allow 0 gravity\r
96         e.vore_oldstomachload = e.stomach_load;\r
97 }\r
98 \r
99 void Vore_Swallow(entity e)\r
100 {\r
101         // this player is beening swallowed by another player, apply the proper changes\r
102         e.vore_oldmovetype = e.movetype;\r
103         e.vore_oldsolid = e.solid;\r
104         e.vore_oldview_ofs_z = e.view_ofs_z;\r
105 \r
106         setorigin(e, e.eater.origin);\r
107         e.velocity = '0 0 0';\r
108         e.movetype = MOVETYPE_FOLLOW;\r
109         e.solid = SOLID_NOT;\r
110         e.alpha = -1; // best way of hiding / showing the eaten player\r
111         e.aiment = e.eater; // follow the predator. Is automatically unset\r
112 \r
113         /*e.cameraeffect_current = e.view_ofs_z * 2;\r
114         e.cameraeffect_target = e.view_ofs_z / 2; // best positioning for the stomach model*/\r
115 \r
116         Vore_CameraEffect_Set(e);\r
117 \r
118         // drop keys (KH) and flags (CTF) when we get swallowed\r
119         kh_Key_DropAll(e, FALSE);\r
120         if(e.flagcarried)\r
121                 DropFlag(e.flagcarried, world, e.eater);\r
122 \r
123         if(stov(cvar_string("g_vore_regurgitatecolor_released")))\r
124                 e.colormod = stov(cvar_string("g_vore_regurgitatecolor_released"));\r
125 \r
126         PlayerSound(e.eater, playersound_swallow, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
127         setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing \ regurgitating\r
128         e.eater.stomach_load += 1;\r
129         e.eater.regurgitate_prepare = 0;\r
130         Vore_Weight_apply(e.eater);\r
131 \r
132         e.system_delay = e.eater.system_delay = time + system_delay_time;\r
133 }\r
134 \r
135 void Vore_Regurgitate(entity e)\r
136 {\r
137         // this player is being released from their predator, apply the proper changes\r
138         e.movetype = e.vore_oldmovetype;\r
139         if(e.health > 0) // leave SOLID_NOT for dead bodies\r
140                 e.solid = e.vore_oldsolid;\r
141         e.view_ofs_z = e.vore_oldview_ofs_z;\r
142         e.alpha = default_player_alpha; // best way of hiding / showing the eaten player\r
143 \r
144         //e.view_ofs_z *= 2; // best positioning for the stomach model\r
145 \r
146         // velocities\r
147         local vector oldforward, oldright, oldup;\r
148         oldforward = v_forward;\r
149         oldright = v_right;\r
150         oldup = v_up;\r
151         makevectors(e.eater.v_angle);\r
152         e.velocity = v_forward * cvar("g_balance_vore_regurgitate_force");\r
153         e.eater.velocity += -v_forward * cvar("g_balance_vore_regurgitate_eaterforce");\r
154         v_forward = oldforward;\r
155         v_right = oldright;\r
156         v_up = oldup;\r
157 \r
158         PlayerSound(e.eater, playersound_regurgitate, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
159         setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing \ regurgitating\r
160         pointparticles(particleeffectnum("regurgitate"), e.eater.origin, '0 0 0', 1);\r
161         e.eater.stomach_load -= 1;\r
162         e.eater.regurgitate_prepare = 0;\r
163         e.eater.swallow_delay = time + cvar("g_balance_vore_swallow_delay");\r
164         Vore_Weight_apply(e.eater);\r
165 \r
166         e.system_delay = e.eater.system_delay = time + system_delay_time;\r
167         e.eater = world;\r
168 }\r
169 \r
170 void Vore_Gurglesound();\r
171 void Vore_Disconnect()\r
172 {\r
173         // frees prey from their predators when someone disconnects or goes spectating\r
174 \r
175         // prey disconnects or goes spectating while inside someone's belly:\r
176         if(self.eater.classname == "player")\r
177         {\r
178                 self.view_ofs_z += 25;\r
179                 self.eater.stomach_load -= 1;\r
180                 Vore_Weight_apply(self.eater);\r
181                 self.eater = world;\r
182         }\r
183 \r
184         // pred disconnects or goes spectating with players in their belly:\r
185         else if(self.stomach_load > 0)\r
186         {\r
187                 entity head;\r
188                 FOR_EACH_PLAYER(head)\r
189                 {\r
190                         if(head.eater == self)\r
191                                 Vore_Regurgitate(head);\r
192                 }\r
193                 Vore_Gurglesound(); // stop the gurgling sound\r
194         }\r
195 }\r
196 \r
197 .float digestion_step;\r
198 void Vore_Digest()\r
199 {\r
200         // apply digestion to prey\r
201         if(time > self.eater.digestion_step + steptime)\r
202         {\r
203                 Damage(self, self.eater, self.eater, cvar("g_balance_vore_digestion_damage"), DEATH_DIGESTION, self.origin, '0 0 0');\r
204                 if(cvar("g_balance_vore_digestion_vampire") && self.eater.health < cvar("g_balance_vore_digestion_vampire_stable"))\r
205                         self.eater.health += cvar("g_balance_vore_digestion_vampire");\r
206 \r
207                 if (self.eater.digestsound_finished < time)\r
208                 {\r
209                         self.eater.digestsound_finished = time + 0.5;\r
210                         PlayerSound (self.eater, playersound_digest, CHAN_PLAYER, VOICETYPE_PLAYERSOUND);\r
211                 }\r
212                 self.eater.digestion_step = time;\r
213         }\r
214 \r
215         if(self.health <= 0)\r
216         if(stov(cvar_string("g_vore_regurgitatecolor_digested")))\r
217                 self.colormod = stov(cvar_string("g_vore_regurgitatecolor_digested"));\r
218 }\r
219 \r
220 .float teamheal_step;\r
221 void Vore_Teamheal()\r
222 {\r
223         if(cvar("g_balance_vore_teamheal") && self.health < cvar("g_balance_vore_teamheal_stable"))\r
224         if(time > self.teamheal_step + steptime)\r
225         {\r
226                 self.health += cvar("g_balance_vore_teamheal");\r
227                 self.teamheal_step = time;\r
228         }\r
229 }\r
230 \r
231 .float stomachkick_delay;\r
232 void Vore_StomachKick()\r
233 {\r
234         // allows prey to kick the predator's stomach and do some damage / attempt to escape, or bring the predator's digestion upon their self when there's no other option\r
235         if(self.eater.classname != "player")\r
236                 return;\r
237 \r
238         // kick the predator's stomach and do damage, or escape if we are lucky\r
239         if(self.BUTTON_ATCK)\r
240         if(time > self.stomachkick_delay)\r
241         {\r
242                 float damage;\r
243                 damage = ceil(random() * (cvar("g_balance_vore_kick_damage_max") - cvar("g_balance_vore_kick_damage_min")) + cvar("g_balance_vore_kick_damage_min"));\r
244                 Damage(self.eater, self, self, damage, DEATH_STOMACHKICK, self.eater.origin, '0 0 0');\r
245                 sound(self.eater, CHAN_PROJECTILE, "weapons/stomachkick.ogg", VOL_BASE, ATTN_NORM);\r
246 \r
247                 if(cvar("g_balance_vore_kick_escapeprobability") >= random())\r
248                         Vore_Regurgitate(self);\r
249 \r
250                 self.stomachkick_delay = time + cvar("g_balance_vore_kick_delay");\r
251         }\r
252 \r
253         // start the predator's digestion\r
254         if(self.BUTTON_ATCK2)\r
255         {\r
256                 centerprint(self.eater, strcat(self.netname, " has triggered your digestion"));\r
257                 self.eater.digesting = TRUE;\r
258         }\r
259 }\r
260 \r
261 .float gurglesound_finished, gurglesound_oldstomachload;\r
262 void Vore_Gurglesound()\r
263 {\r
264         if(time > self.gurglesound_finished || self.gurglesound_oldstomachload != self.stomach_load)\r
265         {\r
266                 GlobalSound(self.playersound_gurgle, CHAN_TRIGGER, VOICETYPE_GURGLE);\r
267 \r
268                 self.gurglesound_finished = time + 11; // yes, hard coded sound length. I know it's bad but what can I do?\r
269                 self.gurglesound_oldstomachload = self.stomach_load;\r
270         }\r
271 }\r
272 \r
273 void Vore()\r
274 {\r
275         // if we are free, show our stomach load on the HUD. Otherwise, show the predator's\r
276         if(self.eater.classname == "player")\r
277         {\r
278                 self.stat_stomachload = self.eater.stomach_load;\r
279                 self.stat_digesting = self.eater.digesting;\r
280                 self.stat_eaten = num_for_edict(self.eater);\r
281         }\r
282         else\r
283         {\r
284                 self.stat_stomachload = self.stomach_load;\r
285                 self.stat_digesting = self.digesting;\r
286                 self.stat_eaten = 0;\r
287         }\r
288 \r
289         // skip the vore system under some circumstances\r
290         if(time < game_starttime)\r
291         {\r
292                 Vore_Disconnect();\r
293                 return;\r
294         }\r
295         if(self.spectatee_status)\r
296                 return;\r
297         if(time < self.system_delay)\r
298                 return;\r
299 \r
300 // --------------------------------\r
301 // Code that addresses predators:\r
302 // --------------------------------\r
303 \r
304         entity prey;\r
305         prey = Swallow_distance_check();\r
306 \r
307         // attempt to swallow our new prey if there's any in range\r
308         if(self.BUTTON_ATCK && !self.BUTTON_REGURGITATE && self.swallow_delay < time)\r
309         if(Swallow_condition_check(prey))\r
310         {\r
311                 prey.eater = self;\r
312                 Vore_Swallow(prey);\r
313                 self.swallow_delay = time + cvar("g_balance_vore_swallow_delay");\r
314 \r
315                 if(self.team == prey.team && teamplay)\r
316                         centerprint(self, "You have swallowed a team mate, use caution!");\r
317 \r
318                 // block firing for a small amount of time when voring, or we'll be firing the next frame after we swallow\r
319                 self.weapon_delay = time + 0.25;\r
320         }\r
321 \r
322         // start / stop digestion on command, if the player has someone in their stomach\r
323         if(self.BUTTON_DIGEST)\r
324         {\r
325                 if(self.stomach_load)\r
326                 {\r
327                         if(time > self.digest_button_delay)\r
328                         {\r
329                                 self.digesting = !self.digesting;\r
330                                 self.digest_button_delay = time + button_delay;\r
331                         }\r
332                 }\r
333                 else if(time > self.complain_swallow)\r
334                 {\r
335                         play2(self, "weapons/unavailable.wav");\r
336                         sprint(self, "There is nothing to digest\n");\r
337                         self.complain_swallow = time + complain_delay;\r
338                 }\r
339         }\r
340         if(!self.stomach_load)\r
341                 self.digesting = FALSE;\r
342 \r
343         // release players from this player's stomach on command\r
344         if(self.BUTTON_REGURGITATE)\r
345         {\r
346                 if(self.stomach_load)\r
347                 {\r
348                         if(time > self.regurgitate_button_delay)\r
349                         {\r
350                                 self.regurgitate_prepare = time + cvar("g_balance_vore_regurgitate_delay");\r
351                                 PlayerSound(self, playersound_regurgitate_prepare, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
352                                 self.regurgitate_button_delay = time + button_delay;\r
353                         }\r
354                 }\r
355                 else if(time > self.complain_swallow)\r
356                 {\r
357                         play2(self, "weapons/unavailable.wav");\r
358                         sprint(self, "There is nothing to regurgitate\n");\r
359                         self.complain_swallow = time + complain_delay;\r
360                 }\r
361         }\r
362 \r
363         if(cvar("g_vore_gurglesound"))\r
364                 Vore_Gurglesound();\r
365 \r
366 // --------------------------------\r
367 // Code that addresses the prey:\r
368 // --------------------------------\r
369 \r
370         if(self.eater.classname != "player")\r
371                 return;\r
372 \r
373         if(self.eater.deadflag || self.deadflag)\r
374                 Vore_Regurgitate(self);\r
375         else if(self.eater.eater.classname == "player") // don't allow a player inside a player inside another player :)\r
376                 Vore_Regurgitate(self);\r
377         else if(vlen(self.eater.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit"))\r
378                 Vore_Regurgitate(self);\r
379 \r
380         // apply delayed regurgitating\r
381         if(self.eater.regurgitate_prepare && time > self.eater.regurgitate_prepare)\r
382         {\r
383                 self.eater.regurgitate_prepare = 0;\r
384                 self.eater.complain_swallow = time + complain_delay;\r
385                 Vore_Regurgitate(self);\r
386         }\r
387 \r
388         if(self.eater.digesting == TRUE)\r
389                 Vore_Digest();\r
390         if(teams_matter && self.team == self.eater.team)\r
391                 Vore_Teamheal();\r
392 \r
393         Vore_StomachKick();\r
394 \r
395         Vore_CameraEffect_Apply();\r
396 }