.float regurgitate_prepare; .float swallow_delay, digest_button_delay, regurgitate_button_delay; .float complain_swallow; const float complain_delay = 1; const float button_delay = 0.5; const float steptime = 0.1; .float vore_oldmovetype, vore_oldsolid, vore_oldstomachload; entity Swallow_distance_check() { // check if we can swallow a player instead of firing our weapon vector w_shotorg, w_shotdir; w_shotorg = self.origin + self.view_ofs; w_shotdir = v_forward; WarpZone_traceline_antilag(self, w_shotorg, w_shotorg + w_shotdir * cvar("g_balance_vore_swallow_range"), FALSE, self, ANTILAG_LATENCY(self)); if(trace_fraction < 1) if(trace_ent.classname == "player") return trace_ent; return world; } float Swallow_condition_check(entity prey) { // checks the necessary conditions for swallowing another player 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 if not(vlen(self.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit")) if(self.eater.classname != "player") // we can't swallow players while inside someone's stomach ourselves { if(self.stomach_load >= cvar("g_balance_vore_swallow_limit")) { if(time > self.complain_swallow) { play2(self, "weapons/unavailable.wav"); sprint(self, strcat("You cannot swallow more than ^2", cvar_string("g_balance_vore_swallow_limit"), "^7 players at a time\n")); self.complain_swallow = time + complain_delay; } return FALSE; } if(cvar("g_vore_biggergut")) if(prey.stomach_load > self.stomach_load) { if(time > self.complain_swallow) { play2(self, "weapons/unavailable.wav"); sprint(self, "You cannot swallow someone with a bigger stomach than yours\n"); self.complain_swallow = time + complain_delay; } return FALSE; } return TRUE; } return FALSE; } void Vore_Weight_apply(entity e) { // apply stomach weight that makes you heavier the more you eat // slowing the player is applied in cl_physics.qc if(e.stomach_load != e.vore_oldstomachload) e.gravity += 1 + (e.stomach_load * cvar("g_balance_vore_weight_gravity") - e.vore_oldstomachload); if(e.gravity == 0) e.gravity = 0.00001; // 0 becomes 1 for .gravity, so do this to allow 0 gravity e.vore_oldstomachload = e.stomach_load; } void Vore_Swallow(entity e) { // this player is beening swallowed by another player, apply the proper changes e.vore_oldmovetype = e.movetype; e.vore_oldsolid = e.solid; setorigin(e, e.eater.origin); e.velocity = '0 0 0'; e.movetype = MOVETYPE_FOLLOW; e.solid = SOLID_NOT; e.alpha = -1; // best way of hiding / showing the eaten player e.aiment = e.eater; // follow the predator. Is automatically unset e.view_ofs_z /= 2; // best positioning for the stomach model e.stat_eaten = TRUE; // drop keys (KH) and flags (CTF) when we get swallowed kh_Key_DropAll(e, FALSE); if(e.flagcarried) DropFlag(e.flagcarried, world, e.eater); if(stov(cvar_string("g_vore_regurgitatecolor_released"))) e.colormod = stov(cvar_string("g_vore_regurgitatecolor_released")); PlayerSound(e.eater, playersound_swallow, CHAN_PAIN, VOICETYPE_PLAYERSOUND); setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing \ regurgitating e.eater.stomach_load += 1; e.eater.regurgitate_prepare = 0; Vore_Weight_apply(e.eater); } void Vore_Regurgitate(entity e) { // this player is being released from their predator, apply the proper changes e.movetype = e.vore_oldmovetype; if(e.health > 0) // leave SOLID_NOT for dead bodies e.solid = e.vore_oldsolid; e.alpha = 0; // best way of hiding / showing the eaten player e.view_ofs_z *= 2; // best positioning for the stomach model e.stat_eaten = FALSE; // velocities local vector oldforward, oldright, oldup; oldforward = v_forward; oldright = v_right; oldup = v_up; makevectors(e.eater.v_angle); e.velocity = v_forward * cvar("g_balance_vore_regurgitate_force"); e.eater.velocity += -v_forward * cvar("g_balance_vore_regurgitate_eaterforce"); v_forward = oldforward; v_right = oldright; v_up = oldup; PlayerSound(e.eater, playersound_regurgitate, CHAN_PAIN, VOICETYPE_PLAYERSOUND); setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing \ regurgitating pointparticles(particleeffectnum("regurgitate"), e.eater.origin, '0 0 0', 1); e.eater.stomach_load -= 1; e.eater.regurgitate_prepare = 0; e.eater.swallow_delay = time + cvar("g_balance_vore_swallow_delay"); Vore_Weight_apply(e.eater); e.eater = world; } void Vore_Disconnect() { // frees prey from their predators when someone disconnects or goes spectating // prey disconnects or goes spectating while inside someone's belly: if(self.eater.classname == "player") { self.view_ofs_z += 25; self.stat_eaten = FALSE; self.eater.stomach_load -= 1; Vore_Weight_apply(self.eater); self.eater = world; } // pred disconnects or goes spectating with players in their belly: else if(self.stomach_load > 0) { entity head; FOR_EACH_PLAYER(head) { if(head.eater == self) Vore_Regurgitate(head); } } } .float digestion_step; void Vore_Digest() { // apply digestion to prey if(time > self.eater.digestion_step + steptime) { Damage(self, self.eater, self.eater, cvar("g_balance_vore_digestion_damage"), DEATH_DIGESTION, self.origin, '0 0 0'); if(cvar("g_balance_vore_digestion_vampire") && self.eater.health < cvar("g_balance_vore_digestion_vampire_stable")) self.eater.health += cvar("g_balance_vore_digestion_vampire"); if (self.eater.digestsound_finished < time) { self.eater.digestsound_finished = time + 0.5; PlayerSound (self.eater, playersound_digest, CHAN_PLAYER, VOICETYPE_PLAYERSOUND); } self.eater.digestion_step = time; } if(self.health <= 0) if(stov(cvar_string("g_vore_regurgitatecolor_digested"))) self.colormod = stov(cvar_string("g_vore_regurgitatecolor_digested")); } .float teamheal_step; void Vore_Teamheal() { if(cvar("g_balance_vore_teamheal") && self.health < cvar("g_balance_vore_teamheal_stable")) if(time > self.teamheal_step + steptime) { self.health += cvar("g_balance_vore_teamheal"); self.teamheal_step = time; } } .float stomachkick_delay; void Vore_StomachKick() { // 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 if(self.eater.classname != "player") return; // kick the predator's stomach and do damage, or escape if we are lucky if(self.BUTTON_ATCK) if(time > self.stomachkick_delay) { float damage; damage = ceil(random() * (cvar("g_balance_vore_kick_damage_max") - cvar("g_balance_vore_kick_damage_min")) + cvar("g_balance_vore_kick_damage_min")); Damage(self.eater, self, self, damage, DEATH_STOMACHKICK, self.eater.origin, '0 0 0'); sound(self.eater, CHAN_PROJECTILE, "weapons/stomachkick.ogg", VOL_BASE, ATTN_NORM); if(cvar("g_balance_vore_kick_escapeprobability") >= random()) Vore_Regurgitate(self); self.stomachkick_delay = time + cvar("g_balance_vore_kick_delay"); } // start the predator's digestion if(self.BUTTON_ATCK2) { centerprint(self.eater, strcat(self.netname, " has triggered your digestion")); self.eater.digesting = TRUE; } } .float gurglesound_finished, gurglesound_oldstomachload; void Vore_Gurglesound() { if(time > self.gurglesound_finished || self.gurglesound_oldstomachload != self.stomach_load) { GlobalSound(self.playersound_gurgle, CHAN_TRIGGER, VOICETYPE_GURGLE); self.gurglesound_finished = time + 11; // yes, hard coded sound length. I know it's bad but what can I do? self.gurglesound_oldstomachload = self.stomach_load; } } void Vore() { // skip the vore system under some circumstances if(time < game_starttime) { Vore_Disconnect(); return; } if(self.spectatee_status) return; // -------------------------------- // Code that addresses predators: // -------------------------------- entity prey; prey = Swallow_distance_check(); // attempt to swallow our new prey if there's any in range if(self.BUTTON_ATCK && !self.BUTTON_REGURGITATE && self.swallow_delay < time) if(Swallow_condition_check(prey)) { prey.eater = self; Vore_Swallow(prey); self.swallow_delay = time + cvar("g_balance_vore_swallow_delay"); if(self.team == prey.team && teamplay) centerprint(self, "You have swallowed a team mate, use caution!"); // block firing for a small amount of time when voring, or we'll be firing the next frame after we swallow self.weapon_delay = time + 0.25; } // start / stop digestion on command, if the player has someone in their stomach if(self.BUTTON_DIGEST) { if(self.stomach_load) { if(time > self.digest_button_delay) { self.digesting = !self.digesting; self.digest_button_delay = time + button_delay; } } else if(time > self.complain_swallow) { play2(self, "weapons/unavailable.wav"); sprint(self, "There is nothing to digest\n"); self.complain_swallow = time + complain_delay; } } if(!self.stomach_load) self.digesting = FALSE; // release players from this player's stomach on command if(self.BUTTON_REGURGITATE) { if(self.stomach_load) { if(time > self.regurgitate_button_delay) { self.regurgitate_prepare = time + cvar("g_balance_vore_regurgitate_delay"); PlayerSound(self, playersound_regurgitate_prepare, CHAN_PAIN, VOICETYPE_PLAYERSOUND); self.regurgitate_button_delay = time + button_delay; } } else if(time > self.complain_swallow) { play2(self, "weapons/unavailable.wav"); sprint(self, "There is nothing to regurgitate\n"); self.complain_swallow = time + complain_delay; } } if(cvar("g_vore_gurglesound")) Vore_Gurglesound(); // -------------------------------- // Code that addresses the prey: // -------------------------------- if(self.eater.classname != "player") return; if(self.eater.deadflag || self.deadflag) Vore_Regurgitate(self); else if(self.eater.eater.classname == "player") // don't allow a player inside a player inside another player :) Vore_Regurgitate(self); else if(vlen(self.eater.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit")) Vore_Regurgitate(self); // apply delayed regurgitating if(self.eater.regurgitate_prepare && time > self.eater.regurgitate_prepare) { self.eater.regurgitate_prepare = 0; self.eater.complain_swallow = time + complain_delay; Vore_Regurgitate(self); } if(self.eater.digesting == TRUE) Vore_Digest(); if(teams_matter && self.team == self.eater.team) Vore_Teamheal(); Vore_StomachKick(); }