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