aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/game/PlayerView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jake2/game/PlayerView.java')
-rw-r--r--src/jake2/game/PlayerView.java2110
1 files changed, 1062 insertions, 1048 deletions
diff --git a/src/jake2/game/PlayerView.java b/src/jake2/game/PlayerView.java
index 289aa0f..4fd338b 100644
--- a/src/jake2/game/PlayerView.java
+++ b/src/jake2/game/PlayerView.java
@@ -1,1054 +1,1068 @@
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ * Copyright (C) 1997-2001 Id Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// Created on 28.12.2003 by RST.
+// $Id: PlayerView.java,v 1.2 2004-09-22 19:22:03 salomo Exp $
+package jake2.game;
-*/
+import jake2.Defines;
+import jake2.Globals;
+import jake2.util.Lib;
+import jake2.util.Math3D;
+
+public class PlayerView {
+
+ public static edict_t current_player;
+
+ public static gclient_t current_client;
+
+ public static float[] forward = { 0, 0, 0 };
+
+ public static float[] right = { 0, 0, 0 };
+
+ public static float[] up = { 0, 0, 0 };
+
+ /*
+ * =============== SV_CalcRoll
+ *
+ * ===============
+ */
+ public static float SV_CalcRoll(float[] angles, float[] velocity) {
+ float sign;
+ float side;
+ float value;
+
+ side = Math3D.DotProduct(velocity, right);
+ sign = side < 0 ? -1 : 1;
+ side = Math.abs(side);
+
+ value = GameBase.sv_rollangle.value;
+
+ if (side < GameBase.sv_rollspeed.value)
+ side = side * value / GameBase.sv_rollspeed.value;
+ else
+ side = value;
+
+ return side * sign;
+ }
+
+ /*
+ * =============== P_DamageFeedback
+ *
+ * Handles color blends and view kicks ===============
+ */
+
+ public static void P_DamageFeedback(edict_t player) {
+ gclient_t client;
+ float side;
+ float realcount, count, kick;
+ float[] v = { 0, 0, 0 };
+ int r, l;
+ float[] power_color = { 0.0f, 1.0f, 0.0f };
+ float[] acolor = { 1.0f, 1.0f, 1.0f };
+ float[] bcolor = { 1.0f, 0.0f, 0.0f };
+
+ client = player.client;
+
+ // flash the backgrounds behind the status numbers
+ client.ps.stats[Defines.STAT_FLASHES] = 0;
+ if (client.damage_blood != 0)
+ client.ps.stats[Defines.STAT_FLASHES] |= 1;
+ if (client.damage_armor != 0
+ && 0 == (player.flags & Defines.FL_GODMODE)
+ && (client.invincible_framenum <= GameBase.level.framenum))
+ client.ps.stats[Defines.STAT_FLASHES] |= 2;
+
+ // total points of damage shot at the player this frame
+ count = (client.damage_blood + client.damage_armor + client.damage_parmor);
+
+ if (count == 0)
+ return; // didn't take any damage
+
+ // start a pain animation if still in the player model
+ if ((client.anim_priority < Defines.ANIM_PAIN)
+ & (player.s.modelindex == 255)) {
+ client.anim_priority = Defines.ANIM_PAIN;
+ if ((client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0) {
+ player.s.frame = M_Player.FRAME_crpain1 - 1;
+ client.anim_end = M_Player.FRAME_crpain4;
+ } else {
+
+ xxxi = (xxxi + 1) % 3;
+ switch (xxxi) {
+ case 0:
+ player.s.frame = M_Player.FRAME_pain101 - 1;
+ client.anim_end = M_Player.FRAME_pain104;
+ break;
+ case 1:
+ player.s.frame = M_Player.FRAME_pain201 - 1;
+ client.anim_end = M_Player.FRAME_pain204;
+ break;
+ case 2:
+ player.s.frame = M_Player.FRAME_pain301 - 1;
+ client.anim_end = M_Player.FRAME_pain304;
+ break;
+ }
+ }
+ }
+
+ realcount = count;
+ if (count < 10)
+ count = 10; // always make a visible effect
+
+ // play an apropriate pain sound
+ if ((GameBase.level.time > player.pain_debounce_time)
+ && 0 == (player.flags & Defines.FL_GODMODE)
+ && (client.invincible_framenum <= GameBase.level.framenum)) {
+ r = 1 + (Lib.rand() & 1);
+ player.pain_debounce_time = GameBase.level.time + 0.7f;
+ if (player.health < 25)
+ l = 25;
+ else if (player.health < 50)
+ l = 50;
+ else if (player.health < 75)
+ l = 75;
+ else
+ l = 100;
+ GameBase.gi.sound(player, Defines.CHAN_VOICE, GameBase.gi
+ .soundindex("*pain" + l + "_" + r + ".wav"), 1,
+ Defines.ATTN_NORM, 0);
+ }
+
+ // the total alpha of the blend is always proportional to count
+ if (client.damage_alpha < 0)
+ client.damage_alpha = 0;
+ client.damage_alpha += count * 0.01f;
+ if (client.damage_alpha < 0.2f)
+ client.damage_alpha = 0.2f;
+ if (client.damage_alpha > 0.6f)
+ client.damage_alpha = 0.6f; // don't go too saturated
+
+ // the color of the blend will vary based on how much was absorbed
+ // by different armors
+ Math3D.VectorClear(v);
+ if (client.damage_parmor != 0)
+ Math3D.VectorMA(v, (float) client.damage_parmor / realcount,
+ power_color, v);
+
+ if (client.damage_armor != 0)
+ Math3D.VectorMA(v, (float) client.damage_armor / realcount, acolor,
+ v);
+
+ if (client.damage_blood != 0)
+ Math3D.VectorMA(v, (float) client.damage_blood / realcount, bcolor,
+ v);
+ Math3D.VectorCopy(v, client.damage_blend);
+
+ //
+ // calculate view angle kicks
+ //
+ kick = Math.abs(client.damage_knockback);
+ if (kick != 0 && player.health > 0) // kick of 0 means no view adjust at
+ // all
+ {
+ kick = kick * 100 / player.health;
+
+ if (kick < count * 0.5)
+ kick = count * 0.5f;
+ if (kick > 50)
+ kick = 50;
+
+ Math3D.VectorSubtract(client.damage_from, player.s.origin, v);
+ Math3D.VectorNormalize(v);
+
+ side = Math3D.DotProduct(v, right);
+ client.v_dmg_roll = kick * side * 0.3f;
+
+ side = -Math3D.DotProduct(v, forward);
+ client.v_dmg_pitch = kick * side * 0.3f;
+
+ client.v_dmg_time = GameBase.level.time + Defines.DAMAGE_TIME;
+ }
+
+ //
+ // clear totals
+ //
+ client.damage_blood = 0;
+ client.damage_armor = 0;
+ client.damage_parmor = 0;
+ client.damage_knockback = 0;
+ }
+
+ /*
+ * =============== SV_CalcViewOffset
+ *
+ * Auto pitching on slopes?
+ *
+ * fall from 128: 400 = 160000 fall from 256: 580 = 336400 fall from 384:
+ * 720 = 518400 fall from 512: 800 = 640000 fall from 640: 960 =
+ *
+ * damage = deltavelocity*deltavelocity * 0.0001
+ *
+ * ===============
+ */
+ public static void SV_CalcViewOffset(edict_t ent) {
+ float angles[] = { 0, 0, 0 };
+ float bob;
+ float ratio;
+ float delta;
+ float[] v = { 0, 0, 0 };
+
+ //===================================
+
+ // base angles
+ angles = ent.client.ps.kick_angles;
+
+ // if dead, fix the angle and don't add any kick
+ if (ent.deadflag != 0) {
+ Math3D.VectorClear(angles);
+
+ ent.client.ps.viewangles[Defines.ROLL] = 40;
+ ent.client.ps.viewangles[Defines.PITCH] = -15;
+ ent.client.ps.viewangles[Defines.YAW] = ent.client.killer_yaw;
+ } else {
+ // add angles based on weapon kick
+
+ Math3D.VectorCopy(ent.client.kick_angles, angles);
+
+ // add angles based on damage kick
+
+ ratio = (ent.client.v_dmg_time - GameBase.level.time)
+ / Defines.DAMAGE_TIME;
+ if (ratio < 0) {
+ ratio = 0;
+ ent.client.v_dmg_pitch = 0;
+ ent.client.v_dmg_roll = 0;
+ }
+ angles[Defines.PITCH] += ratio * ent.client.v_dmg_pitch;
+ angles[Defines.ROLL] += ratio * ent.client.v_dmg_roll;
+
+ // add pitch based on fall kick
+
+ ratio = (ent.client.fall_time - GameBase.level.time)
+ / Defines.FALL_TIME;
+ if (ratio < 0)
+ ratio = 0;
+ angles[Defines.PITCH] += ratio * ent.client.fall_value;
+
+ // add angles based on velocity
+
+ delta = Math3D.DotProduct(ent.velocity, forward);
+ angles[Defines.PITCH] += delta * GameBase.run_pitch.value;
+
+ delta = Math3D.DotProduct(ent.velocity, right);
+ angles[Defines.ROLL] += delta * GameBase.run_roll.value;
+
+ // add angles based on bob
+
+ delta = bobfracsin * GameBase.bob_pitch.value * xyspeed;
+ if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0)
+ delta *= 6; // crouching
+ angles[Defines.PITCH] += delta;
+ delta = bobfracsin * GameBase.bob_roll.value * xyspeed;
+ if ((ent.client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0)
+ delta *= 6; // crouching
+ if ((bobcycle & 1) != 0)
+ delta = -delta;
+ angles[Defines.ROLL] += delta;
+ }
+
+ //===================================
+
+ // base origin
+
+ Math3D.VectorClear(v);
+
+ // add view height
+
+ v[2] += ent.viewheight;
+
+ // add fall height
+
+ ratio = (ent.client.fall_time - GameBase.level.time)
+ / Defines.FALL_TIME;
+ if (ratio < 0)
+ ratio = 0;
+ v[2] -= ratio * ent.client.fall_value * 0.4;
+
+ // add bob height
+
+ bob = bobfracsin * xyspeed * GameBase.bob_up.value;
+ if (bob > 6)
+ bob = 6;
+ //gi.DebugGraph (bob *2, 255);
+ v[2] += bob;
+
+ // add kick offset
+
+ Math3D.VectorAdd(v, ent.client.kick_origin, v);
+
+ // absolutely bound offsets
+ // so the view can never be outside the player box
+
+ if (v[0] < -14)
+ v[0] = -14;
+ else if (v[0] > 14)
+ v[0] = 14;
+ if (v[1] < -14)
+ v[1] = -14;
+ else if (v[1] > 14)
+ v[1] = 14;
+ if (v[2] < -22)
+ v[2] = -22;
+ else if (v[2] > 30)
+ v[2] = 30;
+
+ Math3D.VectorCopy(v, ent.client.ps.viewoffset);
+ }
+
+ /*
+ * ============== SV_CalcGunOffset ==============
+ */
+ public static void SV_CalcGunOffset(edict_t ent) {
+ int i;
+ float delta;
+
+ // gun angles from bobbing
+ ent.client.ps.gunangles[Defines.ROLL] = xyspeed * bobfracsin * 0.005f;
+ ent.client.ps.gunangles[Defines.YAW] = xyspeed * bobfracsin * 0.01f;
+ if ((bobcycle & 1) != 0) {
+ ent.client.ps.gunangles[Defines.ROLL] = -ent.client.ps.gunangles[Defines.ROLL];
+ ent.client.ps.gunangles[Defines.YAW] = -ent.client.ps.gunangles[Defines.YAW];
+ }
+
+ ent.client.ps.gunangles[Defines.PITCH] = xyspeed * bobfracsin * 0.005f;
+
+ // gun angles from delta movement
+ for (i = 0; i < 3; i++) {
+ delta = ent.client.oldviewangles[i] - ent.client.ps.viewangles[i];
+ if (delta > 180)
+ delta -= 360;
+ if (delta < -180)
+ delta += 360;
+ if (delta > 45)
+ delta = 45;
+ if (delta < -45)
+ delta = -45;
+ if (i == Defines.YAW)
+ ent.client.ps.gunangles[Defines.ROLL] += 0.1 * delta;
+ ent.client.ps.gunangles[i] += 0.2 * delta;
+ }
+
+ // gun height
+ Math3D.VectorClear(ent.client.ps.gunoffset);
+ // ent.ps.gunorigin[2] += bob;
+
+ // gun_x / gun_y / gun_z are development tools
+ for (i = 0; i < 3; i++) {
+ ent.client.ps.gunoffset[i] += forward[i] * (GameBase.gun_y.value);
+ ent.client.ps.gunoffset[i] += right[i] * GameBase.gun_x.value;
+ ent.client.ps.gunoffset[i] += up[i] * (-GameBase.gun_z.value);
+ }
+ }
+
+ /*
+ * ============= SV_AddBlend =============
+ */
+ public static void SV_AddBlend(float r, float g, float b, float a,
+ float v_blend[]) {
+ float a2, a3;
+
+ if (a <= 0)
+ return;
+ a2 = v_blend[3] + (1 - v_blend[3]) * a; // new total alpha
+ a3 = v_blend[3] / a2; // fraction of color from old
+
+ v_blend[0] = v_blend[0] * a3 + r * (1 - a3);
+ v_blend[1] = v_blend[1] * a3 + g * (1 - a3);
+ v_blend[2] = v_blend[2] * a3 + b * (1 - a3);
+ v_blend[3] = a2;
+ }
+
+ /*
+ * ============= SV_CalcBlend =============
+ */
+ public static void SV_CalcBlend(edict_t ent) {
+ int contents;
+ float[] vieworg = { 0, 0, 0 };
+ int remaining;
+
+ ent.client.ps.blend[0] = ent.client.ps.blend[1] = ent.client.ps.blend[2] = ent.client.ps.blend[3] = 0;
+
+ // add for contents
+ Math3D.VectorAdd(ent.s.origin, ent.client.ps.viewoffset, vieworg);
+ contents = GameBase.gi.pointcontents.pointcontents(vieworg);
+ if ((contents & (Defines.CONTENTS_LAVA | Defines.CONTENTS_SLIME | Defines.CONTENTS_WATER)) != 0)
+ ent.client.ps.rdflags |= Defines.RDF_UNDERWATER;
+ else
+ ent.client.ps.rdflags &= ~Defines.RDF_UNDERWATER;
+
+ if ((contents & (Defines.CONTENTS_SOLID | Defines.CONTENTS_LAVA)) != 0)
+ SV_AddBlend(1.0f, 0.3f, 0.0f, 0.6f, ent.client.ps.blend);
+ else if ((contents & Defines.CONTENTS_SLIME) != 0)
+ SV_AddBlend(0.0f, 0.1f, 0.05f, 0.6f, ent.client.ps.blend);
+ else if ((contents & Defines.CONTENTS_WATER) != 0)
+ SV_AddBlend(0.5f, 0.3f, 0.2f, 0.4f, ent.client.ps.blend);
+
+ // add for powerups
+ if (ent.client.quad_framenum > GameBase.level.framenum) {
+ remaining = (int) (ent.client.quad_framenum - GameBase.level.framenum);
+ if (remaining == 30) // beginning to fade
+ GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi
+ .soundindex("items/damage2.wav"), 1, Defines.ATTN_NORM,
+ 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(0, 0, 1, 0.08f, ent.client.ps.blend);
+ } else if (ent.client.invincible_framenum > GameBase.level.framenum) {
+ remaining = (int) ent.client.invincible_framenum
+ - GameBase.level.framenum;
+ if (remaining == 30) // beginning to fade
+ GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi
+ .soundindex("items/protect2.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(1, 1, 0, 0.08f, ent.client.ps.blend);
+ } else if (ent.client.enviro_framenum > GameBase.level.framenum) {
+ remaining = (int) ent.client.enviro_framenum
+ - GameBase.level.framenum;
+ if (remaining == 30) // beginning to fade
+ GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi
+ .soundindex("items/airout.wav"), 1, Defines.ATTN_NORM,
+ 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(0, 1, 0, 0.08f, ent.client.ps.blend);
+ } else if (ent.client.breather_framenum > GameBase.level.framenum) {
+ remaining = (int) ent.client.breather_framenum
+ - GameBase.level.framenum;
+ if (remaining == 30) // beginning to fade
+ GameBase.gi.sound(ent, Defines.CHAN_ITEM, GameBase.gi
+ .soundindex("items/airout.wav"), 1, Defines.ATTN_NORM,
+ 0);
+ if (remaining > 30 || (remaining & 4) != 0)
+ SV_AddBlend(0.4f, 1, 0.4f, 0.04f, ent.client.ps.blend);
+ }
+
+ // add for damage
+ if (ent.client.damage_alpha > 0)
+ SV_AddBlend(ent.client.damage_blend[0], ent.client.damage_blend[1],
+ ent.client.damage_blend[2], ent.client.damage_alpha,
+ ent.client.ps.blend);
+
+ if (ent.client.bonus_alpha > 0)
+ SV_AddBlend(0.85f, 0.7f, 0.3f, ent.client.bonus_alpha,
+ ent.client.ps.blend);
+
+ // drop the damage value
+ ent.client.damage_alpha -= 0.06;
+ if (ent.client.damage_alpha < 0)
+ ent.client.damage_alpha = 0;
+
+ // drop the bonus value
+ ent.client.bonus_alpha -= 0.1;
+ if (ent.client.bonus_alpha < 0)
+ ent.client.bonus_alpha = 0;
+ }
+
+ /*
+ * ================= P_FallingDamage =================
+ */
+ public static void P_FallingDamage(edict_t ent) {
+ float delta;
+ int damage;
+ float[] dir = { 0, 0, 0 };
+
+ if (ent.s.modelindex != 255)
+ return; // not in the player model
+
+ if (ent.movetype == Defines.MOVETYPE_NOCLIP)
+ return;
+
+ if ((ent.client.oldvelocity[2] < 0)
+ && (ent.velocity[2] > ent.client.oldvelocity[2])
+ && (null == ent.groundentity)) {
+ delta = ent.client.oldvelocity[2];
+ } else {
+ if (ent.groundentity == null)
+ return;
+ delta = ent.velocity[2] - ent.client.oldvelocity[2];
+ }
+ delta = delta * delta * 0.0001f;
+
+ // never take falling damage if completely underwater
+ if (ent.waterlevel == 3)
+ return;
+ if (ent.waterlevel == 2)
+ delta *= 0.25;
+ if (ent.waterlevel == 1)
+ delta *= 0.5;
+
+ if (delta < 1)
+ return;
+
+ if (delta < 15) {
+ ent.s.event = Defines.EV_FOOTSTEP;
+ return;
+ }
+
+ ent.client.fall_value = delta * 0.5f;
+ if (ent.client.fall_value > 40)
+ ent.client.fall_value = 40;
+ ent.client.fall_time = GameBase.level.time + Defines.FALL_TIME;
+
+ if (delta > 30) {
+ if (ent.health > 0) {
+ if (delta >= 55)
+ ent.s.event = Defines.EV_FALLFAR;
+ else
+ ent.s.event = Defines.EV_FALL;
+ }
+ ent.pain_debounce_time = GameBase.level.time; // no normal pain
+ // sound
+ damage = (int) ((delta - 30) / 2);
+ if (damage < 1)
+ damage = 1;
+ Math3D.VectorSet(dir, 0, 0, 1);
+
+ if (GameBase.deathmatch.value == 0
+ || 0 == ((int) GameBase.dmflags.value & Defines.DF_NO_FALLING))
+ GameUtil.T_Damage(ent, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], dir, ent.s.origin,
+ Globals.vec3_origin, damage, 0, 0, Defines.MOD_FALLING);
+ } else {
+ ent.s.event = Defines.EV_FALLSHORT;
+ return;
+ }
+ }
+
+ /*
+ * ============= P_WorldEffects =============
+ */
+ public static void P_WorldEffects() {
+ boolean breather;
+ boolean envirosuit;
+ int waterlevel, old_waterlevel;
+
+ if (current_player.movetype == Defines.MOVETYPE_NOCLIP) {
+ current_player.air_finished = GameBase.level.time + 12; // don't
+ // need air
+ return;
+ }
+
+ waterlevel = current_player.waterlevel;
+ old_waterlevel = current_client.old_waterlevel;
+ current_client.old_waterlevel = waterlevel;
+
+ breather = current_client.breather_framenum > GameBase.level.framenum;
+ envirosuit = current_client.enviro_framenum > GameBase.level.framenum;
+
+ //
+ // if just entered a water volume, play a sound
+ //
+ if (old_waterlevel == 0 && waterlevel != 0) {
+ GameWeapon.PlayerNoise(current_player, current_player.s.origin,
+ Defines.PNOISE_SELF);
+ if ((current_player.watertype & Defines.CONTENTS_LAVA) != 0)
+ GameBase.gi.sound(current_player, Defines.CHAN_BODY,
+ GameBase.gi.soundindex("player/lava_in.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else if ((current_player.watertype & Defines.CONTENTS_SLIME) != 0)
+ GameBase.gi.sound(current_player, Defines.CHAN_BODY,
+ GameBase.gi.soundindex("player/watr_in.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else if ((current_player.watertype & Defines.CONTENTS_WATER) != 0)
+ GameBase.gi.sound(current_player, Defines.CHAN_BODY,
+ GameBase.gi.soundindex("player/watr_in.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ current_player.flags |= Defines.FL_INWATER;
+
+ // clear damage_debounce, so the pain sound will play immediately
+ current_player.damage_debounce_time = GameBase.level.time - 1;
+ }
+
+ //
+ // if just completely exited a water volume, play a sound
+ //
+ if (old_waterlevel != 0 && waterlevel == 0) {
+ GameWeapon.PlayerNoise(current_player, current_player.s.origin,
+ Defines.PNOISE_SELF);
+ GameBase.gi
+ .sound(current_player, Defines.CHAN_BODY, GameBase.gi
+ .soundindex("player/watr_out.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ current_player.flags &= ~Defines.FL_INWATER;
+ }
+
+ //
+ // check for head just going under water
+ //
+ if (old_waterlevel != 3 && waterlevel == 3) {
+ GameBase.gi.sound(current_player, Defines.CHAN_BODY, GameBase.gi
+ .soundindex("player/watr_un.wav"), 1, Defines.ATTN_NORM, 0);
+ }
+
+ //
+ // check for head just coming out of water
+ //
+ if (old_waterlevel == 3 && waterlevel != 3) {
+ if (current_player.air_finished < GameBase.level.time) { // gasp for
+ // air
+ GameBase.gi.sound(current_player, Defines.CHAN_VOICE,
+ GameBase.gi.soundindex("player/gasp1.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ GameWeapon.PlayerNoise(current_player, current_player.s.origin,
+ Defines.PNOISE_SELF);
+ } else if (current_player.air_finished < GameBase.level.time + 11) { // just
+ // break
+ // surface
+ GameBase.gi.sound(current_player, Defines.CHAN_VOICE,
+ GameBase.gi.soundindex("player/gasp2.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ }
+ }
+
+ //
+ // check for drowning
+ //
+ if (waterlevel == 3) {
+ // breather or envirosuit give air
+ if (breather || envirosuit) {
+ current_player.air_finished = GameBase.level.time + 10;
+
+ if (((int) (current_client.breather_framenum - GameBase.level.framenum) % 25) == 0) {
+ if (current_client.breather_sound == 0)
+ GameBase.gi.sound(current_player, Defines.CHAN_AUTO,
+ GameBase.gi.soundindex("player/u_breath1.wav"),
+ 1, Defines.ATTN_NORM, 0);
+ else
+ GameBase.gi.sound(current_player, Defines.CHAN_AUTO,
+ GameBase.gi.soundindex("player/u_breath2.wav"),
+ 1, Defines.ATTN_NORM, 0);
+ current_client.breather_sound ^= 1;
+ GameWeapon.PlayerNoise(current_player,
+ current_player.s.origin, Defines.PNOISE_SELF);
+ //FIXME: release a bubble?
+ }
+ }
+
+ // if out of air, start drowning
+ if (current_player.air_finished < GameBase.level.time) { // drown!
+ if (current_player.client.next_drown_time < GameBase.level.time
+ && current_player.health > 0) {
+ current_player.client.next_drown_time = GameBase.level.time + 1;
+
+ // take more damage the longer underwater
+ current_player.dmg += 2;
+ if (current_player.dmg > 15)
+ current_player.dmg = 15;
+
+ // play a gurp sound instead of a normal pain sound
+ if (current_player.health <= current_player.dmg)
+ GameBase.gi.sound(current_player, Defines.CHAN_VOICE,
+ GameBase.gi.soundindex("player/drown1.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else if ((Lib.rand() & 1) != 0)
+ GameBase.gi.sound(current_player, Defines.CHAN_VOICE,
+ GameBase.gi.soundindex("*gurp1.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else
+ GameBase.gi.sound(current_player, Defines.CHAN_VOICE,
+ GameBase.gi.soundindex("*gurp2.wav"), 1,
+ Defines.ATTN_NORM, 0);
+
+ current_player.pain_debounce_time = GameBase.level.time;
+
+ GameUtil.T_Damage(current_player, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ current_player.s.origin, Globals.vec3_origin,
+ current_player.dmg, 0, Defines.DAMAGE_NO_ARMOR,
+ Defines.MOD_WATER);
+ }
+ }
+ } else {
+ current_player.air_finished = GameBase.level.time + 12;
+ current_player.dmg = 2;
+ }
+
+ //
+ // check for sizzle damage
+ //
+ if (waterlevel != 0
+ && 0 != (current_player.watertype & (Defines.CONTENTS_LAVA | Defines.CONTENTS_SLIME))) {
+ if ((current_player.watertype & Defines.CONTENTS_LAVA) != 0) {
+ if (current_player.health > 0
+ && current_player.pain_debounce_time <= GameBase.level.time
+ && current_client.invincible_framenum < GameBase.level.framenum) {
+ if ((Lib.rand() & 1) != 0)
+ GameBase.gi.sound(current_player, Defines.CHAN_VOICE,
+ GameBase.gi.soundindex("player/burn1.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else
+ GameBase.gi.sound(current_player, Defines.CHAN_VOICE,
+ GameBase.gi.soundindex("player/burn2.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ current_player.pain_debounce_time = GameBase.level.time + 1;
+ }
+
+ if (envirosuit) // take 1/3 damage with envirosuit
+ GameUtil.T_Damage(current_player, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ current_player.s.origin, Globals.vec3_origin,
+ 1 * waterlevel, 0, 0, Defines.MOD_LAVA);
+ else
+ GameUtil.T_Damage(current_player, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ current_player.s.origin, Globals.vec3_origin,
+ 3 * waterlevel, 0, 0, Defines.MOD_LAVA);
+ }
+
+ if ((current_player.watertype & Defines.CONTENTS_SLIME) != 0) {
+ if (!envirosuit) { // no damage from slime with envirosuit
+ GameUtil.T_Damage(current_player, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ current_player.s.origin, Globals.vec3_origin,
+ 1 * waterlevel, 0, 0, Defines.MOD_SLIME);
+ }
+ }
+ }
+ }
+
+ /*
+ * =============== G_SetClientEffects ===============
+ */
+ public static void G_SetClientEffects(edict_t ent) {
+ int pa_type;
+ int remaining;
+
+ ent.s.effects = 0;
+ ent.s.renderfx = 0;
+
+ if (ent.health <= 0 || GameBase.level.intermissiontime != 0)
+ return;
+
+ if (ent.powerarmor_time > GameBase.level.time) {
+ pa_type = GameUtil.PowerArmorType(ent);
+ if (pa_type == Defines.POWER_ARMOR_SCREEN) {
+ ent.s.effects |= Defines.EF_POWERSCREEN;
+ } else if (pa_type == Defines.POWER_ARMOR_SHIELD) {
+ ent.s.effects |= Defines.EF_COLOR_SHELL;
+ ent.s.renderfx |= Defines.RF_SHELL_GREEN;
+ }
+ }
+
+ if (ent.client.quad_framenum > GameBase.level.framenum) {
+ remaining = (int) ent.client.quad_framenum
+ - GameBase.level.framenum;
+ if (remaining > 30 || 0 != (remaining & 4))
+ ent.s.effects |= Defines.EF_QUAD;
+ }
+
+ if (ent.client.invincible_framenum > GameBase.level.framenum) {
+ remaining = (int) ent.client.invincible_framenum
+ - GameBase.level.framenum;
+ if (remaining > 30 || 0 != (remaining & 4))
+ ent.s.effects |= Defines.EF_PENT;
+ }
+
+ // show cheaters!!!
+ if ((ent.flags & Defines.FL_GODMODE) != 0) {
+ ent.s.effects |= Defines.EF_COLOR_SHELL;
+ ent.s.renderfx |= (Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE);
+ }
+ }
+
+ /*
+ * =============== G_SetClientEvent ===============
+ */
+ public static void G_SetClientEvent(edict_t ent) {
+ if (ent.s.event != 0)
+ return;
+
+ if (ent.groundentity != null && xyspeed > 225) {
+ if ((int) (current_client.bobtime + bobmove) != bobcycle)
+ ent.s.event = Defines.EV_FOOTSTEP;
+ }
+ }
+
+ /*
+ * =============== G_SetClientSound ===============
+ */
+ public static void G_SetClientSound(edict_t ent) {
+ String weap;
+
+ if (ent.client.pers.game_helpchanged != GameBase.game.helpchanged) {
+ ent.client.pers.game_helpchanged = GameBase.game.helpchanged;
+ ent.client.pers.helpchanged = 1;
+ }
+
+ // help beep (no more than three times)
+ if (ent.client.pers.helpchanged != 0
+ && ent.client.pers.helpchanged <= 3
+ && 0 == (GameBase.level.framenum & 63)) {
+ ent.client.pers.helpchanged++;
+ GameBase.gi.sound(ent, Defines.CHAN_VOICE, GameBase.gi
+ .soundindex("misc/pc_up.wav"), 1, Defines.ATTN_STATIC, 0);
+ }
+
+ if (ent.client.pers.weapon != null)
+ weap = ent.client.pers.weapon.classname;
+ else
+ weap = "";
+
+ if (ent.waterlevel != 0
+ && 0 != (ent.watertype & (Defines.CONTENTS_LAVA | Defines.CONTENTS_SLIME)))
+ ent.s.sound = GameBase.snd_fry;
+ else if (Lib.strcmp(weap, "weapon_railgun") == 0)
+ ent.s.sound = GameBase.gi.soundindex("weapons/rg_hum.wav");
+ else if (Lib.strcmp(weap, "weapon_bfg") == 0)
+ ent.s.sound = GameBase.gi.soundindex("weapons/bfg_hum.wav");
+ else if (ent.client.weapon_sound != 0)
+ ent.s.sound = ent.client.weapon_sound;
+ else
+ ent.s.sound = 0;
+ }
+
+ /*
+ * =============== G_SetClientFrame ===============
+ */
+ public static void G_SetClientFrame(edict_t ent) {
+ gclient_t client;
+ boolean duck, run;
+
+ if (ent.s.modelindex != 255)
+ return; // not in the player model
+
+ client = ent.client;
+
+ if ((client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0)
+ duck = true;
+ else
+ duck = false;
+ if (xyspeed != 0)
+ run = true;
+ else
+ run = false;
+
+ boolean skip = false;
+ // check for stand/duck and stop/go transitions
+ if (duck != client.anim_duck
+ && client.anim_priority < Defines.ANIM_DEATH)
+ skip = true;
+
+ if (run != client.anim_run
+ && client.anim_priority == Defines.ANIM_BASIC)
+ skip = true;
+
+ if (null == ent.groundentity
+ && client.anim_priority <= Defines.ANIM_WAVE)
+ skip = true;
+
+ if (!skip) {
+ if (client.anim_priority == Defines.ANIM_REVERSE) {
+ if (ent.s.frame > client.anim_end) {
+ ent.s.frame--;
+ return;
+ }
+ } else if (ent.s.frame < client.anim_end) { // continue an animation
+ ent.s.frame++;
+ return;
+ }
+
+ if (client.anim_priority == Defines.ANIM_DEATH)
+ return; // stay there
+ if (client.anim_priority == Defines.ANIM_JUMP) {
+ if (null == ent.groundentity)
+ return; // stay there
+ ent.client.anim_priority = Defines.ANIM_WAVE;
+ ent.s.frame = M_Player.FRAME_jump3;
+ ent.client.anim_end = M_Player.FRAME_jump6;
+ return;
+ }
+ }
+
+ // return to either a running or standing frame
+ client.anim_priority = Defines.ANIM_BASIC;
+ client.anim_duck = duck;
+ client.anim_run = run;
+
+ if (null == ent.groundentity) {
+ client.anim_priority = Defines.ANIM_JUMP;
+ if (ent.s.frame != M_Player.FRAME_jump2)
+ ent.s.frame = M_Player.FRAME_jump1;
+ client.anim_end = M_Player.FRAME_jump2;
+ } else if (run) { // running
+ if (duck) {
+ ent.s.frame = M_Player.FRAME_crwalk1;
+ client.anim_end = M_Player.FRAME_crwalk6;
+ } else {
+ ent.s.frame = M_Player.FRAME_run1;
+ client.anim_end = M_Player.FRAME_run6;
+ }
+ } else { // standing
+ if (duck) {
+ ent.s.frame = M_Player.FRAME_crstnd01;
+ client.anim_end = M_Player.FRAME_crstnd19;
+ } else {
+ ent.s.frame = M_Player.FRAME_stand01;
+ client.anim_end = M_Player.FRAME_stand40;
+ }
+ }
+ }
+
+ /*
+ * ================= ClientEndServerFrame
+ *
+ * Called for each player at the end of the server frame and right after
+ * spawning =================
+ */
+ public static void ClientEndServerFrame(edict_t ent) {
+ float bobtime;
+ int i;
+
+ current_player = ent;
+ current_client = ent.client;
+
+ //
+ // If the origin or velocity have changed since ClientThink(),
+ // update the pmove values. This will happen when the client
+ // is pushed by a bmodel or kicked by an explosion.
+ //
+ // If it wasn't updated here, the view position would lag a frame
+ // behind the body position when pushed -- "sinking into plats"
+ //
+ for (i = 0; i < 3; i++) {
+ current_client.ps.pmove.origin[i] = (short) (ent.s.origin[i] * 8.0);
+ current_client.ps.pmove.velocity[i] = (short) (ent.velocity[i] * 8.0);
+ }
+
+ //
+ // If the end of unit layout is displayed, don't give
+ // the player any normal movement attributes
+ //
+ if (GameBase.level.intermissiontime != 0) {
+ // FIXME: add view drifting here?
+ current_client.ps.blend[3] = 0;
+ current_client.ps.fov = 90;
+ PlayerHud.G_SetStats(ent);
+ return;
+ }
+
+ Math3D.AngleVectors(ent.client.v_angle, forward, right, up);
+
+ // burn from lava, etc
+ P_WorldEffects();
+
+ //
+ // set model angles from view angles so other things in
+ // the world can tell which direction you are looking
+ //
+ if (ent.client.v_angle[Defines.PITCH] > 180)
+ ent.s.angles[Defines.PITCH] = (-360 + ent.client.v_angle[Defines.PITCH]) / 3;
+ else
+ ent.s.angles[Defines.PITCH] = ent.client.v_angle[Defines.PITCH] / 3;
+ ent.s.angles[Defines.YAW] = ent.client.v_angle[Defines.YAW];
+ ent.s.angles[Defines.ROLL] = 0;
+ ent.s.angles[Defines.ROLL] = SV_CalcRoll(ent.s.angles, ent.velocity) * 4;
+
+ //
+ // calculate speed and cycle to be used for
+ // all cyclic walking effects
+ //
+ xyspeed = (float) Math.sqrt(ent.velocity[0] * ent.velocity[0]
+ + ent.velocity[1] * ent.velocity[1]);
+
+ if (xyspeed < 5) {
+ bobmove = 0;
+ current_client.bobtime = 0; // start at beginning of cycle again
+ } else if (ent.groundentity != null) { // so bobbing only cycles when on
+ // ground
+ if (xyspeed > 210)
+ bobmove = 0.25f;
+ else if (xyspeed > 100)
+ bobmove = 0.125f;
+ else
+ bobmove = 0.0625f;
+ }
+
+ bobtime = (current_client.bobtime += bobmove);
+
+ if ((current_client.ps.pmove.pm_flags & pmove_t.PMF_DUCKED) != 0)
+ bobtime *= 4;
+
+ bobcycle = (int) bobtime;
+ bobfracsin = (float) Math.abs(Math.sin(bobtime * Math.PI));
+
+ // detect hitting the floor
+ P_FallingDamage(ent);
+
+ // apply all the damage taken this frame
+ P_DamageFeedback(ent);
+
+ // determine the view offsets
+ SV_CalcViewOffset(ent);
+
+ // determine the gun offsets
+ SV_CalcGunOffset(ent);
+
+ // determine the full screen color blend
+ // must be after viewoffset, so eye contents can be
+ // accurately determined
+ // FIXME: with client prediction, the contents
+ // should be determined by the client
+ SV_CalcBlend(ent);
+
+ // chase cam stuff
+ if (ent.client.resp.spectator)
+ PlayerHud.G_SetSpectatorStats(ent);
+ else
+ PlayerHud.G_SetStats(ent);
+ PlayerHud.G_CheckChaseStats(ent);
+
+ G_SetClientEvent(ent);
+
+ G_SetClientEffects(ent);
+
+ G_SetClientSound(ent);
+
+ G_SetClientFrame(ent);
+
+ Math3D.VectorCopy(ent.velocity, ent.client.oldvelocity);
+ Math3D.VectorCopy(ent.client.ps.viewangles, ent.client.oldviewangles);
+
+ // clear weapon kicks
+ Math3D.VectorClear(ent.client.kick_origin);
+ Math3D.VectorClear(ent.client.kick_angles);
+
+ // if the scoreboard is up, update it
+ if (ent.client.showscores && 0 == (GameBase.level.framenum & 31)) {
+ PlayerHud.DeathmatchScoreboardMessage(ent, ent.enemy);
+ GameBase.gi.unicast(ent, false);
+ }
+ }
+
+ public static float xyspeed;
+
+ public static float bobmove;
-// Created on 28.12.2003 by RST.
-// $Id: PlayerView.java,v 1.1 2004-07-07 19:59:24 hzi Exp $
+ public static int bobcycle; // odd cycles are right foot going forward
-package jake2.game;
+ public static float bobfracsin; // sin(bobfrac*M_PI)}
-import jake2.*;
-import jake2.client.*;
-import jake2.qcommon.*;
-import jake2.render.*;
-import jake2.server.*;
-
-public class PlayerView extends PlayerClient {
-
- public static edict_t current_player;
- public static gclient_t current_client;
-
- public static float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
- public static float xyspeed;
-
- public static float bobmove;
- public static int bobcycle; // odd cycles are right foot going forward
- public static float bobfracsin; // sin(bobfrac*M_PI)
-
- /*
- ===============
- SV_CalcRoll
-
- ===============
- */
- public static float SV_CalcRoll(float[] angles, float[] velocity) {
- float sign;
- float side;
- float value;
-
- side = DotProduct(velocity, right);
- sign = side < 0 ? -1 : 1;
- side = Math.abs(side);
-
- value = sv_rollangle.value;
-
- if (side < sv_rollspeed.value)
- side = side * value / sv_rollspeed.value;
- else
- side = value;
-
- return side * sign;
- }
-
- /*
- ===============
- P_DamageFeedback
-
- Handles color blends and view kicks
- ===============
- */
- private static int xxxi = 0;
-
- public static void P_DamageFeedback(edict_t player) {
- gclient_t client;
- float side;
- float realcount, count, kick;
- float[] v = { 0, 0, 0 };
- int r, l;
- float[] power_color = { 0.0f, 1.0f, 0.0f };
- float[] acolor = { 1.0f, 1.0f, 1.0f };
- float[] bcolor = { 1.0f, 0.0f, 0.0f };
-
- client = player.client;
-
- // flash the backgrounds behind the status numbers
- client.ps.stats[STAT_FLASHES] = 0;
- if (client.damage_blood != 0)
- client.ps.stats[STAT_FLASHES] |= 1;
- if (client.damage_armor != 0 && 0 == (player.flags & FL_GODMODE) && (client.invincible_framenum <= level.framenum))
- client.ps.stats[STAT_FLASHES] |= 2;
-
- // total points of damage shot at the player this frame
- count = (client.damage_blood + client.damage_armor + client.damage_parmor);
-
- if (count == 0)
- return; // didn't take any damage
-
- // start a pain animation if still in the player model
- if ((client.anim_priority < ANIM_PAIN) & (player.s.modelindex == 255)) {
- client.anim_priority = ANIM_PAIN;
- if ((client.ps.pmove.pm_flags & PMF_DUCKED) != 0) {
- player.s.frame = FRAME_crpain1 - 1;
- client.anim_end = FRAME_crpain4;
- }
- else {
-
- xxxi = (xxxi + 1) % 3;
- switch (xxxi) {
- case 0 :
- player.s.frame = FRAME_pain101 - 1;
- client.anim_end = FRAME_pain104;
- break;
- case 1 :
- player.s.frame = FRAME_pain201 - 1;
- client.anim_end = FRAME_pain204;
- break;
- case 2 :
- player.s.frame = FRAME_pain301 - 1;
- client.anim_end = FRAME_pain304;
- break;
- }
- }
- }
-
- realcount = count;
- if (count < 10)
- count = 10; // always make a visible effect
-
- // play an apropriate pain sound
- if ((level.time > player.pain_debounce_time)
- && 0 == (player.flags & FL_GODMODE)
- && (client.invincible_framenum <= level.framenum)) {
- r = 1 + (rand() & 1);
- player.pain_debounce_time = level.time + 0.7f;
- if (player.health < 25)
- l = 25;
- else if (player.health < 50)
- l = 50;
- else if (player.health < 75)
- l = 75;
- else
- l = 100;
- gi.sound(player, CHAN_VOICE, gi.soundindex("*pain" + l + "_" + r + ".wav"), 1, ATTN_NORM, 0);
- }
-
- // the total alpha of the blend is always proportional to count
- if (client.damage_alpha < 0)
- client.damage_alpha = 0;
- client.damage_alpha += count * 0.01f;
- if (client.damage_alpha < 0.2f)
- client.damage_alpha = 0.2f;
- if (client.damage_alpha > 0.6f)
- client.damage_alpha = 0.6f; // don't go too saturated
-
- // the color of the blend will vary based on how much was absorbed
- // by different armors
- VectorClear(v);
- if (client.damage_parmor != 0)
- VectorMA(v, (float) client.damage_parmor / realcount, power_color, v);
-
- if (client.damage_armor != 0)
- VectorMA(v, (float) client.damage_armor / realcount, acolor, v);
-
- if (client.damage_blood != 0)
- VectorMA(v, (float) client.damage_blood / realcount, bcolor, v);
- VectorCopy(v, client.damage_blend);
-
- //
- // calculate view angle kicks
- //
- kick = Math.abs(client.damage_knockback);
- if (kick != 0 && player.health > 0) // kick of 0 means no view adjust at all
- {
- kick = kick * 100 / player.health;
-
- if (kick < count * 0.5)
- kick = count * 0.5f;
- if (kick > 50)
- kick = 50;
-
- VectorSubtract(client.damage_from, player.s.origin, v);
- VectorNormalize(v);
-
- side = DotProduct(v, right);
- client.v_dmg_roll = kick * side * 0.3f;
-
- side = -DotProduct(v, forward);
- client.v_dmg_pitch = kick * side * 0.3f;
-
- client.v_dmg_time = level.time + DAMAGE_TIME;
- }
-
- //
- // clear totals
- //
- client.damage_blood = 0;
- client.damage_armor = 0;
- client.damage_parmor = 0;
- client.damage_knockback = 0;
- }
-
- /*
- ===============
- SV_CalcViewOffset
-
- Auto pitching on slopes?
-
- fall from 128: 400 = 160000
- fall from 256: 580 = 336400
- fall from 384: 720 = 518400
- fall from 512: 800 = 640000
- fall from 640: 960 =
-
- damage = deltavelocity*deltavelocity * 0.0001
-
- ===============
- */
- public static void SV_CalcViewOffset(edict_t ent) {
- float angles[] = { 0, 0, 0 };
- float bob;
- float ratio;
- float delta;
- float[] v = { 0, 0, 0 };
-
- //===================================
-
- // base angles
- angles = ent.client.ps.kick_angles;
-
- // if dead, fix the angle and don't add any kick
- if (ent.deadflag != 0) {
- VectorClear(angles);
-
- ent.client.ps.viewangles[ROLL] = 40;
- ent.client.ps.viewangles[PITCH] = -15;
- ent.client.ps.viewangles[YAW] = ent.client.killer_yaw;
- }
- else {
- // add angles based on weapon kick
-
- VectorCopy(ent.client.kick_angles, angles);
-
- // add angles based on damage kick
-
- ratio = (ent.client.v_dmg_time - level.time) / DAMAGE_TIME;
- if (ratio < 0) {
- ratio = 0;
- ent.client.v_dmg_pitch = 0;
- ent.client.v_dmg_roll = 0;
- }
- angles[PITCH] += ratio * ent.client.v_dmg_pitch;
- angles[ROLL] += ratio * ent.client.v_dmg_roll;
-
- // add pitch based on fall kick
-
- ratio = (ent.client.fall_time - level.time) / FALL_TIME;
- if (ratio < 0)
- ratio = 0;
- angles[PITCH] += ratio * ent.client.fall_value;
-
- // add angles based on velocity
-
- delta = DotProduct(ent.velocity, forward);
- angles[PITCH] += delta * run_pitch.value;
-
- delta = DotProduct(ent.velocity, right);
- angles[ROLL] += delta * run_roll.value;
-
- // add angles based on bob
-
- delta = bobfracsin * bob_pitch.value * xyspeed;
- if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0)
- delta *= 6; // crouching
- angles[PITCH] += delta;
- delta = bobfracsin * bob_roll.value * xyspeed;
- if ((ent.client.ps.pmove.pm_flags & PMF_DUCKED) != 0)
- delta *= 6; // crouching
- if ((bobcycle & 1) != 0)
- delta = -delta;
- angles[ROLL] += delta;
- }
-
- //===================================
-
- // base origin
-
- VectorClear(v);
-
- // add view height
-
- v[2] += ent.viewheight;
-
- // add fall height
-
- ratio = (ent.client.fall_time - level.time) / FALL_TIME;
- if (ratio < 0)
- ratio = 0;
- v[2] -= ratio * ent.client.fall_value * 0.4;
-
- // add bob height
-
- bob = bobfracsin * xyspeed * bob_up.value;
- if (bob > 6)
- bob = 6;
- //gi.DebugGraph (bob *2, 255);
- v[2] += bob;
-
- // add kick offset
-
- VectorAdd(v, ent.client.kick_origin, v);
-
- // absolutely bound offsets
- // so the view can never be outside the player box
-
- if (v[0] < -14)
- v[0] = -14;
- else if (v[0] > 14)
- v[0] = 14;
- if (v[1] < -14)
- v[1] = -14;
- else if (v[1] > 14)
- v[1] = 14;
- if (v[2] < -22)
- v[2] = -22;
- else if (v[2] > 30)
- v[2] = 30;
-
- VectorCopy(v, ent.client.ps.viewoffset);
- }
-
- /*
- ==============
- SV_CalcGunOffset
- ==============
- */
- public static void SV_CalcGunOffset(edict_t ent) {
- int i;
- float delta;
-
- // gun angles from bobbing
- ent.client.ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005f;
- ent.client.ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01f;
- if ((bobcycle & 1) != 0) {
- ent.client.ps.gunangles[ROLL] = -ent.client.ps.gunangles[ROLL];
- ent.client.ps.gunangles[YAW] = -ent.client.ps.gunangles[YAW];
- }
-
- ent.client.ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005f;
-
- // gun angles from delta movement
- for (i = 0; i < 3; i++) {
- delta = ent.client.oldviewangles[i] - ent.client.ps.viewangles[i];
- if (delta > 180)
- delta -= 360;
- if (delta < -180)
- delta += 360;
- if (delta > 45)
- delta = 45;
- if (delta < -45)
- delta = -45;
- if (i == YAW)
- ent.client.ps.gunangles[ROLL] += 0.1 * delta;
- ent.client.ps.gunangles[i] += 0.2 * delta;
- }
-
- // gun height
- VectorClear(ent.client.ps.gunoffset);
- // ent.ps.gunorigin[2] += bob;
-
- // gun_x / gun_y / gun_z are development tools
- for (i = 0; i < 3; i++) {
- ent.client.ps.gunoffset[i] += forward[i] * (gun_y.value);
- ent.client.ps.gunoffset[i] += right[i] * gun_x.value;
- ent.client.ps.gunoffset[i] += up[i] * (-gun_z.value);
- }
- }
-
- /*
- =============
- SV_AddBlend
- =============
- */
- public static void SV_AddBlend(float r, float g, float b, float a, float v_blend[]) {
- float a2, a3;
-
- if (a <= 0)
- return;
- a2 = v_blend[3] + (1 - v_blend[3]) * a; // new total alpha
- a3 = v_blend[3] / a2; // fraction of color from old
-
- v_blend[0] = v_blend[0] * a3 + r * (1 - a3);
- v_blend[1] = v_blend[1] * a3 + g * (1 - a3);
- v_blend[2] = v_blend[2] * a3 + b * (1 - a3);
- v_blend[3] = a2;
- }
-
- /*
- =============
- SV_CalcBlend
- =============
- */
- public static void SV_CalcBlend(edict_t ent) {
- int contents;
- float[] vieworg = { 0, 0, 0 };
- int remaining;
-
- ent.client.ps.blend[0] = ent.client.ps.blend[1] = ent.client.ps.blend[2] = ent.client.ps.blend[3] = 0;
-
- // add for contents
- VectorAdd(ent.s.origin, ent.client.ps.viewoffset, vieworg);
- contents = gi.pointcontents.pointcontents(vieworg);
- if ((contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) != 0)
- ent.client.ps.rdflags |= RDF_UNDERWATER;
- else
- ent.client.ps.rdflags &= ~RDF_UNDERWATER;
-
- if ((contents & (CONTENTS_SOLID | CONTENTS_LAVA)) != 0)
- SV_AddBlend(1.0f, 0.3f, 0.0f, 0.6f, ent.client.ps.blend);
- else if ((contents & CONTENTS_SLIME) != 0)
- SV_AddBlend(0.0f, 0.1f, 0.05f, 0.6f, ent.client.ps.blend);
- else if ((contents & CONTENTS_WATER) != 0)
- SV_AddBlend(0.5f, 0.3f, 0.2f, 0.4f, ent.client.ps.blend);
-
- // add for powerups
- if (ent.client.quad_framenum > level.framenum) {
- remaining = (int) (ent.client.quad_framenum - level.framenum);
- if (remaining == 30) // beginning to fade
- gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
- if (remaining > 30 || (remaining & 4) != 0)
- SV_AddBlend(0, 0, 1, 0.08f, ent.client.ps.blend);
- }
- else if (ent.client.invincible_framenum > level.framenum) {
- remaining = (int) ent.client.invincible_framenum - level.framenum;
- if (remaining == 30) // beginning to fade
- gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
- if (remaining > 30 || (remaining & 4) != 0)
- SV_AddBlend(1, 1, 0, 0.08f, ent.client.ps.blend);
- }
- else if (ent.client.enviro_framenum > level.framenum) {
- remaining = (int) ent.client.enviro_framenum - level.framenum;
- if (remaining == 30) // beginning to fade
- gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
- if (remaining > 30 || (remaining & 4) != 0)
- SV_AddBlend(0, 1, 0, 0.08f, ent.client.ps.blend);
- }
- else if (ent.client.breather_framenum > level.framenum) {
- remaining = (int) ent.client.breather_framenum - level.framenum;
- if (remaining == 30) // beginning to fade
- gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
- if (remaining > 30 || (remaining & 4) != 0)
- SV_AddBlend(0.4f, 1, 0.4f, 0.04f, ent.client.ps.blend);
- }
-
- // add for damage
- if (ent.client.damage_alpha > 0)
- SV_AddBlend(
- ent.client.damage_blend[0],
- ent.client.damage_blend[1],
- ent.client.damage_blend[2],
- ent.client.damage_alpha,
- ent.client.ps.blend);
-
- if (ent.client.bonus_alpha > 0)
- SV_AddBlend(0.85f, 0.7f, 0.3f, ent.client.bonus_alpha, ent.client.ps.blend);
-
- // drop the damage value
- ent.client.damage_alpha -= 0.06;
- if (ent.client.damage_alpha < 0)
- ent.client.damage_alpha = 0;
-
- // drop the bonus value
- ent.client.bonus_alpha -= 0.1;
- if (ent.client.bonus_alpha < 0)
- ent.client.bonus_alpha = 0;
- }
-
- /*
- =================
- P_FallingDamage
- =================
- */
- public static void P_FallingDamage(edict_t ent) {
- float delta;
- int damage;
- float[] dir = { 0, 0, 0 };
-
- if (ent.s.modelindex != 255)
- return; // not in the player model
-
- if (ent.movetype == MOVETYPE_NOCLIP)
- return;
-
- if ((ent.client.oldvelocity[2] < 0) && (ent.velocity[2] > ent.client.oldvelocity[2]) && (null == ent.groundentity)) {
- delta = ent.client.oldvelocity[2];
- }
- else {
- if (ent.groundentity == null)
- return;
- delta = ent.velocity[2] - ent.client.oldvelocity[2];
- }
- delta = delta * delta * 0.0001f;
-
- // never take falling damage if completely underwater
- if (ent.waterlevel == 3)
- return;
- if (ent.waterlevel == 2)
- delta *= 0.25;
- if (ent.waterlevel == 1)
- delta *= 0.5;
-
- if (delta < 1)
- return;
-
- if (delta < 15) {
- ent.s.event = EV_FOOTSTEP;
- return;
- }
-
- ent.client.fall_value = delta * 0.5f;
- if (ent.client.fall_value > 40)
- ent.client.fall_value = 40;
- ent.client.fall_time = level.time + FALL_TIME;
-
- if (delta > 30) {
- if (ent.health > 0) {
- if (delta >= 55)
- ent.s.event = EV_FALLFAR;
- else
- ent.s.event = EV_FALL;
- }
- ent.pain_debounce_time = level.time; // no normal pain sound
- damage = (int) ((delta - 30) / 2);
- if (damage < 1)
- damage = 1;
- VectorSet(dir, 0, 0, 1);
-
- if (deathmatch.value == 0 || 0 == ((int) dmflags.value & DF_NO_FALLING))
- T_Damage(ent, g_edicts[0], g_edicts[0], dir, ent.s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
- }
- else {
- ent.s.event = EV_FALLSHORT;
- return;
- }
- }
-
- /*
- =============
- P_WorldEffects
- =============
- */
- public static void P_WorldEffects() {
- boolean breather;
- boolean envirosuit;
- int waterlevel, old_waterlevel;
-
- if (current_player.movetype == MOVETYPE_NOCLIP) {
- current_player.air_finished = level.time + 12; // don't need air
- return;
- }
-
- waterlevel = current_player.waterlevel;
- old_waterlevel = current_client.old_waterlevel;
- current_client.old_waterlevel = waterlevel;
-
- breather = current_client.breather_framenum > level.framenum;
- envirosuit = current_client.enviro_framenum > level.framenum;
-
- //
- // if just entered a water volume, play a sound
- //
- if (old_waterlevel == 0 && waterlevel != 0) {
- PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
- if ((current_player.watertype & CONTENTS_LAVA) != 0)
- gi.sound(current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
- else if ((current_player.watertype & CONTENTS_SLIME) != 0)
- gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
- else if ((current_player.watertype & CONTENTS_WATER) != 0)
- gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
- current_player.flags |= FL_INWATER;
-
- // clear damage_debounce, so the pain sound will play immediately
- current_player.damage_debounce_time = level.time - 1;
- }
-
- //
- // if just completely exited a water volume, play a sound
- //
- if (old_waterlevel != 0 && waterlevel == 0) {
- PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
- gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
- current_player.flags &= ~FL_INWATER;
- }
-
- //
- // check for head just going under water
- //
- if (old_waterlevel != 3 && waterlevel == 3) {
- gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
- }
-
- //
- // check for head just coming out of water
- //
- if (old_waterlevel == 3 && waterlevel != 3) {
- if (current_player.air_finished < level.time) { // gasp for air
- gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
- PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
- }
- else if (current_player.air_finished < level.time + 11) { // just break surface
- gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
- }
- }
-
- //
- // check for drowning
- //
- if (waterlevel == 3) {
- // breather or envirosuit give air
- if (breather || envirosuit) {
- current_player.air_finished = level.time + 10;
-
- if (((int) (current_client.breather_framenum - level.framenum) % 25) == 0) {
- if (current_client.breather_sound == 0)
- gi.sound(current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
- else
- gi.sound(current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
- current_client.breather_sound ^= 1;
- PlayerNoise(current_player, current_player.s.origin, PNOISE_SELF);
- //FIXME: release a bubble?
- }
- }
-
- // if out of air, start drowning
- if (current_player.air_finished < level.time) { // drown!
- if (current_player.client.next_drown_time < level.time && current_player.health > 0) {
- current_player.client.next_drown_time = level.time + 1;
-
- // take more damage the longer underwater
- current_player.dmg += 2;
- if (current_player.dmg > 15)
- current_player.dmg = 15;
-
- // play a gurp sound instead of a normal pain sound
- if (current_player.health <= current_player.dmg)
- gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
- else if ((rand() & 1) != 0)
- gi.sound(current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
- else
- gi.sound(current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
-
- current_player.pain_debounce_time = level.time;
-
- T_Damage(
- current_player,
- g_edicts[0],
- g_edicts[0],
- vec3_origin,
- current_player.s.origin,
- vec3_origin,
- current_player.dmg,
- 0,
- DAMAGE_NO_ARMOR,
- MOD_WATER);
- }
- }
- }
- else {
- current_player.air_finished = level.time + 12;
- current_player.dmg = 2;
- }
-
- //
- // check for sizzle damage
- //
- if (waterlevel != 0 && 0 != (current_player.watertype & (CONTENTS_LAVA | CONTENTS_SLIME))) {
- if ((current_player.watertype & CONTENTS_LAVA) != 0) {
- if (current_player.health > 0
- && current_player.pain_debounce_time <= level.time
- && current_client.invincible_framenum < level.framenum) {
- if ((rand() & 1) != 0)
- gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
- else
- gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
- current_player.pain_debounce_time = level.time + 1;
- }
-
- if (envirosuit) // take 1/3 damage with envirosuit
- T_Damage(
- current_player,
- g_edicts[0],
- g_edicts[0],
- vec3_origin,
- current_player.s.origin,
- vec3_origin,
- 1 * waterlevel,
- 0,
- 0,
- MOD_LAVA);
- else
- T_Damage(
- current_player,
- g_edicts[0],
- g_edicts[0],
- vec3_origin,
- current_player.s.origin,
- vec3_origin,
- 3 * waterlevel,
- 0,
- 0,
- MOD_LAVA);
- }
-
- if ((current_player.watertype & CONTENTS_SLIME) != 0) {
- if (!envirosuit) { // no damage from slime with envirosuit
- T_Damage(
- current_player,
- g_edicts[0],
- g_edicts[0],
- vec3_origin,
- current_player.s.origin,
- vec3_origin,
- 1 * waterlevel,
- 0,
- 0,
- MOD_SLIME);
- }
- }
- }
- }
-
- /*
- ===============
- G_SetClientEffects
- ===============
- */
- public static void G_SetClientEffects(edict_t ent) {
- int pa_type;
- int remaining;
-
- ent.s.effects = 0;
- ent.s.renderfx = 0;
-
- if (ent.health <= 0 || level.intermissiontime != 0)
- return;
-
- if (ent.powerarmor_time > level.time) {
- pa_type = PowerArmorType(ent);
- if (pa_type == POWER_ARMOR_SCREEN) {
- ent.s.effects |= EF_POWERSCREEN;
- }
- else if (pa_type == POWER_ARMOR_SHIELD) {
- ent.s.effects |= EF_COLOR_SHELL;
- ent.s.renderfx |= RF_SHELL_GREEN;
- }
- }
-
- if (ent.client.quad_framenum > level.framenum) {
- remaining = (int) ent.client.quad_framenum - level.framenum;
- if (remaining > 30 || 0 != (remaining & 4))
- ent.s.effects |= EF_QUAD;
- }
-
- if (ent.client.invincible_framenum > level.framenum) {
- remaining = (int) ent.client.invincible_framenum - level.framenum;
- if (remaining > 30 || 0 != (remaining & 4))
- ent.s.effects |= EF_PENT;
- }
-
- // show cheaters!!!
- if ((ent.flags & FL_GODMODE) != 0) {
- ent.s.effects |= EF_COLOR_SHELL;
- ent.s.renderfx |= (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE);
- }
- }
-
- /*
- ===============
- G_SetClientEvent
- ===============
- */
- public static void G_SetClientEvent(edict_t ent) {
- if (ent.s.event != 0)
- return;
-
- if (ent.groundentity != null && xyspeed > 225) {
- if ((int) (current_client.bobtime + bobmove) != bobcycle)
- ent.s.event = EV_FOOTSTEP;
- }
- }
-
- /*
- ===============
- G_SetClientSound
- ===============
- */
- public static void G_SetClientSound(edict_t ent) {
- String weap;
-
- if (ent.client.pers.game_helpchanged != game.helpchanged) {
- ent.client.pers.game_helpchanged = game.helpchanged;
- ent.client.pers.helpchanged = 1;
- }
-
- // help beep (no more than three times)
- if (ent.client.pers.helpchanged != 0 && ent.client.pers.helpchanged <= 3 && 0 == (level.framenum & 63)) {
- ent.client.pers.helpchanged++;
- gi.sound(ent, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
- }
-
- if (ent.client.pers.weapon != null)
- weap = ent.client.pers.weapon.classname;
- else
- weap = "";
-
- if (ent.waterlevel != 0 && 0 != (ent.watertype & (CONTENTS_LAVA | CONTENTS_SLIME)))
- ent.s.sound = snd_fry;
- else if (strcmp(weap, "weapon_railgun") == 0)
- ent.s.sound = gi.soundindex("weapons/rg_hum.wav");
- else if (strcmp(weap, "weapon_bfg") == 0)
- ent.s.sound = gi.soundindex("weapons/bfg_hum.wav");
- else if (ent.client.weapon_sound != 0)
- ent.s.sound = ent.client.weapon_sound;
- else
- ent.s.sound = 0;
- }
-
- /*
- ===============
- G_SetClientFrame
- ===============
- */
- public static void G_SetClientFrame(edict_t ent) {
- gclient_t client;
- boolean duck, run;
-
- if (ent.s.modelindex != 255)
- return; // not in the player model
-
- client = ent.client;
-
- if ((client.ps.pmove.pm_flags & PMF_DUCKED)!=0)
- duck = true;
- else
- duck = false;
- if (xyspeed!=0)
- run = true;
- else
- run = false;
-
- boolean skip = false;
- // check for stand/duck and stop/go transitions
- if (duck != client.anim_duck && client.anim_priority < ANIM_DEATH)
- skip = true;
-
- if (run != client.anim_run && client.anim_priority == ANIM_BASIC)
- skip = true;
-
- if (null==ent.groundentity && client.anim_priority <= ANIM_WAVE)
- skip = true;
-
- if (!skip) {
- if (client.anim_priority == ANIM_REVERSE) {
- if (ent.s.frame > client.anim_end) {
- ent.s.frame--;
- return;
- }
- }
- else if (ent.s.frame < client.anim_end) { // continue an animation
- ent.s.frame++;
- return;
- }
-
- if (client.anim_priority == ANIM_DEATH)
- return; // stay there
- if (client.anim_priority == ANIM_JUMP) {
- if (null==ent.groundentity)
- return; // stay there
- ent.client.anim_priority = ANIM_WAVE;
- ent.s.frame = FRAME_jump3;
- ent.client.anim_end = FRAME_jump6;
- return;
- }
- }
-
- // return to either a running or standing frame
- client.anim_priority = ANIM_BASIC;
- client.anim_duck = duck;
- client.anim_run = run;
-
- if (null==ent.groundentity) {
- client.anim_priority = ANIM_JUMP;
- if (ent.s.frame != FRAME_jump2)
- ent.s.frame = FRAME_jump1;
- client.anim_end = FRAME_jump2;
- }
- else if (run) { // running
- if (duck) {
- ent.s.frame = FRAME_crwalk1;
- client.anim_end = FRAME_crwalk6;
- }
- else {
- ent.s.frame = FRAME_run1;
- client.anim_end = FRAME_run6;
- }
- }
- else { // standing
- if (duck) {
- ent.s.frame = FRAME_crstnd01;
- client.anim_end = FRAME_crstnd19;
- }
- else {
- ent.s.frame = FRAME_stand01;
- client.anim_end = FRAME_stand40;
- }
- }
- }
-
- /*
- =================
- ClientEndServerFrame
-
- Called for each player at the end of the server frame
- and right after spawning
- =================
- */
- public static void ClientEndServerFrame(edict_t ent) {
- float bobtime;
- int i;
-
- current_player = ent;
- current_client = ent.client;
-
- //
- // If the origin or velocity have changed since ClientThink(),
- // update the pmove values. This will happen when the client
- // is pushed by a bmodel or kicked by an explosion.
- //
- // If it wasn't updated here, the view position would lag a frame
- // behind the body position when pushed -- "sinking into plats"
- //
- for (i = 0; i < 3; i++) {
- current_client.ps.pmove.origin[i] = (short) (ent.s.origin[i] * 8.0);
- current_client.ps.pmove.velocity[i] = (short) (ent.velocity[i] * 8.0);
- }
-
- //
- // If the end of unit layout is displayed, don't give
- // the player any normal movement attributes
- //
- if (level.intermissiontime!=0) {
- // FIXME: add view drifting here?
- current_client.ps.blend[3] = 0;
- current_client.ps.fov = 90;
- G_SetStats(ent);
- return;
- }
-
- AngleVectors(ent.client.v_angle, forward, right, up);
-
- // burn from lava, etc
- P_WorldEffects();
-
- //
- // set model angles from view angles so other things in
- // the world can tell which direction you are looking
- //
- if (ent.client.v_angle[PITCH] > 180)
- ent.s.angles[PITCH] = (-360 + ent.client.v_angle[PITCH]) / 3;
- else
- ent.s.angles[PITCH] = ent.client.v_angle[PITCH] / 3;
- ent.s.angles[YAW] = ent.client.v_angle[YAW];
- ent.s.angles[ROLL] = 0;
- ent.s.angles[ROLL] = SV_CalcRoll(ent.s.angles, ent.velocity) * 4;
-
- //
- // calculate speed and cycle to be used for
- // all cyclic walking effects
- //
- xyspeed = (float) Math.sqrt(ent.velocity[0] * ent.velocity[0] + ent.velocity[1] * ent.velocity[1]);
-
- if (xyspeed < 5) {
- bobmove = 0;
- current_client.bobtime = 0; // start at beginning of cycle again
- }
- else if (ent.groundentity!=null) { // so bobbing only cycles when on ground
- if (xyspeed > 210)
- bobmove = 0.25f;
- else if (xyspeed > 100)
- bobmove = 0.125f;
- else
- bobmove = 0.0625f;
- }
-
- bobtime = (current_client.bobtime += bobmove);
-
- if ((current_client.ps.pmove.pm_flags & PMF_DUCKED)!=0)
- bobtime *= 4;
-
- bobcycle = (int) bobtime;
- bobfracsin = (float) Math.abs(Math.sin(bobtime * Math.PI));
-
- // detect hitting the floor
- P_FallingDamage(ent);
-
- // apply all the damage taken this frame
- P_DamageFeedback(ent);
-
- // determine the view offsets
- SV_CalcViewOffset(ent);
-
- // determine the gun offsets
- SV_CalcGunOffset(ent);
-
- // determine the full screen color blend
- // must be after viewoffset, so eye contents can be
- // accurately determined
- // FIXME: with client prediction, the contents
- // should be determined by the client
- SV_CalcBlend(ent);
-
- // chase cam stuff
- if (ent.client.resp.spectator)
- G_SetSpectatorStats(ent);
- else
- G_SetStats(ent);
- G_CheckChaseStats(ent);
-
- G_SetClientEvent(ent);
-
- G_SetClientEffects(ent);
-
- G_SetClientSound(ent);
-
- G_SetClientFrame(ent);
-
- VectorCopy(ent.velocity, ent.client.oldvelocity);
- VectorCopy(ent.client.ps.viewangles, ent.client.oldviewangles);
-
- // clear weapon kicks
- VectorClear(ent.client.kick_origin);
- VectorClear(ent.client.kick_angles);
-
- // if the scoreboard is up, update it
- if (ent.client.showscores && 0==(level.framenum & 31)) {
- DeathmatchScoreboardMessage(ent, ent.enemy);
- gi.unicast(ent, false);
- }
- }
-}
+ private static int xxxi = 0;
+} \ No newline at end of file