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 // 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
64 e.cameraeffect_current = 1;
\r
65 e.cameraeffect_target = 2;
\r
67 void Vore_CameraEffect_Apply()
\r
69 if(self.eater.classname != "player")
\r
72 if(self.cvar_cl_vore_cameraspeed)
\r
75 step = self.cvar_cl_vore_cameraspeed * frametime;
\r
77 // not sure if these maths are good, as the effect should be smoother
\r
78 if(self.cameraeffect_current >= self.cameraeffect_target + step)
\r
79 self.cameraeffect_current -= step;
\r
80 else if(self.cameraeffect_current <= self.cameraeffect_target - step)
\r
81 self.cameraeffect_current += step;
\r
84 self.cameraeffect_current = self.cameraeffect_target;
\r
86 self.view_ofs_z = self.vore_oldview_ofs_z / self.cameraeffect_current;
\r
89 void Vore_Weight_apply(entity e)
\r
91 // apply stomach weight that makes you heavier the more you eat
\r
92 // slowing the player is applied in cl_physics.qc
\r
93 if(e.stomach_load != e.vore_oldstomachload)
\r
94 e.gravity += 1 + (e.stomach_load * cvar("g_balance_vore_weight_gravity") - e.vore_oldstomachload);
\r
96 e.gravity = 0.00001; // 0 becomes 1 for .gravity, so do this to allow 0 gravity
\r
97 e.vore_oldstomachload = e.stomach_load;
\r
102 void Vore_Swallow(entity e)
\r
104 // this player is beening swallowed by another player, apply the proper changes
\r
105 e.vore_oldmovetype = e.movetype;
\r
106 e.vore_oldsolid = e.solid;
\r
107 e.vore_oldview_ofs_z = e.view_ofs_z;
\r
110 setorigin(e, e.eater.origin);
\r
111 e.velocity = '0 0 0';
\r
112 e.movetype = MOVETYPE_FOLLOW;
\r
113 e.solid = SOLID_NOT;
\r
114 e.alpha = -1; // best way of hiding / showing the eaten player
\r
115 e.aiment = e.eater; // follow the predator. Is automatically unset
\r
117 // drop keys (KH) and flags (CTF) when we get swallowed
\r
118 kh_Key_DropAll(e, FALSE);
\r
120 DropFlag(e.flagcarried, world, e.eater);
\r
122 Vore_CameraEffect_Set(e);
\r
124 if(stov(cvar_string("g_vore_regurgitatecolor_released")))
\r
125 e.colormod = stov(cvar_string("g_vore_regurgitatecolor_released"));
\r
127 if(e.team == e.eater.team && teamplay)
\r
129 centerprint(e, "^3You have been swallowed by a team mate, don't kick!");
\r
130 centerprint(e.eater, "^3You have swallowed a team mate, use caution!");
\r
133 PlayerSound(e.eater, playersound_swallow, CHAN_PAIN, VOICETYPE_PLAYERSOUND);
\r
134 setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing / regurgitating
\r
135 e.eater.stomach_load += 1;
\r
136 e.eater.regurgitate_prepare = 0;
\r
137 Vore_Weight_apply(e.eater);
\r
139 // block firing for a small amount of time when voring, or we'll be firing the next frame after we swallow
\r
140 e.eater.weapon_delay = time + button_delay;
\r
141 e.eater.swallow_delay = time + cvar("g_balance_vore_swallow_delay");
\r
142 e.system_delay = e.eater.system_delay = time + system_delay_time;
\r
145 void Vore_Regurgitate(entity e)
\r
147 // this player is being released from their predator, apply the proper changes
\r
148 e.movetype = e.vore_oldmovetype;
\r
149 if(e.health > 0) // leave SOLID_NOT for dead bodies
\r
150 e.solid = e.vore_oldsolid;
\r
151 e.view_ofs_z = e.vore_oldview_ofs_z;
\r
152 e.alpha = default_player_alpha; // best way of hiding / showing the eaten player
\r
155 local vector oldforward, oldright, oldup;
\r
156 oldforward = v_forward;
\r
157 oldright = v_right;
\r
159 makevectors(e.eater.v_angle);
\r
160 e.velocity = v_forward * cvar("g_balance_vore_regurgitate_force");
\r
161 e.eater.velocity += -v_forward * cvar("g_balance_vore_regurgitate_eaterforce");
\r
162 v_forward = oldforward;
\r
163 v_right = oldright;
\r
166 e.pusher = e.eater; // so we can frag players by regurgitating them in deadly pits
\r
167 e.pushltime = time + cvar("g_maxpushtime");
\r
169 PlayerSound(e.eater, playersound_regurgitate, CHAN_PAIN, VOICETYPE_PLAYERSOUND);
\r
170 setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing / regurgitating
\r
171 pointparticles(particleeffectnum("regurgitate"), e.eater.origin, '0 0 0', 1);
\r
172 e.eater.stomach_load -= 1;
\r
173 e.eater.regurgitate_prepare = 0;
\r
174 e.eater.swallow_delay = time + cvar("g_balance_vore_swallow_delay");
\r
175 Vore_Weight_apply(e.eater);
\r
177 // block firing for a small amount of time when getting regurgitated, or we'll be firing the next frame
\r
178 e.weapon_delay = time + button_delay;
\r
179 e.system_delay = e.eater.system_delay = time + system_delay_time;
\r
183 void Vore_Gurglesound();
\r
184 void Vore_Disconnect()
\r
186 // frees prey from their predators when someone disconnects or goes spectating
\r
188 // prey disconnects or goes spectating while inside someone's belly:
\r
189 if(self.eater.classname == "player")
\r
191 self.view_ofs_z = self.vore_oldview_ofs_z;
\r
192 self.eater.stomach_load -= 1;
\r
193 Vore_Weight_apply(self.eater);
\r
194 self.eater = world;
\r
197 // pred disconnects or goes spectating with players in their belly:
\r
198 else if(self.stomach_load > 0)
\r
201 FOR_EACH_PLAYER(head)
\r
203 if(head.eater == self)
\r
204 Vore_Regurgitate(head);
\r
206 Vore_Gurglesound(); // stop the gurgling sound
\r
210 .float digestion_step;
\r
213 // apply digestion to prey
\r
214 if(time > self.eater.digestion_step + steptime)
\r
216 Damage(self, self.eater, self.eater, cvar("g_balance_vore_digestion_damage"), DEATH_DIGESTION, self.origin, '0 0 0');
\r
217 if(cvar("g_balance_vore_digestion_vampire") && self.eater.health < cvar("g_balance_vore_digestion_vampire_stable"))
\r
218 self.eater.health += cvar("g_balance_vore_digestion_vampire");
\r
220 if (self.eater.digestsound_finished < time)
\r
222 self.eater.digestsound_finished = time + 0.5;
\r
223 PlayerSound (self.eater, playersound_digest, CHAN_PLAYER, VOICETYPE_PLAYERSOUND);
\r
225 self.eater.digestion_step = time;
\r
228 if(self.health <= 0)
\r
229 if(stov(cvar_string("g_vore_regurgitatecolor_digested")))
\r
230 self.colormod = stov(cvar_string("g_vore_regurgitatecolor_digested"));
\r
233 .float teamheal_step;
\r
234 void Vore_Teamheal()
\r
236 if(cvar("g_balance_vore_teamheal") && self.health < cvar("g_balance_vore_teamheal_stable"))
\r
237 if(time > self.teamheal_step + steptime)
\r
239 self.health += cvar("g_balance_vore_teamheal");
\r
240 self.teamheal_step = time;
\r
244 .float stomachkick_delay;
\r
245 void Vore_StomachKick()
\r
247 // allows prey to kick the predator's stomach and do some damage or attempt to escape
\r
248 if(self.eater.classname != "player")
\r
251 if(time > self.stomachkick_delay)
\r
254 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
255 Damage(self.eater, self, self, damage, DEATH_STOMACHKICK, self.eater.origin, '0 0 0');
\r
256 sound(self.eater, CHAN_PROJECTILE, "weapons/stomachkick.ogg", VOL_BASE, ATTN_NORM);
\r
258 if(cvar("g_balance_vore_kick_escapeprobability") >= random())
\r
259 Vore_Regurgitate(self);
\r
261 self.stomachkick_delay = time + cvar("g_balance_vore_kick_delay");
\r
265 void Vore_StomachLeave()
\r
267 // allows players to get out of their predator at will in some circumstances, such as team mates
\r
270 canleave = (teams_matter && self.team == self.eater.team); // currently, the only circumstance where you can use this if for team mates
\r
273 Vore_Regurgitate(self);
\r
274 else if(time > self.complain_swallow)
\r
276 play2(self, "weapons/unavailable.wav");
\r
277 sprint(self, strcat("You can't willingly get out of ", self.eater.netname, "\n"));
\r
278 self.complain_swallow = time + complain_delay;
\r
282 .float gurglesound_finished, gurglesound_oldstomachload;
\r
283 void Vore_Gurglesound()
\r
285 if(time > self.gurglesound_finished || self.gurglesound_oldstomachload != self.stomach_load)
\r
287 GlobalSound(self.playersound_gurgle, CHAN_TRIGGER, VOICETYPE_GURGLE);
\r
289 self.gurglesound_finished = time + 11; // yes, hard coded sound length. I know it's bad but what can I do?
\r
290 self.gurglesound_oldstomachload = self.stomach_load;
\r
296 // if we are free, show our stomach load on the HUD. Otherwise, show the predator's
\r
297 if(self.eater.classname == "player")
\r
299 self.stat_stomachload = self.eater.stomach_load;
\r
300 self.stat_digesting = self.eater.digesting;
\r
301 self.stat_eaten = num_for_edict(self.eater);
\r
305 self.stat_stomachload = self.stomach_load;
\r
306 self.stat_digesting = self.digesting;
\r
307 self.stat_eaten = 0;
\r
310 // skip the vore system under some circumstances
\r
311 if(time < game_starttime)
\r
316 if(self.spectatee_status)
\r
318 if(time < self.system_delay)
\r
321 // --------------------------------
\r
322 // Code that addresses predators:
\r
323 // --------------------------------
\r
326 prey = Swallow_distance_check();
\r
328 // attempt to swallow our new prey if there's any in range
\r
329 if(self.BUTTON_ATCK && !self.BUTTON_REGURGITATE && self.swallow_delay < time)
\r
330 if(Swallow_condition_check(prey))
\r
331 Vore_Swallow(prey);
\r
333 // start / stop digestion on command, if the player has someone in their stomach
\r
334 if(self.BUTTON_DIGEST)
\r
336 if(self.stomach_load)
\r
338 if(time > self.digest_button_delay)
\r
340 self.digesting = !self.digesting;
\r
341 self.digest_button_delay = time + button_delay;
\r
344 else if(time > self.complain_swallow)
\r
346 play2(self, "weapons/unavailable.wav");
\r
347 sprint(self, "There is nothing to digest\n");
\r
348 self.complain_swallow = time + complain_delay;
\r
351 if(!self.stomach_load)
\r
352 self.digesting = FALSE;
\r
354 // release players from this player's stomach on command
\r
355 if(self.BUTTON_REGURGITATE)
\r
357 if(self.stomach_load)
\r
359 if(time > self.regurgitate_button_delay)
\r
361 self.regurgitate_prepare = time + cvar("g_balance_vore_regurgitate_delay");
\r
362 PlayerSound(self, playersound_regurgitate_prepare, CHAN_VOICE, VOICETYPE_PLAYERSOUND);
\r
363 self.regurgitate_button_delay = time + button_delay;
\r
366 else if(time > self.complain_swallow)
\r
368 play2(self, "weapons/unavailable.wav");
\r
369 sprint(self, "There is nothing to regurgitate\n");
\r
370 self.complain_swallow = time + complain_delay;
\r
374 if(cvar("g_vore_gurglesound"))
\r
375 Vore_Gurglesound();
\r
377 // --------------------------------
\r
378 // Code that addresses the prey:
\r
379 // --------------------------------
\r
381 if(self.eater.classname != "player")
\r
384 if(self.eater.deadflag || self.deadflag)
\r
385 Vore_Regurgitate(self);
\r
386 else if(self.eater.eater.classname == "player") // don't allow a player inside a player inside another player :)
\r
388 entity targeteater, oldself;
\r
389 targeteater = self.eater.eater;
\r
391 Vore_Regurgitate(self);
\r
392 if(random() < cvar("g_vore_stealprey"))
\r
393 if(Swallow_condition_check(self))
\r
396 self = targeteater;
\r
397 Vore_Swallow(oldself);
\r
401 else if(vlen(self.eater.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit"))
\r
402 Vore_Regurgitate(self);
\r
404 // apply delayed regurgitating
\r
405 if(self.eater.regurgitate_prepare && time > self.eater.regurgitate_prepare)
\r
407 self.eater.regurgitate_prepare = 0;
\r
408 self.eater.complain_swallow = time + complain_delay;
\r
409 Vore_Regurgitate(self);
\r
412 if(self.eater.digesting == TRUE)
\r
414 if(teams_matter && self.team == self.eater.team)
\r
417 if(self.BUTTON_ATCK)
\r
418 Vore_StomachKick();
\r
419 else if(self.BUTTON_ATCK2)
\r
420 Vore_StomachLeave();
\r
422 Vore_CameraEffect_Apply();
\r