From de86f7bf49296db1c01da06673d59a641ef3dd05 Mon Sep 17 00:00:00 2001 From: Chris Dawalt Date: Sun, 1 Aug 2021 05:12:11 -0400 Subject: [PATCH] Fake Spectator and weapon select cleanup --- src/client/cmds.qc | 2 + src/client/draw.qc | 12 -- src/client/hud.qc | 158 ++++++++++--------- src/client/hud_weaponselect.h | 5 +- src/client/hud_weaponselect.qc | 227 ++++------------------------ src/server/gamerules_multiplayer.qc | 83 ++++++++-- src/shared/player.h | 41 ++++- src/shared/player.qc | 34 ++++- src/shared/weapons/weapon_karate.qc | 3 + 9 files changed, 254 insertions(+), 311 deletions(-) diff --git a/src/client/cmds.qc b/src/client/cmds.qc index d151f99..602ea56 100644 --- a/src/client/cmds.qc +++ b/src/client/cmds.qc @@ -94,6 +94,8 @@ ClientGame_ConsoleCommand(void) //If we're in spectator mode we can do this // no-screen check, not necessary probably: pSeatLocal->fVGUI_Display == VGUI_SCREEN::NONE && + + printfline("WOO HOO YEA BOY %s", getplayerkeyvalue( player_localnum, "*spec" )); if(getplayerkeyvalue( player_localnum, "*spec" ) != "0"){ //we can show it! VGUI_ChangeScreen(VGUI_SCREEN::BUYSIDEMENU); diff --git a/src/client/draw.qc b/src/client/draw.qc index f8a5dfd..0989ca8 100644 --- a/src/client/draw.qc +++ b/src/client/draw.qc @@ -96,14 +96,6 @@ drawPainArrows(void) - - - - - - - - // and now for the screen-wide pain flash. void drawPainFlash(void) @@ -144,7 +136,3 @@ ClientGame_DamageDraw(void){ } - - - - diff --git a/src/client/hud.qc b/src/client/hud.qc index ff62124..18325b3 100644 --- a/src/client/hud.qc +++ b/src/client/hud.qc @@ -55,83 +55,117 @@ void HUD_Draw(void) { player pl = (player)pSeat->m_ePlayer; + + + if(pl.iState == PLAYER_STATE::SPAWNED){ + // A player + + g_hud_color = autocvar_con_color * (1 / 255); - g_hud_color = autocvar_con_color * (1 / 255); + /* little point in not drawing these, even if you don't have a suit */ + Weapons_DrawCrosshair(); + HUD_DrawWeaponSelect(); + Obituary_Draw(); + Textmenu_Draw(); + + + //TAGGG - NEw + ////////////////////////////////////////////////////////////// + //View_HandleZoom(); + + //printfline("SCOPE LEVEL %.2f", pl.flZoomLevel); + if(pl.flZoomLevel < 0.5){ //is this < 40? yes. + HUD_DrawScope(); + }else{ + // We'll leave details like extra details for the lasersight and the weight bars at a bare minimum + // (should be drawn at all times, oversight in TS 2.1 that they're missing from melee views + // like with knives, katana, corrected in 3.0 of all things) + HUD_DrawCrosshair(); + } + ////////////////////////////////////////////////////////////// + + GameClient_PlayerInputRaw(); - /* little point in not drawing these, even if you don't have a suit */ - Weapons_DrawCrosshair(); - HUD_DrawWeaponSelect(); - Obituary_Draw(); - Textmenu_Draw(); - - -//TAGGG - NEw -////////////////////////////////////////////////////////////// - //View_HandleZoom(); - - //printfline("SCOPE LEVEL %.2f", pl.flZoomLevel); - if(pl.flZoomLevel < 0.5){ //is this < 40? yes. - HUD_DrawScope(); + //TAGGG - NEw + ////////////////////////////////////////////////////////////// + drawTimer(); + drawPlayerStats(); + //TAGGG - CRITICAL. Nope, Weapons_DrawCrosshair actually calls a weapon's custom HUD drawing method. + // Odd name, but yes, it's not actually focused on just crosshairs. TS uses the more generic + // "HUD_DrawCrosshair" call above. + //drawPlayerCurrentWeaponStats(); + ////////////////////////////////////////////////////////////// + + + // TEST! Just for nuclide, doesn't matter what m_iHUDWeaponSelected is exactly, + // just 0 or non-zero has significance in it. + pSeat->m_iHUDWeaponSelected = (pl.weaponSelectHighlightID != -1); + + + TS_keyRefTapped = 0; //reset. + + HUD_DrawNotify(); + // Nuclide provided method, draws the HL pain arrows + // Nope! Replaced with a completely new version that does that and more for more control. + // And not even calling from here, leaving that to PostDraw (draw.qc) instead. + // Might stop the pain flash from affecting the color of HUD draw's. + //Damage_Draw(); + //ClientGame_DamageDraw(); + + + }else{ - // We'll leave details like extra details for the lasersight and the weight bars at a bare minimum - // (should be drawn at all times, oversight in TS 2.1 that they're missing from melee views - // like with knives, katana, corrected in 3.0 of all things) - HUD_DrawCrosshair(); - } -////////////////////////////////////////////////////////////// - - GameClient_PlayerInputRaw(); + // Fake spectator really. + + //printfline("I AM FAKE"); + + drawfont = FONT_20; + // TAGGG - could have some message from server-to-client on changing from player to spectator + // to call this only then, but I think doing this every frame for spectator is harmless anyway. + // Changing the FOV isn't necessary, that already comes with the spec/player change, some + // things are nicely defaulted for us in FTE. + setsensitivityscaler(1.0f); -//TAGGG - NEw -////////////////////////////////////////////////////////////// - drawTimer(); - drawPlayerStats(); - //TAGGG - CRITICAL. Nope, Weapons_DrawCrosshair actually calls a weapon's custom HUD drawing method. - // Odd name, but yes, it's not actually focused on just crosshairs. TS uses the more generic - // "HUD_DrawCrosshair" call above. - //drawPlayerCurrentWeaponStats(); -////////////////////////////////////////////////////////////// + + GameClient_SpectatorInputRaw(); + + + drawTimer(); + + //TAGGG - Moved over! Is it wise for this to go here? + // Links to drawing the MoTD and buymenu when appropriate + //TAGGG - CRITICAL. "self" is a spectator, not a player!! + // Send over the above "spec" instead too! + CSQC_VGUI_Draw(pl); + + }// pl.iState check - - // TEST! Just for nuclide, doesn't matter what m_iHUDWeaponSelected is exactly, - // just 0 or non-zero has significance in it. - pSeat->m_iHUDWeaponSelected = (pl.weaponSelectHighlightID != -1); - - - TS_keyRefTapped = 0; //reset. - - HUD_DrawNotify(); - // Nuclide provided method, draws the HL pain arrows - // Nope! Replaced with a completely new version that does that and more for more control. - // And not even calling from here, leaving that to PostDraw (draw.qc) instead. - // Might stop the pain flash from affecting the color of HUD draw's. - //Damage_Draw(); - //ClientGame_DamageDraw(); + } -/* + string g_specmodes[] = { "Free Camera", "Third Person", "First Person" }; -*/ + // specatator main entry +// NOTE! This is for the real, Nuclide-provided spectator. +// The fake spectator is a normal player entity with iState set to PLAYER_STATE::NOCLIP. +// HUD_DRAW above is still called in that case. That needs the MoTD and buymenu. void HUD_DrawSpectator(void) { - Textmenu_Draw(); spectator spec = (spectator)pSeat->m_ePlayer; drawfont = FONT_20; - /* vector vecPos; string strText; - // No need to display these. strText = sprintf("Tracking: %s", getplayerkeyvalue(spec.spec_ent - 1, "name")); vecPos[0] = g_hudmins[0] + (g_hudres[0] / 2) - (stringwidth(strText, TRUE, [20,20]) / 2); vecPos[1] = g_hudmins[1] + g_hudres[1] - 60; @@ -141,25 +175,5 @@ HUD_DrawSpectator(void) vecPos[0] = g_hudmins[0] + (g_hudres[0] / 2) - (stringwidth(strText, TRUE, [20,20]) / 2); vecPos[1] = g_hudmins[1] + g_hudres[1] - 40; drawstring(vecPos, strText, [20,20], [1,1,1], 1.0f, DRAWFLAG_ADDITIVE); - */ - - - // TAGGG - could have some message from server-to-client on changing from player to spectator - // to call this only then, but I think doing this every frame for spectator is harmless anyway. - // Changing the FOV isn't necessary, that already comes with the spec/player change, some - // things are nicely defaulted for us in FTE. - setsensitivityscaler(1.0f); - - - GameClient_SpectatorInputRaw(); - - - drawTimer(); - - //TAGGG - Moved over! Is it wise for this to go here? - // Links to drawing the MoTD and buymenu when appropriate - //TAGGG - CRITICAL. "self" is a spectator, not a player!! - // Send over the above "spec" instead too! - CSQC_VGUI_Draw( (player)self ); } diff --git a/src/client/hud_weaponselect.h b/src/client/hud_weaponselect.h index 64079dd..23d7009 100644 --- a/src/client/hud_weaponselect.h +++ b/src/client/hud_weaponselect.h @@ -1,9 +1,6 @@ //NEW FILE. - -//whatever needs to be accessed out of order. - +// whatever needs to be accessed out of order. BOOLEAN HUD_DrawWeaponSelect_CheckClick(void); - BOOLEAN HUD_CloseWeaponSelect(BOOL playOffSound); diff --git a/src/client/hud_weaponselect.qc b/src/client/hud_weaponselect.qc index ce09968..59d1b5a 100644 --- a/src/client/hud_weaponselect.qc +++ b/src/client/hud_weaponselect.qc @@ -14,23 +14,8 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -vector g_vecHUDNums[6] = -{ - [168 / 256, 72 / 128], - [188 / 256, 72 / 128], - [208 / 256, 72 / 128], - [168 / 256, 92 / 128], - [188 / 256, 92 / 128], - [208 / 256, 92 / 128] -}; - - - - var float fHUDWeaponLast; - - typedef struct { string sSprite; vector vOrigin; @@ -61,7 +46,6 @@ HUD_DrawWeaponSelect_PreviousItem(int weaponID_toStartFrom, BOOLEAN freeSlotMove { player pl = (player)pSeat->m_ePlayer; - // set to TRUE if we start at an invalid range, so that we may include the first valid of any sort. BOOLEAN canAcceptSame = FALSE; @@ -81,8 +65,6 @@ HUD_DrawWeaponSelect_PreviousItem(int weaponID_toStartFrom, BOOLEAN freeSlotMove int currentSlot = -1; - - if(weaponID_toStartFrom != -1){ // Get what slot the currently equipped weapon is on. // If it doesn't match the forcedSlot (if applicable: 1-5 keys forcing one), @@ -93,8 +75,6 @@ HUD_DrawWeaponSelect_PreviousItem(int weaponID_toStartFrom, BOOLEAN freeSlotMove // to start from. dynaRef = pl.ary_myWeapons[weaponID_toStartFrom]; - - if(!freeSlotMovement ){ //That is, if the player was selecting a weapon in akimbo, but the slot is no longer 5.. @@ -113,7 +93,6 @@ HUD_DrawWeaponSelect_PreviousItem(int weaponID_toStartFrom, BOOLEAN freeSlotMove //notice: picking an akimbo weapon choice while a non-akimbo weapon is selected // will trigger this too, since the forcedSlot will be 5. non-akimbo weapons never have that. - if(currentSlot != forcedSlot){ weaponID_toStartFrom = -1; //hack to start at #0 instead canAcceptSame = FALSE; @@ -123,9 +102,7 @@ HUD_DrawWeaponSelect_PreviousItem(int weaponID_toStartFrom, BOOLEAN freeSlotMove pl.weaponSelectHighlightAkimbo = (forcedSlot == 5); currentSlot = forcedSlot; }else{ - - - + if(!pl.weaponSelectHighlightAkimbo){ //So we have a place to start looking from. Off we go, find the next weapon that belongs to this same slot. @@ -172,7 +149,6 @@ HUD_DrawWeaponSelect_PreviousItem(int weaponID_toStartFrom, BOOLEAN freeSlotMove weaponID_toStartFromThisSlot -= 1; } - BOOLEAN scheduleTermination = FALSE; //int lastWeaponToCheck = 0; @@ -229,9 +205,7 @@ HUD_DrawWeaponSelect_PreviousItem(int weaponID_toStartFrom, BOOLEAN freeSlotMove } return i; } - } - } //Moving on to check a different slot? Reset weaponID_toStartFromThisSlot then @@ -270,7 +244,6 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement return pl.ary_myWeapons_softMax-1; } - weapondynamic_t dynaRef; weapondata_basic_t* weaponBasicP; @@ -278,10 +251,8 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement int currentSlot = -1; - //printfline("HUD_DrawWeaponSelect_NextItem weaponID_toStartFrom:%i", weaponID_toStartFrom); - if(weaponID_toStartFrom != -1){ dynaRef = pl.ary_myWeapons[weaponID_toStartFrom]; @@ -309,7 +280,6 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement } } - if(pl.weaponSelectHighlightAkimbo != (forcedSlot==5) ){ weaponID_toStartFrom = 1; //hack to start at #max instead canAcceptSame = FALSE; @@ -321,7 +291,6 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement pl.weaponSelectHighlightAkimbo = (forcedSlot == 5); currentSlot = forcedSlot; }else{ - if(!pl.weaponSelectHighlightAkimbo){ @@ -366,8 +335,6 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement currentSlot = forcedSlot; } - - //we only use the toStartFrom offset for finding the next/previous weapon in the same slot. //After that we start from the beginning/end of the next/previous slot accordingly for searching. int weaponID_toStartFromThisSlot = weaponID_toStartFrom; @@ -378,7 +345,6 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement BOOLEAN scheduleTermination = FALSE; //int lastWeaponToCheck = 0; - //printfline("weaponID_toStartFromThisSlot:%i, canAcceptSame:%d", weaponID_toStartFromThisSlot, canAcceptSame); for(int slotOffset = 0; slotOffset <= 5; slotOffset++){ @@ -439,13 +405,9 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement } return i; } - - } - } - //Moving on to check a different slot? Reset weaponID_toStartFromThisSlot then // hack to make it start at ary_myWeapons_softMax. That is not having "- 1". weaponID_toStartFromThisSlot = pl.ary_myWeapons_softMax; @@ -459,7 +421,6 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement }else{ slotOffset -= 1; //keep the slot exactly the same - scheduleTermination = TRUE; } }//END OF LOOP THROUGH SLOTS @@ -471,12 +432,13 @@ HUD_DrawWeaponSelect_NextItem(int weaponID_toStartFrom, BOOLEAN freeSlotMovement }//HUD_DrawWeaponSelect_NextItem - - void HUD_DrawWeaponSelect_Forward(void) { player pl = (player)pSeat->m_ePlayer; + if(pl.iState != PLAYER_STATE::SPAWNED){ + return; + } if(pl.weaponSelectHighlightID == -1){ //pick the weapon after then @@ -510,6 +472,9 @@ void HUD_DrawWeaponSelect_Back(void) { player pl = (player)pSeat->m_ePlayer; + if(pl.iState != PLAYER_STATE::SPAWNED){ + return; + } if(pl.weaponSelectHighlightID == -1){ //pick the weapon after then @@ -548,6 +513,11 @@ HUD_DrawWeaponSelect_Back(void) void HUD_DrawWeaponSelect_Trigger(void) { + player pl = (player)pSeat->m_ePlayer; + if(pl.iState != PLAYER_STATE::SPAWNED){ + return; + } + //TAGGG - TODO - was commented out in old FreeTS, doing so here too. // But figure out what it needs to do, this likely wasn't pointless /* @@ -578,7 +548,7 @@ HUD_DrawWeaponSelect_Trigger(void) -//Cheap way to instantly close the weapon select area +// Cheap way to instantly close the weapon select area BOOLEAN HUD_CloseWeaponSelect(BOOL playOffSound) { @@ -638,59 +608,7 @@ HUD_DrawWeaponSelect(void) drawPlayerInventory_TopBar(-1, FALSE); - // FreeHL WAY! - /* - player pl = (player)pSeat->m_ePlayer; - if (!pl.inventoryEquippedIndex) { - return; - } - if (pSeat->m_flHUDWeaponSelectTime < time) { - if (pSeat->m_iHUDWeaponSelected) { - sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudoff.wav", 0.5, ATTN_NONE); - pSeat->m_iHUDWeaponSelected = 0; - } - return; - } - - vector vecPos = g_hudmins + [16,16]; - - int b; - int wantslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot; - int wantpos = g_weapons[pSeat->m_iHUDWeaponSelected].slot_pos; - for (int i = 0; i < 5; i++) { - int slot_selected = 0; - vecPos[1] = g_hudmins[1] + 16; - HUD_DrawWeaponSelect_Num(vecPos, i); - vecPos[1] += 20; - for (int x = 0; x < 32; x++) { - if (i == wantslot) { - slot_selected = TRUE; - if (x == wantpos) { - // Selected Sprite - Weapons_HUDPic(pSeat->m_iHUDWeaponSelected, 1, vecPos, 1.0f); - drawsubpic(vecPos, [170,45], g_hud3_spr, - [0,180/256], [170/256,45/256], g_hud_color, 1, DRAWFLAG_ADDITIVE); - vecPos[1] += 50; - } else if ((b=HUD_InSlotPos(i, x)) != -1) { - // Unselected Sprite - Weapons_HUDPic(b, 0, vecPos, 1.0f); - vecPos[1] += 50; - } - } else if (HUD_InSlotPos(i, x) != -1) { - HUD_DrawWeaponSelect_Num(vecPos, 5); - vecPos[1] += 25; - } - } - - if (slot_selected == TRUE) { - vecPos[0] += 175; - } else { - vecPos[0] += 25; - } - } - */ - -}//END OF HUD_DrawWeaponSelect +}//HUD_DrawWeaponSelect @@ -700,9 +618,8 @@ HUD_DrawWeaponSelect(void) BOOLEAN HUD_DrawWeaponSelect_CheckClick(void) { - if(getplayerkeyvalue(player_localnum, "*spec") != "0"){ - //some form of spectator? NOT ALLOWED. - //printfline("HEY there closing my weapon select 2"); + player pl = (player)pSeat->m_ePlayer; + if(pl.iState != PLAYER_STATE::SPAWNED){ HUD_CloseWeaponSelect(FALSE); return FALSE; } @@ -745,45 +662,23 @@ HUD_DrawWeaponSelect_Last(void) */ } -/* -void -HUD_DrawWeaponSelect_Num(vector vecPos, float fValue) -{ - drawsubpic(vecPos, [20,20], g_hud7_spr, g_vecHUDNums[fValue], [20/256, 20/128], g_hud_color, 1, DRAWFLAG_ADDITIVE); -} -*/ -/* -int -HUD_InSlotPos(int slot, int pos) + +void +HUD_SlotSelect(int slot) { player pl = (player)pSeat->m_ePlayer; - for (int i = 1; i < g_weapons.length; i++) { - if (g_weapons[i].slot == slot && g_weapons[i].slot_pos == pos) { - if (pl.g_items & g_weapons[i].id) { - return i; - } else { - return (-1); - } - } + if(pl.iState != PLAYER_STATE::SPAWNED){ + return; } - return (-1); -} -*/ - - - - - -void -TS_SelectSlot(int slotPicked) -{ - player pl = (player)pSeat->m_ePlayer; + int slotPicked = slot+1; + + // Keep track of the currently open slot. Navigate through it... - // move to another slot if needed... - + // move to another slot if needed + //printlinef("HUD_SlotSelect: %i maxweap:%i classname:%s\n", slot, pl.ary_myWeapons_softMax, pl.classname); //printfline("weapon slot currently highlighted: %i", pl.weaponSelectHighlightID); if(pl.weaponSelectHighlightID == -1){ @@ -810,75 +705,5 @@ TS_SelectSlot(int slotPicked) } } -}//TS_SelectSlot - - -void -HUD_SlotSelect(int slot) -{ - player pl = (player)pSeat->m_ePlayer; - - //printlinef("HUD_SlotSelect: %i maxweap:%i classname:%s\n", slot, pl.ary_myWeapons_softMax, pl.classname); - - if(getplayerkeyvalue(player_localnum, "*spec") != "0"){ - // A spectator? Stop. - return; - } - - //TAGGG - redirect. - TS_SelectSlot(slot + 1); - - - /* - player pl = (player)pSeat->m_ePlayer; - int curslot = g_weapons[pSeat->m_iHUDWeaponSelected].slot; - int i; - - if (g_textmenu != "") { - Textmenu_Input(slot); - return; - } - - // hack to see if we have ANY weapons at all. - if (!pl.inventoryEquippedIndex) { - return; - } - - if (pSeat->m_flHUDWeaponSelectTime < time) { - sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_hudon.wav", 0.5, ATTN_NONE); - } else { - sound(pSeat->m_ePlayer, CHAN_ITEM, "common/wpn_moveselect.wav", 0.5, ATTN_NONE); - } - - // weren't in that slot? select the first one then - if (curslot != slot) { - for (i = 1; i < g_weapons.length; i++) { - if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) { - pSeat->m_iHUDWeaponSelected = i; - pSeat->m_flHUDWeaponSelectTime = time + 3; - break; - } - } - } else { - int first = -1; - for (i = 1; i < g_weapons.length; i++) { - if (g_weapons[i].slot == slot && pl.g_items & g_weapons[i].id) { - if (i < pSeat->m_iHUDWeaponSelected && first == -1) { - first = i; - } else if (i > pSeat->m_iHUDWeaponSelected) { - first = -1; - pSeat->m_iHUDWeaponSelected = i; - pSeat->m_flHUDWeaponSelectTime = time + 3; - break; - } - } - } - - if (first > 0) { - pSeat->m_iHUDWeaponSelected = first; - pSeat->m_flHUDWeaponSelectTime = time + 3; - } - } - */ } diff --git a/src/server/gamerules_multiplayer.qc b/src/server/gamerules_multiplayer.qc index 0d6b142..c049fb9 100644 --- a/src/server/gamerules_multiplayer.qc +++ b/src/server/gamerules_multiplayer.qc @@ -320,9 +320,8 @@ TSMultiplayerRules::PlayerDeath(base_player pp) TS_resetViewModel(pl); pl.setInventoryEquippedIndex(-1); - printfline("How many weapons do you have mr player??? %i", pl.ary_myWeapons_softMax); + printfline("How many weapons do you have, dead player? %i", pl.ary_myWeapons_softMax); for(int i = pl.ary_myWeapons_softMax-1; i >= 0; i--){ - printfline("Dropping this weapon my boy", i); pl.dropWeapon(i, TRUE); } @@ -583,6 +582,11 @@ TSMultiplayerRules::RestartRound(int iWipe) for (entity eFind = world; (eFind = find(eFind, ::classname, "player"));) { //self = eFind; player pl = (player)eFind; + + // only affect players ingame! + if(pl.iState != PLAYER_STATE::SPAWNED){ + continue; + } //printfline("PLAYER MONEY 1: %i", pl.money); @@ -592,7 +596,9 @@ TSMultiplayerRules::RestartRound(int iWipe) // Something about this resets the player money..? Is it changing to Spectator // right before Player that did it here? - PlayerMakeSpectator(pl); + //PlayerMakeSpectator(pl); + // just let PlayerMakePlayable work. + pl.iState = PLAYER_STATE::NOCLIP; PlayerMakePlayable(pl); } @@ -704,6 +710,7 @@ TSMultiplayerRules::CountPlayers(void) } } + // These would be authentic spectators, or those that can't even open the buy menu. for (entity eFind = world; (eFind = find(eFind, ::classname, "spectator"));) { g_ts_player_spectator++; } @@ -940,9 +947,6 @@ void TSMultiplayerRules::MakePlayerInvisible(player pl){ pl.SetMovetype(MOVETYPE_NONE); pl.SetSolid(SOLID_NOT); pl.takedamage = DAMAGE_NO; - // Don't know what these have to do with being invisible. - pl.armor = pl.activeweapon = pl.g_items = 0; - pl.health = 0; } @@ -983,8 +987,17 @@ void TSMultiplayerRules::PlayerMakePlayable(base_player pp) { player pl = (player)pp; + if(pl.iState == PLAYER_STATE::SPAWNED){ + // no need to do this again. + // Set pl.iState to something else first if this was an intentional re-spawn + // for an ingame player + return; + } - MakePlayable(pp); + pl.iState = PLAYER_STATE::SPAWNED; + printfline("HERE I AM MAKING IT SPAWNED!!!"); + // Nope! + //MakePlayable(pp); forceinfokey(pl, "*team", ftos(pl.team)); PlayerRespawn(pl, pl.team); @@ -1002,14 +1015,43 @@ TSMultiplayerRules::PlayerMakeSpectator(base_player pp) { player pl = (player)pp; - if(pl.classname != "spectator" && pl.modelindex != 0){ + if(pl.iState == PLAYER_STATE::NOCLIP){ + // Already in fake spectator! Stop. + return; + } + + + //if(pl.classname != "spectator" && pl.modelindex != 0){ + if(pl.modelindex != 0){ // assume this is necessary MakePlayerInvisible(pl); } // is that necessary still? //TS_resetPlayer(pl, TRUE); - MakeSpectator(pl); + // And don't do this! Just change iState + //MakeSpectator(pl); + pl.iState = PLAYER_STATE::NOCLIP; + + printfline("WELL??? %d", pl.iState), + + // And do the rest of the lines to finish that + // (copied from the Nuclide spectator's constructor) + // Lines already handled by MakePlayerInvisible not here. + pl.flags = FL_CLIENT; + pl.think = NULL; + pl.nextthink = 0.0f; + pl.maxspeed = 250; + //pl.spec_ent = 0; + //pl.spec_mode = 0; + + //#ifdef SERVER + forceinfokey(pl, "*spec", "1"); + //#endif + + pl.armor = pl.activeweapon = pl.g_items = 0; + pl.health = 0; + pl.SetMovetype(MOVETYPE_NOCLIP); } @@ -1019,6 +1061,15 @@ TSMultiplayerRules::PlayerMakeSpectator(base_player pp) void TSMultiplayerRules::PlayerMakeSpectatorDelayed(base_player pp) { + // Nevermind, this has no significance anymore with the client entity change no longer + // happening. Redirect to the normal version + + player pl = (player)pp; + printfline("SO WHAT %d", pl.iState), + PlayerMakeSpectator(pp); + + + /* player pl = (player)pp; if(pl.classname != "spectator" && pl.modelindex != 0){ @@ -1039,6 +1090,7 @@ TSMultiplayerRules::PlayerMakeSpectatorDelayed(base_player pp) // "dead" should already be set. //forceinfokey(pl, "*dead", "1"); //forceinfokey(pl, "*team", ftos(pl.team)); + */ } /* @@ -1055,6 +1107,19 @@ TSMultiplayerRules::PlayerSpawn(base_player pp) { player pl = (player)pp; + //printfline("PlayerSpawn, what is classname before anything has been done? %s %s", self.classname, pp.classname); + + // Apparently the player already arrives as a "player", a Nuclide-implemented event called + // ClientConnect makes the client entity a "player" by using spawnfunc. + // Having the "player" class available that early makes me wonder why "base_player" is used so + // often in implemented methods, but not an issue. + // ClientConnect is called before PutClientInServer (the one that leads to the gamerules + // PlayerSpawn, right here), just for info. + + // What this means is, no need for spawnfunc_player here. + + + // should "Frags" be an infokey to be better preserved through player/spectator changes? // No clue. And setting these only that way further down by forceinfokey too. //pl.frags = 0; diff --git a/src/shared/player.h b/src/shared/player.h index 3ec246f..46f3554 100644 --- a/src/shared/player.h +++ b/src/shared/player.h @@ -3,9 +3,43 @@ class TSWorldGun; +// NOTE- +// even on the "Press Fire To Play!" text, that shows up after the spawn countdown +// finishes (shown on trying to spawn too early), there is actually 1 second left +// until clicking to spawn does anything. Kindof odd, probably an oversight. + +// State of the player for whether they're ingame, thirdperson recently on death, +// or in fake-spectator (buy menu). +// Players enter the server in the NOCLIP state. +enum PLAYER_STATE{ + // Nothing special. Collision, gravity, equips things. + SPAWNED = 0, + // Like a third-person view of the player's most recent position, unsure + // if it follows the corpse, try dying while moving in TS to see. + // Slowly zooms out to a point. + // Changes to DEAD_NOCLIP (aka "Fake Spectator") on clicking between 1 + // and 2.5 seconds, or waiting out the 2.5 seconds (happens anyway) + DEAD_RECENT, + // Starts at the exact point where the dead player was. + // Would probably be better to just leave the camera where it is insead of + // jumping to the player's old point, unnecessary to do that and kinda jarring. + NOCLIP +}; + + +#define PREDICTED_CUSTOM(arg_t, x) arg_t x; arg_t x ##_net + + noref int input_sequence; class player:base_player { + + // On death, the player cannot change the camera to fake-specator until at least 1 second + // has passed. + // On death, set this to 2.5. If it is less than 1.5, + float deathCameraChangeTime; + + //TAGGG - I'm not messing around with that memory issue from last time. // But try again with this removed whenever it turns out ok, see if this is needed anymore. //virtual void (void)dummyBufferMethod; @@ -24,11 +58,8 @@ class player:base_player //TAGGG - TODO! Put the PREDICTED_INT/FLOAT/whatever stuff on what needs it. - // Determines if this player should be a fake-spectator with MoTD and buymenu (FALSE) - // or be a physical player that can equip weapons and interact with the world (TRUE). - // Jumping to fake-spectator on death will force this to FALSE too. - // Yet to be implemented. - BOOL spawned; + PREDICTED_CUSTOM(PLAYER_STATE, iState); + #ifdef SSQC diff --git a/src/shared/player.qc b/src/shared/player.qc index d769346..1668e5f 100644 --- a/src/shared/player.qc +++ b/src/shared/player.qc @@ -149,6 +149,9 @@ player::ReceiveEntity(float new, float fl) ///////////////////////////////////////////////////// + + iState = readfloat(); + int inventoryEquippedIndex_temp = readbyte(); // Overflow can do funny things. -1 comes as 255 because thats how bits work @@ -291,7 +294,8 @@ player::PredictPreFrame(void) SAVE_STATE(ammo_rpg_state); SAVE_STATE(mode_tempstate); */ - + + SAVE_STATE(iState); SAVE_STATE(inventoryEquippedIndex); SAVE_STATE(weaponEquippedAkimbo); SAVE_STATE(w_attack_akimbo_next); @@ -356,6 +360,7 @@ player::PredictPostFrame(void) ROLL_BACK(mode_tempstate); */ + ROLL_BACK(iState); ROLL_BACK(inventoryEquippedIndex); ROLL_BACK(weaponEquippedAkimbo); ROLL_BACK(w_attack_akimbo_next); @@ -465,6 +470,7 @@ player::EvaluateEntity(void) SAVE_STATE(anim_bottom); SAVE_STATE(anim_bottom_time); + SAVE_STATE(iState); SAVE_STATE(inventoryEquippedIndex); SAVE_STATE(weaponEquippedAkimbo); SAVE_STATE(w_attack_akimbo_next); @@ -574,6 +580,7 @@ player::SendEntity(entity ePEnt, float fChanged) // OR if a particular weapon states to update its features, perhaps sending itself // through + WriteFloat(MSG_ENTITY, iState); WriteByte(MSG_ENTITY, inventoryEquippedIndex ); WriteByte(MSG_ENTITY, weaponEquippedAkimbo ); WriteFloat(MSG_ENTITY, w_attack_akimbo_next ); @@ -657,6 +664,8 @@ void player::player(void){ // just in case? this.classname = "player"; + // reasonable default? + iState = PLAYER_STATE::NOCLIP; #ifdef SSQC money = 0; //safety? @@ -688,8 +697,11 @@ void player::player(void){ flKarateBlockCooldown = 0; - setInventoryEquippedIndex(-1); + + // Should we? + //setInventoryEquippedIndex(-1); inventoryEquippedIndex_previous = -1; + weaponEquippedAkimbo = FALSE; //safe default. @@ -754,6 +766,10 @@ player::reset(BOOLEAN resetInventory){ INPUT_TAP_RESET(this) + // should this even make any assumptions about this? + //iState = ?; + + #ifdef CSQC // For safety, doing this. @@ -1399,7 +1415,7 @@ player::dropWeapon(int arg_weaponID, BOOLEAN completeDrop){ // It sees the "drop" command called and so sends an event to the server that got to this "dropWeapon" method // here in player. okay. - printfline("playerDrop: Anything?"); + printfline("playerDrop. weaponID:%i completeDrop:%d", arg_weaponID, completeDrop); weapondynamic_t dynaRefPRE = ary_myWeapons[arg_weaponID]; weapondata_basic_t* basicP = getInventoryWeaponData(arg_weaponID, TRUE); @@ -1410,9 +1426,11 @@ player::dropWeapon(int arg_weaponID, BOOLEAN completeDrop){ // WARNING! This is still checking the possibly akimbo variant for having a // worldmodel. The drops are still the singular variant in any case, but verify that. if((*basicP).sWorldModelPath == ""){ - //if the world model path is empty, we can't be dropped. - // Safe assumption. - printfline("...no world model?"); + // if the world model path is empty, we can't be dropped. + if(completeDrop){ + // But if this is a completeDrop (dead player), delete it anyway. + removeWeaponFromInventory(this, arg_weaponID); + } return; } @@ -1426,7 +1444,7 @@ player::dropWeapon(int arg_weaponID, BOOLEAN completeDrop){ }else{ // don't bother with the equip-ideal call that equippedWeaponDeleteCheck does. deletedCurrentWeapon = inventoryWeaponDeleteCheck(arg_weaponID); - setInventoryEquippedIndex(-1); + //setInventoryEquippedIndex(-1); } }else{ // Still, see if this weapon would prefer to disappear rather than @@ -1442,7 +1460,7 @@ player::dropWeapon(int arg_weaponID, BOOLEAN completeDrop){ // No, just use basicPS for below. //basicP = getEquippedWeaponData_Singular(); - printfline("playerDrop: deletedCurrentWeapon? %d", deletedCurrentWeapon); + printfline("-deletedCurrentWeapon? %d", deletedCurrentWeapon); if(deletedCurrentWeapon){ // STOP. Apparently the player deleted this weapon in the holster call above, diff --git a/src/shared/weapons/weapon_karate.qc b/src/shared/weapons/weapon_karate.qc index bf07535..eab4bad 100644 --- a/src/shared/weapons/weapon_karate.qc +++ b/src/shared/weapons/weapon_karate.qc @@ -2,6 +2,9 @@ //TAGGG - TODO - some kicks should disarm the player hit, I forget if it's all kicks // or just crouch-kicks. +// ALSO, weapons that lack world-models will never drop, safe assumption. +// That is why karate never drops. + enum weaponseq_karate{ //nothing = 0