diff --git a/src/client/hud.qc b/src/client/hud.qc index 5c47506..6a0a095 100644 --- a/src/client/hud.qc +++ b/src/client/hud.qc @@ -264,6 +264,19 @@ HUD_DrawAmmo3(void) HUD_DrawNums(pl.a_ammo3, pos, pSeat->m_flAmmo3Alpha, g_hud_color); } +/* ammo bar */ +void +HUD_DrawAmmoBar(vector pos, float val, float max, float a) +{ + if (val <= 0) + return; + + float perc; + perc = val / max; + drawfill(pos + [10,0], [20,4], g_hud_color, a, DRAWFLAG_NORMAL); + drawfill(pos + [10,0], [20 * perc,4], [0,1,0], a, DRAWFLAG_NORMAL); +} + /* flashlight/torch indicator */ void HUD_DrawFlashlight(void) diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc index b81684f..c78f66b 100644 --- a/src/server/gamerules.qc +++ b/src/server/gamerules.qc @@ -125,7 +125,6 @@ HHDMultiplayerRules::PlayerSpawn(base_player pp) pl.velocity = [0,0,0]; pl.gravity = __NULL__; pl.frame = 1; - pl.SendEntity = Player_SendEntity; pl.SendFlags = UPDATE_ALL; pl.customphysics = Empty; pl.iBleeds = TRUE; diff --git a/src/shared/player.qc b/src/shared/player.qc index f938efc..d846602 100644 --- a/src/shared/player.qc +++ b/src/shared/player.qc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 Marco Hladik + * Copyright (c) 2016-2021 Marco Hladik * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,29 +14,408 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -int input_sequence; +/* all potential SendFlags bits we can possibly send */ +enumflags +{ + PLAYER_KEEPALIVE, + PLAYER_MODELINDEX, + PLAYER_ORIGIN, + PLAYER_ORIGIN_Z, + PLAYER_ANGLES_X, + PLAYER_ANGLES_Y, + PLAYER_ANGLES_Z, + PLAYER_VELOCITY, + PLAYER_VELOCITY_Z, + PLAYER_FLAGS, + PLAYER_WEAPON, + PLAYER_ITEMS, + PLAYER_HEALTH, + PLAYER_ARMOR, + PLAYER_MOVETYPE, + PLAYER_VIEWOFS, + PLAYER_BASEFRAME, + PLAYER_FRAME, + PLAYER_AMMO1, + PLAYER_AMMO2, + PLAYER_AMMO3, + PLAYER_UNUSED1, + PLAYER_UNUSED2 +}; +noref int input_sequence; class player:base_player { + /* Weapon specific */ + int ammo_forks; int ammo_forks_net; + int ammo_knives; int ammo_knives_net; + int ammo_legogrenade; int ammo_legogrenade_net; + int ammo_legos; int ammo_legos_net; + int ammo_soda; int ammo_soda_net; + int ammo_spray; int ammo_spray_net; + #ifdef CLIENT /* External model */ entity p_model; int p_hand_bone; int p_model_bone; - float pitch; float lastweapon; virtual void(void) gun_offset; virtual void(void) draw; virtual float() predraw; virtual void(void) postdraw; + virtual void(float) ReceiveEntity; + virtual void(void) PredictPreFrame; + virtual void(void) PredictPostFrame; #else - int ammo_forks; - int ammo_knives; - int ammo_legogrenade; - int ammo_legos; - int ammo_soda; - int ammo_spray; float powerup_time; + + virtual void(void) EvaluateEntity; + virtual float(entity, float) SendEntity; #endif }; + +#ifdef CLIENT +void Weapons_AmmoUpdate(entity); +/* +================= +player::ReceiveEntity +================= +*/ +void +player::ReceiveEntity(float new) +{ + float fl; + if (new == FALSE) { + /* Go through all the physics code between the last received frame + * and the newest frame and keep the changes this time around instead + * of rolling back, because we'll apply the new server-verified values + * right after anyway. */ + /* FIXME: splitscreen */ + if (entnum == player_localentnum) { + /* FIXME: splitscreen */ + pSeat = &g_seats[0]; + + for (int i = sequence+1; i <= servercommandframe; i++) { + /* ...maybe the input state is too old? */ + if (!getinputstate(i)) { + break; + } + input_sequence = i; + PMove_Run(); + } + + /* any differences in things that are read below are now + * officially from prediction misses. */ + } + } + + /* seed for our prediction table */ + sequence = servercommandframe; + + fl = readfloat(); + + /* HACK: we need to make this more reliable */ + if (fl == UPDATE_ALL) { + /* we respawned */ + gravity = __NULL__; + } + + if (fl & PLAYER_MODELINDEX) + modelindex = readshort(); + + if (fl & PLAYER_ORIGIN) { + origin[0] = readcoord(); + origin[1] = readcoord(); + } + + if (fl & PLAYER_ORIGIN_Z) + origin[2] = readcoord(); + if (fl & PLAYER_ANGLES_X) + pitch = readfloat(); + if (fl & PLAYER_ANGLES_Y) + angles[1] = readfloat(); + if (fl & PLAYER_ANGLES_Z) + angles[2] = readfloat(); + + if (fl & PLAYER_VELOCITY) { + velocity[0] = readcoord(); + velocity[1] = readcoord(); + } + + if (fl & PLAYER_VELOCITY_Z) + velocity[2] = readcoord(); + if (fl & PLAYER_FLAGS) { + flags = readfloat(); + gflags = readfloat(); + } + if (fl & PLAYER_WEAPON) + activeweapon = readbyte(); + if (fl & PLAYER_ITEMS) + g_items = (__variant)readfloat(); + if (fl & PLAYER_HEALTH) + health = readbyte(); + if (fl & PLAYER_ARMOR) + armor = readbyte(); + if (fl & PLAYER_MOVETYPE) + movetype = readbyte(); + if (fl & PLAYER_VIEWOFS) + view_ofs[2] = readfloat(); + if (fl & PLAYER_BASEFRAME) + baseframe = readbyte(); + if (fl & PLAYER_FRAME) { + frame = readbyte(); + frame1time = 0.0f; + frame2time = 0.0f; + } + + if (fl & PLAYER_AMMO1) { + } + + if (fl & PLAYER_AMMO2) { + ammo_forks = readbyte(); + ammo_knives = readbyte(); + ammo_legogrenade = readbyte(); + ammo_legos = readbyte(); + ammo_soda = readbyte(); + ammo_spray = readbyte(); + } + + if (fl & PLAYER_AMMO3) { + } + + if (fl & PLAYER_AMMO1 || fl & PLAYER_AMMO2 || fl & PLAYER_AMMO3) + Weapons_AmmoUpdate(this); + + setorigin(this, origin); +} + +/* +================= +player::PredictPostFrame + +Save the last valid server values away in the _net variants of each field +so we can roll them back later. +================= +*/ +void +player::PredictPreFrame(void) +{ + ammo_forks_net = ammo_forks; + ammo_knives_net = ammo_knives; + ammo_legogrenade_net = ammo_legogrenade; + ammo_legos_net = ammo_legos; + ammo_soda_net = ammo_soda; + ammo_spray_net = ammo_spray; +} + +/* +================= +player::PredictPostFrame + +Where we roll back our values to the ones last sent/verified by the server. +================= +*/ +void +player::PredictPostFrame(void) +{ + ammo_forks = ammo_forks_net; + ammo_knives = ammo_knives_net; + ammo_legogrenade = ammo_legogrenade_net; + ammo_legos = ammo_legos_net; + ammo_soda = ammo_soda_net; + ammo_spray = ammo_spray_net; +} + +#else +void +player::EvaluateEntity(void) +{ + SendFlags |= PLAYER_KEEPALIVE; + + if (old_modelindex != modelindex) + SendFlags |= PLAYER_MODELINDEX; + + if (old_origin[0] != origin[0]) + SendFlags |= PLAYER_ORIGIN; + + if (old_origin[1] != origin[1]) + SendFlags |= PLAYER_ORIGIN; + + if (old_origin[2] != origin[2]) + SendFlags |= PLAYER_ORIGIN_Z; + + if (old_angles[0] != v_angle[0]) + SendFlags |= PLAYER_ANGLES_X; + + if (old_angles[1] != angles[1]) + SendFlags |= PLAYER_ANGLES_Y; + + if (old_angles[2] != angles[2]) + SendFlags |= PLAYER_ANGLES_Z; + + if (old_velocity[0] != velocity[0]) + SendFlags |= PLAYER_VELOCITY; + + if (old_velocity[1] != velocity[1]) + SendFlags |= PLAYER_VELOCITY; + + if (old_velocity[2] != velocity[2]) + SendFlags |= PLAYER_VELOCITY_Z; + + if (old_flags != flags) + SendFlags |= PLAYER_FLAGS; + + if (old_gflags != gflags) + SendFlags |= PLAYER_FLAGS; + + if (old_activeweapon != activeweapon) + SendFlags |= PLAYER_WEAPON; + + if (old_items != g_items) + SendFlags |= PLAYER_ITEMS; + + if (old_health != health) + SendFlags |= PLAYER_HEALTH; + + if (old_armor != armor) + SendFlags |= PLAYER_ARMOR; + + if (old_movetype != movetype) + SendFlags |= PLAYER_MOVETYPE; + + if (old_viewofs != view_ofs[2]) + SendFlags |= PLAYER_VIEWOFS; + + if (old_baseframe != baseframe) + SendFlags |= PLAYER_BASEFRAME; + + if (old_frame != frame) + SendFlags |= PLAYER_FRAME; + + old_modelindex = modelindex; + old_origin = origin; + old_angles = angles; + old_angles[0] = v_angle[0]; + old_velocity = velocity; + old_flags = flags; + old_gflags = gflags; + old_activeweapon = activeweapon; + old_items = g_items; + old_health = health; + old_armor = armor; + old_movetype = movetype; + old_viewofs = view_ofs[2]; + old_baseframe = baseframe; + old_frame = frame; + + if (ammo_forks_net == ammo_forks) + SendFlags |= PLAYER_AMMO2; + if (ammo_knives_net == ammo_knives) + SendFlags |= PLAYER_AMMO2; + if (ammo_legogrenade_net == ammo_legogrenade) + SendFlags |= PLAYER_AMMO2; + if (ammo_legos_net == ammo_legos) + SendFlags |= PLAYER_AMMO2; + if (ammo_soda_net == ammo_soda) + SendFlags |= PLAYER_AMMO2; + if (ammo_spray_net == ammo_spray) + SendFlags |= PLAYER_AMMO2; + + ammo_forks_net = ammo_forks; + ammo_knives_net = ammo_knives; + ammo_legogrenade_net = ammo_legogrenade; + ammo_legos_net = ammo_legos; + ammo_soda_net = ammo_soda; + ammo_spray_net = ammo_spray; +} + +/* +================= +player::SendEntity +================= +*/ +float +player::SendEntity(entity ePEnt, float fChanged) +{ + if (health <= 0 && ePEnt != this) { + return FALSE; + } + + if (clienttype(ePEnt) != CLIENTTYPE_REAL) { + return FALSE; + } + + if (ePEnt != self) { + fChanged &= ~PLAYER_ITEMS; + fChanged &= ~PLAYER_HEALTH; + fChanged &= ~PLAYER_ARMOR; + fChanged &= ~PLAYER_VIEWOFS; + fChanged &= ~PLAYER_AMMO1; + fChanged &= ~PLAYER_AMMO2; + fChanged &= ~PLAYER_AMMO3; + } + + WriteByte(MSG_ENTITY, ENT_PLAYER); + WriteFloat(MSG_ENTITY, fChanged); + + /* really trying to get our moneys worth with 23 bits of mantissa */ + if (fChanged & PLAYER_MODELINDEX) + WriteShort(MSG_ENTITY, modelindex); + if (fChanged & PLAYER_ORIGIN) { + WriteCoord(MSG_ENTITY, origin[0]); + WriteCoord(MSG_ENTITY, origin[1]); + } + if (fChanged & PLAYER_ORIGIN_Z) + WriteCoord(MSG_ENTITY, origin[2]); + if (fChanged & PLAYER_ANGLES_X) + WriteFloat(MSG_ENTITY, v_angle[0]); + if (fChanged & PLAYER_ANGLES_Y) + WriteFloat(MSG_ENTITY, angles[1]); + if (fChanged & PLAYER_ANGLES_Z) + WriteFloat(MSG_ENTITY, angles[2]); + if (fChanged & PLAYER_VELOCITY) { + WriteCoord(MSG_ENTITY, velocity[0]); + WriteCoord(MSG_ENTITY, velocity[1]); + } + if (fChanged & PLAYER_VELOCITY_Z) + WriteCoord(MSG_ENTITY, velocity[2]); + if (fChanged & PLAYER_FLAGS) { + WriteFloat(MSG_ENTITY, flags); + WriteFloat(MSG_ENTITY, gflags); + } + if (fChanged & PLAYER_WEAPON) + WriteByte(MSG_ENTITY, activeweapon); + if (fChanged & PLAYER_ITEMS) + WriteFloat(MSG_ENTITY, (__variant)g_items); + if (fChanged & PLAYER_HEALTH) + WriteByte(MSG_ENTITY, bound(0, health, 255)); + if (fChanged & PLAYER_ARMOR) + WriteByte(MSG_ENTITY, armor); + if (fChanged & PLAYER_MOVETYPE) + WriteByte(MSG_ENTITY, movetype); + if (fChanged & PLAYER_VIEWOFS) + WriteFloat(MSG_ENTITY, view_ofs[2]); + if (fChanged & PLAYER_BASEFRAME) + WriteByte(MSG_ENTITY, baseframe); + if (fChanged & PLAYER_FRAME) + WriteByte(MSG_ENTITY, frame); + + if (fChanged & PLAYER_AMMO1) { + } + + if (fChanged & PLAYER_AMMO2) { + WriteByte(MSG_ENTITY, ammo_forks); + WriteByte(MSG_ENTITY, ammo_knives); + WriteByte(MSG_ENTITY, ammo_legogrenade); + WriteByte(MSG_ENTITY, ammo_legos); + WriteByte(MSG_ENTITY, ammo_soda); + WriteByte(MSG_ENTITY, ammo_spray); + } + + if (fChanged & PLAYER_AMMO3) { + } + + return TRUE; +} +#endif diff --git a/src/shared/w_broom.qc b/src/shared/w_broom.qc index a3bee67..6ec95d1 100644 --- a/src/shared/w_broom.qc +++ b/src/shared/w_broom.qc @@ -44,19 +44,15 @@ w_broom_precache(void) void w_broom_updateammo(player pl) { -#ifdef SERVER Weapons_UpdateAmmo(pl, -1, -1, -1); -#endif } string w_broom_wmodel(void) { return "models/w_broom.mdl"; - /* model = "models/w_broom.mdl"; - SetRenderMode(RM_FULLBRIGHT); - SetRenderAmt(255); */ } + string w_broom_pmodel(void) { diff --git a/src/shared/w_forks.qc b/src/shared/w_forks.qc index 2372a94..16aacdb 100644 --- a/src/shared/w_forks.qc +++ b/src/shared/w_forks.qc @@ -55,9 +55,7 @@ w_forks_precache(void) void w_forks_updateammo(player pl) { -#ifdef SERVER - Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_forks, __NULL__); -#endif + Weapons_UpdateAmmo(pl, -1, pl.ammo_forks, -1); } string @@ -164,7 +162,7 @@ w_forks_secondary(void) /* Ammo check */ #ifdef CLIENT - if (pl.a_ammo2 <= 0) { + if (pl.ammo_forks <= 0) { return; } #else diff --git a/src/shared/w_glove.qc b/src/shared/w_glove.qc index e0dc691..0805cc6 100644 --- a/src/shared/w_glove.qc +++ b/src/shared/w_glove.qc @@ -236,7 +236,7 @@ w_glove_hudpic(int selected, vector pos, float a) weapon_t w_glove = { .name = "glove", - .id = ITEM_GLOVE, + .id = ITEM_GLOVE, .slot = 1, .slot_pos = 0, .draw = w_glove_draw, diff --git a/src/shared/w_hairspray.qc b/src/shared/w_hairspray.qc index 8fbd1f3..7b94dc3 100644 --- a/src/shared/w_hairspray.qc +++ b/src/shared/w_hairspray.qc @@ -48,9 +48,7 @@ w_hairspray_precache(void) void w_hairspray_updateammo(player pl) { -#ifdef SERVER - Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_spray, __NULL__); -#endif + Weapons_UpdateAmmo(pl, -1, pl.ammo_spray, -1); } string @@ -125,7 +123,7 @@ w_hairspray_primary(void) /* Ammo check */ #ifdef CLIENT - if (pl.a_ammo2 <= 0) { + if (pl.ammo_spray <= 0) { return; } #else @@ -137,7 +135,7 @@ w_hairspray_primary(void) /* Actual firing */ #ifdef CLIENT Weapons_ViewAnimation(HAIRSPRAY_FIRE); - pl.a_ammo2--; + pl.ammo_spray--; #else Weapons_MakeVectors(); entity flame = spawn(); diff --git a/src/shared/w_knife.qc b/src/shared/w_knife.qc index 7d4f9f3..0b97af4 100644 --- a/src/shared/w_knife.qc +++ b/src/shared/w_knife.qc @@ -52,9 +52,7 @@ w_knife_precache(void) void w_knife_updateammo(player pl) { -#ifdef SERVER - Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_knives, __NULL__); -#endif + Weapons_UpdateAmmo(pl, -1, pl.ammo_knives, -1); } string @@ -114,7 +112,7 @@ w_knife_primary(void) /* Ammo check */ #ifdef CLIENT - if (pl.a_ammo2 <= 0) { + if (pl.ammo_knives <= 0) { return; } #else diff --git a/src/shared/w_lego.qc b/src/shared/w_lego.qc index cce89de..d24600e 100644 --- a/src/shared/w_lego.qc +++ b/src/shared/w_lego.qc @@ -41,9 +41,7 @@ void w_lego_precache(void) } void w_lego_updateammo(player pl) { -#ifdef SERVER Weapons_UpdateAmmo(pl, -1, pl.ammo_legogrenade, -1); -#endif } string w_lego_wmodel(void) { @@ -140,7 +138,7 @@ void w_lego_primary(void) /* Ammo check */ #ifdef CLIENT - if (pl.a_ammo2 <= 0) { + if (pl.ammo_legogrenade <= 0) { return; } #else @@ -198,7 +196,7 @@ void w_lego_release(void) if (pl.a_ammo3 == 1) { #ifdef CLIENT - pl.a_ammo2--; + pl.ammo_legogrenade--; Weapons_ViewAnimation(LEGO_THROW); #else pl.ammo_legogrenade--; diff --git a/src/shared/w_legolauncher.qc b/src/shared/w_legolauncher.qc index 3d5da6b..e9c52ee 100644 --- a/src/shared/w_legolauncher.qc +++ b/src/shared/w_legolauncher.qc @@ -48,9 +48,7 @@ w_legolauncher_precache(void) void w_legolauncher_updateammo(player pl) { -#ifdef SERVER Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_legos, __NULL__); -#endif } string @@ -155,7 +153,7 @@ w_legolauncher_primary(void) /* Ammo check */ #ifdef CLIENT - if (pl.a_ammo2 <= 0) { + if (pl.ammo_legos <= 0) { return; } #else diff --git a/src/shared/w_sodalauncher.qc b/src/shared/w_sodalauncher.qc index 858d0ad..ffb1760 100644 --- a/src/shared/w_sodalauncher.qc +++ b/src/shared/w_sodalauncher.qc @@ -68,9 +68,7 @@ w_sodalauncher_pickup(int new, int startammo) void w_sodalauncher_updateammo(player pl) { -#ifdef SERVER - Weapons_UpdateAmmo(pl, __NULL__, pl.ammo_soda, __NULL__); -#endif + Weapons_UpdateAmmo(pl, -1, pl.ammo_soda, -1); } string @@ -182,7 +180,7 @@ w_sodalauncher_primary(void) /* Ammo check */ #ifdef CLIENT - if (pl.a_ammo2 <= 0) { + if (pl.ammo_soda <= 0) { return; } #else @@ -218,7 +216,7 @@ w_sodalauncher_secondary(void) /* Ammo check */ #ifdef CLIENT - if (pl.a_ammo2 <= 0) { + if (pl.ammo_soda <= 0) { return; } #else