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
9 .float vore_oldmovetype, vore_oldsolid, vore_oldstomachload, vore_oldview_ofs_z;
\r
11 entity Swallow_distance_check()
\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
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
25 float Swallow_condition_check(entity prey)
\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
32 if(self.stomach_load >= cvar("g_balance_vore_swallow_limit"))
\r
34 if(time > self.complain_swallow)
\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
43 if(cvar("g_vore_biggergut"))
\r
44 if(prey.stomach_load > self.stomach_load)
\r
46 if(time > self.complain_swallow)
\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
59 float Vore_PreyCanLeave()
\r
61 if(teams_matter && self.team == self.eater.team)
\r
66 // make the camera smoothly lower itself when we get swallowed
\r
67 // 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
68 .float cameraeffect_current, cameraeffect_target;
\r
69 void Vore_CameraEffect_Set(entity e)
\r
71 e.cameraeffect_current = 1;
\r
72 e.cameraeffect_target = 2;
\r
74 void Vore_CameraEffect_Apply()
\r
76 if(self.eater.classname != "player")
\r
79 if(self.cvar_cl_vore_cameraspeed)
\r
82 step = self.cvar_cl_vore_cameraspeed * frametime;
\r
84 // not sure if these maths are good, as the effect should be smoother
\r
85 if(self.cameraeffect_current >= self.cameraeffect_target + step)
\r
86 self.cameraeffect_current -= step;
\r
87 else if(self.cameraeffect_current <= self.cameraeffect_target - step)
\r
88 self.cameraeffect_current += step;
\r
91 self.cameraeffect_current = self.cameraeffect_target;
\r
93 self.view_ofs_z = self.vore_oldview_ofs_z / self.cameraeffect_current;
\r
96 void Vore_Weight_apply(entity e)
\r
98 // apply stomach weight that makes you heavier the more you eat
\r
99 // slowing the player is applied in cl_physics.qc
\r
100 if(e.stomach_load != e.vore_oldstomachload)
\r
101 e.gravity += 1 + (e.stomach_load * cvar("g_balance_vore_weight_gravity") - e.vore_oldstomachload);
\r
103 e.gravity = 0.00001; // 0 becomes 1 for .gravity, so do this to allow 0 gravity
\r
104 e.vore_oldstomachload = e.stomach_load;
\r
109 void Vore_Swallow(entity e)
\r
111 // this player is beening swallowed by another player, apply the proper changes
\r
112 e.vore_oldmovetype = e.movetype;
\r
113 e.vore_oldsolid = e.solid;
\r
114 e.vore_oldview_ofs_z = e.view_ofs_z;
\r
117 setorigin(e, e.eater.origin);
\r
118 e.velocity = '0 0 0';
\r
119 e.movetype = MOVETYPE_FOLLOW;
\r
120 e.solid = SOLID_NOT;
\r
121 e.alpha = -1; // best way of hiding / showing the eaten player
\r
122 e.aiment = e.eater; // follow the predator. Is automatically unset
\r
124 // drop keys (KH) and flags (CTF) when we get swallowed
\r
125 kh_Key_DropAll(e, FALSE);
\r
127 DropFlag(e.flagcarried, world, e.eater);
\r
129 Vore_CameraEffect_Set(e);
\r
131 if(stov(cvar_string("g_vore_regurgitatecolor_released")))
\r
132 e.colormod = stov(cvar_string("g_vore_regurgitatecolor_released"));
\r
134 if(e.team == e.eater.team && teamplay)
\r
136 centerprint(e, "^3You have been swallowed by a team mate, don't kick!");
\r
137 centerprint(e.eater, "^3You have swallowed a team mate, use caution!");
\r
140 PlayerSound(e.eater, playersound_swallow, CHAN_PAIN, VOICETYPE_PLAYERSOUND);
\r
141 setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing / regurgitating
\r
142 e.eater.stomach_load += 1;
\r
143 e.eater.regurgitate_prepare = 0;
\r
144 Vore_Weight_apply(e.eater);
\r
146 // block firing for a small amount of time when voring, or we'll be firing the next frame after we swallow
\r
147 e.eater.weapon_delay = time + button_delay;
\r
148 e.eater.swallow_delay = time + cvar("g_balance_vore_swallow_delay");
\r
149 e.system_delay = e.eater.system_delay = time + system_delay_time;
\r
152 void Vore_Regurgitate(entity e)
\r
154 // this player is being released from their predator, apply the proper changes
\r
155 e.movetype = e.vore_oldmovetype;
\r
156 if(e.health > 0) // leave SOLID_NOT for dead bodies
\r
157 e.solid = e.vore_oldsolid;
\r
158 e.view_ofs_z = e.vore_oldview_ofs_z;
\r
159 e.alpha = default_player_alpha; // best way of hiding / showing the eaten player
\r
162 local vector oldforward, oldright, oldup;
\r
163 oldforward = v_forward;
\r
164 oldright = v_right;
\r
166 makevectors(e.eater.v_angle);
\r
167 e.velocity = v_forward * cvar("g_balance_vore_regurgitate_force");
\r
168 e.eater.velocity += -v_forward * cvar("g_balance_vore_regurgitate_eaterforce");
\r
169 v_forward = oldforward;
\r
170 v_right = oldright;
\r
173 e.pusher = e.eater; // so we can frag players by regurgitating them in deadly pits
\r
174 e.pushltime = time + cvar("g_maxpushtime");
\r
176 PlayerSound(e.eater, playersound_regurgitate, CHAN_PAIN, VOICETYPE_PLAYERSOUND);
\r
177 setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing / regurgitating
\r
178 pointparticles(particleeffectnum("regurgitate"), e.eater.origin, '0 0 0', 1);
\r
179 e.eater.stomach_load -= 1;
\r
180 e.eater.regurgitate_prepare = 0;
\r
181 e.eater.swallow_delay = time + cvar("g_balance_vore_swallow_delay");
\r
182 Vore_Weight_apply(e.eater);
\r
184 // block firing for a small amount of time when getting regurgitated, or we'll be firing the next frame
\r
185 e.weapon_delay = time + button_delay;
\r
186 e.system_delay = e.eater.system_delay = time + system_delay_time;
\r
190 void Vore_Gurglesound();
\r
191 void Vore_Disconnect()
\r
193 // frees prey from their predators when someone disconnects or goes spectating
\r
195 // prey disconnects or goes spectating while inside someone's belly:
\r
196 if(self.eater.classname == "player")
\r
198 self.view_ofs_z = self.vore_oldview_ofs_z;
\r
199 self.eater.stomach_load -= 1;
\r
200 Vore_Weight_apply(self.eater);
\r
201 self.eater = world;
\r
204 // pred disconnects or goes spectating with players in their belly:
\r
205 else if(self.stomach_load > 0)
\r
208 FOR_EACH_PLAYER(head)
\r
210 if(head.eater == self)
\r
211 Vore_Regurgitate(head);
\r
213 Vore_Gurglesound(); // stop the gurgling sound
\r
217 .float digestion_step;
\r
220 // apply digestion to prey
\r
221 if(time > self.eater.digestion_step + steptime)
\r
223 Damage(self, self.eater, self.eater, cvar("g_balance_vore_digestion_damage"), DEATH_DIGESTION, self.origin, '0 0 0');
\r
224 if(cvar("g_balance_vore_digestion_vampire") && self.eater.health < cvar("g_balance_vore_digestion_vampire_stable"))
\r
225 self.eater.health += cvar("g_balance_vore_digestion_vampire");
\r
227 if (self.eater.digestsound_finished < time)
\r
229 self.eater.digestsound_finished = time + 0.5;
\r
230 PlayerSound (self.eater, playersound_digest, CHAN_PLAYER, VOICETYPE_PLAYERSOUND);
\r
232 self.eater.digestion_step = time;
\r
235 if(self.health <= 0)
\r
236 if(stov(cvar_string("g_vore_regurgitatecolor_digested")))
\r
237 self.colormod = stov(cvar_string("g_vore_regurgitatecolor_digested"));
\r
240 .float teamheal_step;
\r
241 void Vore_Teamheal()
\r
243 if(cvar("g_balance_vore_teamheal") && self.health < cvar("g_balance_vore_teamheal_stable"))
\r
244 if(time > self.teamheal_step + steptime)
\r
246 self.health += cvar("g_balance_vore_teamheal");
\r
247 self.teamheal_step = time;
\r
251 .float stomachkick_delay;
\r
252 void Vore_StomachKick()
\r
254 // allows prey to kick the predator's stomach and do some damage or attempt to escape
\r
255 if(self.eater.classname != "player")
\r
258 if(time > self.stomachkick_delay)
\r
261 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
262 Damage(self.eater, self, self, damage, DEATH_STOMACHKICK, self.eater.origin, '0 0 0');
\r
263 sound(self.eater, CHAN_PROJECTILE, "weapons/stomachkick.ogg", VOL_BASE, ATTN_NORM);
\r
265 if(cvar("g_balance_vore_kick_escapeprobability") >= random())
\r
266 Vore_Regurgitate(self);
\r
268 self.stomachkick_delay = time + cvar("g_balance_vore_kick_delay");
\r
272 void Vore_StomachLeave()
\r
274 // allows players to get out of their predator at will in some circumstances, such as team mates
\r
276 if(Vore_PreyCanLeave())
\r
277 Vore_Regurgitate(self);
\r
278 else if(time > self.complain_swallow)
\r
280 play2(self, "weapons/unavailable.wav");
\r
281 sprint(self, strcat("You cannot get out of ", self.eater.netname, "\n"));
\r
282 self.complain_swallow = time + complain_delay;
\r
286 .float gurglesound_finished, gurglesound_oldstomachload;
\r
287 void Vore_Gurglesound()
\r
289 if(time > self.gurglesound_finished || self.gurglesound_oldstomachload != self.stomach_load)
\r
291 GlobalSound(self.playersound_gurgle, CHAN_TRIGGER, VOICETYPE_GURGLE);
\r
293 self.gurglesound_finished = time + 11; // yes, hard coded sound length. I know it's bad but what can I do?
\r
294 self.gurglesound_oldstomachload = self.stomach_load;
\r
300 // if we are free, show our stomach load on the HUD. Otherwise, show the predator's
\r
301 if(self.eater.classname == "player")
\r
303 self.stat_stomachload = self.eater.stomach_load;
\r
304 self.stat_digesting = self.eater.digesting;
\r
305 self.stat_eaten = num_for_edict(self.eater);
\r
309 self.stat_stomachload = self.stomach_load;
\r
310 self.stat_digesting = self.digesting;
\r
311 self.stat_eaten = 0;
\r
314 // skip the vore system under some circumstances
\r
315 if(time < game_starttime)
\r
320 if(self.spectatee_status)
\r
322 if(time < self.system_delay)
\r
325 // --------------------------------
\r
326 // Code that addresses predators:
\r
327 // --------------------------------
\r
330 prey = Swallow_distance_check();
\r
332 // attempt to swallow our new prey if there's any in range
\r
333 if(self.BUTTON_ATCK && !self.BUTTON_REGURGITATE && self.swallow_delay < time)
\r
334 if(Swallow_condition_check(prey))
\r
335 Vore_Swallow(prey);
\r
337 // start / stop digestion on command, if the player has someone in their stomach
\r
338 if(self.BUTTON_DIGEST)
\r
340 if(self.stomach_load)
\r
342 if(time > self.digest_button_delay)
\r
344 self.digesting = !self.digesting;
\r
345 self.digest_button_delay = time + button_delay;
\r
348 else if(time > self.complain_swallow)
\r
350 play2(self, "weapons/unavailable.wav");
\r
351 sprint(self, "There is nothing to digest\n");
\r
352 self.complain_swallow = time + complain_delay;
\r
355 if(!self.stomach_load)
\r
356 self.digesting = FALSE;
\r
358 // release players from this player's stomach on command
\r
359 if(self.BUTTON_REGURGITATE)
\r
361 if(self.stomach_load)
\r
363 if(time > self.regurgitate_button_delay)
\r
365 self.regurgitate_prepare = time + cvar("g_balance_vore_regurgitate_delay");
\r
366 PlayerSound(self, playersound_regurgitate_prepare, CHAN_VOICE, VOICETYPE_PLAYERSOUND);
\r
367 self.regurgitate_button_delay = time + button_delay;
\r
370 else if(time > self.complain_swallow)
\r
372 play2(self, "weapons/unavailable.wav");
\r
373 sprint(self, "There is nothing to regurgitate\n");
\r
374 self.complain_swallow = time + complain_delay;
\r
378 if(cvar("g_vore_gurglesound"))
\r
379 Vore_Gurglesound();
\r
381 // --------------------------------
\r
382 // Code that addresses the prey:
\r
383 // --------------------------------
\r
385 if(self.eater.classname != "player")
\r
388 if(self.eater.deadflag || self.deadflag)
\r
389 Vore_Regurgitate(self);
\r
390 else if(self.eater.eater.classname == "player") // don't allow a player inside a player inside another player :)
\r
392 entity targeteater, oldself;
\r
393 targeteater = self.eater.eater;
\r
395 Vore_Regurgitate(self);
\r
396 if(random() < cvar("g_vore_stealprey"))
\r
397 if(Swallow_condition_check(self))
\r
400 self = targeteater;
\r
401 Vore_Swallow(oldself);
\r
405 else if(vlen(self.eater.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit"))
\r
406 Vore_Regurgitate(self);
\r
408 // apply delayed regurgitating
\r
409 if(self.eater.regurgitate_prepare && time > self.eater.regurgitate_prepare)
\r
411 self.eater.regurgitate_prepare = 0;
\r
412 self.eater.complain_swallow = time + complain_delay;
\r
413 Vore_Regurgitate(self);
\r
416 if(self.eater.digesting == TRUE)
\r
418 if(teams_matter && self.team == self.eater.team)
\r
421 if(self.BUTTON_ATCK)
\r
422 Vore_StomachKick();
\r
423 if(self.BUTTON_JUMP)
\r
424 Vore_StomachLeave();
\r
426 self.stat_canleave = Vore_PreyCanLeave();
\r
428 Vore_CameraEffect_Apply();
\r