]> git.xonotic.org Git - voretournament/voretournament.git/blobdiff - data/qcsrc/server/vore.qc
Predator progress causes your prey progress to drop more quickly and the other way...
[voretournament/voretournament.git] / data / qcsrc / server / vore.qc
index c4480e4ddc54653a6b2f59486eeb9eaab1aa41dd..9e71f036aab10161cda9e93cdc29c33647de87c6 100644 (file)
@@ -139,9 +139,14 @@ void Vore_GurgleSound()
 {\r
        if(time > self.gurglesound_finished || (self.gurgle_oldstomachload != self.stomach_load && !self.digesting))\r
        {\r
-               GlobalSound(self.playersound_gurgle, CHAN_TRIGGER, VOICETYPE_GURGLE);\r
+               GlobalSound(self.playersound_gurgle, CHAN_TRIGGER, VOICETYPE_GURGLE, VOL_BASE);\r
+\r
+               // yes, hard coded sound length. I know it's bad but what can I do?\r
+               if(cvar("g_healthsize") && cvar("g_healthsize_pitch"))\r
+                       self.gurglesound_finished = time + 11 * pow(self.scale, -cvar("g_healthsize_pitch")); // modified sound pitch, based on player scale\r
+               else\r
+                       self.gurglesound_finished = time + 11; // yes, hard coded sound length. I know it's bad but what can I do?\r
 \r
-               self.gurglesound_finished = time + 11; // yes, hard coded sound length. I know it's bad but what can I do?\r
                self.gurgle_oldstomachload = self.stomach_load;\r
        }\r
 }\r
@@ -152,10 +157,12 @@ void Vore_AutoDigest(entity e)
 \r
        if(!cvar("g_vore_digestion") || e.digesting)\r
                return;\r
-       if(clienttype(e) != CLIENTTYPE_REAL)\r
-               return; // this feature is only for players, not bots\r
+       if(g_rpg)\r
+               return; // RPG is choice based, so don't do things automatically there\r
        if(e.stomach_load)\r
                return; // don't start digestion if we already ate someone, as that means we manually disabled it after the first prey and want it off\r
+       if(clienttype(e) != CLIENTTYPE_REAL)\r
+               return; // this feature is only for players, not bots\r
        if(Stomach_TeamMates_check(e))\r
                return; // never begin automatic digestion if we've swallowed a team mate\r
 \r
@@ -202,30 +209,30 @@ void Vore_StomachLoad_Apply()
        self.stomach_load = final_load;\r
 \r
        // apply weight\r
-       self.gravity = 1 + (self.stomach_load / self.stomach_maxload) * cvar("g_balance_vore_load_pred_weight");\r
+       self.gravity = 1 * (cvar("g_healthsize") ? pow(self.scale, cvar("g_healthsize_weight")) : 1) + (self.stomach_load / self.stomach_maxload) * cvar("g_balance_vore_load_pred_weight");\r
        if(!self.gravity && self.stomach_load)\r
                self.gravity = 0.00001; // 0 becomes 1 for gravity, so do this to allow 0 gravity\r
 }\r
 \r
 .entity swallow_model;\r
-float Vore_SwallowModel_CustomizeEntityForClient()\r
+float Vore_GulletModel_CustomizeEntityForClient()\r
 {\r
        // use the same system as the weapon model\r
 \r
        self.viewmodelforclient = self.owner;\r
-       self.alpha = self.owner.cvar_cl_vore_swallowmodel;\r
+       self.alpha = self.owner.cvar_cl_vore_gulletmodel;\r
 \r
        if(other.classname == "spectator")\r
        if(other.enemy == self.owner)\r
        {\r
                self.viewmodelforclient = other;\r
-               self.alpha = other.cvar_cl_vore_swallowmodel;\r
+               self.alpha = other.cvar_cl_vore_gulletmodel;\r
        }\r
 \r
        return TRUE;\r
 }\r
 \r
-void Vore_SwallowModel_Think()\r
+void Vore_GulletModel_Think()\r
 {\r
        // update the position of the swallow model to match our swallow progress\r
        float dist;\r
@@ -246,7 +253,7 @@ void Vore_SwallowModel_Think()
        self.nextthink = time;\r
 }\r
 \r
-void Vore_SwallowModel_Update(entity prey, entity pred)\r
+void Vore_GulletModel_Update(entity prey, entity pred)\r
 {\r
        // if we don't have a swallow model already, spawn one\r
        if(!prey.swallow_model)\r
@@ -257,16 +264,16 @@ void Vore_SwallowModel_Update(entity prey, entity pred)
                //prey.swallow_model.effects |= EF_NOGUNBOB; // let it bob\r
                prey.swallow_model.effects |= EF_NODEPTHTEST; // don't hide behind walls\r
                prey.swallow_model.owner = prey;\r
-               prey.swallow_model.customizeentityforclient = Vore_SwallowModel_CustomizeEntityForClient;\r
-               prey.swallow_model.think = Vore_SwallowModel_Think;\r
+               prey.swallow_model.customizeentityforclient = Vore_GulletModel_CustomizeEntityForClient;\r
+               prey.swallow_model.think = Vore_GulletModel_Think;\r
                prey.swallow_model.nextthink = time;\r
        }\r
 \r
        // properties that should update whenever possible, but when the predator is available\r
-       string player_swallowmodel;\r
-       player_swallowmodel = strcat(substring(pred.playermodel, 0, strlen(pred.playermodel) - 4), "_swallow.md3"); // 4 is the extension length\r
-       if(prey.swallow_model.model != player_swallowmodel) // player model can be changed while the predator is active\r
-               setmodel(prey.swallow_model, player_swallowmodel);\r
+       string player_gulletmodel;\r
+       player_gulletmodel = strcat(substring(pred.playermodel, 0, strlen(pred.playermodel) - 4), "_gullet.iqm"); // 4 is the extension length\r
+       if(prey.swallow_model.model != player_gulletmodel) // player model can be changed while the predator is active\r
+               setmodel(prey.swallow_model, player_gulletmodel);\r
        if(prey.swallow_model.skin != pred.skin) // player skin can be changed while the predator is active\r
                prey.swallow_model.skin = pred.skin;\r
        if(cvar("g_healthsize"))\r
@@ -292,10 +299,14 @@ void Vore_Swallow(entity e)
        e.predator = self;\r
        setorigin(e, e.predator.origin);\r
        e.velocity = '0 0 0';\r
+       e.punchangle = '0 0 0';\r
        e.movetype = MOVETYPE_FOLLOW;\r
        e.solid = SOLID_NOT;\r
        e.aiment = e.predator; // follow the predator, automatically unset when regurgitated\r
 \r
+       float scalediff;\r
+       scalediff = cvar("g_healthsize") ? e.scale / e.predator.scale : 1; // the tighter the gut, the greater the effect\r
+\r
        // drop keys (KH) and flags (CTF) when we get swallowed\r
        kh_Key_DropAll(e, FALSE);\r
        if(e.flagcarried)\r
@@ -314,7 +325,9 @@ void Vore_Swallow(entity e)
 \r
        PlayerSound(e.predator, playersound_swallow, CHAN_VOICE, VOICETYPE_PLAYERSOUND);\r
        setanim(e.predator, e.predator.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing / regurgitating\r
-       e.predator.punchangle_x -= cvar("g_balance_vore_swallow_predator_punchangle");\r
+       e.predator.punchangle_x = crandom() * cvar("g_balance_vore_swallow_predator_punchangle") * scalediff;\r
+       e.predator.punchangle_y = crandom() * cvar("g_balance_vore_swallow_predator_punchangle") * scalediff;\r
+       e.predator.punchangle_z = crandom() * cvar("g_balance_vore_swallow_predator_punchangle") * scalediff;\r
        e.predator.regurgitate_prepare = 0;\r
        e.predator.spawnshieldtime = 0; // lose spawn shield when we vore\r
        e.predator.hitsound += 1; // play this for team mates too, as we could be swallowing them to heal them\r
@@ -329,24 +342,46 @@ void Vore_Swallow(entity e)
 \r
 void Vore_SwallowStep(entity e)\r
 {\r
-       if(!cvar("g_balance_vore_swallow_speed_fill"))\r
+       if(!cvar("g_balance_vore_swallow_speed_fill_player"))\r
        {\r
                Vore_Swallow(e);\r
                return;\r
        }\r
 \r
-       Vore_SwallowModel_Update(e, self);\r
+       // when the predator starts swallowing, play his grab sound\r
+       if(!self.swallow_progress_pred)\r
+               PlayerSound(self, playersound_grab, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
+\r
+       // apply prey orientation\r
+       if(cvar("g_balance_vore_swallow_prey_orient"))\r
+       {\r
+               e.punchangle = self.angles - e.angles;\r
+               e.punchangle_speed = cvar("g_balance_vore_swallow_prey_orient_speed") * (1 - e.swallow_progress_prey);\r
+       }\r
+\r
+       Vore_GulletModel_Update(e, self);\r
 \r
        // increase the progress value until it reaches 1, then swallow the player\r
        if(e.swallow_progress_prey < 1)\r
        {\r
                float fill;\r
-               fill = cvar("g_balance_vore_swallow_speed_fill") * frametime;\r
-               if(cvar("g_healthsize") && cvar("g_balance_vore_swallow_speed_fill_scalediff")) // fill rate depends on predator size compared to prey size\r
-                       fill *= pow(self.scale / e.scale, cvar("g_balance_vore_swallow_speed_fill_scalediff"));\r
+               fill = cvar("g_balance_vore_swallow_speed_fill_player") * frametime;\r
+               if(cvar("g_healthsize") && cvar("g_balance_vore_swallow_speed_fill_scalediff_player")) // fill rate depends on predator size compared to prey size\r
+                       fill *= pow(self.scale / e.scale, cvar("g_balance_vore_swallow_speed_fill_scalediff_player"));\r
                if(cvar("g_balance_vore_swallow_speed_fill_stomachload") && e.stomach_load) // fill rate is influenced by the prey's stomach load\r
                        fill *= (1 - ((e.stomach_load / e.stomach_maxload) * bound(0, cvar("g_balance_vore_swallow_speed_fill_stomachload"), 1)));\r
 \r
+               // skill-based speed offset for bots\r
+               if(skill && cvar("skill_offset"))\r
+               {\r
+                       float ofs;\r
+                       ofs = pow(skill / cvar("skill_offset_center"), cvar("skill_offset"));\r
+                       if(clienttype(self) == CLIENTTYPE_BOT)\r
+                               fill *= ofs;\r
+                       if(clienttype(e) == CLIENTTYPE_BOT)\r
+                               fill /= ofs;\r
+               }\r
+\r
                e.swallow_progress_prey += fill;\r
        }\r
        else\r
@@ -370,6 +405,7 @@ void Vore_Regurgitate(entity e)
        e.punchvector_z = -cvar("g_balance_vore_regurgitate_prey_punchvector");\r
 \r
        // if the prey has been fully digested, silently detach them\r
+       if(cvar("g_balance_vore_regurgitate_death_silent"))\r
        if(e.deadflag != DEAD_NO && e.health <= cvar("g_balance_vore_digestion_limit"))\r
        {\r
                e.predator = world;\r
@@ -377,22 +413,32 @@ void Vore_Regurgitate(entity e)
                return;\r
        }\r
 \r
+       float scalediff;\r
+       scalediff = cvar("g_healthsize") ? e.scale / e.predator.scale : 1; // the tighter the gut, the greater the effect\r
+\r
        // apply velocities\r
        makevectors(e.predator.v_angle);\r
-       e.velocity = v_forward * cvar("g_balance_vore_regurgitate_force");\r
-       e.predator.velocity += -v_forward * cvar("g_balance_vore_regurgitate_predatorforce");\r
+       e.velocity = v_forward * cvar("g_balance_vore_regurgitate_force") * scalediff;\r
+       e.predator.velocity += -v_forward * cvar("g_balance_vore_regurgitate_predatorforce") * scalediff;\r
        e.pusher = e.predator; // allows us to frag players by regurgitating them in deadly pits\r
        e.pushltime = time + cvar("g_maxpushtime");\r
 \r
+       // apply prey orientation\r
+       if(cvar("g_balance_vore_swallow_prey_orient"))\r
+       {\r
+               e.punchangle = e.predator.angles - e.angles;\r
+               e.punchangle_speed = cvar("g_balance_vore_swallow_prey_orient_speed") * (1 - e.swallow_progress_prey);\r
+       }\r
+\r
        // if the dead body of the prey is below gibbing health, gib it\r
        e.stat_eaten = 0; // necessary for gibs to show\r
        PlayerGib(e, e.predator);\r
 \r
        // regurgitated prey is given this amount of swallow progress, to simulate being more vulnerable\r
-       if(cvar("g_balance_vore_swallow_speed_fill") && cvar("g_balance_vore_regurgitate_swallowprogress"))\r
+       if(cvar("g_balance_vore_swallow_speed_fill_player") && cvar("g_balance_vore_regurgitate_swallowprogress"))\r
        {\r
                e.swallow_progress_prey = cvar("g_balance_vore_regurgitate_swallowprogress");\r
-               Vore_SwallowModel_Update(e, e.predator);\r
+               Vore_GulletModel_Update(e, e.predator);\r
        }\r
 \r
        // apply regurgitation damage to the predator\r
@@ -407,8 +453,10 @@ void Vore_Regurgitate(entity e)
 \r
        PlayerSound(e.predator, playersound_regurgitate, CHAN_VOICE, VOICETYPE_PLAYERSOUND);\r
        setanim(e.predator, e.predator.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing / regurgitating\r
-       pointparticles(particleeffectnum("vore_regurgitate"), e.predator.origin, '0 0 0', 1);\r
-       e.predator.punchangle_x += cvar("g_balance_vore_regurgitate_predator_punchangle");\r
+       pointparticles(particleeffectnum("vore_regurgitate"), e.predator.origin, '0 0 0', floor(scalediff * PARTICLE_MULTIPLIER));\r
+       e.predator.punchangle_x = crandom() * cvar("g_balance_vore_regurgitate_predator_punchangle") * scalediff;\r
+       e.predator.punchangle_y = crandom() * cvar("g_balance_vore_regurgitate_predator_punchangle") * scalediff;\r
+       e.predator.punchangle_z = crandom() * cvar("g_balance_vore_regurgitate_predator_punchangle") * scalediff;\r
        e.predator.regurgitate_prepare = 0;\r
        e.predator.action_delay = time + cvar("g_balance_vore_action_delay");\r
        Vore_SetPreyPositions(e.predator);\r
@@ -419,9 +467,10 @@ void Vore_Regurgitate(entity e)
        e.predator = world;\r
 }\r
 \r
-void Vore_Disconnect()\r
+void Vore_Disconnect(float consumables)\r
 {\r
        // frees prey from their predators when someone disconnects or goes spectating, or in other circumstances\r
+       entity e;\r
 \r
        // prey disconnects or goes spectating while inside someone's belly\r
        if(self.stat_eaten)\r
@@ -434,6 +483,15 @@ void Vore_Disconnect()
                if(head.predator == self)\r
                        Vore_Regurgitate(head);\r
        }\r
+       // remove consumable items when we disconnect\r
+       if(consumables)\r
+       {\r
+               for(e = world; (e = find(e, classname, "consumable")); )\r
+               {\r
+                       if(e.predator == self)\r
+                               Item_Consumable_Remove(e, TRUE);\r
+               }\r
+       }\r
 \r
        self.stomach_load = self.gravity = 0; // prevents a bug\r
        Vore_GurgleSound(); // stop the gurgling sound\r
@@ -513,27 +571,38 @@ void Vore_StomachKick()
        if(self.deadflag != DEAD_NO)\r
                return;\r
 \r
+       float scalediff;\r
+       scalediff = pow(self.scale / self.predator.scale, cvar("g_balance_vore_kick_scalediff"));\r
+\r
        if(time > self.stomachkick_delay && !self.kick_pressed)\r
        {\r
-               float damage, vol;\r
+               float damage, vol, pitch;\r
                vector force;\r
                damage = cvar("g_balance_vore_kick_damage");\r
                force = v_forward * cvar("g_balance_vore_kick_force");\r
                vol = VOL_BASE;\r
 \r
+               // modified sound pitch, based on player scale\r
+               if(cvar("g_healthsize") && cvar("g_healthsize_pitch"))\r
+                       pitch = pow(self.predator.scale, -cvar("g_healthsize_pitch"));\r
+\r
                // apply player scale to the damage / force of the kick\r
                if(cvar("g_healthsize") && cvar("g_balance_vore_kick_scalediff"))\r
                {\r
-                       damage *= pow(self.scale / self.predator.scale, cvar("g_balance_vore_kick_scalediff"));\r
-                       force *= pow(self.scale / self.predator.scale, cvar("g_balance_vore_kick_scalediff"));\r
-                       vol *= pow(self.scale / self.predator.scale, cvar("g_balance_vore_kick_scalediff")); // kick sound volume based on the same scale\r
+                       damage *= scalediff;\r
+                       force *= scalediff;\r
+                       vol *= scalediff; // kick sound volume based on the same scale\r
                }\r
                vol = bound(0, vol, 1);\r
 \r
                Damage(self.predator, self, self, damage, DEATH_STOMACHKICK, self.predator.origin, force);\r
-               sound(self.predator, CHAN_PROJECTILE, strcat("weapons/hit", ftos(floor(random() * 8)), ".wav"), vol, ATTN_NORM);\r
-               self.predator.punchangle_x -= cvar("g_balance_vore_kick_predator_punchangle");\r
-               self.punchangle_x += cvar("g_balance_vore_kick_prey_punchangle");\r
+               sound7(self.predator, CHAN_PROJECTILE, strcat("weapons/hit", ftos(floor(random() * 8)), ".wav"), vol, ATTN_NORM, 100 * pitch, 0);\r
+               self.predator.punchangle_x = crandom() * cvar("g_balance_vore_kick_predator_punchangle") * scalediff;\r
+               self.predator.punchangle_y = crandom() * cvar("g_balance_vore_kick_predator_punchangle") * scalediff;\r
+               self.predator.punchangle_z = crandom() * cvar("g_balance_vore_kick_predator_punchangle") * scalediff;\r
+               self.punchangle_x = crandom() * cvar("g_balance_vore_kick_prey_punchangle") * scalediff;\r
+               self.punchangle_y = crandom() * cvar("g_balance_vore_kick_prey_punchangle") * scalediff;\r
+               self.punchangle_z = crandom() * cvar("g_balance_vore_kick_prey_punchangle") * scalediff;\r
 \r
                // abort the predator's scheduled regurgitation\r
                if(random() < cvar("g_balance_vore_kick_cutregurgitate"))\r
@@ -641,7 +710,6 @@ void Vore_SetSbarRings()
 }\r
 \r
 .float regurgitatecolor_particles_tick;\r
-.float grabsound;\r
 void Vore()\r
 {\r
        // main vore code, this is where it all happens\r
@@ -676,7 +744,7 @@ void Vore()
                if(cvar("g_vore_regurgitatecolor_particles"))\r
                if(self.regurgitatecolor_particles_tick < time)\r
                {\r
-                       pointparticles(particleeffectnum("vore_regurgitate_constant"), self.origin, '0 0 0', 1);\r
+                       pointparticles(particleeffectnum("vore_regurgitate_constant"), self.origin, '0 0 0', floor((cvar("g_healthsize") ? self.scale : 1) * PARTICLE_MULTIPLIER));\r
                        self.regurgitatecolor_particles_tick = time + cvar("g_vore_regurgitatecolor_particles") * vlen(self.colormod); // particle time depends on how dirty the player is\r
                }\r
        }\r
@@ -710,15 +778,17 @@ void Vore()
        {\r
                if(self.swallow_progress_pred)\r
                {\r
-                       self.swallow_progress_pred -= cvar("g_balance_vore_swallow_speed_decrease") * frametime;\r
-                       if(self.swallow_progress_pred < 0)\r
-                               self.swallow_progress_pred = 0;\r
+                       float speed = cvar("g_balance_vore_swallow_speed_decrease");\r
+                       if(cvar("g_balance_vore_swallow_speed_decrease_even"))\r
+                               speed += self.swallow_progress_prey * cvar("g_balance_vore_swallow_speed_decrease_even");\r
+                       self.swallow_progress_pred = max(0, self.swallow_progress_pred - speed * frametime);\r
                }\r
                if(self.swallow_progress_prey)\r
                {\r
-                       self.swallow_progress_prey -= cvar("g_balance_vore_swallow_speed_decrease") * frametime;\r
-                       if(self.swallow_progress_prey < 0)\r
-                               self.swallow_progress_prey = 0;\r
+                       float speed = cvar("g_balance_vore_swallow_speed_decrease");\r
+                       if(cvar("g_balance_vore_swallow_speed_decrease_even"))\r
+                               speed += self.swallow_progress_pred * cvar("g_balance_vore_swallow_speed_decrease_even");\r
+                       self.swallow_progress_prey = max(0, self.swallow_progress_prey - cvar("g_balance_vore_swallow_speed_decrease") * frametime);\r
                }\r
        }\r
 \r
@@ -728,12 +798,12 @@ void Vore()
        // apply delays and skip the vore system under some circumstances\r
        if(!cvar("g_vore")) // the vore system is disabled\r
        {\r
-               Vore_Disconnect();\r
+               Vore_Disconnect(TRUE);\r
                return;\r
        }\r
        if(time < game_starttime || (time < warmup && !inWarmupStage)) // don't allow vore before a round begins\r
        {\r
-               Vore_Disconnect();\r
+               Vore_Disconnect(FALSE);\r
                return;\r
        }\r
        if(self.spectatee_status)\r
@@ -759,18 +829,7 @@ void Vore()
                        self.stat_canswallow = 1;\r
 \r
                if(self.BUTTON_ATCK)\r
-               {\r
                        Vore_SwallowStep(prey);\r
-\r
-                       // when the predator starts swallowing, play the grab sound\r
-                       if(!self.grabsound)\r
-                       {\r
-                               PlayerSound(self, playersound_grab, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
-                               self.grabsound = TRUE;\r
-                       }\r
-               }\r
-               else if(self.grabsound)\r
-                       self.grabsound = FALSE; // clear the grab sound\r
        }\r
        else if(prey != world)\r
                self.stat_canswallow = -1;\r
@@ -798,6 +857,7 @@ void Vore()
 \r
        // predator wishes to regurgitate his prey\r
        if(self.BUTTON_REGURGITATE && time > self.action_delay)\r
+       if(!self.regurgitate_prepare)\r
        {\r
                if(self.stomach_load)\r
                {\r
@@ -870,9 +930,8 @@ void Vore()
        // apply delayed regurgitating if it was scheduled\r
        if(self.predator.regurgitate_prepare && time > self.predator.regurgitate_prepare)\r
        {\r
-               self.predator.regurgitate_prepare = 0;\r
-               self.predator.complain_vore = time + complain_delay_time; // prevent complaining the next frame if this empties our stomach\r
                Vore_Regurgitate(self);\r
+               self.predator.complain_vore = time + complain_delay_time; // prevent complaining the next frame if this empties our stomach\r
        }\r
 \r
        // execute digesting and team healing\r
@@ -899,4 +958,4 @@ void Vore()
 \r
        // always position camera at the center of the stomach, to reduce probability of the view poking out\r
        self.view_ofs_z = PL_PREY_VIEW_OFS_z * self.predator.scale;\r
-}
\ No newline at end of file
+}\r