X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=data%2Fqcsrc%2Fserver%2Fcl_player.qc;h=c0887e40ab197aa7869cb645a8433ddb21273f8f;hb=cf4f57c4dedbc5059d219d6199ba924594c6468a;hp=bef0ec68355d2b26fd0af6c57ac306384673c69a;hpb=3c344811f2558a51041374ffe7d9771e3d57547a;p=voretournament%2Fvoretournament.git diff --git a/data/qcsrc/server/cl_player.qc b/data/qcsrc/server/cl_player.qc index bef0ec68..c0887e40 100644 --- a/data/qcsrc/server/cl_player.qc +++ b/data/qcsrc/server/cl_player.qc @@ -104,8 +104,6 @@ void WeaponStats_LogKill(float awep, float vwep) void CopyBody(float keepvelocity) { local entity oldself; - if (self.fakeprey) - return; if (self.effects & EF_NODRAW || self.alpha < 0) return; oldself = self; @@ -114,6 +112,7 @@ void CopyBody(float keepvelocity) self.lip = oldself.lip; self.colormap = oldself.colormap; self.colormod = oldself.colormod; + self.glowmod = oldself.glowmod; self.iscreature = oldself.iscreature; self.angles = oldself.angles; self.avelocity = oldself.avelocity; @@ -143,6 +142,7 @@ void CopyBody(float keepvelocity) self.solid = oldself.solid; self.takedamage = oldself.takedamage; self.think = oldself.think; + self.scale = oldself.scale; self.customizeentityforclient = oldself.customizeentityforclient; self.uncustomizeentityforclient = oldself.uncustomizeentityforclient; self.uncustomizeentityforclient_set = oldself.uncustomizeentityforclient_set; @@ -218,76 +218,41 @@ float player_getspecies() void player_setupanimsformodel() { - local string animfilename; - local float animfile; // defaults for legacy .zym models without animinfo files - self.anim_die1 = '0 1 0.5'; // 2 seconds - self.anim_die2 = '1 1 0.5'; // 2 seconds - self.anim_draw = '2 1 3'; // TODO: analyze models and set framerate - self.anim_duck = '3 1 100'; // this anim seems bogus in most models, so make it play VERY briefly! - self.anim_duckwalk = '4 1 1'; - self.anim_duckjump = '5 1 100'; // zym anims keep playing until changed, so this only has to start the anim, landing will end it - self.anim_duckidle = '6 1 1'; - self.anim_idle = '7 1 1'; - self.anim_jump = '8 1 100'; // zym anims keep playing until changed, so this only has to start the anim, landing will end it - self.anim_pain1 = '9 1 2'; // 0.5 seconds - self.anim_pain2 = '10 1 2'; // 0.5 seconds - self.anim_shoot = '11 1 5'; // TODO: analyze models and set framerate - self.anim_taunt = '12 1 0.33'; // FIXME? there is no code using this anim - self.anim_run = '13 1 1'; - self.anim_runbackwards = '14 1 1'; - self.anim_strafeleft = '15 1 1'; - self.anim_straferight = '16 1 1'; - self.anim_dead1 = '17 1 1'; - self.anim_dead2 = '18 1 1'; - self.anim_forwardright = '19 1 1'; - self.anim_forwardleft = '20 1 1'; - self.anim_backright = '21 1 1'; - self.anim_backleft = '22 1 1'; - animparseerror = FALSE; - animfilename = strcat(self.model, ".animinfo"); - animfile = fopen(animfilename, FILE_READ); - if (animfile >= 0) - { - self.anim_die1 = animparseline(animfile); - self.anim_die2 = animparseline(animfile); - self.anim_draw = animparseline(animfile); - self.anim_duck = animparseline(animfile); - self.anim_duckwalk = animparseline(animfile); - self.anim_duckjump = animparseline(animfile); - self.anim_duckidle = animparseline(animfile); - self.anim_idle = animparseline(animfile); - self.anim_jump = animparseline(animfile); - self.anim_pain1 = animparseline(animfile); - self.anim_pain2 = animparseline(animfile); - self.anim_shoot = animparseline(animfile); - self.anim_taunt = animparseline(animfile); - self.anim_run = animparseline(animfile); - self.anim_runbackwards = animparseline(animfile); - self.anim_strafeleft = animparseline(animfile); - self.anim_straferight = animparseline(animfile); - self.anim_forwardright = animparseline(animfile); - self.anim_forwardleft = animparseline(animfile); - self.anim_backright = animparseline(animfile); - self.anim_backleft = animparseline(animfile); - fclose(animfile); - - // derived anims - self.anim_dead1 = '0 1 1' + '1 0 0' * (self.anim_die1_x + self.anim_die1_y - 1); - self.anim_dead2 = '0 1 1' + '1 0 0' * (self.anim_die2_x + self.anim_die2_y - 1); - - if (animparseerror) - print("Parse error in ", animfilename, ", some player animations are broken\n"); - } - else - dprint("File ", animfilename, " not found, assuming legacy .zym model animation timings\n"); - - // the line below is disabled due to issues with the stomach model, which cannot be animated. - // customizeentityforclient cannot let this part of the code know whether it's the stomach model or normal - // player model we're using. Attempting to animate the stomach model causes BIG issues, and must not be allowed. - + self.anim_die1 = animfixfps(self, '0 1 0.5'); // 2 seconds + self.anim_die2 = animfixfps(self, '1 1 0.5'); // 2 seconds + self.anim_draw = animfixfps(self, '2 1 3'); + // self.anim_duck = '3 1 100'; // This anim is broken, use slot 3 as a new free slot in the future ;) + self.anim_duckwalk = animfixfps(self, '4 1 1'); + self.anim_duckjump = '5 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it + self.anim_duckidle = animfixfps(self, '6 1 1'); + self.anim_idle = animfixfps(self, '7 1 1'); + self.anim_jump = '8 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it + self.anim_pain1 = animfixfps(self, '9 1 2'); // 0.5 seconds + self.anim_pain2 = animfixfps(self, '10 1 2'); // 0.5 seconds + self.anim_shoot = animfixfps(self, '11 1 5'); // analyze models and set framerate + self.anim_taunt = animfixfps(self, '12 1 0.33'); + self.anim_run = animfixfps(self, '13 1 1'); + self.anim_runbackwards = animfixfps(self, '14 1 1'); + self.anim_strafeleft = animfixfps(self, '15 1 1'); + self.anim_straferight = animfixfps(self, '16 1 1'); + //self.anim_dead1 = animfixfps(self, '17 1 1'); + //self.anim_dead2 = animfixfps(self, '18 1 1'); + self.anim_forwardright = animfixfps(self, '19 1 1'); + self.anim_forwardleft = animfixfps(self, '20 1 1'); + self.anim_backright = animfixfps(self, '21 1 1'); + self.anim_backleft = animfixfps(self, '22 1 1'); + self.anim_melee = animfixfps(self, '23 1 1'); + self.anim_duckwalkbackwards = animfixfps(self, '24 1 1'); + self.anim_duckwalkstrafeleft = animfixfps(self, '25 1 1'); + self.anim_duckwalkstraferight = animfixfps(self, '26 1 1'); + self.anim_duckwalkforwardright = animfixfps(self, '27 1 1'); + self.anim_duckwalkforwardleft = animfixfps(self, '28 1 1'); + self.anim_duckwalkbackright = animfixfps(self, '29 1 1'); + self.anim_duckwalkbackleft = animfixfps(self, '30 1 1'); + // TODO introspect models for finding right "fps" value (1/duration) // reset animstate now - //setanim(self, self.anim_idle, TRUE, FALSE, TRUE); + setanim(self, self.anim_idle, TRUE, FALSE, TRUE); }; void player_anim (void) @@ -312,7 +277,18 @@ void player_anim (void) if (!self.animstate_override) { - if (!(self.flags & FL_ONGROUND)) + if(self.swallow_progress_pred) + setanim(self, self.anim_duckjump, TRUE, FALSE, FALSE); // looks good for predators who are swallowing + else if(self.swallow_progress_prey) + setanim(self, self.anim_die2, FALSE, FALSE, FALSE); // looks good for prey who's getting swallowed + else if(self.stat_eaten) + { + if(self.BUTTON_ATCK || self.predator.digesting) + setanim(self, self.anim_pain2, FALSE, TRUE, FALSE); // looks good for prey attacking the stomach or being digested + else + setanim(self, self.anim_jump, FALSE, TRUE, FALSE); // looks good for prey idling inside the stomach + } + else if (!(self.flags & FL_ONGROUND)) { if (self.crouch) setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump); @@ -322,8 +298,22 @@ void player_anim (void) } else if (self.crouch) { - if (self.movement_x * self.movement_x + self.movement_y * self.movement_y > 20) + if (self.movement_x > 0 && self.movement_y == 0) setanim(self, self.anim_duckwalk, TRUE, FALSE, FALSE); + else if (self.movement_x < 0 && self.movement_y == 0) + setanim(self, self.anim_duckwalkbackwards, TRUE, FALSE, FALSE); + else if (self.movement_x == 0 && self.movement_y > 0) + setanim(self, self.anim_duckwalkstraferight, TRUE, FALSE, FALSE); + else if (self.movement_x == 0 && self.movement_y < 0) + setanim(self, self.anim_duckwalkstrafeleft, TRUE, FALSE, FALSE); + else if (self.movement_x > 0 && self.movement_y > 0) + setanim(self, self.anim_duckwalkforwardright, TRUE, FALSE, FALSE); + else if (self.movement_x > 0 && self.movement_y < 0) + setanim(self, self.anim_duckwalkforwardleft, TRUE, FALSE, FALSE); + else if (self.movement_x < 0 && self.movement_y > 0) + setanim(self, self.anim_duckwalkbackright, TRUE, FALSE, FALSE); + else if (self.movement_x < 0 && self.movement_y < 0) + setanim(self, self.anim_duckwalkbackleft, TRUE, FALSE, FALSE); else setanim(self, self.anim_duckidle, TRUE, FALSE, FALSE); } @@ -354,12 +344,21 @@ void player_anim (void) if (self.weaponentity) if (!self.weaponentity.animstate_override) - setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE); + { + if(self.swallow_progress_pred) + setanim(self.weaponentity, self.weaponentity.anim_fire2, TRUE, FALSE, FALSE); // looks good for predators who are swallowing + else if(self.swallow_progress_prey) + setanim(self.weaponentity, self.weaponentity.anim_reload, TRUE, FALSE, FALSE); // looks good for prey who's getting swallowed + else if(self.stat_eaten && self.BUTTON_ATCK) + setanim(self.weaponentity, self.weaponentity.anim_fire1, TRUE, FALSE, FALSE); // looks good for prey attacking the stomach + else + setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE); + } } -void SpawnThrownWeapon (vector org, float w) +void SpawnThrownWeapon (vector org, float w, float doreduce) { - W_ThrowWeapon(randomvec() * 125 + '0 0 200', org - self.origin, FALSE); + W_ThrowWeapon(randomvec() * 125 + '0 0 200', org - self.origin, doreduce); } void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) @@ -402,18 +401,7 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float self.dmg_take = self.dmg_take + take;//max(take - 10, 0); self.dmg_inflictor = inflictor; - if (self.health <= -75 && self.modelindex != 0) - { - // don't use any animations as a gib - self.frame = 0; - self.dead_frame = 0; - // view just above the floor - self.view_ofs = '0 0 4'; - - Violence_GibSplash(self, 1, 1, attacker); - self.modelindex = 0; // restore later - self.solid = SOLID_NOT; // restore later - } + PlayerGib(self, attacker); } void ClientKill_Now_TeamChange(); @@ -593,7 +581,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // clear selected player display ClearSelectedPlayer(); // throw a weapon - SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon); + SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon, FALSE); // print an obituary message Obituary (attacker, inflictor, self, deathtype); race_PreDie(); @@ -614,19 +602,25 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht } // clear waypoints WaypointSprite_PlayerDead(); - // make the corpse upright (not tilted) - self.angles_x = 0; - self.angles_z = 0; - // don't spin - self.avelocity = '0 0 0'; - // view from the floor - self.view_ofs = '0 0 -8'; - // toss the corpse - self.movetype = MOVETYPE_TOSS; - // shootable corpse - self.solid = SOLID_CORPSE; - // don't stick to the floor - self.flags &~= FL_ONGROUND; + + // configure these properties if the dead body is not a prey + if(!self.stat_eaten) + { + // make the corpse upright (not tilted) + self.angles_x = 0; + self.angles_z = 0; + // don't spin + self.avelocity = '0 0 0'; + // view from the floor + self.view_ofs = '0 0 -8'; + // toss the corpse + self.movetype = MOVETYPE_TOSS; + // shootable corpse + self.solid = SOLID_CORPSE; + // don't stick to the floor + self.flags &~= FL_ONGROUND; + } + // dying animation self.deadflag = DEAD_DYING; // when to allow respawn @@ -745,7 +739,6 @@ void ClearSelectedPlayer() } } -.float dropweapon_check; void UpdateSelectedPlayer() { entity selected; @@ -753,12 +746,12 @@ void UpdateSelectedPlayer() selected = world; selected_score = 0.95; // 18 degrees - if(self.predator.classname == "player") + if(self.stat_eaten) { if(!self.dropweapon_check) if(self.predator.team != self.team) // don't disarm team mates when swallowing them if(random() < cvar("g_balance_vore_swallow_dropweapon")) - SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon); + SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon, TRUE); self.dropweapon_check = TRUE; } else @@ -1211,10 +1204,12 @@ void UpdatePlayerSounds() LoadPlayerSounds(strcat(self.model, ".sounds"), 0); } -void GlobalSound(string sample, float chan, float voicetype) +void GlobalSound(string sample, float chan, float voicetype, float vol) { float n; float tauntrand; + float vol_scale, vol_prey, vol_apply; + float pitch; if(sample == "") return; @@ -1226,6 +1221,17 @@ void GlobalSound(string sample, float chan, float voicetype) else sample = strcat(argv(0), ".wav"); // randomization + // modified volume, used for attenuated (non-radio) voices + vol_scale = vol_prey = 1; + if(cvar("g_healthsize") && cvar("g_healthsize_soundfactor")) // amplify or reduce sound volume based on the size of the player + vol_scale *= bound(0, pow(self.scale, cvar("g_healthsize_soundfactor")), 1); + if(self.stat_eaten && cvar("g_vore_soundocclusion")) // reduce sound volume for prey, to simulate stomach culling + vol_prey *= bound(0, cvar("g_vore_soundocclusion"), 1); + + // modified sound pitch, based on player scale + if(cvar("g_healthsize") && cvar("g_healthsize_pitch")) + pitch = pow(self.scale, -cvar("g_healthsize_pitch")); + switch(voicetype) { case VOICETYPE_LASTATTACKER_ONLY: @@ -1237,13 +1243,12 @@ void GlobalSound(string sample, float chan, float voicetype) { if(msg_entity.cvar_cl_voice_directional == 1) { - if(self.predator.classname == "player") - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE * bound(0, cvar("g_vore_soundocclusion"), 1), ATTN_MIN); - else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); + vol_apply = vol; + vol_apply *= (self.predator != msg_entity.predator && self != msg_entity) ? vol_scale * vol_prey : vol_scale; + soundto(MSG_ONE, self, chan, sample, vol_apply, ATTN_MIN, pitch); } else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); + soundto(MSG_ONE, self, chan, sample, vol, ATTN_NONE, pitch); } } break; @@ -1256,17 +1261,16 @@ void GlobalSound(string sample, float chan, float voicetype) { if(msg_entity.cvar_cl_voice_directional == 1) { - if(self.predator.classname == "player") - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE * bound(0, cvar("g_vore_soundocclusion"), 1), ATTN_MIN); - else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); + vol_apply = vol; + vol_apply *= (self.predator != msg_entity.predator && self != msg_entity) ? vol_scale * vol_prey : vol_scale; + soundto(MSG_ONE, self, chan, sample, vol_apply, ATTN_MIN, pitch); } else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); + soundto(MSG_ONE, self, chan, sample, vol, ATTN_NONE, pitch); } msg_entity = self; if(clienttype(msg_entity) == CLIENTTYPE_REAL) - soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NONE); + soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NONE, pitch); } break; case VOICETYPE_TEAMRADIO: @@ -1275,13 +1279,12 @@ void GlobalSound(string sample, float chan, float voicetype) { if(msg_entity.cvar_cl_voice_directional == 1) { - if(self.predator.classname == "player") - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE * bound(0, cvar("g_vore_soundocclusion"), 1), ATTN_MIN); - else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); + vol_apply = vol; + vol_apply *= (self.predator != msg_entity.predator && self != msg_entity) ? vol_scale * vol_prey : vol_scale; + soundto(MSG_ONE, self, chan, sample, vol_apply, ATTN_MIN, pitch); } else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); + soundto(MSG_ONE, self, chan, sample, vol, ATTN_NONE, pitch); } break; case VOICETYPE_AUTOTAUNT: @@ -1293,18 +1296,17 @@ void GlobalSound(string sample, float chan, float voicetype) break; tauntrand = random(); FOR_EACH_REALCLIENT(msg_entity) - { if (tauntrand < msg_entity.cvar_cl_autotaunt) - if (msg_entity.cvar_cl_voice_directional >= 1) { - if(self.predator.classname == "player") - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE * bound(0, cvar("g_vore_soundocclusion"), 1), bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX)); + if (msg_entity.cvar_cl_voice_directional >= 1) + { + vol_apply = vol; + vol_apply *= (self.predator != msg_entity.predator && self != msg_entity) ? vol_scale * vol_prey : vol_scale; + soundto(MSG_ONE, self, chan, sample, vol_apply, bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX), pitch); + } else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX)); + soundto(MSG_ONE, self, chan, sample, vol, ATTN_NONE, pitch); } - else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); - } break; case VOICETYPE_TAUNT: if(self.classname == "player") @@ -1318,23 +1320,25 @@ void GlobalSound(string sample, float chan, float voicetype) { if (msg_entity.cvar_cl_voice_directional >= 1) { - if(self.predator.classname == "player") - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE * bound(0, cvar("g_vore_soundocclusion"), 1), bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX)); - else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX)); + vol_apply = vol; + vol_apply *= (self.predator != msg_entity.predator && self != msg_entity) ? vol_scale * vol_prey : vol_scale; + soundto(MSG_ONE, self, chan, sample, vol_apply, bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX), pitch); } else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); + soundto(MSG_ONE, self, chan, sample, vol, ATTN_NONE, pitch); } case VOICETYPE_PLAYERSOUND: - if(self.predator.classname == "player") - sound(self, chan, sample, VOL_BASE * bound(0, cvar("g_vore_soundocclusion"), 1), ATTN_NORM); - else - sound(self, chan, sample, VOL_BASE, ATTN_NORM); + FOR_EACH_REALCLIENT(msg_entity) + { + vol_apply = vol; + vol_apply *= (self.predator != msg_entity.predator && self != msg_entity) ? vol_scale * vol_prey : vol_scale; + soundto(MSG_ONE, self, chan, sample, vol_apply, ATTN_NORM, pitch); + } break; case VOICETYPE_GURGLE: + // since players can't be prey and predators at the same time, we don't use the prey modifier for the gurgle sound volume if(self.stomach_load) - sound(self, chan, sample, VOL_BASE * self.stomach_load / cvar("g_balance_vore_swallow_limit"), ATTN_NORM); + sound7(self, chan, sample, bound(0, vol_scale * (self.stomach_load / self.stomach_maxload), 1), ATTN_NORM, pitch * 100, 0); else stopsound(self, chan); break; @@ -1352,7 +1356,7 @@ void PlayerSound(entity player, .string samplefield, float chan, float voicetype oldself = self; self = player; sample = self.samplefield; - GlobalSound(sample, chan, voicetype); + GlobalSound(sample, chan, voicetype, VOL_BASEVOICE); self = oldself; }