X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=data%2Fqcsrc%2Fserver%2Fcl_client.qc;h=33406554dd2ac92b7a0780b3b54c26205b6719ee;hb=c52c03d5245ba090e31c0d5b7da630940647292b;hp=69404cb855267f1d807420b5d3d3622b6083b3dc;hpb=a59798ff492b6bb761c12d8c3e97dad25d236cd4;p=voretournament%2Fvoretournament.git diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index 69404cb8..33406554 100644 --- a/data/qcsrc/server/cl_client.qc +++ b/data/qcsrc/server/cl_client.qc @@ -396,7 +396,7 @@ Checks if the argument string can be a valid playermodel. Returns a valid one in doubt. ============= */ -string FallbackPlayerModel = "models/player/vixen.zym"; +string FallbackPlayerModel = "models/player/vixen.iqm"; string CheckPlayerModel(string plyermodel) { if(strlen(plyermodel) < 4) return FallbackPlayerModel; @@ -435,8 +435,16 @@ string setmodel_state() newmodel_name = substring(self.playermodel, 0, strlen(self.playermodel) - 4); newmodel_extension = substring(self.playermodel, strlen(self.playermodel) - 4, 4); - if(self.stomach_load) - applymodel = strcat(newmodel_name, "_state", ftos(floor(self.stomach_load)), newmodel_extension); + float vore_state; + if(self.stomach_load > self.stomach_maxload * 0.75) + vore_state = 3; + else if(self.stomach_load > self.stomach_maxload * 0.5) + vore_state = 2; + else if(self.stomach_load > self.stomach_maxload * 0.25) + vore_state = 1; + + if(vore_state) + applymodel = strcat(newmodel_name, "_state", ftos(vore_state), newmodel_extension); else applymodel = self.playermodel; @@ -451,7 +459,7 @@ Client_customizeentityforclient void Client_setmodel(string applymodel) { local vector m1, m2; - if(self.classname != "player" || self.deadflag != DEAD_NO) // prevent some bugs + if(self.classname != "player") // prevent some bugs return; if(applymodel == self.model || self.spectatee_status) // no change to apply return; @@ -515,23 +523,32 @@ float Client_customizeentityforclient() // this is only visible to the prey however, otherwise players would appear as a floating stomach to everyone (ewww) stomachmodel = strcat(substring(self.playermodel, 0, strlen(self.playermodel) - 4), "_stomach.md3"); // 4 is the extension length - if(other.spectatee_status) + float chase; + chase = other.cvar_chase_active; + + if(other.spectatee_status && other.spectatee_status == num_for_edict(other.enemy)) other = other.enemy; // also do this for the player we are spectating // don't do this if we have chase_active enabled, as we'd be seeing a floating stomach from third person view - if not(other.cvar_chase_active || other.classname == "observer") // the observer check prevents a bug - if(other.predator == self || other.fakepredator == self) + if not(chase || other.classname == "observer") // the observer check prevents a bug + if(other.predator == self) { Client_setmodel(stomachmodel); + self.angles_x = self.angles_z = 0; // don't apply player leaning to stomach models + self.effects |= EF_NODEPTHTEST; // don't hide behind walls self.alpha = other.cvar_cl_vore_stomachmodel; return TRUE; } Client_setmodel(setmodel_state()); - if not(self.stat_eaten || self.fakeprey) + self.effects &~= EF_NODEPTHTEST; + if not(self.stat_eaten) self.alpha = default_player_alpha; - else if(cvar("g_vore_neighborprey_distance") && (self.predator == other.predator || self.predator == other.fakepredator) && self != other && !(other.cvar_chase_active || other.classname == "observer")) + else if(cvar("g_vore_neighborprey_distance") && self.predator == other.predator && !(chase || other.classname == "observer")) + { self.alpha = default_player_alpha; // allow seeing neighboring prey + self.effects |= EF_NODEPTHTEST; // don't hide behind the stomach's own EF_NODEPTHTEST + } else self.alpha = -1; // hide prey return TRUE; @@ -564,6 +581,13 @@ void PutObserverInServer (void) } Vore_Disconnect(); + entity e; + for(e = world; (e = find(e, classname, "consumable")); ) + { + // remove consumable items when we spectate + if(e.predator == self) + Item_Consumable_Remove(e, TRUE); + } kh_Key_DropAll(self, TRUE); @@ -599,7 +623,7 @@ void PutObserverInServer (void) self.health = -666; self.takedamage = DAMAGE_NO; self.solid = SOLID_NOT; - self.movetype = MOVETYPE_NOCLIP; + self.movetype = MOVETYPE_FLY_WORLDONLY; // user preference is controlled by playerprethink self.flags = FL_CLIENT | FL_NOTARGET; self.armorvalue = 666; self.effects = 0; @@ -628,9 +652,9 @@ void PutObserverInServer (void) self.fixangle = TRUE; self.crouch = FALSE; - self.view_ofs = PL_VIEW_OFS; + self.view_ofs = '0 0 0'; // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS" setorigin (self, spot.origin); - setsize (self, '0 0 0', '0 0 0'); + setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY self.prevorigin = self.origin; self.items = 0; self.weapons = 0; @@ -786,6 +810,8 @@ Called when a client spawns in the server //void() ctf_playerchanged; void PutClientInServer (void) { + entity e; + if(clienttype(self) == CLIENTTYPE_BOT) { self.classname = "player"; @@ -830,8 +856,14 @@ void PutClientInServer (void) RemoveGrabber(self); // Wazat's Grabber - Vore_DeadPrey_Detach(self); - self.fakeprey = FALSE; // clear the fakeprey status + Vore_Disconnect(); + self.swallow_progress_pred = self.swallow_progress_prey = 0; + for(e = world; (e = find(e, classname, "consumable")); ) + { + // remove consumable items when we respawn + if(e.predator == self) + Item_Consumable_Remove(e, FALSE); + } self.classname = "player"; self.wasplayer = TRUE; @@ -912,6 +944,7 @@ void PutClientInServer (void) self.angles_z = 0; // never spawn tilted even if the spot says to self.fixangle = TRUE; // turn this way immediately + self.leanangle_damage_force = '0 0 0'; self.velocity = '0 0 0'; self.avelocity = '0 0 0'; self.punchangle = '0 0 0'; @@ -983,6 +1016,7 @@ void PutClientInServer (void) if (cvar("g_spawnsound")) sound (self, CHAN_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTN_NORM); + pointparticles(particleeffectnum("player_respawn"), self.origin, '0 0 0', 1); if(g_assault) { if(self.team == assault_attacker_team) @@ -999,10 +1033,9 @@ void PutClientInServer (void) weapon_action(j, WR_RESETPLAYER); // all weapons must be fully loaded when we spawn - entity e; e = get_weaponinfo(j); if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars - self.weapon_load[j] = cvar(strcat("g_balance_", e.netname, "_reload_ammo")); + self.(weapon_load[j]) = cvar(strcat("g_balance_", e.netname, "_reload_ammo")); } oldself = self; @@ -1030,12 +1063,33 @@ float ClientInit_SendEntity(entity to, float sf) WriteString(MSG_ENTITY, world.fog); else WriteString(MSG_ENTITY, ""); - WriteCoord(MSG_ENTITY, cvar("g_campaign")); + WriteShort(MSG_ENTITY, cvar("g_campaign")); WriteByte(MSG_ENTITY, cvar("g_balance_armor_blockpercent") * 255.0); WriteByte(MSG_ENTITY, cvar("g_balance_weaponswitchdelay") * 255.0); - WriteCoord(MSG_ENTITY, cvar("g_vore")); - WriteCoord(MSG_ENTITY, cvar("g_balance_vore_swallow_limit")); + WriteShort(MSG_ENTITY, cvar("g_vore")); + if(cvar("g_healthsize")) + WriteShort(MSG_ENTITY, cvar("g_healthsize_center")); + else + WriteShort(MSG_ENTITY, -1); // healthsize is disabled + WriteShort(MSG_ENTITY, cvar("g_healthsize_min")); + WriteShort(MSG_ENTITY, cvar("g_healthsize_max")); + + // tell the client if this server uses armor + float armor_max; + if(cvar("g_balance_armor_start") || (cvar("g_lms") && cvar("g_lms_start_armor")) /*|| (inWarmupStage && cvar("g_warmup_start_armor"))*/ || cvar("g_balance_armor_regen") || cvar("g_balance_armor_regenlinear")) + armor_max = cvar("g_balance_armor_limit"); + WriteCoord(MSG_ENTITY, armor_max); + + float teamheal_max; + if(cvar("g_vore") && cvar("g_vore_teamvore") && cvar("g_balance_vore_teamheal")) + teamheal_max = cvar("g_balance_vore_teamheal_stable"); + WriteCoord(MSG_ENTITY, teamheal_max); + + WriteShort(MSG_ENTITY, cvar("g_power")); + WriteShort(MSG_ENTITY, cvar("g_power_reboot")); + WriteByte(MSG_ENTITY, cvar("g_power_reboot_spawn")); + return TRUE; } @@ -1090,6 +1144,7 @@ Called when a client types 'kill' in the console ============= */ +.float clientkill_nexttime; void ClientKill_Now_TeamChange() { if(self.killindicator_teamchange == -1) @@ -1097,24 +1152,32 @@ void ClientKill_Now_TeamChange() self.team = -1; JoinBestTeam( self, FALSE, FALSE ); } + else if(self.killindicator_teamchange == -2) + { + if(g_ca) + self.caplayer = 0; + if(blockSpectators) + sprint(self, strcat("^7You have to become a player within the next ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n")); + PutObserverInServer(); + } else SV_ChangeTeam(self.killindicator_teamchange - 1); } void ClientKill_Now() -{ +{ + if(self.killindicator && !wasfreed(self.killindicator)) + remove(self.killindicator); + + self.killindicator = world; + if(self.killindicator_teamchange) ClientKill_Now_TeamChange(); // in any case: Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0'); - if(self.killindicator) - { - dprint("Cleaned up after a leaked kill indicator.\n"); - remove(self.killindicator); - self.killindicator = world; - } + // now I am sure the player IS dead } void KillIndicator_Think() { @@ -1131,6 +1194,11 @@ void KillIndicator_Think() ClientKill_Now(); // no oldself needed return; } + else if(g_cts && self.health == 1) // health == 1 means that it's silent + { + self.nextthink = time + 1; + self.cnt -= 1; + } else { if(self.cnt <= 10) @@ -1143,6 +1211,8 @@ void KillIndicator_Think() { if(self.owner.killindicator_teamchange == -1) centerprint(self.owner, strcat("Changing team in ", ftos(self.cnt), " seconds")); + else if(self.owner.killindicator_teamchange == -2) + centerprint(self.owner, strcat("Spectating in ", ftos(self.cnt), " seconds")); else centerprint(self.owner, strcat("Changing to ", ColoredTeamName(self.owner.killindicator_teamchange), " in ", ftos(self.cnt), " seconds")); } @@ -1154,19 +1224,34 @@ void KillIndicator_Think() } } -void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto +void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2 = spec { float killtime; entity e; killtime = cvar("g_balance_kill_delay"); - if(g_race_qualifying) + if(g_race_qualifying || g_cts) killtime = 0; + if(g_cts && self.killindicator && self.killindicator.health == 1) // self.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill + { + remove(self.killindicator); + self.killindicator = world; + + ClientKill_Now(); // allow instant kill in this case + return; + } + self.killindicator_teamchange = targetteam; - if(!self.killindicator) + if(!self.killindicator) { + if(self.modelindex && self.deadflag == DEAD_NO) + { + killtime = max(killtime, self.clientkill_nexttime - time); + self.clientkill_nexttime = time + killtime + cvar("g_balance_kill_antispam"); + } + if(killtime <= 0 || !self.modelindex || self.deadflag != DEAD_NO) { ClientKill_Now(); @@ -1182,7 +1267,7 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto self.killindicator.nextthink = time + (self.lip) * 0.05; self.killindicator.cnt = ceil(killtime); self.killindicator.count = bound(0, ceil(killtime), 10); - sprint(self, strcat("^1You'll be dead in ", ftos(self.killindicator.cnt), " seconds\n")); + //sprint(self, strcat("^1You'll be dead in ", ftos(self.killindicator.cnt), " seconds\n")); for(e = world; (e = find(e, classname, "body")) != world; ) { @@ -1202,22 +1287,42 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto } if(self.killindicator) { - if(targetteam) - self.killindicator.colormod = TeamColor(targetteam); - else + if(targetteam == 0) // just die self.killindicator.colormod = '0 0 0'; + else if(targetteam == -1) // auto + self.killindicator.colormod = '0 1 0'; + else if(targetteam == -2) // spectate + self.killindicator.colormod = '0.5 0.5 0.5'; + else + self.killindicator.colormod = TeamColor(targetteam); } } void ClientKill (void) { - ClientKill_TeamChange(0); + if((g_arena || g_ca) && ((champion && champion.classname == "player" && player_count > 1) || player_count == 1)) // don't allow a kill in this case either + { + // do nothing + } + else + ClientKill_TeamChange(0); +} + +void CTS_ClientKill (entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed +{ + e.killindicator = spawn(); + e.killindicator.owner = e; + e.killindicator.think = KillIndicator_Think; + e.killindicator.nextthink = time + (e.lip) * 0.05; + e.killindicator.cnt = ceil(cvar("g_cts_finish_kill_delay")); + e.killindicator.health = 1; // this is used to indicate that it should be silent + e.lip = 0; } void DoTeamChange(float destteam) { float t, c0; - if(!teams_matter) + if(!teamplay) { if(destteam >= 0) SetPlayerColors(self, destteam); @@ -1437,8 +1542,7 @@ void ClientConnect (void) ctf_clientconnect(); }*/ - if(teams_matter || radar_showennemies) - attach_entcs(); + attach_entcs(); bot_relinkplayerlist(); @@ -1519,7 +1623,6 @@ Called when a client disconnects from the server ============= */ .entity chatbubbleentity; -.entity teambubbleentity; void ReadyCount(); void ClientDisconnect (void) { @@ -1530,6 +1633,13 @@ void ClientDisconnect (void) } Vore_Disconnect(); + entity e; + for(e = world; (e = find(e, classname, "consumable")); ) + { + // remove consumable items when we disconnect + if(e.predator == self) + Item_Consumable_Remove(e, TRUE); + } CheatShutdownClient(); @@ -1567,9 +1677,6 @@ void ClientDisconnect (void) if (self.chatbubbleentity) remove (self.chatbubbleentity); - if (self.teambubbleentity) - remove (self.teambubbleentity); - if (self.killindicator) remove (self.killindicator); @@ -1614,7 +1721,7 @@ void ChatBubbleThink() remove(self); return; } - if ((self.owner.BUTTON_CHAT && !self.owner.deadflag && !self.owner.stat_eaten && self.owner.fakepredator.classname != "player") + if ((self.owner.BUTTON_CHAT && !self.owner.deadflag && !self.owner.stat_eaten) #ifdef TETRIS || self.owner.tetris_on #endif @@ -1646,57 +1753,6 @@ void UpdateChatBubble() } } -void TeamBubbleThink() -{ - self.nextthink = time; - if (!self.owner.modelindex || self.owner.teambubbleentity != self) - { - if(self.owner) // but why can that ever be world? - self.owner.teambubbleentity = world; - remove(self); - return; - } -// setorigin(self, self.owner.origin + '0 0 15' + self.owner.maxs_z * '0 0 1'); // bandwidth hog. setattachment does this now - if (self.owner.BUTTON_CHAT || self.owner.deadflag || self.owner.killindicator || self.owner.stat_eaten) - self.model = ""; - else - { - if(cvar("g_balance_vore_teamheal") && cvar("g_vore_teamvore")) - if(self.owner.health < cvar("g_balance_vore_teamheal_stable")) - setmodel(self, "models/misc/teambubbleheal.spr"); // indicate that this player can be teamhealed - else - setmodel(self, "models/misc/teambubble.spr"); - } -}; - -float TeamBubble_customizeentityforclient() -{ - return (self.owner != other && self.owner.team == other.team && other.killcount > -666); -} - -void UpdateTeamBubble() -{ - if (!self.modelindex || !teams_matter) - return; - // spawn a teambubble entity if needed - if (!self.teambubbleentity && teams_matter) - { - self.teambubbleentity = spawn(); - self.teambubbleentity.owner = self; - self.teambubbleentity.exteriormodeltoclient = self; - self.teambubbleentity.think = TeamBubbleThink; - self.teambubbleentity.nextthink = time; - setmodel(self.teambubbleentity, "models/misc/teambubble.spr"); // precision set below -// setorigin(self.teambubbleentity, self.origin + '0 0 15' + self.maxs_z * '0 0 1'); - setorigin(self.teambubbleentity, '0 0 15' + self.maxs_z * '0 0 1'); - setattachment(self.teambubbleentity, self, ""); // sticks to moving player better, also conserves bandwidth -// self.teambubbleentity.mdl = self.teambubbleentity.model; -// self.teambubbleentity.model = self.teambubbleentity.mdl; - self.teambubbleentity.customizeentityforclient = TeamBubble_customizeentityforclient; - self.teambubbleentity.effects = EF_LOWPRECISION; - } -} - // LordHavoc: this hack will be removed when proper _pants/_shirt layers are // added to the model skins /*void UpdateColorModHack() @@ -1716,6 +1772,12 @@ void UpdateTeamBubble() .float oldcolormap; void respawn(void) { + // don't allow respawing if the prey is still digesting + if(cvar("g_balance_vore_digestion_limit_blockrespawn")) + if(self.predator.digesting && self.health > cvar("g_balance_vore_digestion_limit")) + return; + + setmodel(self, self.playermodel); // prevents an issue with dead predators if(self.alpha >= 0 && self.modelindex != 0 && cvar("g_respawn_ghosts")) { self.solid = SOLID_NOT; @@ -2078,7 +2140,10 @@ void SpectateCopy(entity spectatee) { self.fixangle = TRUE; self.stomach_load = spectatee.stomach_load; self.stat_eaten = spectatee.stat_eaten; + self.swallow_progress_prey = spectatee.swallow_progress_prey; + self.swallow_progress_pred = spectatee.swallow_progress_pred; self.stat_stomachload = spectatee.stat_stomachload; + self.stat_stomachmaxload = spectatee.stomach_maxload; self.stat_digesting = spectatee.stat_digesting; self.stat_canleave = spectatee.stat_canleave; self.stat_canswallow = spectatee.stat_canswallow; @@ -2277,13 +2342,16 @@ float vercmp(string v1, string v2) return vercmp_recursive(v1, v2); } +.float last_alive_scale; void SetPlayerSize() { - if(cvar("g_healthsize")) + if(!cvar("g_healthsize")) + return; + + if(self.deadflag == DEAD_NO) { // change player scale based on the amount of health we have - - self.scale = bound(cvar("g_healthsize_min"), self.health, cvar("g_healthsize_max")) / cvar("g_healthsize"); + self.scale = pow(bound(cvar("g_healthsize_min"), self.health, cvar("g_healthsize_max")) / cvar("g_healthsize_center"), cvar("g_healthsize")); // The following code sets the bounding box to match the player's size. // It is currently disabled because of issues with engine movement prediction (cl_movement). @@ -2301,28 +2369,41 @@ void SetPlayerSize() if(!self.stat_eaten) self.view_ofs = PL_VIEW_OFS * self.scale; } + + self.last_alive_scale = self.scale; + } + else if(self.last_alive_scale) + { + // if the player is dead, use the last scale he had when he was alive + self.scale = self.last_alive_scale; } - if(self.stat_eaten && cvar("g_vore_neighborprey_distance")) + if(cvar("g_healthsize_death") && self.deadflag != DEAD_NO) { - // resize prey if neighborprey is enabled - self.scale *= cvar("g_vore_neighborprey_scale"); + // dead players shrink to zero as they head toward the health limit + self.scale *= 1 - bound(0, (self.health / cvar("g_healthsize_death_min")) * cvar("g_healthsize_death"), 1); } + + if(self.scale < 0.1) + self.scale = 0.1; // stuff breaks if scale is smaller than this } void ObserverThink() { + float prefered_movetype; if (self.flags & FL_JUMPRELEASED) { if (self.BUTTON_JUMP && !self.version_mismatch) { - self.welcomemessage_time = 0; self.flags &~= FL_JUMPRELEASED; self.flags |= FL_SPAWNING; } else if(self.BUTTON_ATCK && !self.version_mismatch) { - self.welcomemessage_time = 0; self.flags &~= FL_JUMPRELEASED; if(SpectateNext() == 1) { self.classname = "spectator"; } + } else { + prefered_movetype = ((!self.BUTTON_USE ? self.cvar_cl_clippedspectating : !self.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP); + if (self.movetype != prefered_movetype) + self.movetype = prefered_movetype; } } else { if (!(self.BUTTON_ATCK || self.BUTTON_JUMP)) { @@ -2335,6 +2416,7 @@ void ObserverThink() } } } + PrintWelcomeMessage(self); } @@ -2392,6 +2474,8 @@ Called every frame for each client before the physics are run */ void() ctf_setstatus; .float items_added; +.vector avg_vel; +.float power_sounded; void PlayerPreThink (void) { self.stat_game_starttime = game_starttime; @@ -2422,6 +2506,18 @@ void PlayerPreThink (void) // core code for the vore system Vore(); + // play power fail sound + if(self.armorvalue < cvar("g_power")) + { + if(!self.power_sounded) + { + sound(self, CHAN_TRIGGER, "misc/power_fail.ogg", VOL_BASE, ATTN_NORM); + self.power_sounded = TRUE; + } + } + else + self.power_sounded = FALSE; + // version nagging if(self.version_nagtime) if(self.cvar_g_voretournamentversion) @@ -2496,8 +2592,85 @@ void PlayerPreThink (void) self.fixangle = TRUE; } + if(self.deadflag == DEAD_NO && !self.stat_eaten) // prevents bugs + { + // lean the player with damage and acceleration + // credits go to divVerent for these maths :) + vector L0, L1, LF, LA; + + LA = AnglesTransform_FromAngles(self.angles); + + // acceleration leaning + if(cvar("g_leanplayer_acceleration")) + { + // average velocity to obtain a smooth acceleration + float f; + f = frametime * cvar("g_leanplayer_acceleration_fade"); + self.avg_vel = self.avg_vel * (1 - f) + self.velocity * f; + } + + vector accel; + accel = self.velocity - self.avg_vel * cvar("g_leanplayer_acceleration"); // acceleration + + // bound angles to the specified limit + accel_x = bound(-cvar("g_leanplayer_acceleration_max"), accel_x, cvar("g_leanplayer_acceleration_max")); + accel_y = bound(-cvar("g_leanplayer_acceleration_max"), accel_y, cvar("g_leanplayer_acceleration_max")); + accel_z = bound(-cvar("g_leanplayer_acceleration_max"), accel_z, cvar("g_leanplayer_acceleration_max")); + + L0_x = vlen(accel) * -1; + L0_y = L1_y = vectoyaw(accel); + + L0 = AnglesTransform_FromAngles(L0); + L1 = AnglesTransform_FromAngles(L1); + LF = AnglesTransform_Multiply(AnglesTransform_Invert(L1), L0); + LA = AnglesTransform_Multiply(LA, LF); + // end of acceleration leaning + + // damage leaning + L0 = vectoangles(self.leanangle_damage_loc); + L1 = vectoangles(self.leanangle_damage_loc + self.leanangle_damage_force); + + L0 = AnglesTransform_FromAngles(L0); + L1 = AnglesTransform_FromAngles(L1); + LF = AnglesTransform_Multiply(AnglesTransform_Invert(L1), L0); + + LA = AnglesTransform_Multiply(LA, LF); + + // fade the player back to normal rotation each frame + self.leanangle_damage_force = self.leanangle_damage_force * cvar("g_leanplayer_damage_fade"); + // end of damage leaning + + self.angles = AnglesTransform_Normalize(AnglesTransform_ToAngles(LA), TRUE); + } + + SetPlayerSize(); + if(frametime) { + if(self.health <= 0 && cvar("g_deathglow")) + { + if(self.glowmod_x > 0) + self.glowmod_x -= cvar("g_deathglow") * frametime; + else + self.glowmod_x = -1; + if(self.glowmod_y > 0) + self.glowmod_y -= cvar("g_deathglow") * frametime; + else + self.glowmod_y = -1; + if(self.glowmod_z > 0) + self.glowmod_z -= cvar("g_deathglow") * frametime; + else + self.glowmod_z = -1; + } + else + { + // set weapon and player glowmod + self.glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2; + if(self.armorvalue < cvar("g_power")) + self.glowmod = self.glowmod * random(); // make glow flicker when power is down + self.weaponentity_glowmod = self.glowmod; + } + player_powerups(); } @@ -2632,8 +2805,6 @@ void PlayerPreThink (void) } } - SetPlayerSize(); - FixPlayermodel(); GrabberFrame(); @@ -2837,7 +3008,6 @@ void PlayerPostThink (void) if(self.classname == "player") { CheckRules_Player(); UpdateChatBubble(); - UpdateTeamBubble(); if (self.impulse) ImpulseCommands(); if (intermission_running)