From e88bb4d0548595bc326fa635ccb1f35683c313b5 Mon Sep 17 00:00:00 2001 From: tojba <1348625+tojba@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:08:35 +0200 Subject: [PATCH 1/5] Extract existing EntWatch world-text HUD renderer --- AMBuilder | 1 + src/entwatch.cpp | 14 +---- src/entwatch_hud.h | 25 ++++++++ src/entwatch_hud_worldtext.cpp | 108 +++++++++++++++++++++++++++++++++ src/playermanager.cpp | 68 +-------------------- src/playermanager.h | 1 + 6 files changed, 138 insertions(+), 79 deletions(-) create mode 100644 src/entwatch_hud.h create mode 100644 src/entwatch_hud_worldtext.cpp diff --git a/AMBuilder b/AMBuilder index 66d4347d..fb28c1b0 100644 --- a/AMBuilder +++ b/AMBuilder @@ -58,6 +58,7 @@ for sdk_target in MMSPlugin.sdk_targets: 'src/discord.cpp', 'src/map_votes.cpp', 'src/entwatch.cpp', + 'src/entwatch_hud_worldtext.cpp', 'src/user_preferences.cpp', 'src/zombiereborn.cpp', 'src/customio.cpp', diff --git a/src/entwatch.cpp b/src/entwatch.cpp index 3c77ee84..c8a40392 100644 --- a/src/entwatch.cpp +++ b/src/entwatch.cpp @@ -18,6 +18,7 @@ */ #include "entwatch.h" +#include "entwatch_hud.h" #include "commands.h" #include "cs2fixes.h" #include "ctimer.h" @@ -1957,18 +1958,7 @@ float EW_UpdateHud() if (!zpPlayer) continue; - EWHudMode mode = (EWHudMode)(zpPlayer->GetEntwatchHudMode()); - - CPointWorldText* pText = zpPlayer->GetEntwatchHud(); - if (!pText) - continue; - - if (mode == EWHudMode::Hud_On) - pText->AcceptInput("SetMessage", sHudText.c_str()); - else if (mode == EWHudMode::Hud_ItemOnly) - pText->AcceptInput("SetMessage", sHudTextNoPlayerNames.c_str()); - else - pText->AcceptInput("SetMessage", ""); + EW_RenderWorldText(zpPlayer, sHudText, sHudTextNoPlayerNames); } return EW_HUD_TICKRATE; diff --git a/src/entwatch_hud.h b/src/entwatch_hud.h new file mode 100644 index 00000000..a0674793 --- /dev/null +++ b/src/entwatch_hud.h @@ -0,0 +1,25 @@ +/** + * ============================================================================= + * CS2Fixes + * Copyright (C) 2023-2026 Source2ZE + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * 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, see . + */ + +#pragma once + +#include + +class ZEPlayer; +void EW_RenderWorldText(ZEPlayer* pPlayer, const std::string& sHudText, const std::string& sHudTextNoPlayerNames); diff --git a/src/entwatch_hud_worldtext.cpp b/src/entwatch_hud_worldtext.cpp new file mode 100644 index 00000000..c62a6004 --- /dev/null +++ b/src/entwatch_hud_worldtext.cpp @@ -0,0 +1,108 @@ +/** + * ============================================================================= + * CS2Fixes + * Copyright (C) 2023-2026 Source2ZE + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * 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, see . + */ + +#include "entity/ccsplayercontroller.h" +#include "entwatch.h" +#include "entwatch_hud.h" +#include "playermanager.h" +#include "utils/entity.h" + +void ZEPlayer::CreateEntwatchWorldHud() +{ + CCSPlayerController* pController = CCSPlayerController::FromSlot(GetPlayerSlot()); + if (!pController) + return; + + CCSPlayerPawn* pPawn = pController->GetPlayerPawn(); + if (!pPawn) + return; + + CPointOrient* pOrient = GetPointOrient(); + if (!pOrient) + return; + + CPointWorldText* pText = GetEntwatchHud(); + if (pText) + { + pText->Remove(); + pText = nullptr; + } + + pText = CreateEntityByName("point_worldtext"); + pText->m_bEnabled(true); + pText->m_bFullbright(true); + pText->m_flFontSize(GetEntwatchHudSize()); + + Color col; + int a = m_colorEntwatchHud.a(); + if (a == 255) // 254 allows it to be visible through some items + col.SetColor(m_colorEntwatchHud.r(), m_colorEntwatchHud.g(), m_colorEntwatchHud.b(), 254); + else + col.SetColor(m_colorEntwatchHud.r(), m_colorEntwatchHud.g(), m_colorEntwatchHud.b(), a); + + pText->m_Color = col; + + pText->m_flWorldUnitsPerPx(0.005f); + pText->m_nJustifyVertical(PointWorldTextJustifyVertical_t::POINT_WORLD_TEXT_JUSTIFY_VERTICAL_TOP); + + V_strncpy(pText->m_FontName, "Verdana Bold", 64); + + pText->SetMessage(""); + + pText->DispatchSpawn(); + SetEntwatchHud(pText); + + pText->AcceptInput("SetParent", "!activator", pOrient); + + Vector origin = pOrient->GetAbsOrigin(); + QAngle vmangles = pOrient->GetAbsRotation(); + + Vector forward; + Vector right; + Vector up; + AngleVectors(vmangles, &forward, &right, &up); + + origin += (forward * 7.0f); + + // -x = move left, +x = move right + origin += (right * GetEntwatchHudX()); + + // -y = move up, +y = move down + origin -= (up * GetEntwatchHudY()); + + QAngle angles; + angles.x = 0.0f; + angles.y = AngleNormalize(vmangles.y - 90.0f); + angles.z = AngleNormalize(-vmangles.x + 90.0f); + + pText->Teleport(&origin, &angles, nullptr); +} + +void EW_RenderWorldText(ZEPlayer* pPlayer, const std::string& sHudText, const std::string& sHudTextNoPlayerNames) +{ + CPointWorldText* pText = pPlayer->GetEntwatchHud(); + if (!pText) return; + EWHudMode mode = (EWHudMode)pPlayer->GetEntwatchHudMode(); + if (mode == EWHudMode::Hud_On) + pText->AcceptInput("SetMessage", sHudText.c_str()); + else if (mode == EWHudMode::Hud_ItemOnly) + pText->AcceptInput("SetMessage", sHudTextNoPlayerNames.c_str()); + else + pText->AcceptInput("SetMessage", ""); +} diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 6f932105..6aaf5cfa 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -740,73 +740,7 @@ void ZEPlayer::ToggleThirdPerson(float flDistance, bool bForce) void ZEPlayer::CreateEntwatchHud() { - CCSPlayerController* pController = CCSPlayerController::FromSlot(GetPlayerSlot()); - if (!pController) - return; - - CCSPlayerPawn* pPawn = pController->GetPlayerPawn(); - if (!pPawn) - return; - - CPointOrient* pOrient = GetPointOrient(); - if (!pOrient) - return; - - CPointWorldText* pText = GetEntwatchHud(); - if (pText) - { - pText->Remove(); - pText = nullptr; - } - - pText = CreateEntityByName("point_worldtext"); - pText->m_bEnabled(true); - pText->m_bFullbright(true); - pText->m_flFontSize(GetEntwatchHudSize()); - - Color col; - int a = m_colorEntwatchHud.a(); - if (a == 255) // 254 allows it to be visible through some items - col.SetColor(m_colorEntwatchHud.r(), m_colorEntwatchHud.g(), m_colorEntwatchHud.b(), 254); - else - col.SetColor(m_colorEntwatchHud.r(), m_colorEntwatchHud.g(), m_colorEntwatchHud.b(), a); - - pText->m_Color = col; - - pText->m_flWorldUnitsPerPx(0.005f); - pText->m_nJustifyVertical(PointWorldTextJustifyVertical_t::POINT_WORLD_TEXT_JUSTIFY_VERTICAL_TOP); - - V_strncpy(pText->m_FontName, "Verdana Bold", 64); - - pText->SetMessage(""); - - pText->DispatchSpawn(); - SetEntwatchHud(pText); - - pText->AcceptInput("SetParent", "!activator", pOrient); - - Vector origin = pOrient->GetAbsOrigin(); - QAngle vmangles = pOrient->GetAbsRotation(); - - Vector forward; - Vector right; - Vector up; - AngleVectors(vmangles, &forward, &right, &up); - - origin += (forward * 7.0f); - - // -x = move left, +x = move right - origin += (right * GetEntwatchHudX()); - - // -y = move up, +y = move down - origin -= (up * GetEntwatchHudY()); - - QAngle angles; - angles.x = 0.0f; - angles.y = AngleNormalize(vmangles.y - 90.0f); - angles.z = AngleNormalize(-vmangles.x + 90.0f); - - pText->Teleport(&origin, &angles, nullptr); + CreateEntwatchWorldHud(); } int ZEPlayer::GetEntwatchHudMode() diff --git a/src/playermanager.h b/src/playermanager.h index ee7eac18..eb3d4fdc 100644 --- a/src/playermanager.h +++ b/src/playermanager.h @@ -271,6 +271,7 @@ class ZEPlayer void SetActiveZRClass(std::shared_ptr pZRModel) { m_pActiveZRClass = pZRModel; } void SetActiveZRModel(std::shared_ptr pZRClass) { m_pActiveZRModel = pZRClass; } void SetEntwatchHudMode(int iMode); + void CreateEntwatchWorldHud(); void SetPointOrient(CPointOrient* pOrient) { m_hPointOrient.Set(pOrient); } void SetEntwatchHud(CPointWorldText* pWorldText) { m_hEntwatchHud.Set(pWorldText); } void SetEntwatchHudColor(Color colorHud); From bec47cb46b4db5bd6cdffb31146711ea3e1db6fa Mon Sep 17 00:00:00 2001 From: tojba <1348625+tojba@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:08:36 +0200 Subject: [PATCH 2/5] Add Panorama EntWatch item HUD and resource pipeline --- .gitignore | 3 + AMBuilder | 1 + PackageScript | 6 + assets_source/panorama/README.md | 17 + .../panorama/layout/custom_game/hud.xml | 712 ++++++++++++++++++ .../panorama/styles/entwatch/hud.css | 25 + cfg/cs2fixes/cs2fixes.cfg | 3 +- scripts/compile-panorama.ps1 | 31 + src/cs2_sdk/entity/customhudlayout.cpp | 8 +- src/cs2fixes.cpp | 2 + src/entwatch.cpp | 122 ++- src/entwatch_hud.cpp | 155 ++++ src/entwatch_hud.h | 22 +- src/entwatch_hud_worldtext.cpp | 54 +- src/playermanager.cpp | 18 +- src/playermanager.h | 1 + 16 files changed, 1084 insertions(+), 96 deletions(-) create mode 100644 assets_source/panorama/README.md create mode 100644 assets_source/panorama/layout/custom_game/hud.xml create mode 100644 assets_source/panorama/styles/entwatch/hud.css create mode 100644 scripts/compile-panorama.ps1 create mode 100644 src/entwatch_hud.cpp diff --git a/.gitignore b/.gitignore index 590a8dad..f8e77785 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ bld/ .vscode /dockerbuild .idea/* + +# Compiled Panorama resources; regenerate with scripts/compile-panorama.ps1. +/assets/panorama/**/*_c diff --git a/AMBuilder b/AMBuilder index fb28c1b0..9ab20344 100644 --- a/AMBuilder +++ b/AMBuilder @@ -58,6 +58,7 @@ for sdk_target in MMSPlugin.sdk_targets: 'src/discord.cpp', 'src/map_votes.cpp', 'src/entwatch.cpp', + 'src/entwatch_hud.cpp', 'src/entwatch_hud_worldtext.cpp', 'src/user_preferences.cpp', 'src/zombiereborn.cpp', diff --git a/PackageScript b/PackageScript index b68cbc84..8cb0acc8 100644 --- a/PackageScript +++ b/PackageScript @@ -105,6 +105,12 @@ for task in MMSPlugin.binaries: packages[sdk_name].addBinary(task.debug) # Add custom stuff here + panorama_root = os.path.join(builder.sourcePath, 'assets', 'panorama') + for resource in glob.glob(os.path.join(panorama_root, '**', '*_c'), recursive = True): + relative_path = os.path.relpath(resource, panorama_root) + destination = os.path.join(packages[sdk_name].sdk_name, 'panorama', relative_path) + builder.AddFolder(os.path.dirname(destination)) + builder.AddCopy(resource, destination) builder.AddFolder(os.path.join(packages[sdk_name].sdk_name, 'addons', MMSPlugin.metadata['name'], 'data')) configs_folder = builder.AddFolder(os.path.join(packages[sdk_name].sdk_name, 'addons', MMSPlugin.metadata['name'], 'configs')) zr_folder = builder.AddFolder(os.path.join(packages[sdk_name].sdk_name, 'addons', MMSPlugin.metadata['name'], 'configs', 'zr')) diff --git a/assets_source/panorama/README.md b/assets_source/panorama/README.md new file mode 100644 index 00000000..75da15c5 --- /dev/null +++ b/assets_source/panorama/README.md @@ -0,0 +1,17 @@ +The HUD sources are `layout/custom_game/hud.xml` and `styles/entwatch/hud.css`. + +With CS2 Workshop Tools installed, regenerate the compiled assets from the repository root: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File scripts/compile-panorama.ps1 -Cs2Root "F:\steamgames\steamapps\common\Counter-Strike Global Offensive" +``` + +The script stages a local `cs2fixes_hud` addon and copies its compiled VXML/CSS into `assets/panorama`. AMBuild packages those resources under `package/cs2/panorama`, alongside the existing sounds and particles. Rebuild CS2Fixes after compiling. + +Install the package into `game/csgo`. Clients must also have these resources installed or mounted through an addon; installing a server plugin does not distribute files to clients. The staged local addon is available for Workshop Tools testing. + +The green reload icon represents the item's EntWatch ability cooldown. The orange ammo icon represents remaining configured uses or a math-counter value, not the weapon's bullet magazine. Multiple visible handlers are separated with `|`. Items without these handlers show their normal ready state. + +Player-name font size is 16px at 100% HUD size. + +If server-side Panorama resources are missing or entity creation fails, the HUD temporarily falls back to world text and retries at most once every 30 seconds. The player's selected renderer is retained. This cannot detect missing client-side resources. Enable `cs2f_entwatch_panorama_debug 1` for creation diagnostics; it is off by default. Normal disconnect/spawn timing does not generate warnings. diff --git a/assets_source/panorama/layout/custom_game/hud.xml b/assets_source/panorama/layout/custom_game/hud.xml new file mode 100644 index 00000000..1ab12a3d --- /dev/null +++ b/assets_source/panorama/layout/custom_game/hud.xml @@ -0,0 +1,712 @@ + + + + + + diff --git a/assets_source/panorama/styles/entwatch/hud.css b/assets_source/panorama/styles/entwatch/hud.css new file mode 100644 index 00000000..c6a6190d --- /dev/null +++ b/assets_source/panorama/styles/entwatch/hud.css @@ -0,0 +1,25 @@ +.Root { width: 100%; height: 100%; } +.EntWatch { horizontal-align: left; margin-left: 2%; margin-top: 15%; flow-children: down; max-height: 720px; overflow: squish scroll; } +.Hidden { visibility: collapse; } +.Item { width: 480px; padding: 8px 12px; margin-bottom: 5px; background-color: #121820e8; border-left: 3px solid #94a6bd; flow-children: right; } +.Heading { width: fill-parent-flow(1); flow-children: right; vertical-align: center; } +.ItemName { max-width: 50%; white-space: nowrap; text-overflow: ellipsis; vertical-align: center; font-family: Arial; font-size: 18px; font-weight: bold; color: #eef3fa; } +.Owner { width: fill-parent-flow(1); margin-left: 8px; white-space: nowrap; text-overflow: ellipsis; vertical-align: center; font-family: Arial; font-size: 16px; color: #a6b1c2; } +.NamesOnly .Owner { visibility: collapse; } +.NamesOnly .ItemName { max-width: 100%; } +.Status { flow-children: right; margin-left: 12px; vertical-align: center; } +.Status Label { vertical-align: center; font-family: Arial; font-size: 16px; } +.Icon { margin-right: 5px; font-size: 19px; } +.Cooldown { visibility: collapse; flow-children: right; vertical-align: center; } +.Cooldown Label { color: #62df87; } +.Reloading .Cooldown { visibility: visible; } +.Ammo { visibility: collapse; flow-children: right; margin-right: 12px; vertical-align: center; } +.Ammo Label { color: #ffbd55; } +.HasAmmo .Ammo { visibility: visible; } +.Ready { color: #a6b1c2; } +.Reloading .Ready, .HasAmmo .Ready { visibility: collapse; } +.Overflow { font-family: Arial; font-size: 14px; color: #a6b1c2; } + +.ReloadIcon { width: 22px; height: 22px; margin-left: 5px; margin-right: 0px; text-align: center; vertical-align: center; } +.Reloading .ReloadIcon { animation-name: ReloadSpin; animation-duration: 1s; animation-timing-function: linear; animation-iteration-count: infinite; } +@keyframes 'ReloadSpin' { 0% { transform: rotateZ(0deg); } 100% { transform: rotateZ(360deg); } } diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 2ed7948d..aca4ce08 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -162,6 +162,7 @@ entwatch_enable 0 // Whether to enable EntWatch features entwatch_auto_filter 1 // Whether to automatically block non-item holders from triggering uses entwatch_clantag 1 // Whether to set item holder's clantag and set 9999 score entwatch_hud 1 // Whether to enable the EntWatch hud and related commands +entwatch_hud_style 1 // Default renderer: 0 = world text, 1 = Panorama; players can use !hudstyle entwatch_score 9999 // Score to give item holders (0 = dont change score at all) Requires entwatch_clantag 1 entwatch_glow 1000 // Distance that dropped item weapon glow will be visible (0 = glow disabled) entwatch_glow_team 0 // Whether dropped item glow is only visible to the team the item belongs to (0 = glow to all players) @@ -180,4 +181,4 @@ cs2f_mapmigrations_20260922 2 // Current mode for 2026-09-22 CS2 update map mi cs2f_thirdperson_enable 0 // Whether to enable thirdperson cs2f_thirdperson_distance_default 65.0 // Default distance for thirdperson cs2f_thirdperson_distance_min 15.0 // Minimum distance allowed for thirdperson -cs2f_thirdperson_distance_max 150.0 // Maximum distance allowed for thirdperson \ No newline at end of file +cs2f_thirdperson_distance_max 150.0 // Maximum distance allowed for thirdperson diff --git a/scripts/compile-panorama.ps1 b/scripts/compile-panorama.ps1 new file mode 100644 index 00000000..03c653fb --- /dev/null +++ b/scripts/compile-panorama.ps1 @@ -0,0 +1,31 @@ +param( + [Parameter(Mandatory = $true)] + [string]$Cs2Root +) +$ErrorActionPreference = 'Stop' +$repo = Split-Path $PSScriptRoot -Parent +$content = Join-Path $Cs2Root 'content\csgo_addons\cs2fixes_hud' +$output = Join-Path $Cs2Root 'game\csgo_addons\cs2fixes_hud' +$compiler = Join-Path $Cs2Root 'game\bin\win64\resourcecompiler.exe' +if (-not (Test-Path -LiteralPath $compiler)) { throw 'Install CS2 Workshop Tools to obtain resourcecompiler.exe.' } +$layout = Join-Path $content 'panorama\layout\custom_game\hud.xml' +$style = Join-Path $content 'panorama\styles\entwatch\hud.css' +New-Item -ItemType Directory -Force (Split-Path $layout), (Split-Path $style) | Out-Null +Copy-Item -LiteralPath (Join-Path $repo 'assets_source\panorama\layout\custom_game\hud.xml') -Destination $layout -Force +Copy-Item -LiteralPath (Join-Path $repo 'assets_source\panorama\styles\entwatch\hud.css') -Destination $style -Force +Set-Content -LiteralPath (Join-Path $content 'panorama\preprocessor_config.txt') -Encoding ascii -Value '"PanzipCfg" { "BlockDefs" {} }' +Set-Content -LiteralPath (Join-Path $content 'addoninfo.txt') -Encoding utf8 -Value @' + +{ IsPlayable = false } +'@ +& $compiler -game (Join-Path $Cs2Root 'game\csgo') -i $style -i $layout -f -nop4 +if ($LASTEXITCODE -ne 0) { throw "Panorama compiler failed: $LASTEXITCODE" } +foreach ($relative in @('panorama\layout\custom_game\hud.vxml_c', 'panorama\styles\entwatch\hud.vcss_c')) { + $compiled = Join-Path $output $relative + if (-not (Test-Path -LiteralPath $compiled)) { throw "Missing compiled resource: $compiled" } + $destination = Join-Path $repo ('assets\' + $relative) + New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null + Copy-Item -LiteralPath $compiled -Destination $destination -Force +} +Copy-Item -LiteralPath (Join-Path $content 'addoninfo.txt') -Destination (Join-Path $output 'addoninfo.txt') -Force +Write-Host 'Compiled Panorama resources copied into assets/panorama.' diff --git a/src/cs2_sdk/entity/customhudlayout.cpp b/src/cs2_sdk/entity/customhudlayout.cpp index 72f25a87..9d35e94c 100644 --- a/src/cs2_sdk/entity/customhudlayout.cpp +++ b/src/cs2_sdk/entity/customhudlayout.cpp @@ -25,7 +25,6 @@ std::unordered_map CCSCustomHudLayout::sm_mapCu CCSCustomHudLayout* CCSCustomHudLayout::Create(std::string sLayout, std::string sTargetName) { CCSCustomHudLayout* pLayout = CreateEntityByName("custom_hud_layout"); - if (!pLayout) return nullptr; @@ -49,12 +48,14 @@ void CCSCustomHudLayout::ClearCallbacks() void CCSCustomHudLayout::OnClick(CCSPlayerController* pController, const std::string& sButtonId) { - if (auto it = sm_mapCustomLayoutCallbacks.find(GetHandle().ToInt()); it != sm_mapCustomLayoutCallbacks.end()) + if (auto it = sm_mapCustomLayoutCallbacks.find(GetHandle().ToInt()); it != sm_mapCustomLayoutCallbacks.end() && it->second.m_OnClick) it->second.m_OnClick(pController, this, sButtonId); } void CCSCustomHudLayout::OnClientDisconnect(int slot) { + if (slot < 0 || slot >= MAXPLAYERS) + return; auto iterator = sm_mapCustomLayoutCallbacks.begin(); while (iterator != sm_mapCustomLayoutCallbacks.end()) @@ -67,7 +68,8 @@ void CCSCustomHudLayout::OnClientDisconnect(int slot) continue; } - iterator->second.m_OnDisconnect(pLayout, slot); + if (iterator->second.m_OnDisconnect) + iterator->second.m_OnDisconnect(pLayout, slot); iterator++; } } diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 8e3290d2..9cb3a732 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -34,6 +34,7 @@ #include "entitylistener.h" #include "entitysystem.h" #include "entwatch.h" +#include "entwatch_hud.h" #include "eventlistener.h" #include "gameconfig.h" #include "gamesystem.h" @@ -226,6 +227,7 @@ bool CS2Fixes::Unload(char* error, size_t maxlen) CommandList().clear(); UndoPatches(); RemoveAllTimers(); + EW_DestroyHud(); UnregisterEventListeners(); if (g_GameConfig) diff --git a/src/entwatch.cpp b/src/entwatch.cpp index c8a40392..469a49f1 100644 --- a/src/entwatch.cpp +++ b/src/entwatch.cpp @@ -18,7 +18,6 @@ */ #include "entwatch.h" -#include "entwatch_hud.h" #include "commands.h" #include "cs2fixes.h" #include "ctimer.h" @@ -33,6 +32,7 @@ #include "entity/cpointworldtext.h" #include "entity/cteam.h" #include "entity/services.h" +#include "entwatch_hud.h" #include "eventlistener.h" #include "gameevents.pb.h" #include "leader.h" @@ -927,7 +927,7 @@ std::string EWItemInstance::GetHandlerStateText() bool first = true; for (int i = 0; i < (vecHandlers).size(); i++) { - if (!vecHandlers[i]->bShowHud || (int)(vecHandlers[i]->mode) >= EWMode_Last) + if (!vecHandlers[i] || !vecHandlers[i]->bShowHud || (int)(vecHandlers[i]->mode) >= EWMode_Last) continue; vecHandlers[i]->UpdateHudText(); @@ -1064,6 +1064,7 @@ void CEWHandler::UnLoadConfig() vecHookedTriggers.clear(); m_bConfigLoaded = false; + EW_UpdateHud(); } /* @@ -1876,91 +1877,58 @@ KHook::Return CEWHandler::Hook_Use(CBaseEntity* pThis, InputData_t* pInput // Update cd and uses of all held items float EW_UpdateHud() { - if (!GetGlobals()) + if (!GetGlobals() || !g_pEWHandler || !g_playerManager) return EW_HUD_TICKRATE; - std::string sHudText = ""; - std::string sHudTextNoPlayerNames = ""; - static bool bWasEmptyPreviously = false; - - bool bFirst = true; - for (int i = 0; i < (g_pEWHandler->vecItems).size(); i++) + std::vector rows; + for (const auto& item : g_pEWHandler->vecItems) { - std::shared_ptr pItem = g_pEWHandler->vecItems[i]; - if (!pItem) + if (!item || item->iOwnerSlot < 0 || item->iOwnerSlot >= MAXPLAYERS || item->iWeaponEnt == -1 || !item->bShowHud) continue; - - if (pItem->iOwnerSlot == -1 || pItem->iWeaponEnt == -1) - continue; - - if (!pItem->bShowHud) - continue; - - CCSPlayerController* pOwner = CCSPlayerController::FromSlot(CPlayerSlot(pItem->iOwnerSlot)); - if (!pOwner) - continue; - - std::string sItemText = pItem->GetHandlerStateText(); - - if (g_cvarUseEntwatchClantag.Get()) + auto owner = CCSPlayerController::FromSlot(CPlayerSlot(item->iOwnerSlot)); + if (!owner || !owner->IsConnected()) continue; + EntwatchHudRow row; + row.name = item->szShortName; + row.owner = owner->GetPlayerName(); + row.state = item->GetHandlerStateText(); + for (const auto& handler : item->vecHandlers) { - V_snprintf(pItem->sClantag, sizeof(EWItemInstance::sClantag), "%s: %s", sItemText.c_str(), pItem->szShortName.c_str()); - if (pItem->bHasThisClantag) - pOwner->SetClanTag(pItem->sClantag); + if (!handler || !handler->bShowHud || handler->mode < Cooldown || handler->mode >= EWMode_Last) + continue; + // Use the same countdown rounding as the legacy handler text. + const int seconds = handler->flLastUsed == -1.0f ? 0 : + static_cast(handler->flCooldown - (GetGlobals()->curtime - (handler->flLastUsed + 1))); + if (handler->mode != CounterValue && seconds > 0) + { + if (!row.cooldown.empty()) row.cooldown += " | "; + row.cooldown += std::to_string(seconds) + "s"; + } + std::string ammo; + if (handler->mode == MaxUses || handler->mode == CooldownAfterUses) + ammo = std::to_string(std::max(0, handler->iMaxUses - handler->iCurrentUses)) + "/" + std::to_string(handler->iMaxUses); + else if (handler->mode == CounterValue) + ammo = std::to_string(std::max(0, static_cast(std::round(handler->flCounterValue)))) + "/" + std::to_string(static_cast(std::round(handler->flCounterMax))); + if (!ammo.empty()) + { + if (!row.ammo.empty()) row.ammo += " | "; + row.ammo += ammo; + } } - - if (!g_cvarEnableEntwatchHud.Get()) - continue; - - // std::format not supported in clang16 by default (steamrt3) - if (!bFirst) + if (g_cvarUseEntwatchClantag.Get()) { - sHudText.append("\n"); - sHudTextNoPlayerNames.append("\n"); + V_snprintf(item->sClantag, sizeof(EWItemInstance::sClantag), "%s: %s", row.state.c_str(), item->szShortName.c_str()); + if (item->bHasThisClantag) owner->SetClanTag(item->sClantag); } - else - bFirst = false; - - sHudText.append("["); - sHudText.append(sItemText); - sHudText.append("]"); - sHudText.append(pItem->szShortName); - sHudText.append(": "); - sHudText.append(pOwner->GetPlayerName()); - - // sHudTextNoPlayerNames.append(std::format("\n[{}]{}", sItemText, pItem->szShortName)); - sHudTextNoPlayerNames.append("["); - sHudTextNoPlayerNames.append(sItemText); - sHudTextNoPlayerNames.append("]"); - sHudTextNoPlayerNames.append(pItem->szShortName); - } - - if (sHudText != "") - { - bWasEmptyPreviously = false; - } - else - { - if (bWasEmptyPreviously) - return EW_HUD_TICKRATE; - bWasEmptyPreviously = true; + rows.push_back(std::move(row)); } - - for (int i = 0; i < GetGlobals()->maxClients; i++) + // Always render empty lists too: drops, round resets and disabled HUDs must hide immediately. + for (int slot = 0; slot < std::min(GetGlobals()->maxClients, MAXPLAYERS); ++slot) { - CCSPlayerController* pController = CCSPlayerController::FromSlot(i); - if (!pController) - continue; - auto pPawn = pController->GetPawn(); - if (!pPawn) - continue; - ZEPlayer* zpPlayer = g_playerManager->GetPlayer(CPlayerSlot(i)); - if (!zpPlayer) - continue; - - EW_RenderWorldText(zpPlayer, sHudText, sHudTextNoPlayerNames); + auto controller = CCSPlayerController::FromSlot(slot); + auto player = g_playerManager->GetPlayer(CPlayerSlot(slot)); + if (controller && controller->IsConnected() && player && !player->IsFakeClient()) + EW_RenderHud(player, rows); } - return EW_HUD_TICKRATE; } @@ -1977,6 +1945,7 @@ void EW_RoundPreStart() g_pEWHandler->ResetAllClantags(); g_pEWHandler->ClearItems(); + EW_UpdateHud(); } void EW_OnEntitySpawned(CEntityInstance* pEntity) @@ -2589,6 +2558,7 @@ CON_COMMAND_CHAT(hud, "- Toggle EntWatch HUD") mode = EWHudMode::Hud_None; zpPlayer->SetEntwatchHudMode((int)mode); + EW_UpdateHud(); if (mode == EWHudMode::Hud_None) ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "EntWatch HUD\x07 disabled."); diff --git a/src/entwatch_hud.cpp b/src/entwatch_hud.cpp new file mode 100644 index 00000000..369c3601 --- /dev/null +++ b/src/entwatch_hud.cpp @@ -0,0 +1,155 @@ +/** + * ============================================================================= + * CS2Fixes + * Copyright (C) 2023-2026 Source2ZE + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * 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, see . + */ + +#include "entwatch_hud.h" +#include "commands.h" +#include "cs2fixes.h" +#include "entity/customhudlayout.h" +#include "entwatch.h" +#include "filesystem.h" +#include "playermanager.h" +#include "utils/entity.h" +#include + +CConVar g_cvarEntwatchHudStyle("entwatch_hud_style", FCVAR_NONE, "Default HUD renderer: 0 = world text, 1 = Panorama", 1, true, 0, true, 1); +CConVar g_cvarEntwatchPanoramaDebug("cs2f_entwatch_panorama_debug", FCVAR_NONE, "Log EntWatch HUD creation and Panorama resource diagnostics", false); + +namespace +{ + constexpr size_t MaxRows = 64; + CHandle s_layout; + std::array s_previous; + std::array s_initialized{}; + std::array, MAXPLAYERS> s_rows; + std::array s_mode{}; + double s_flNextCreateAttempt = 0.0; + + CCSCustomHudLayout* GetPanoramaHud(bool create) + { + if (s_layout.Get() || !create) + return s_layout.Get(); + if (g_flUniversalTime < s_flNextCreateAttempt) + return nullptr; + s_flNextCreateAttempt = g_flUniversalTime + 30.0; + if (!g_pFullFileSystem || !g_pFullFileSystem->FileExists("panorama/layout/custom_game/hud.vxml_c", "GAME") || !g_pFullFileSystem->FileExists("panorama/styles/entwatch/hud.vcss_c", "GAME")) + { + Warning("[EntWatch HUD] Missing compiled Panorama resources; using world text. Install the packaged panorama directory on server and clients. Retrying in 30 seconds.\n"); + return nullptr; + } + auto layout = CCSCustomHudLayout::Create("hud", "entwatchHud"); + if (!layout) + { + Warning("[EntWatch HUD] Failed to create custom_hud_layout; using world text. Retrying in 30 seconds.\n"); + return nullptr; + } + s_layout = layout->GetHandle(); + s_initialized.fill(false); + for (auto& vecRows : s_rows) vecRows.clear(); + layout->Activate(true); + if (g_cvarEntwatchPanoramaDebug.Get()) + Message("[EntWatch Panorama] Created shared entity=%d layout=%s server resource=%d\n", layout->entindex(), layout->m_strLayout().String(), + g_pFullFileSystem->FileExists("panorama/layout/custom_game/hud.vxml_c", "GAME")); + return layout; + } + + bool RenderPanorama(ZEPlayer* player, const std::vector& rows, bool visible) + { + auto layout = GetPanoramaHud(visible); + if (!layout) + return !visible; + const int slot = player->GetPlayerSlot().Get(); + if (slot < 0 || slot >= MAXPLAYERS) return false; + std::string signature = visible ? "on" : "off"; + signature += std::to_string(player->GetEntwatchHudMode()); + if (visible) + { + signature += std::to_string(rows.size()) + ":"; + for (size_t i = 0; i < std::min(rows.size(), MaxRows); ++i) + for (const auto& value : {rows[i].name, rows[i].owner, rows[i].state, rows[i].cooldown, rows[i].ammo}) + signature += std::to_string(value.size()) + ":" + value; + } + if (s_initialized[slot] && s_previous[slot] == signature) return true; + s_initialized[slot] = true; + s_previous[slot] = signature; + layout->SetHasClass("entwatch", "Hidden", !visible, slot); + for (size_t i = 0; i < MaxRows; ++i) + { + const std::string id = "item_" + std::to_string(i); + const bool active = visible && i < rows.size(); + if (!active && i >= s_rows[slot].size()) continue; + if (active && i < s_rows[slot].size() && rows[i] == s_rows[slot][i] && s_mode[slot] == player->GetEntwatchHudMode()) continue; + layout->SetHasClass(id, "Hidden", !active, slot); + if (!active) continue; + const auto& row = rows[i]; + layout->SetDialogVariableString(id, "item", row.name, slot); + layout->SetDialogVariableString(id, "owner", row.owner, slot); + layout->SetDialogVariableString(id, "state", row.state, slot); + layout->SetDialogVariableString(id, "cooldown", row.cooldown, slot); + layout->SetDialogVariableString(id, "ammo", row.ammo, slot); + layout->SetHasClass(id, "NamesOnly", player->GetEntwatchHudMode() == Hud_ItemOnly, slot); + layout->SetHasClass(id, "Reloading", !row.cooldown.empty(), slot); + layout->SetHasClass(id, "HasAmmo", !row.ammo.empty(), slot); + } + layout->SetDialogVariableString("overflow", "count", std::to_string(rows.size() > MaxRows ? rows.size() - MaxRows : 0), slot); + layout->SetHasClass("overflow", "Hidden", !visible || rows.size() <= MaxRows, slot); + s_rows[slot].assign(rows.begin(), rows.begin() + (visible ? std::min(rows.size(), MaxRows) : 0)); + s_mode[slot] = player->GetEntwatchHudMode(); + return true; + } +} // namespace + +int EW_DefaultHudStyle() +{ return g_cvarEntwatchHudStyle.Get(); } + +void EW_DestroyHud() +{ + if (auto layout = s_layout.Get()) layout->Remove(); + s_layout = nullptr; + s_flNextCreateAttempt = 0.0; + s_initialized.fill(false); + for (auto& previous : s_previous) previous.clear(); + for (auto& vecRows : s_rows) vecRows.clear(); +} + +void EW_ForgetHudPlayer(int slot) +{ + if (slot >= 0 && slot < 64) + { + s_initialized[slot] = false; + s_previous[slot].clear(); + s_rows[slot].clear(); + auto pPlayer = g_playerManager ? g_playerManager->GetPlayer(CPlayerSlot(slot)) : nullptr; + if (pPlayer) + { + if (auto pText = pPlayer->GetEntwatchHud()) + pText->Remove(); + pPlayer->SetEntwatchHud(nullptr); + } + } +} + +void EW_RenderHud(ZEPlayer* player, const std::vector& rows) +{ + if (!player || player->IsFakeClient() || player->GetPlayerSlot().Get() < 0 || player->GetPlayerSlot().Get() >= MAXPLAYERS) + return; + const bool visible = g_cvarEnableEntWatch.Get() && g_cvarEnableEntwatchHud.Get() && player->GetEntwatchHudMode() != Hud_None && !rows.empty(); + const bool panorama = player->GetEntwatchHudStyle() == 1; + const bool bPanoramaReady = RenderPanorama(player, rows, visible && panorama); + EW_RenderWorldText(player, rows, visible && (!panorama || !bPanoramaReady)); +} diff --git a/src/entwatch_hud.h b/src/entwatch_hud.h index a0674793..3b089502 100644 --- a/src/entwatch_hud.h +++ b/src/entwatch_hud.h @@ -20,6 +20,26 @@ #pragma once #include +#include class ZEPlayer; -void EW_RenderWorldText(ZEPlayer* pPlayer, const std::string& sHudText, const std::string& sHudTextNoPlayerNames); +class CCSPlayerController; +class CCommand; + +struct EntwatchHudRow +{ + std::string name; + std::string owner; + std::string state; + std::string cooldown; + std::string ammo; + + bool operator==(const EntwatchHudRow&) const = default; +}; + +// Keep the item model independent of either HUD entity implementation. +void EW_RenderHud(ZEPlayer* player, const std::vector& rows); +void EW_RenderWorldText(ZEPlayer* player, const std::vector& rows, bool visible); +void EW_ForgetHudPlayer(int slot); +void EW_DestroyHud(); +int EW_DefaultHudStyle(); diff --git a/src/entwatch_hud_worldtext.cpp b/src/entwatch_hud_worldtext.cpp index c62a6004..5b72d944 100644 --- a/src/entwatch_hud_worldtext.cpp +++ b/src/entwatch_hud_worldtext.cpp @@ -17,14 +17,40 @@ * this program. If not, see . */ -#include "entity/ccsplayercontroller.h" +#include "commands.h" #include "entwatch.h" #include "entwatch_hud.h" #include "playermanager.h" #include "utils/entity.h" +extern CConVar g_cvarEntwatchPanoramaDebug; + +void EW_RenderWorldText(ZEPlayer* player, const std::vector& rows, bool visible) +{ + if (!player) + return; + auto text = player->GetEntwatchHud(); + if (!text && visible) + { + player->CreateEntwatchWorldHud(); + text = player->GetEntwatchHud(); + } + if (!text) + return; + std::string message; + if (visible) + for (const auto& row : rows) + { + if (!message.empty()) message += "\n"; + message += "[" + row.state + "]" + row.name; + if (player->GetEntwatchHudMode() == Hud_On) message += ": " + row.owner; + } + text->AcceptInput("SetMessage", message.c_str()); +} + void ZEPlayer::CreateEntwatchWorldHud() { + const bool bDebug = g_cvarEntwatchPanoramaDebug.Get(); CCSPlayerController* pController = CCSPlayerController::FromSlot(GetPlayerSlot()); if (!pController) return; @@ -41,10 +67,21 @@ void ZEPlayer::CreateEntwatchWorldHud() if (pText) { pText->Remove(); + SetEntwatchHud(nullptr); pText = nullptr; } pText = CreateEntityByName("point_worldtext"); + if (!pText) + { + static double flNextWarning = 0.0; + if (g_flUniversalTime >= flNextWarning) + { + Warning("[EntWatch HUD] Failed to create point_worldtext for slot %d.\n", GetPlayerSlot().Get()); + flNextWarning = g_flUniversalTime + 30.0; + } + return; + } pText->m_bEnabled(true); pText->m_bFullbright(true); pText->m_flFontSize(GetEntwatchHudSize()); @@ -67,6 +104,8 @@ void ZEPlayer::CreateEntwatchWorldHud() pText->DispatchSpawn(); SetEntwatchHud(pText); + if (bDebug) + Message("[EntWatch HUD] Created world-text HUD for slot %d.\n", GetPlayerSlot().Get()); pText->AcceptInput("SetParent", "!activator", pOrient); @@ -93,16 +132,3 @@ void ZEPlayer::CreateEntwatchWorldHud() pText->Teleport(&origin, &angles, nullptr); } - -void EW_RenderWorldText(ZEPlayer* pPlayer, const std::string& sHudText, const std::string& sHudTextNoPlayerNames) -{ - CPointWorldText* pText = pPlayer->GetEntwatchHud(); - if (!pText) return; - EWHudMode mode = (EWHudMode)pPlayer->GetEntwatchHudMode(); - if (mode == EWHudMode::Hud_On) - pText->AcceptInput("SetMessage", sHudText.c_str()); - else if (mode == EWHudMode::Hud_ItemOnly) - pText->AcceptInput("SetMessage", sHudTextNoPlayerNames.c_str()); - else - pText->AcceptInput("SetMessage", ""); -} diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 6aaf5cfa..a8ad2c42 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -25,6 +25,7 @@ #include "engine/igameeventsystem.h" #include "entity/ccsplayercontroller.h" #include "entwatch.h" +#include "entwatch_hud.h" #include "leader.h" #include "map_votes.h" #include "networksystem/inetworkmessages.h" @@ -740,7 +741,21 @@ void ZEPlayer::ToggleThirdPerson(float flDistance, bool bForce) void ZEPlayer::CreateEntwatchHud() { - CreateEntwatchWorldHud(); + if (GetEntwatchHudStyle() == 0) + CreateEntwatchWorldHud(); + else + { + if (auto text = GetEntwatchHud()) + { + text->Remove(); + SetEntwatchHud(nullptr); + } + } +} + +int ZEPlayer::GetEntwatchHudStyle() +{ + return EW_DefaultHudStyle(); } int ZEPlayer::GetEntwatchHudMode() @@ -850,6 +865,7 @@ void CPlayerManager::OnClientDisconnect(CPlayerSlot slot) g_pUserPreferencesSystem->PushPreferences(slot.Get()); g_pUserPreferencesSystem->ClearPreferences(slot.Get()); + EW_ForgetHudPlayer(slot.Get()); if (g_cvarEnableEntWatch.Get()) EW_PlayerDisconnect(slot.Get()); diff --git a/src/playermanager.h b/src/playermanager.h index eb3d4fdc..0760f526 100644 --- a/src/playermanager.h +++ b/src/playermanager.h @@ -272,6 +272,7 @@ class ZEPlayer void SetActiveZRModel(std::shared_ptr pZRClass) { m_pActiveZRModel = pZRClass; } void SetEntwatchHudMode(int iMode); void CreateEntwatchWorldHud(); + int GetEntwatchHudStyle(); void SetPointOrient(CPointOrient* pOrient) { m_hPointOrient.Set(pOrient); } void SetEntwatchHud(CPointWorldText* pWorldText) { m_hEntwatchHud.Set(pWorldText); } void SetEntwatchHudColor(Color colorHud); From 4cd0aea6b4e9d0394ebe899d3d38f5f55c466070 Mon Sep 17 00:00:00 2001 From: tojba <1348625+tojba@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:08:36 +0200 Subject: [PATCH 3/5] Add per-style HUD commands and persistent preferences --- assets_source/panorama/README.md | 21 + .../panorama/styles/entwatch/hud.css | 1565 +++++++++++++++++ src/entwatch.cpp | 45 +- src/entwatch.h | 6 +- src/entwatch_hud.cpp | 164 ++ src/entwatch_hud.h | 9 + src/playermanager.cpp | 20 +- src/playermanager.h | 19 +- src/user_preferences.cpp | 7 +- 9 files changed, 1839 insertions(+), 17 deletions(-) diff --git a/assets_source/panorama/README.md b/assets_source/panorama/README.md index 75da15c5..7a850b63 100644 --- a/assets_source/panorama/README.md +++ b/assets_source/panorama/README.md @@ -10,8 +10,29 @@ The script stages a local `cs2fixes_hud` addon and copies its compiled VXML/CSS Install the package into `game/csgo`. Clients must also have these resources installed or mounted through an addon; installing a server plugin does not distribute files to clients. The staged local addon is available for Workshop Tools testing. +The item HUD uses one shared `custom_hud_layout` with per-player classes and dialog variables. `src/entwatch.cpp` gathers held items; `src/entwatch_hud.cpp` implements Panorama and renderer selection, while `src/entwatch_hud_worldtext.cpp` preserves the world-text renderer without any Panorama dependency. It shows up to 64 stacked items and an overflow count. Only configured, held items with `ui: true` are shown. No client scripts are required. + +`!hudstyle old`, `!hudstyle new`, or `!hudstyle default` select a renderer and persist the player's preference; bare `!hudstyle` toggles. `entwatch_hud_style 0/1` selects the server default for players without an override. `!hud` still cycles visibility and owner names. `!hudpos` and `!hudsize` configure the currently selected renderer. Each renderer keeps its own position and size. `!hudcolor` still customizes world text; Panorama colors live in the CSS. + The green reload icon represents the item's EntWatch ability cooldown. The orange ammo icon represents remaining configured uses or a math-counter value, not the weapon's bullet magazine. Multiple visible handlers are separated with `|`. Items without these handlers show their normal ready state. +`!hudpos [x y|reset]` configures the active style: world-space coordinates for old HUD, whole screen percentages (0-100) for Panorama. Panorama defaults to 2% left / 15% top; keep enough space to the right and below for the item list. `!hudpos2` remains an explicit Panorama-only alias. + +`!hudsize [size|reset]` configures the active style: old HUD font size (20-255, default 60), or Panorama size as a whole percentage (50-200, default 100). Panorama scales the rows, padding, fonts and icons together while keeping its screen anchor. Bare commands report the active style's values. Client console equivalents are `c_hudpos` and `c_hudsize`. + +World text retains the existing `entwatch_hudpos_x`, `entwatch_hudpos_y`, and `entwatch_hudfontsize` preference keys. Panorama uses separate `entwatch_panorama_hudpos_x`, `entwatch_panorama_hudpos_y`, and `entwatch_panorama_hudsize` keys. Both sets stay on the player independently of `entwatch_hud_style`. The user-preferences system keeps values in memory per player slot; persistence across reconnects/restarts requires the existing `cs2f_user_prefs_api` REST backend, keyed by SteamID. These commands do not write a local config file. + +Panorama item and owner names share one line, with long names ellipsized to preserve the right-aligned status area. Ammo appears before the cooldown; the green reload icon sits at the far right and rotates while cooling down. Size preferences scale the compact row and icon together. + Player-name font size is 16px at 100% HUD size. If server-side Panorama resources are missing or entity creation fails, the HUD temporarily falls back to world text and retries at most once every 30 seconds. The player's selected renderer is retained. This cannot detect missing client-side resources. Enable `cs2f_entwatch_panorama_debug 1` for creation diagnostics; it is off by default. Normal disconnect/spawn timing does not generate warnings. + +Release verification still requires an in-game pass with the packaged resources on server and clients: + +- Pick up, transfer, drop and exhaust items; check cooldowns and multiple handlers in both renderers. +- Switch styles, names-only mode and visibility; change/reset position and size independently for both styles. +- Reconnect and change map/round, including after disabling EntWatch; check that player slots do not inherit HUD contents. +- With the preference REST backend configured, reconnect and restart the server and verify both styles' settings. Check malformed numeric preferences and command arguments (`nan`, `inf`, overflow and trailing text). +- Remove server-side resources in a test installation and verify the warning/fallback/retry behavior; restore resources and confirm recovery. +- Exercise 64 players/items and overflow, long names, several resolutions and HUD sizes. Confirm readable text and acceptable network traffic. diff --git a/assets_source/panorama/styles/entwatch/hud.css b/assets_source/panorama/styles/entwatch/hud.css index c6a6190d..d1d4830a 100644 --- a/assets_source/panorama/styles/entwatch/hud.css +++ b/assets_source/panorama/styles/entwatch/hud.css @@ -20,6 +20,1571 @@ .Reloading .Ready, .HasAmmo .Ready { visibility: collapse; } .Overflow { font-family: Arial; font-size: 14px; color: #a6b1c2; } +/* Screen-space percentages, selected independently for each player. */ +.EntWatch.PosX0 { margin-left: 0%; } +.EntWatch.PosY0 { margin-top: 0%; } +.EntWatch.PosX1 { margin-left: 1%; } +.EntWatch.PosY1 { margin-top: 1%; } +.EntWatch.PosX2 { margin-left: 2%; } +.EntWatch.PosY2 { margin-top: 2%; } +.EntWatch.PosX3 { margin-left: 3%; } +.EntWatch.PosY3 { margin-top: 3%; } +.EntWatch.PosX4 { margin-left: 4%; } +.EntWatch.PosY4 { margin-top: 4%; } +.EntWatch.PosX5 { margin-left: 5%; } +.EntWatch.PosY5 { margin-top: 5%; } +.EntWatch.PosX6 { margin-left: 6%; } +.EntWatch.PosY6 { margin-top: 6%; } +.EntWatch.PosX7 { margin-left: 7%; } +.EntWatch.PosY7 { margin-top: 7%; } +.EntWatch.PosX8 { margin-left: 8%; } +.EntWatch.PosY8 { margin-top: 8%; } +.EntWatch.PosX9 { margin-left: 9%; } +.EntWatch.PosY9 { margin-top: 9%; } +.EntWatch.PosX10 { margin-left: 10%; } +.EntWatch.PosY10 { margin-top: 10%; } +.EntWatch.PosX11 { margin-left: 11%; } +.EntWatch.PosY11 { margin-top: 11%; } +.EntWatch.PosX12 { margin-left: 12%; } +.EntWatch.PosY12 { margin-top: 12%; } +.EntWatch.PosX13 { margin-left: 13%; } +.EntWatch.PosY13 { margin-top: 13%; } +.EntWatch.PosX14 { margin-left: 14%; } +.EntWatch.PosY14 { margin-top: 14%; } +.EntWatch.PosX15 { margin-left: 15%; } +.EntWatch.PosY15 { margin-top: 15%; } +.EntWatch.PosX16 { margin-left: 16%; } +.EntWatch.PosY16 { margin-top: 16%; } +.EntWatch.PosX17 { margin-left: 17%; } +.EntWatch.PosY17 { margin-top: 17%; } +.EntWatch.PosX18 { margin-left: 18%; } +.EntWatch.PosY18 { margin-top: 18%; } +.EntWatch.PosX19 { margin-left: 19%; } +.EntWatch.PosY19 { margin-top: 19%; } +.EntWatch.PosX20 { margin-left: 20%; } +.EntWatch.PosY20 { margin-top: 20%; } +.EntWatch.PosX21 { margin-left: 21%; } +.EntWatch.PosY21 { margin-top: 21%; } +.EntWatch.PosX22 { margin-left: 22%; } +.EntWatch.PosY22 { margin-top: 22%; } +.EntWatch.PosX23 { margin-left: 23%; } +.EntWatch.PosY23 { margin-top: 23%; } +.EntWatch.PosX24 { margin-left: 24%; } +.EntWatch.PosY24 { margin-top: 24%; } +.EntWatch.PosX25 { margin-left: 25%; } +.EntWatch.PosY25 { margin-top: 25%; } +.EntWatch.PosX26 { margin-left: 26%; } +.EntWatch.PosY26 { margin-top: 26%; } +.EntWatch.PosX27 { margin-left: 27%; } +.EntWatch.PosY27 { margin-top: 27%; } +.EntWatch.PosX28 { margin-left: 28%; } +.EntWatch.PosY28 { margin-top: 28%; } +.EntWatch.PosX29 { margin-left: 29%; } +.EntWatch.PosY29 { margin-top: 29%; } +.EntWatch.PosX30 { margin-left: 30%; } +.EntWatch.PosY30 { margin-top: 30%; } +.EntWatch.PosX31 { margin-left: 31%; } +.EntWatch.PosY31 { margin-top: 31%; } +.EntWatch.PosX32 { margin-left: 32%; } +.EntWatch.PosY32 { margin-top: 32%; } +.EntWatch.PosX33 { margin-left: 33%; } +.EntWatch.PosY33 { margin-top: 33%; } +.EntWatch.PosX34 { margin-left: 34%; } +.EntWatch.PosY34 { margin-top: 34%; } +.EntWatch.PosX35 { margin-left: 35%; } +.EntWatch.PosY35 { margin-top: 35%; } +.EntWatch.PosX36 { margin-left: 36%; } +.EntWatch.PosY36 { margin-top: 36%; } +.EntWatch.PosX37 { margin-left: 37%; } +.EntWatch.PosY37 { margin-top: 37%; } +.EntWatch.PosX38 { margin-left: 38%; } +.EntWatch.PosY38 { margin-top: 38%; } +.EntWatch.PosX39 { margin-left: 39%; } +.EntWatch.PosY39 { margin-top: 39%; } +.EntWatch.PosX40 { margin-left: 40%; } +.EntWatch.PosY40 { margin-top: 40%; } +.EntWatch.PosX41 { margin-left: 41%; } +.EntWatch.PosY41 { margin-top: 41%; } +.EntWatch.PosX42 { margin-left: 42%; } +.EntWatch.PosY42 { margin-top: 42%; } +.EntWatch.PosX43 { margin-left: 43%; } +.EntWatch.PosY43 { margin-top: 43%; } +.EntWatch.PosX44 { margin-left: 44%; } +.EntWatch.PosY44 { margin-top: 44%; } +.EntWatch.PosX45 { margin-left: 45%; } +.EntWatch.PosY45 { margin-top: 45%; } +.EntWatch.PosX46 { margin-left: 46%; } +.EntWatch.PosY46 { margin-top: 46%; } +.EntWatch.PosX47 { margin-left: 47%; } +.EntWatch.PosY47 { margin-top: 47%; } +.EntWatch.PosX48 { margin-left: 48%; } +.EntWatch.PosY48 { margin-top: 48%; } +.EntWatch.PosX49 { margin-left: 49%; } +.EntWatch.PosY49 { margin-top: 49%; } +.EntWatch.PosX50 { margin-left: 50%; } +.EntWatch.PosY50 { margin-top: 50%; } +.EntWatch.PosX51 { margin-left: 51%; } +.EntWatch.PosY51 { margin-top: 51%; } +.EntWatch.PosX52 { margin-left: 52%; } +.EntWatch.PosY52 { margin-top: 52%; } +.EntWatch.PosX53 { margin-left: 53%; } +.EntWatch.PosY53 { margin-top: 53%; } +.EntWatch.PosX54 { margin-left: 54%; } +.EntWatch.PosY54 { margin-top: 54%; } +.EntWatch.PosX55 { margin-left: 55%; } +.EntWatch.PosY55 { margin-top: 55%; } +.EntWatch.PosX56 { margin-left: 56%; } +.EntWatch.PosY56 { margin-top: 56%; } +.EntWatch.PosX57 { margin-left: 57%; } +.EntWatch.PosY57 { margin-top: 57%; } +.EntWatch.PosX58 { margin-left: 58%; } +.EntWatch.PosY58 { margin-top: 58%; } +.EntWatch.PosX59 { margin-left: 59%; } +.EntWatch.PosY59 { margin-top: 59%; } +.EntWatch.PosX60 { margin-left: 60%; } +.EntWatch.PosY60 { margin-top: 60%; } +.EntWatch.PosX61 { margin-left: 61%; } +.EntWatch.PosY61 { margin-top: 61%; } +.EntWatch.PosX62 { margin-left: 62%; } +.EntWatch.PosY62 { margin-top: 62%; } +.EntWatch.PosX63 { margin-left: 63%; } +.EntWatch.PosY63 { margin-top: 63%; } +.EntWatch.PosX64 { margin-left: 64%; } +.EntWatch.PosY64 { margin-top: 64%; } +.EntWatch.PosX65 { margin-left: 65%; } +.EntWatch.PosY65 { margin-top: 65%; } +.EntWatch.PosX66 { margin-left: 66%; } +.EntWatch.PosY66 { margin-top: 66%; } +.EntWatch.PosX67 { margin-left: 67%; } +.EntWatch.PosY67 { margin-top: 67%; } +.EntWatch.PosX68 { margin-left: 68%; } +.EntWatch.PosY68 { margin-top: 68%; } +.EntWatch.PosX69 { margin-left: 69%; } +.EntWatch.PosY69 { margin-top: 69%; } +.EntWatch.PosX70 { margin-left: 70%; } +.EntWatch.PosY70 { margin-top: 70%; } +.EntWatch.PosX71 { margin-left: 71%; } +.EntWatch.PosY71 { margin-top: 71%; } +.EntWatch.PosX72 { margin-left: 72%; } +.EntWatch.PosY72 { margin-top: 72%; } +.EntWatch.PosX73 { margin-left: 73%; } +.EntWatch.PosY73 { margin-top: 73%; } +.EntWatch.PosX74 { margin-left: 74%; } +.EntWatch.PosY74 { margin-top: 74%; } +.EntWatch.PosX75 { margin-left: 75%; } +.EntWatch.PosY75 { margin-top: 75%; } +.EntWatch.PosX76 { margin-left: 76%; } +.EntWatch.PosY76 { margin-top: 76%; } +.EntWatch.PosX77 { margin-left: 77%; } +.EntWatch.PosY77 { margin-top: 77%; } +.EntWatch.PosX78 { margin-left: 78%; } +.EntWatch.PosY78 { margin-top: 78%; } +.EntWatch.PosX79 { margin-left: 79%; } +.EntWatch.PosY79 { margin-top: 79%; } +.EntWatch.PosX80 { margin-left: 80%; } +.EntWatch.PosY80 { margin-top: 80%; } +.EntWatch.PosX81 { margin-left: 81%; } +.EntWatch.PosY81 { margin-top: 81%; } +.EntWatch.PosX82 { margin-left: 82%; } +.EntWatch.PosY82 { margin-top: 82%; } +.EntWatch.PosX83 { margin-left: 83%; } +.EntWatch.PosY83 { margin-top: 83%; } +.EntWatch.PosX84 { margin-left: 84%; } +.EntWatch.PosY84 { margin-top: 84%; } +.EntWatch.PosX85 { margin-left: 85%; } +.EntWatch.PosY85 { margin-top: 85%; } +.EntWatch.PosX86 { margin-left: 86%; } +.EntWatch.PosY86 { margin-top: 86%; } +.EntWatch.PosX87 { margin-left: 87%; } +.EntWatch.PosY87 { margin-top: 87%; } +.EntWatch.PosX88 { margin-left: 88%; } +.EntWatch.PosY88 { margin-top: 88%; } +.EntWatch.PosX89 { margin-left: 89%; } +.EntWatch.PosY89 { margin-top: 89%; } +.EntWatch.PosX90 { margin-left: 90%; } +.EntWatch.PosY90 { margin-top: 90%; } +.EntWatch.PosX91 { margin-left: 91%; } +.EntWatch.PosY91 { margin-top: 91%; } +.EntWatch.PosX92 { margin-left: 92%; } +.EntWatch.PosY92 { margin-top: 92%; } +.EntWatch.PosX93 { margin-left: 93%; } +.EntWatch.PosY93 { margin-top: 93%; } +.EntWatch.PosX94 { margin-left: 94%; } +.EntWatch.PosY94 { margin-top: 94%; } +.EntWatch.PosX95 { margin-left: 95%; } +.EntWatch.PosY95 { margin-top: 95%; } +.EntWatch.PosX96 { margin-left: 96%; } +.EntWatch.PosY96 { margin-top: 96%; } +.EntWatch.PosX97 { margin-left: 97%; } +.EntWatch.PosY97 { margin-top: 97%; } +.EntWatch.PosX98 { margin-left: 98%; } +.EntWatch.PosY98 { margin-top: 98%; } +.EntWatch.PosX99 { margin-left: 99%; } +.EntWatch.PosY99 { margin-top: 99%; } +.EntWatch.PosX100 { margin-left: 100%; } +.EntWatch.PosY100 { margin-top: 100%; } + .ReloadIcon { width: 22px; height: 22px; margin-left: 5px; margin-right: 0px; text-align: center; vertical-align: center; } .Reloading .ReloadIcon { animation-name: ReloadSpin; animation-duration: 1s; animation-timing-function: linear; animation-iteration-count: infinite; } @keyframes 'ReloadSpin' { 0% { transform: rotateZ(0deg); } 100% { transform: rotateZ(360deg); } } + +/* Per-player size scales row geometry and typography, preserving screen position. */ +.EntWatch.Size50 .Item { width: 240px; padding: 4px 6px; margin-bottom: 2.5px; border-left-width: 1.5px; } +.EntWatch.Size50 .ItemName { font-size: 9px; } +.EntWatch.Size50 .Owner { font-size: 8px; margin-left: 4px; } +.EntWatch.Size50 .Status { margin-left: 6px; } +.EntWatch.Size50 .Status Label { font-size: 8px; } +.EntWatch.Size50 .Status .Icon { font-size: 9.5px; margin-right: 2.5px; } +.EntWatch.Size50 .Status .ReloadIcon { width: 11px; height: 11px; margin-left: 2.5px; margin-right: 0px; } +.EntWatch.Size50 .Ammo { margin-right: 6px; } +.EntWatch.Size50 .Overflow { font-size: 7px; } +.EntWatch.Size51 .Item { width: 244.8px; padding: 4.08px 6.12px; margin-bottom: 2.55px; border-left-width: 1.53px; } +.EntWatch.Size51 .ItemName { font-size: 9.18px; } +.EntWatch.Size51 .Owner { font-size: 8.16px; margin-left: 4.08px; } +.EntWatch.Size51 .Status { margin-left: 6.12px; } +.EntWatch.Size51 .Status Label { font-size: 8.16px; } +.EntWatch.Size51 .Status .Icon { font-size: 9.69px; margin-right: 2.55px; } +.EntWatch.Size51 .Status .ReloadIcon { width: 11.22px; height: 11.22px; margin-left: 2.55px; margin-right: 0px; } +.EntWatch.Size51 .Ammo { margin-right: 6.12px; } +.EntWatch.Size51 .Overflow { font-size: 7.14px; } +.EntWatch.Size52 .Item { width: 249.6px; padding: 4.16px 6.24px; margin-bottom: 2.6px; border-left-width: 1.56px; } +.EntWatch.Size52 .ItemName { font-size: 9.36px; } +.EntWatch.Size52 .Owner { font-size: 8.32px; margin-left: 4.16px; } +.EntWatch.Size52 .Status { margin-left: 6.24px; } +.EntWatch.Size52 .Status Label { font-size: 8.32px; } +.EntWatch.Size52 .Status .Icon { font-size: 9.88px; margin-right: 2.6px; } +.EntWatch.Size52 .Status .ReloadIcon { width: 11.44px; height: 11.44px; margin-left: 2.6px; margin-right: 0px; } +.EntWatch.Size52 .Ammo { margin-right: 6.24px; } +.EntWatch.Size52 .Overflow { font-size: 7.28px; } +.EntWatch.Size53 .Item { width: 254.4px; padding: 4.24px 6.36px; margin-bottom: 2.65px; border-left-width: 1.59px; } +.EntWatch.Size53 .ItemName { font-size: 9.54px; } +.EntWatch.Size53 .Owner { font-size: 8.48px; margin-left: 4.24px; } +.EntWatch.Size53 .Status { margin-left: 6.36px; } +.EntWatch.Size53 .Status Label { font-size: 8.48px; } +.EntWatch.Size53 .Status .Icon { font-size: 10.07px; margin-right: 2.65px; } +.EntWatch.Size53 .Status .ReloadIcon { width: 11.66px; height: 11.66px; margin-left: 2.65px; margin-right: 0px; } +.EntWatch.Size53 .Ammo { margin-right: 6.36px; } +.EntWatch.Size53 .Overflow { font-size: 7.42px; } +.EntWatch.Size54 .Item { width: 259.2px; padding: 4.32px 6.48px; margin-bottom: 2.7px; border-left-width: 1.62px; } +.EntWatch.Size54 .ItemName { font-size: 9.72px; } +.EntWatch.Size54 .Owner { font-size: 8.64px; margin-left: 4.32px; } +.EntWatch.Size54 .Status { margin-left: 6.48px; } +.EntWatch.Size54 .Status Label { font-size: 8.64px; } +.EntWatch.Size54 .Status .Icon { font-size: 10.26px; margin-right: 2.7px; } +.EntWatch.Size54 .Status .ReloadIcon { width: 11.88px; height: 11.88px; margin-left: 2.7px; margin-right: 0px; } +.EntWatch.Size54 .Ammo { margin-right: 6.48px; } +.EntWatch.Size54 .Overflow { font-size: 7.56px; } +.EntWatch.Size55 .Item { width: 264px; padding: 4.4px 6.6px; margin-bottom: 2.75px; border-left-width: 1.65px; } +.EntWatch.Size55 .ItemName { font-size: 9.9px; } +.EntWatch.Size55 .Owner { font-size: 8.8px; margin-left: 4.4px; } +.EntWatch.Size55 .Status { margin-left: 6.6px; } +.EntWatch.Size55 .Status Label { font-size: 8.8px; } +.EntWatch.Size55 .Status .Icon { font-size: 10.45px; margin-right: 2.75px; } +.EntWatch.Size55 .Status .ReloadIcon { width: 12.1px; height: 12.1px; margin-left: 2.75px; margin-right: 0px; } +.EntWatch.Size55 .Ammo { margin-right: 6.6px; } +.EntWatch.Size55 .Overflow { font-size: 7.7px; } +.EntWatch.Size56 .Item { width: 268.8px; padding: 4.48px 6.72px; margin-bottom: 2.8px; border-left-width: 1.68px; } +.EntWatch.Size56 .ItemName { font-size: 10.08px; } +.EntWatch.Size56 .Owner { font-size: 8.96px; margin-left: 4.48px; } +.EntWatch.Size56 .Status { margin-left: 6.72px; } +.EntWatch.Size56 .Status Label { font-size: 8.96px; } +.EntWatch.Size56 .Status .Icon { font-size: 10.64px; margin-right: 2.8px; } +.EntWatch.Size56 .Status .ReloadIcon { width: 12.32px; height: 12.32px; margin-left: 2.8px; margin-right: 0px; } +.EntWatch.Size56 .Ammo { margin-right: 6.72px; } +.EntWatch.Size56 .Overflow { font-size: 7.84px; } +.EntWatch.Size57 .Item { width: 273.6px; padding: 4.56px 6.84px; margin-bottom: 2.85px; border-left-width: 1.71px; } +.EntWatch.Size57 .ItemName { font-size: 10.26px; } +.EntWatch.Size57 .Owner { font-size: 9.12px; margin-left: 4.56px; } +.EntWatch.Size57 .Status { margin-left: 6.84px; } +.EntWatch.Size57 .Status Label { font-size: 9.12px; } +.EntWatch.Size57 .Status .Icon { font-size: 10.83px; margin-right: 2.85px; } +.EntWatch.Size57 .Status .ReloadIcon { width: 12.54px; height: 12.54px; margin-left: 2.85px; margin-right: 0px; } +.EntWatch.Size57 .Ammo { margin-right: 6.84px; } +.EntWatch.Size57 .Overflow { font-size: 7.98px; } +.EntWatch.Size58 .Item { width: 278.4px; padding: 4.64px 6.96px; margin-bottom: 2.9px; border-left-width: 1.74px; } +.EntWatch.Size58 .ItemName { font-size: 10.44px; } +.EntWatch.Size58 .Owner { font-size: 9.28px; margin-left: 4.64px; } +.EntWatch.Size58 .Status { margin-left: 6.96px; } +.EntWatch.Size58 .Status Label { font-size: 9.28px; } +.EntWatch.Size58 .Status .Icon { font-size: 11.02px; margin-right: 2.9px; } +.EntWatch.Size58 .Status .ReloadIcon { width: 12.76px; height: 12.76px; margin-left: 2.9px; margin-right: 0px; } +.EntWatch.Size58 .Ammo { margin-right: 6.96px; } +.EntWatch.Size58 .Overflow { font-size: 8.12px; } +.EntWatch.Size59 .Item { width: 283.2px; padding: 4.72px 7.08px; margin-bottom: 2.95px; border-left-width: 1.77px; } +.EntWatch.Size59 .ItemName { font-size: 10.62px; } +.EntWatch.Size59 .Owner { font-size: 9.44px; margin-left: 4.72px; } +.EntWatch.Size59 .Status { margin-left: 7.08px; } +.EntWatch.Size59 .Status Label { font-size: 9.44px; } +.EntWatch.Size59 .Status .Icon { font-size: 11.21px; margin-right: 2.95px; } +.EntWatch.Size59 .Status .ReloadIcon { width: 12.98px; height: 12.98px; margin-left: 2.95px; margin-right: 0px; } +.EntWatch.Size59 .Ammo { margin-right: 7.08px; } +.EntWatch.Size59 .Overflow { font-size: 8.26px; } +.EntWatch.Size60 .Item { width: 288px; padding: 4.8px 7.2px; margin-bottom: 3px; border-left-width: 1.8px; } +.EntWatch.Size60 .ItemName { font-size: 10.8px; } +.EntWatch.Size60 .Owner { font-size: 9.6px; margin-left: 4.8px; } +.EntWatch.Size60 .Status { margin-left: 7.2px; } +.EntWatch.Size60 .Status Label { font-size: 9.6px; } +.EntWatch.Size60 .Status .Icon { font-size: 11.4px; margin-right: 3px; } +.EntWatch.Size60 .Status .ReloadIcon { width: 13.2px; height: 13.2px; margin-left: 3px; margin-right: 0px; } +.EntWatch.Size60 .Ammo { margin-right: 7.2px; } +.EntWatch.Size60 .Overflow { font-size: 8.4px; } +.EntWatch.Size61 .Item { width: 292.8px; padding: 4.88px 7.32px; margin-bottom: 3.05px; border-left-width: 1.83px; } +.EntWatch.Size61 .ItemName { font-size: 10.98px; } +.EntWatch.Size61 .Owner { font-size: 9.76px; margin-left: 4.88px; } +.EntWatch.Size61 .Status { margin-left: 7.32px; } +.EntWatch.Size61 .Status Label { font-size: 9.76px; } +.EntWatch.Size61 .Status .Icon { font-size: 11.59px; margin-right: 3.05px; } +.EntWatch.Size61 .Status .ReloadIcon { width: 13.42px; height: 13.42px; margin-left: 3.05px; margin-right: 0px; } +.EntWatch.Size61 .Ammo { margin-right: 7.32px; } +.EntWatch.Size61 .Overflow { font-size: 8.54px; } +.EntWatch.Size62 .Item { width: 297.6px; padding: 4.96px 7.44px; margin-bottom: 3.1px; border-left-width: 1.86px; } +.EntWatch.Size62 .ItemName { font-size: 11.16px; } +.EntWatch.Size62 .Owner { font-size: 9.92px; margin-left: 4.96px; } +.EntWatch.Size62 .Status { margin-left: 7.44px; } +.EntWatch.Size62 .Status Label { font-size: 9.92px; } +.EntWatch.Size62 .Status .Icon { font-size: 11.78px; margin-right: 3.1px; } +.EntWatch.Size62 .Status .ReloadIcon { width: 13.64px; height: 13.64px; margin-left: 3.1px; margin-right: 0px; } +.EntWatch.Size62 .Ammo { margin-right: 7.44px; } +.EntWatch.Size62 .Overflow { font-size: 8.68px; } +.EntWatch.Size63 .Item { width: 302.4px; padding: 5.04px 7.56px; margin-bottom: 3.15px; border-left-width: 1.89px; } +.EntWatch.Size63 .ItemName { font-size: 11.34px; } +.EntWatch.Size63 .Owner { font-size: 10.08px; margin-left: 5.04px; } +.EntWatch.Size63 .Status { margin-left: 7.56px; } +.EntWatch.Size63 .Status Label { font-size: 10.08px; } +.EntWatch.Size63 .Status .Icon { font-size: 11.97px; margin-right: 3.15px; } +.EntWatch.Size63 .Status .ReloadIcon { width: 13.86px; height: 13.86px; margin-left: 3.15px; margin-right: 0px; } +.EntWatch.Size63 .Ammo { margin-right: 7.56px; } +.EntWatch.Size63 .Overflow { font-size: 8.82px; } +.EntWatch.Size64 .Item { width: 307.2px; padding: 5.12px 7.68px; margin-bottom: 3.2px; border-left-width: 1.92px; } +.EntWatch.Size64 .ItemName { font-size: 11.52px; } +.EntWatch.Size64 .Owner { font-size: 10.24px; margin-left: 5.12px; } +.EntWatch.Size64 .Status { margin-left: 7.68px; } +.EntWatch.Size64 .Status Label { font-size: 10.24px; } +.EntWatch.Size64 .Status .Icon { font-size: 12.16px; margin-right: 3.2px; } +.EntWatch.Size64 .Status .ReloadIcon { width: 14.08px; height: 14.08px; margin-left: 3.2px; margin-right: 0px; } +.EntWatch.Size64 .Ammo { margin-right: 7.68px; } +.EntWatch.Size64 .Overflow { font-size: 8.96px; } +.EntWatch.Size65 .Item { width: 312px; padding: 5.2px 7.8px; margin-bottom: 3.25px; border-left-width: 1.95px; } +.EntWatch.Size65 .ItemName { font-size: 11.7px; } +.EntWatch.Size65 .Owner { font-size: 10.4px; margin-left: 5.2px; } +.EntWatch.Size65 .Status { margin-left: 7.8px; } +.EntWatch.Size65 .Status Label { font-size: 10.4px; } +.EntWatch.Size65 .Status .Icon { font-size: 12.35px; margin-right: 3.25px; } +.EntWatch.Size65 .Status .ReloadIcon { width: 14.3px; height: 14.3px; margin-left: 3.25px; margin-right: 0px; } +.EntWatch.Size65 .Ammo { margin-right: 7.8px; } +.EntWatch.Size65 .Overflow { font-size: 9.1px; } +.EntWatch.Size66 .Item { width: 316.8px; padding: 5.28px 7.92px; margin-bottom: 3.3px; border-left-width: 1.98px; } +.EntWatch.Size66 .ItemName { font-size: 11.88px; } +.EntWatch.Size66 .Owner { font-size: 10.56px; margin-left: 5.28px; } +.EntWatch.Size66 .Status { margin-left: 7.92px; } +.EntWatch.Size66 .Status Label { font-size: 10.56px; } +.EntWatch.Size66 .Status .Icon { font-size: 12.54px; margin-right: 3.3px; } +.EntWatch.Size66 .Status .ReloadIcon { width: 14.52px; height: 14.52px; margin-left: 3.3px; margin-right: 0px; } +.EntWatch.Size66 .Ammo { margin-right: 7.92px; } +.EntWatch.Size66 .Overflow { font-size: 9.24px; } +.EntWatch.Size67 .Item { width: 321.6px; padding: 5.36px 8.04px; margin-bottom: 3.35px; border-left-width: 2.01px; } +.EntWatch.Size67 .ItemName { font-size: 12.06px; } +.EntWatch.Size67 .Owner { font-size: 10.72px; margin-left: 5.36px; } +.EntWatch.Size67 .Status { margin-left: 8.04px; } +.EntWatch.Size67 .Status Label { font-size: 10.72px; } +.EntWatch.Size67 .Status .Icon { font-size: 12.73px; margin-right: 3.35px; } +.EntWatch.Size67 .Status .ReloadIcon { width: 14.74px; height: 14.74px; margin-left: 3.35px; margin-right: 0px; } +.EntWatch.Size67 .Ammo { margin-right: 8.04px; } +.EntWatch.Size67 .Overflow { font-size: 9.38px; } +.EntWatch.Size68 .Item { width: 326.4px; padding: 5.44px 8.16px; margin-bottom: 3.4px; border-left-width: 2.04px; } +.EntWatch.Size68 .ItemName { font-size: 12.24px; } +.EntWatch.Size68 .Owner { font-size: 10.88px; margin-left: 5.44px; } +.EntWatch.Size68 .Status { margin-left: 8.16px; } +.EntWatch.Size68 .Status Label { font-size: 10.88px; } +.EntWatch.Size68 .Status .Icon { font-size: 12.92px; margin-right: 3.4px; } +.EntWatch.Size68 .Status .ReloadIcon { width: 14.96px; height: 14.96px; margin-left: 3.4px; margin-right: 0px; } +.EntWatch.Size68 .Ammo { margin-right: 8.16px; } +.EntWatch.Size68 .Overflow { font-size: 9.52px; } +.EntWatch.Size69 .Item { width: 331.2px; padding: 5.52px 8.28px; margin-bottom: 3.45px; border-left-width: 2.07px; } +.EntWatch.Size69 .ItemName { font-size: 12.42px; } +.EntWatch.Size69 .Owner { font-size: 11.04px; margin-left: 5.52px; } +.EntWatch.Size69 .Status { margin-left: 8.28px; } +.EntWatch.Size69 .Status Label { font-size: 11.04px; } +.EntWatch.Size69 .Status .Icon { font-size: 13.11px; margin-right: 3.45px; } +.EntWatch.Size69 .Status .ReloadIcon { width: 15.18px; height: 15.18px; margin-left: 3.45px; margin-right: 0px; } +.EntWatch.Size69 .Ammo { margin-right: 8.28px; } +.EntWatch.Size69 .Overflow { font-size: 9.66px; } +.EntWatch.Size70 .Item { width: 336px; padding: 5.6px 8.4px; margin-bottom: 3.5px; border-left-width: 2.1px; } +.EntWatch.Size70 .ItemName { font-size: 12.6px; } +.EntWatch.Size70 .Owner { font-size: 11.2px; margin-left: 5.6px; } +.EntWatch.Size70 .Status { margin-left: 8.4px; } +.EntWatch.Size70 .Status Label { font-size: 11.2px; } +.EntWatch.Size70 .Status .Icon { font-size: 13.3px; margin-right: 3.5px; } +.EntWatch.Size70 .Status .ReloadIcon { width: 15.4px; height: 15.4px; margin-left: 3.5px; margin-right: 0px; } +.EntWatch.Size70 .Ammo { margin-right: 8.4px; } +.EntWatch.Size70 .Overflow { font-size: 9.8px; } +.EntWatch.Size71 .Item { width: 340.8px; padding: 5.68px 8.52px; margin-bottom: 3.55px; border-left-width: 2.13px; } +.EntWatch.Size71 .ItemName { font-size: 12.78px; } +.EntWatch.Size71 .Owner { font-size: 11.36px; margin-left: 5.68px; } +.EntWatch.Size71 .Status { margin-left: 8.52px; } +.EntWatch.Size71 .Status Label { font-size: 11.36px; } +.EntWatch.Size71 .Status .Icon { font-size: 13.49px; margin-right: 3.55px; } +.EntWatch.Size71 .Status .ReloadIcon { width: 15.62px; height: 15.62px; margin-left: 3.55px; margin-right: 0px; } +.EntWatch.Size71 .Ammo { margin-right: 8.52px; } +.EntWatch.Size71 .Overflow { font-size: 9.94px; } +.EntWatch.Size72 .Item { width: 345.6px; padding: 5.76px 8.64px; margin-bottom: 3.6px; border-left-width: 2.16px; } +.EntWatch.Size72 .ItemName { font-size: 12.96px; } +.EntWatch.Size72 .Owner { font-size: 11.52px; margin-left: 5.76px; } +.EntWatch.Size72 .Status { margin-left: 8.64px; } +.EntWatch.Size72 .Status Label { font-size: 11.52px; } +.EntWatch.Size72 .Status .Icon { font-size: 13.68px; margin-right: 3.6px; } +.EntWatch.Size72 .Status .ReloadIcon { width: 15.84px; height: 15.84px; margin-left: 3.6px; margin-right: 0px; } +.EntWatch.Size72 .Ammo { margin-right: 8.64px; } +.EntWatch.Size72 .Overflow { font-size: 10.08px; } +.EntWatch.Size73 .Item { width: 350.4px; padding: 5.84px 8.76px; margin-bottom: 3.65px; border-left-width: 2.19px; } +.EntWatch.Size73 .ItemName { font-size: 13.14px; } +.EntWatch.Size73 .Owner { font-size: 11.68px; margin-left: 5.84px; } +.EntWatch.Size73 .Status { margin-left: 8.76px; } +.EntWatch.Size73 .Status Label { font-size: 11.68px; } +.EntWatch.Size73 .Status .Icon { font-size: 13.87px; margin-right: 3.65px; } +.EntWatch.Size73 .Status .ReloadIcon { width: 16.06px; height: 16.06px; margin-left: 3.65px; margin-right: 0px; } +.EntWatch.Size73 .Ammo { margin-right: 8.76px; } +.EntWatch.Size73 .Overflow { font-size: 10.22px; } +.EntWatch.Size74 .Item { width: 355.2px; padding: 5.92px 8.88px; margin-bottom: 3.7px; border-left-width: 2.22px; } +.EntWatch.Size74 .ItemName { font-size: 13.32px; } +.EntWatch.Size74 .Owner { font-size: 11.84px; margin-left: 5.92px; } +.EntWatch.Size74 .Status { margin-left: 8.88px; } +.EntWatch.Size74 .Status Label { font-size: 11.84px; } +.EntWatch.Size74 .Status .Icon { font-size: 14.06px; margin-right: 3.7px; } +.EntWatch.Size74 .Status .ReloadIcon { width: 16.28px; height: 16.28px; margin-left: 3.7px; margin-right: 0px; } +.EntWatch.Size74 .Ammo { margin-right: 8.88px; } +.EntWatch.Size74 .Overflow { font-size: 10.36px; } +.EntWatch.Size75 .Item { width: 360px; padding: 6px 9px; margin-bottom: 3.75px; border-left-width: 2.25px; } +.EntWatch.Size75 .ItemName { font-size: 13.5px; } +.EntWatch.Size75 .Owner { font-size: 12px; margin-left: 6px; } +.EntWatch.Size75 .Status { margin-left: 9px; } +.EntWatch.Size75 .Status Label { font-size: 12px; } +.EntWatch.Size75 .Status .Icon { font-size: 14.25px; margin-right: 3.75px; } +.EntWatch.Size75 .Status .ReloadIcon { width: 16.5px; height: 16.5px; margin-left: 3.75px; margin-right: 0px; } +.EntWatch.Size75 .Ammo { margin-right: 9px; } +.EntWatch.Size75 .Overflow { font-size: 10.5px; } +.EntWatch.Size76 .Item { width: 364.8px; padding: 6.08px 9.12px; margin-bottom: 3.8px; border-left-width: 2.28px; } +.EntWatch.Size76 .ItemName { font-size: 13.68px; } +.EntWatch.Size76 .Owner { font-size: 12.16px; margin-left: 6.08px; } +.EntWatch.Size76 .Status { margin-left: 9.12px; } +.EntWatch.Size76 .Status Label { font-size: 12.16px; } +.EntWatch.Size76 .Status .Icon { font-size: 14.44px; margin-right: 3.8px; } +.EntWatch.Size76 .Status .ReloadIcon { width: 16.72px; height: 16.72px; margin-left: 3.8px; margin-right: 0px; } +.EntWatch.Size76 .Ammo { margin-right: 9.12px; } +.EntWatch.Size76 .Overflow { font-size: 10.64px; } +.EntWatch.Size77 .Item { width: 369.6px; padding: 6.16px 9.24px; margin-bottom: 3.85px; border-left-width: 2.31px; } +.EntWatch.Size77 .ItemName { font-size: 13.86px; } +.EntWatch.Size77 .Owner { font-size: 12.32px; margin-left: 6.16px; } +.EntWatch.Size77 .Status { margin-left: 9.24px; } +.EntWatch.Size77 .Status Label { font-size: 12.32px; } +.EntWatch.Size77 .Status .Icon { font-size: 14.63px; margin-right: 3.85px; } +.EntWatch.Size77 .Status .ReloadIcon { width: 16.94px; height: 16.94px; margin-left: 3.85px; margin-right: 0px; } +.EntWatch.Size77 .Ammo { margin-right: 9.24px; } +.EntWatch.Size77 .Overflow { font-size: 10.78px; } +.EntWatch.Size78 .Item { width: 374.4px; padding: 6.24px 9.36px; margin-bottom: 3.9px; border-left-width: 2.34px; } +.EntWatch.Size78 .ItemName { font-size: 14.04px; } +.EntWatch.Size78 .Owner { font-size: 12.48px; margin-left: 6.24px; } +.EntWatch.Size78 .Status { margin-left: 9.36px; } +.EntWatch.Size78 .Status Label { font-size: 12.48px; } +.EntWatch.Size78 .Status .Icon { font-size: 14.82px; margin-right: 3.9px; } +.EntWatch.Size78 .Status .ReloadIcon { width: 17.16px; height: 17.16px; margin-left: 3.9px; margin-right: 0px; } +.EntWatch.Size78 .Ammo { margin-right: 9.36px; } +.EntWatch.Size78 .Overflow { font-size: 10.92px; } +.EntWatch.Size79 .Item { width: 379.2px; padding: 6.32px 9.48px; margin-bottom: 3.95px; border-left-width: 2.37px; } +.EntWatch.Size79 .ItemName { font-size: 14.22px; } +.EntWatch.Size79 .Owner { font-size: 12.64px; margin-left: 6.32px; } +.EntWatch.Size79 .Status { margin-left: 9.48px; } +.EntWatch.Size79 .Status Label { font-size: 12.64px; } +.EntWatch.Size79 .Status .Icon { font-size: 15.01px; margin-right: 3.95px; } +.EntWatch.Size79 .Status .ReloadIcon { width: 17.38px; height: 17.38px; margin-left: 3.95px; margin-right: 0px; } +.EntWatch.Size79 .Ammo { margin-right: 9.48px; } +.EntWatch.Size79 .Overflow { font-size: 11.06px; } +.EntWatch.Size80 .Item { width: 384px; padding: 6.4px 9.6px; margin-bottom: 4px; border-left-width: 2.4px; } +.EntWatch.Size80 .ItemName { font-size: 14.4px; } +.EntWatch.Size80 .Owner { font-size: 12.8px; margin-left: 6.4px; } +.EntWatch.Size80 .Status { margin-left: 9.6px; } +.EntWatch.Size80 .Status Label { font-size: 12.8px; } +.EntWatch.Size80 .Status .Icon { font-size: 15.2px; margin-right: 4px; } +.EntWatch.Size80 .Status .ReloadIcon { width: 17.6px; height: 17.6px; margin-left: 4px; margin-right: 0px; } +.EntWatch.Size80 .Ammo { margin-right: 9.6px; } +.EntWatch.Size80 .Overflow { font-size: 11.2px; } +.EntWatch.Size81 .Item { width: 388.8px; padding: 6.48px 9.72px; margin-bottom: 4.05px; border-left-width: 2.43px; } +.EntWatch.Size81 .ItemName { font-size: 14.58px; } +.EntWatch.Size81 .Owner { font-size: 12.96px; margin-left: 6.48px; } +.EntWatch.Size81 .Status { margin-left: 9.72px; } +.EntWatch.Size81 .Status Label { font-size: 12.96px; } +.EntWatch.Size81 .Status .Icon { font-size: 15.39px; margin-right: 4.05px; } +.EntWatch.Size81 .Status .ReloadIcon { width: 17.82px; height: 17.82px; margin-left: 4.05px; margin-right: 0px; } +.EntWatch.Size81 .Ammo { margin-right: 9.72px; } +.EntWatch.Size81 .Overflow { font-size: 11.34px; } +.EntWatch.Size82 .Item { width: 393.6px; padding: 6.56px 9.84px; margin-bottom: 4.1px; border-left-width: 2.46px; } +.EntWatch.Size82 .ItemName { font-size: 14.76px; } +.EntWatch.Size82 .Owner { font-size: 13.12px; margin-left: 6.56px; } +.EntWatch.Size82 .Status { margin-left: 9.84px; } +.EntWatch.Size82 .Status Label { font-size: 13.12px; } +.EntWatch.Size82 .Status .Icon { font-size: 15.58px; margin-right: 4.1px; } +.EntWatch.Size82 .Status .ReloadIcon { width: 18.04px; height: 18.04px; margin-left: 4.1px; margin-right: 0px; } +.EntWatch.Size82 .Ammo { margin-right: 9.84px; } +.EntWatch.Size82 .Overflow { font-size: 11.48px; } +.EntWatch.Size83 .Item { width: 398.4px; padding: 6.64px 9.96px; margin-bottom: 4.15px; border-left-width: 2.49px; } +.EntWatch.Size83 .ItemName { font-size: 14.94px; } +.EntWatch.Size83 .Owner { font-size: 13.28px; margin-left: 6.64px; } +.EntWatch.Size83 .Status { margin-left: 9.96px; } +.EntWatch.Size83 .Status Label { font-size: 13.28px; } +.EntWatch.Size83 .Status .Icon { font-size: 15.77px; margin-right: 4.15px; } +.EntWatch.Size83 .Status .ReloadIcon { width: 18.26px; height: 18.26px; margin-left: 4.15px; margin-right: 0px; } +.EntWatch.Size83 .Ammo { margin-right: 9.96px; } +.EntWatch.Size83 .Overflow { font-size: 11.62px; } +.EntWatch.Size84 .Item { width: 403.2px; padding: 6.72px 10.08px; margin-bottom: 4.2px; border-left-width: 2.52px; } +.EntWatch.Size84 .ItemName { font-size: 15.12px; } +.EntWatch.Size84 .Owner { font-size: 13.44px; margin-left: 6.72px; } +.EntWatch.Size84 .Status { margin-left: 10.08px; } +.EntWatch.Size84 .Status Label { font-size: 13.44px; } +.EntWatch.Size84 .Status .Icon { font-size: 15.96px; margin-right: 4.2px; } +.EntWatch.Size84 .Status .ReloadIcon { width: 18.48px; height: 18.48px; margin-left: 4.2px; margin-right: 0px; } +.EntWatch.Size84 .Ammo { margin-right: 10.08px; } +.EntWatch.Size84 .Overflow { font-size: 11.76px; } +.EntWatch.Size85 .Item { width: 408px; padding: 6.8px 10.2px; margin-bottom: 4.25px; border-left-width: 2.55px; } +.EntWatch.Size85 .ItemName { font-size: 15.3px; } +.EntWatch.Size85 .Owner { font-size: 13.6px; margin-left: 6.8px; } +.EntWatch.Size85 .Status { margin-left: 10.2px; } +.EntWatch.Size85 .Status Label { font-size: 13.6px; } +.EntWatch.Size85 .Status .Icon { font-size: 16.15px; margin-right: 4.25px; } +.EntWatch.Size85 .Status .ReloadIcon { width: 18.7px; height: 18.7px; margin-left: 4.25px; margin-right: 0px; } +.EntWatch.Size85 .Ammo { margin-right: 10.2px; } +.EntWatch.Size85 .Overflow { font-size: 11.9px; } +.EntWatch.Size86 .Item { width: 412.8px; padding: 6.88px 10.32px; margin-bottom: 4.3px; border-left-width: 2.58px; } +.EntWatch.Size86 .ItemName { font-size: 15.48px; } +.EntWatch.Size86 .Owner { font-size: 13.76px; margin-left: 6.88px; } +.EntWatch.Size86 .Status { margin-left: 10.32px; } +.EntWatch.Size86 .Status Label { font-size: 13.76px; } +.EntWatch.Size86 .Status .Icon { font-size: 16.34px; margin-right: 4.3px; } +.EntWatch.Size86 .Status .ReloadIcon { width: 18.92px; height: 18.92px; margin-left: 4.3px; margin-right: 0px; } +.EntWatch.Size86 .Ammo { margin-right: 10.32px; } +.EntWatch.Size86 .Overflow { font-size: 12.04px; } +.EntWatch.Size87 .Item { width: 417.6px; padding: 6.96px 10.44px; margin-bottom: 4.35px; border-left-width: 2.61px; } +.EntWatch.Size87 .ItemName { font-size: 15.66px; } +.EntWatch.Size87 .Owner { font-size: 13.92px; margin-left: 6.96px; } +.EntWatch.Size87 .Status { margin-left: 10.44px; } +.EntWatch.Size87 .Status Label { font-size: 13.92px; } +.EntWatch.Size87 .Status .Icon { font-size: 16.53px; margin-right: 4.35px; } +.EntWatch.Size87 .Status .ReloadIcon { width: 19.14px; height: 19.14px; margin-left: 4.35px; margin-right: 0px; } +.EntWatch.Size87 .Ammo { margin-right: 10.44px; } +.EntWatch.Size87 .Overflow { font-size: 12.18px; } +.EntWatch.Size88 .Item { width: 422.4px; padding: 7.04px 10.56px; margin-bottom: 4.4px; border-left-width: 2.64px; } +.EntWatch.Size88 .ItemName { font-size: 15.84px; } +.EntWatch.Size88 .Owner { font-size: 14.08px; margin-left: 7.04px; } +.EntWatch.Size88 .Status { margin-left: 10.56px; } +.EntWatch.Size88 .Status Label { font-size: 14.08px; } +.EntWatch.Size88 .Status .Icon { font-size: 16.72px; margin-right: 4.4px; } +.EntWatch.Size88 .Status .ReloadIcon { width: 19.36px; height: 19.36px; margin-left: 4.4px; margin-right: 0px; } +.EntWatch.Size88 .Ammo { margin-right: 10.56px; } +.EntWatch.Size88 .Overflow { font-size: 12.32px; } +.EntWatch.Size89 .Item { width: 427.2px; padding: 7.12px 10.68px; margin-bottom: 4.45px; border-left-width: 2.67px; } +.EntWatch.Size89 .ItemName { font-size: 16.02px; } +.EntWatch.Size89 .Owner { font-size: 14.24px; margin-left: 7.12px; } +.EntWatch.Size89 .Status { margin-left: 10.68px; } +.EntWatch.Size89 .Status Label { font-size: 14.24px; } +.EntWatch.Size89 .Status .Icon { font-size: 16.91px; margin-right: 4.45px; } +.EntWatch.Size89 .Status .ReloadIcon { width: 19.58px; height: 19.58px; margin-left: 4.45px; margin-right: 0px; } +.EntWatch.Size89 .Ammo { margin-right: 10.68px; } +.EntWatch.Size89 .Overflow { font-size: 12.46px; } +.EntWatch.Size90 .Item { width: 432px; padding: 7.2px 10.8px; margin-bottom: 4.5px; border-left-width: 2.7px; } +.EntWatch.Size90 .ItemName { font-size: 16.2px; } +.EntWatch.Size90 .Owner { font-size: 14.4px; margin-left: 7.2px; } +.EntWatch.Size90 .Status { margin-left: 10.8px; } +.EntWatch.Size90 .Status Label { font-size: 14.4px; } +.EntWatch.Size90 .Status .Icon { font-size: 17.1px; margin-right: 4.5px; } +.EntWatch.Size90 .Status .ReloadIcon { width: 19.8px; height: 19.8px; margin-left: 4.5px; margin-right: 0px; } +.EntWatch.Size90 .Ammo { margin-right: 10.8px; } +.EntWatch.Size90 .Overflow { font-size: 12.6px; } +.EntWatch.Size91 .Item { width: 436.8px; padding: 7.28px 10.92px; margin-bottom: 4.55px; border-left-width: 2.73px; } +.EntWatch.Size91 .ItemName { font-size: 16.38px; } +.EntWatch.Size91 .Owner { font-size: 14.56px; margin-left: 7.28px; } +.EntWatch.Size91 .Status { margin-left: 10.92px; } +.EntWatch.Size91 .Status Label { font-size: 14.56px; } +.EntWatch.Size91 .Status .Icon { font-size: 17.29px; margin-right: 4.55px; } +.EntWatch.Size91 .Status .ReloadIcon { width: 20.02px; height: 20.02px; margin-left: 4.55px; margin-right: 0px; } +.EntWatch.Size91 .Ammo { margin-right: 10.92px; } +.EntWatch.Size91 .Overflow { font-size: 12.74px; } +.EntWatch.Size92 .Item { width: 441.6px; padding: 7.36px 11.04px; margin-bottom: 4.6px; border-left-width: 2.76px; } +.EntWatch.Size92 .ItemName { font-size: 16.56px; } +.EntWatch.Size92 .Owner { font-size: 14.72px; margin-left: 7.36px; } +.EntWatch.Size92 .Status { margin-left: 11.04px; } +.EntWatch.Size92 .Status Label { font-size: 14.72px; } +.EntWatch.Size92 .Status .Icon { font-size: 17.48px; margin-right: 4.6px; } +.EntWatch.Size92 .Status .ReloadIcon { width: 20.24px; height: 20.24px; margin-left: 4.6px; margin-right: 0px; } +.EntWatch.Size92 .Ammo { margin-right: 11.04px; } +.EntWatch.Size92 .Overflow { font-size: 12.88px; } +.EntWatch.Size93 .Item { width: 446.4px; padding: 7.44px 11.16px; margin-bottom: 4.65px; border-left-width: 2.79px; } +.EntWatch.Size93 .ItemName { font-size: 16.74px; } +.EntWatch.Size93 .Owner { font-size: 14.88px; margin-left: 7.44px; } +.EntWatch.Size93 .Status { margin-left: 11.16px; } +.EntWatch.Size93 .Status Label { font-size: 14.88px; } +.EntWatch.Size93 .Status .Icon { font-size: 17.67px; margin-right: 4.65px; } +.EntWatch.Size93 .Status .ReloadIcon { width: 20.46px; height: 20.46px; margin-left: 4.65px; margin-right: 0px; } +.EntWatch.Size93 .Ammo { margin-right: 11.16px; } +.EntWatch.Size93 .Overflow { font-size: 13.02px; } +.EntWatch.Size94 .Item { width: 451.2px; padding: 7.52px 11.28px; margin-bottom: 4.7px; border-left-width: 2.82px; } +.EntWatch.Size94 .ItemName { font-size: 16.92px; } +.EntWatch.Size94 .Owner { font-size: 15.04px; margin-left: 7.52px; } +.EntWatch.Size94 .Status { margin-left: 11.28px; } +.EntWatch.Size94 .Status Label { font-size: 15.04px; } +.EntWatch.Size94 .Status .Icon { font-size: 17.86px; margin-right: 4.7px; } +.EntWatch.Size94 .Status .ReloadIcon { width: 20.68px; height: 20.68px; margin-left: 4.7px; margin-right: 0px; } +.EntWatch.Size94 .Ammo { margin-right: 11.28px; } +.EntWatch.Size94 .Overflow { font-size: 13.16px; } +.EntWatch.Size95 .Item { width: 456px; padding: 7.6px 11.4px; margin-bottom: 4.75px; border-left-width: 2.85px; } +.EntWatch.Size95 .ItemName { font-size: 17.1px; } +.EntWatch.Size95 .Owner { font-size: 15.2px; margin-left: 7.6px; } +.EntWatch.Size95 .Status { margin-left: 11.4px; } +.EntWatch.Size95 .Status Label { font-size: 15.2px; } +.EntWatch.Size95 .Status .Icon { font-size: 18.05px; margin-right: 4.75px; } +.EntWatch.Size95 .Status .ReloadIcon { width: 20.9px; height: 20.9px; margin-left: 4.75px; margin-right: 0px; } +.EntWatch.Size95 .Ammo { margin-right: 11.4px; } +.EntWatch.Size95 .Overflow { font-size: 13.3px; } +.EntWatch.Size96 .Item { width: 460.8px; padding: 7.68px 11.52px; margin-bottom: 4.8px; border-left-width: 2.88px; } +.EntWatch.Size96 .ItemName { font-size: 17.28px; } +.EntWatch.Size96 .Owner { font-size: 15.36px; margin-left: 7.68px; } +.EntWatch.Size96 .Status { margin-left: 11.52px; } +.EntWatch.Size96 .Status Label { font-size: 15.36px; } +.EntWatch.Size96 .Status .Icon { font-size: 18.24px; margin-right: 4.8px; } +.EntWatch.Size96 .Status .ReloadIcon { width: 21.12px; height: 21.12px; margin-left: 4.8px; margin-right: 0px; } +.EntWatch.Size96 .Ammo { margin-right: 11.52px; } +.EntWatch.Size96 .Overflow { font-size: 13.44px; } +.EntWatch.Size97 .Item { width: 465.6px; padding: 7.76px 11.64px; margin-bottom: 4.85px; border-left-width: 2.91px; } +.EntWatch.Size97 .ItemName { font-size: 17.46px; } +.EntWatch.Size97 .Owner { font-size: 15.52px; margin-left: 7.76px; } +.EntWatch.Size97 .Status { margin-left: 11.64px; } +.EntWatch.Size97 .Status Label { font-size: 15.52px; } +.EntWatch.Size97 .Status .Icon { font-size: 18.43px; margin-right: 4.85px; } +.EntWatch.Size97 .Status .ReloadIcon { width: 21.34px; height: 21.34px; margin-left: 4.85px; margin-right: 0px; } +.EntWatch.Size97 .Ammo { margin-right: 11.64px; } +.EntWatch.Size97 .Overflow { font-size: 13.58px; } +.EntWatch.Size98 .Item { width: 470.4px; padding: 7.84px 11.76px; margin-bottom: 4.9px; border-left-width: 2.94px; } +.EntWatch.Size98 .ItemName { font-size: 17.64px; } +.EntWatch.Size98 .Owner { font-size: 15.68px; margin-left: 7.84px; } +.EntWatch.Size98 .Status { margin-left: 11.76px; } +.EntWatch.Size98 .Status Label { font-size: 15.68px; } +.EntWatch.Size98 .Status .Icon { font-size: 18.62px; margin-right: 4.9px; } +.EntWatch.Size98 .Status .ReloadIcon { width: 21.56px; height: 21.56px; margin-left: 4.9px; margin-right: 0px; } +.EntWatch.Size98 .Ammo { margin-right: 11.76px; } +.EntWatch.Size98 .Overflow { font-size: 13.72px; } +.EntWatch.Size99 .Item { width: 475.2px; padding: 7.92px 11.88px; margin-bottom: 4.95px; border-left-width: 2.97px; } +.EntWatch.Size99 .ItemName { font-size: 17.82px; } +.EntWatch.Size99 .Owner { font-size: 15.84px; margin-left: 7.92px; } +.EntWatch.Size99 .Status { margin-left: 11.88px; } +.EntWatch.Size99 .Status Label { font-size: 15.84px; } +.EntWatch.Size99 .Status .Icon { font-size: 18.81px; margin-right: 4.95px; } +.EntWatch.Size99 .Status .ReloadIcon { width: 21.78px; height: 21.78px; margin-left: 4.95px; margin-right: 0px; } +.EntWatch.Size99 .Ammo { margin-right: 11.88px; } +.EntWatch.Size99 .Overflow { font-size: 13.86px; } +.EntWatch.Size100 .Item { width: 480px; padding: 8px 12px; margin-bottom: 5px; border-left-width: 3px; } +.EntWatch.Size100 .ItemName { font-size: 18px; } +.EntWatch.Size100 .Owner { font-size: 16px; margin-left: 8px; } +.EntWatch.Size100 .Status { margin-left: 12px; } +.EntWatch.Size100 .Status Label { font-size: 16px; } +.EntWatch.Size100 .Status .Icon { font-size: 19px; margin-right: 5px; } +.EntWatch.Size100 .Status .ReloadIcon { width: 22px; height: 22px; margin-left: 5px; margin-right: 0px; } +.EntWatch.Size100 .Ammo { margin-right: 12px; } +.EntWatch.Size100 .Overflow { font-size: 14px; } +.EntWatch.Size101 .Item { width: 484.8px; padding: 8.08px 12.12px; margin-bottom: 5.05px; border-left-width: 3.03px; } +.EntWatch.Size101 .ItemName { font-size: 18.18px; } +.EntWatch.Size101 .Owner { font-size: 16.16px; margin-left: 8.08px; } +.EntWatch.Size101 .Status { margin-left: 12.12px; } +.EntWatch.Size101 .Status Label { font-size: 16.16px; } +.EntWatch.Size101 .Status .Icon { font-size: 19.19px; margin-right: 5.05px; } +.EntWatch.Size101 .Status .ReloadIcon { width: 22.22px; height: 22.22px; margin-left: 5.05px; margin-right: 0px; } +.EntWatch.Size101 .Ammo { margin-right: 12.12px; } +.EntWatch.Size101 .Overflow { font-size: 14.14px; } +.EntWatch.Size102 .Item { width: 489.6px; padding: 8.16px 12.24px; margin-bottom: 5.1px; border-left-width: 3.06px; } +.EntWatch.Size102 .ItemName { font-size: 18.36px; } +.EntWatch.Size102 .Owner { font-size: 16.32px; margin-left: 8.16px; } +.EntWatch.Size102 .Status { margin-left: 12.24px; } +.EntWatch.Size102 .Status Label { font-size: 16.32px; } +.EntWatch.Size102 .Status .Icon { font-size: 19.38px; margin-right: 5.1px; } +.EntWatch.Size102 .Status .ReloadIcon { width: 22.44px; height: 22.44px; margin-left: 5.1px; margin-right: 0px; } +.EntWatch.Size102 .Ammo { margin-right: 12.24px; } +.EntWatch.Size102 .Overflow { font-size: 14.28px; } +.EntWatch.Size103 .Item { width: 494.4px; padding: 8.24px 12.36px; margin-bottom: 5.15px; border-left-width: 3.09px; } +.EntWatch.Size103 .ItemName { font-size: 18.54px; } +.EntWatch.Size103 .Owner { font-size: 16.48px; margin-left: 8.24px; } +.EntWatch.Size103 .Status { margin-left: 12.36px; } +.EntWatch.Size103 .Status Label { font-size: 16.48px; } +.EntWatch.Size103 .Status .Icon { font-size: 19.57px; margin-right: 5.15px; } +.EntWatch.Size103 .Status .ReloadIcon { width: 22.66px; height: 22.66px; margin-left: 5.15px; margin-right: 0px; } +.EntWatch.Size103 .Ammo { margin-right: 12.36px; } +.EntWatch.Size103 .Overflow { font-size: 14.42px; } +.EntWatch.Size104 .Item { width: 499.2px; padding: 8.32px 12.48px; margin-bottom: 5.2px; border-left-width: 3.12px; } +.EntWatch.Size104 .ItemName { font-size: 18.72px; } +.EntWatch.Size104 .Owner { font-size: 16.64px; margin-left: 8.32px; } +.EntWatch.Size104 .Status { margin-left: 12.48px; } +.EntWatch.Size104 .Status Label { font-size: 16.64px; } +.EntWatch.Size104 .Status .Icon { font-size: 19.76px; margin-right: 5.2px; } +.EntWatch.Size104 .Status .ReloadIcon { width: 22.88px; height: 22.88px; margin-left: 5.2px; margin-right: 0px; } +.EntWatch.Size104 .Ammo { margin-right: 12.48px; } +.EntWatch.Size104 .Overflow { font-size: 14.56px; } +.EntWatch.Size105 .Item { width: 504px; padding: 8.4px 12.6px; margin-bottom: 5.25px; border-left-width: 3.15px; } +.EntWatch.Size105 .ItemName { font-size: 18.9px; } +.EntWatch.Size105 .Owner { font-size: 16.8px; margin-left: 8.4px; } +.EntWatch.Size105 .Status { margin-left: 12.6px; } +.EntWatch.Size105 .Status Label { font-size: 16.8px; } +.EntWatch.Size105 .Status .Icon { font-size: 19.95px; margin-right: 5.25px; } +.EntWatch.Size105 .Status .ReloadIcon { width: 23.1px; height: 23.1px; margin-left: 5.25px; margin-right: 0px; } +.EntWatch.Size105 .Ammo { margin-right: 12.6px; } +.EntWatch.Size105 .Overflow { font-size: 14.7px; } +.EntWatch.Size106 .Item { width: 508.8px; padding: 8.48px 12.72px; margin-bottom: 5.3px; border-left-width: 3.18px; } +.EntWatch.Size106 .ItemName { font-size: 19.08px; } +.EntWatch.Size106 .Owner { font-size: 16.96px; margin-left: 8.48px; } +.EntWatch.Size106 .Status { margin-left: 12.72px; } +.EntWatch.Size106 .Status Label { font-size: 16.96px; } +.EntWatch.Size106 .Status .Icon { font-size: 20.14px; margin-right: 5.3px; } +.EntWatch.Size106 .Status .ReloadIcon { width: 23.32px; height: 23.32px; margin-left: 5.3px; margin-right: 0px; } +.EntWatch.Size106 .Ammo { margin-right: 12.72px; } +.EntWatch.Size106 .Overflow { font-size: 14.84px; } +.EntWatch.Size107 .Item { width: 513.6px; padding: 8.56px 12.84px; margin-bottom: 5.35px; border-left-width: 3.21px; } +.EntWatch.Size107 .ItemName { font-size: 19.26px; } +.EntWatch.Size107 .Owner { font-size: 17.12px; margin-left: 8.56px; } +.EntWatch.Size107 .Status { margin-left: 12.84px; } +.EntWatch.Size107 .Status Label { font-size: 17.12px; } +.EntWatch.Size107 .Status .Icon { font-size: 20.33px; margin-right: 5.35px; } +.EntWatch.Size107 .Status .ReloadIcon { width: 23.54px; height: 23.54px; margin-left: 5.35px; margin-right: 0px; } +.EntWatch.Size107 .Ammo { margin-right: 12.84px; } +.EntWatch.Size107 .Overflow { font-size: 14.98px; } +.EntWatch.Size108 .Item { width: 518.4px; padding: 8.64px 12.96px; margin-bottom: 5.4px; border-left-width: 3.24px; } +.EntWatch.Size108 .ItemName { font-size: 19.44px; } +.EntWatch.Size108 .Owner { font-size: 17.28px; margin-left: 8.64px; } +.EntWatch.Size108 .Status { margin-left: 12.96px; } +.EntWatch.Size108 .Status Label { font-size: 17.28px; } +.EntWatch.Size108 .Status .Icon { font-size: 20.52px; margin-right: 5.4px; } +.EntWatch.Size108 .Status .ReloadIcon { width: 23.76px; height: 23.76px; margin-left: 5.4px; margin-right: 0px; } +.EntWatch.Size108 .Ammo { margin-right: 12.96px; } +.EntWatch.Size108 .Overflow { font-size: 15.12px; } +.EntWatch.Size109 .Item { width: 523.2px; padding: 8.72px 13.08px; margin-bottom: 5.45px; border-left-width: 3.27px; } +.EntWatch.Size109 .ItemName { font-size: 19.62px; } +.EntWatch.Size109 .Owner { font-size: 17.44px; margin-left: 8.72px; } +.EntWatch.Size109 .Status { margin-left: 13.08px; } +.EntWatch.Size109 .Status Label { font-size: 17.44px; } +.EntWatch.Size109 .Status .Icon { font-size: 20.71px; margin-right: 5.45px; } +.EntWatch.Size109 .Status .ReloadIcon { width: 23.98px; height: 23.98px; margin-left: 5.45px; margin-right: 0px; } +.EntWatch.Size109 .Ammo { margin-right: 13.08px; } +.EntWatch.Size109 .Overflow { font-size: 15.26px; } +.EntWatch.Size110 .Item { width: 528px; padding: 8.8px 13.2px; margin-bottom: 5.5px; border-left-width: 3.3px; } +.EntWatch.Size110 .ItemName { font-size: 19.8px; } +.EntWatch.Size110 .Owner { font-size: 17.6px; margin-left: 8.8px; } +.EntWatch.Size110 .Status { margin-left: 13.2px; } +.EntWatch.Size110 .Status Label { font-size: 17.6px; } +.EntWatch.Size110 .Status .Icon { font-size: 20.9px; margin-right: 5.5px; } +.EntWatch.Size110 .Status .ReloadIcon { width: 24.2px; height: 24.2px; margin-left: 5.5px; margin-right: 0px; } +.EntWatch.Size110 .Ammo { margin-right: 13.2px; } +.EntWatch.Size110 .Overflow { font-size: 15.4px; } +.EntWatch.Size111 .Item { width: 532.8px; padding: 8.88px 13.32px; margin-bottom: 5.55px; border-left-width: 3.33px; } +.EntWatch.Size111 .ItemName { font-size: 19.98px; } +.EntWatch.Size111 .Owner { font-size: 17.76px; margin-left: 8.88px; } +.EntWatch.Size111 .Status { margin-left: 13.32px; } +.EntWatch.Size111 .Status Label { font-size: 17.76px; } +.EntWatch.Size111 .Status .Icon { font-size: 21.09px; margin-right: 5.55px; } +.EntWatch.Size111 .Status .ReloadIcon { width: 24.42px; height: 24.42px; margin-left: 5.55px; margin-right: 0px; } +.EntWatch.Size111 .Ammo { margin-right: 13.32px; } +.EntWatch.Size111 .Overflow { font-size: 15.54px; } +.EntWatch.Size112 .Item { width: 537.6px; padding: 8.96px 13.44px; margin-bottom: 5.6px; border-left-width: 3.36px; } +.EntWatch.Size112 .ItemName { font-size: 20.16px; } +.EntWatch.Size112 .Owner { font-size: 17.92px; margin-left: 8.96px; } +.EntWatch.Size112 .Status { margin-left: 13.44px; } +.EntWatch.Size112 .Status Label { font-size: 17.92px; } +.EntWatch.Size112 .Status .Icon { font-size: 21.28px; margin-right: 5.6px; } +.EntWatch.Size112 .Status .ReloadIcon { width: 24.64px; height: 24.64px; margin-left: 5.6px; margin-right: 0px; } +.EntWatch.Size112 .Ammo { margin-right: 13.44px; } +.EntWatch.Size112 .Overflow { font-size: 15.68px; } +.EntWatch.Size113 .Item { width: 542.4px; padding: 9.04px 13.56px; margin-bottom: 5.65px; border-left-width: 3.39px; } +.EntWatch.Size113 .ItemName { font-size: 20.34px; } +.EntWatch.Size113 .Owner { font-size: 18.08px; margin-left: 9.04px; } +.EntWatch.Size113 .Status { margin-left: 13.56px; } +.EntWatch.Size113 .Status Label { font-size: 18.08px; } +.EntWatch.Size113 .Status .Icon { font-size: 21.47px; margin-right: 5.65px; } +.EntWatch.Size113 .Status .ReloadIcon { width: 24.86px; height: 24.86px; margin-left: 5.65px; margin-right: 0px; } +.EntWatch.Size113 .Ammo { margin-right: 13.56px; } +.EntWatch.Size113 .Overflow { font-size: 15.82px; } +.EntWatch.Size114 .Item { width: 547.2px; padding: 9.12px 13.68px; margin-bottom: 5.7px; border-left-width: 3.42px; } +.EntWatch.Size114 .ItemName { font-size: 20.52px; } +.EntWatch.Size114 .Owner { font-size: 18.24px; margin-left: 9.12px; } +.EntWatch.Size114 .Status { margin-left: 13.68px; } +.EntWatch.Size114 .Status Label { font-size: 18.24px; } +.EntWatch.Size114 .Status .Icon { font-size: 21.66px; margin-right: 5.7px; } +.EntWatch.Size114 .Status .ReloadIcon { width: 25.08px; height: 25.08px; margin-left: 5.7px; margin-right: 0px; } +.EntWatch.Size114 .Ammo { margin-right: 13.68px; } +.EntWatch.Size114 .Overflow { font-size: 15.96px; } +.EntWatch.Size115 .Item { width: 552px; padding: 9.2px 13.8px; margin-bottom: 5.75px; border-left-width: 3.45px; } +.EntWatch.Size115 .ItemName { font-size: 20.7px; } +.EntWatch.Size115 .Owner { font-size: 18.4px; margin-left: 9.2px; } +.EntWatch.Size115 .Status { margin-left: 13.8px; } +.EntWatch.Size115 .Status Label { font-size: 18.4px; } +.EntWatch.Size115 .Status .Icon { font-size: 21.85px; margin-right: 5.75px; } +.EntWatch.Size115 .Status .ReloadIcon { width: 25.3px; height: 25.3px; margin-left: 5.75px; margin-right: 0px; } +.EntWatch.Size115 .Ammo { margin-right: 13.8px; } +.EntWatch.Size115 .Overflow { font-size: 16.1px; } +.EntWatch.Size116 .Item { width: 556.8px; padding: 9.28px 13.92px; margin-bottom: 5.8px; border-left-width: 3.48px; } +.EntWatch.Size116 .ItemName { font-size: 20.88px; } +.EntWatch.Size116 .Owner { font-size: 18.56px; margin-left: 9.28px; } +.EntWatch.Size116 .Status { margin-left: 13.92px; } +.EntWatch.Size116 .Status Label { font-size: 18.56px; } +.EntWatch.Size116 .Status .Icon { font-size: 22.04px; margin-right: 5.8px; } +.EntWatch.Size116 .Status .ReloadIcon { width: 25.52px; height: 25.52px; margin-left: 5.8px; margin-right: 0px; } +.EntWatch.Size116 .Ammo { margin-right: 13.92px; } +.EntWatch.Size116 .Overflow { font-size: 16.24px; } +.EntWatch.Size117 .Item { width: 561.6px; padding: 9.36px 14.04px; margin-bottom: 5.85px; border-left-width: 3.51px; } +.EntWatch.Size117 .ItemName { font-size: 21.06px; } +.EntWatch.Size117 .Owner { font-size: 18.72px; margin-left: 9.36px; } +.EntWatch.Size117 .Status { margin-left: 14.04px; } +.EntWatch.Size117 .Status Label { font-size: 18.72px; } +.EntWatch.Size117 .Status .Icon { font-size: 22.23px; margin-right: 5.85px; } +.EntWatch.Size117 .Status .ReloadIcon { width: 25.74px; height: 25.74px; margin-left: 5.85px; margin-right: 0px; } +.EntWatch.Size117 .Ammo { margin-right: 14.04px; } +.EntWatch.Size117 .Overflow { font-size: 16.38px; } +.EntWatch.Size118 .Item { width: 566.4px; padding: 9.44px 14.16px; margin-bottom: 5.9px; border-left-width: 3.54px; } +.EntWatch.Size118 .ItemName { font-size: 21.24px; } +.EntWatch.Size118 .Owner { font-size: 18.88px; margin-left: 9.44px; } +.EntWatch.Size118 .Status { margin-left: 14.16px; } +.EntWatch.Size118 .Status Label { font-size: 18.88px; } +.EntWatch.Size118 .Status .Icon { font-size: 22.42px; margin-right: 5.9px; } +.EntWatch.Size118 .Status .ReloadIcon { width: 25.96px; height: 25.96px; margin-left: 5.9px; margin-right: 0px; } +.EntWatch.Size118 .Ammo { margin-right: 14.16px; } +.EntWatch.Size118 .Overflow { font-size: 16.52px; } +.EntWatch.Size119 .Item { width: 571.2px; padding: 9.52px 14.28px; margin-bottom: 5.95px; border-left-width: 3.57px; } +.EntWatch.Size119 .ItemName { font-size: 21.42px; } +.EntWatch.Size119 .Owner { font-size: 19.04px; margin-left: 9.52px; } +.EntWatch.Size119 .Status { margin-left: 14.28px; } +.EntWatch.Size119 .Status Label { font-size: 19.04px; } +.EntWatch.Size119 .Status .Icon { font-size: 22.61px; margin-right: 5.95px; } +.EntWatch.Size119 .Status .ReloadIcon { width: 26.18px; height: 26.18px; margin-left: 5.95px; margin-right: 0px; } +.EntWatch.Size119 .Ammo { margin-right: 14.28px; } +.EntWatch.Size119 .Overflow { font-size: 16.66px; } +.EntWatch.Size120 .Item { width: 576px; padding: 9.6px 14.4px; margin-bottom: 6px; border-left-width: 3.6px; } +.EntWatch.Size120 .ItemName { font-size: 21.6px; } +.EntWatch.Size120 .Owner { font-size: 19.2px; margin-left: 9.6px; } +.EntWatch.Size120 .Status { margin-left: 14.4px; } +.EntWatch.Size120 .Status Label { font-size: 19.2px; } +.EntWatch.Size120 .Status .Icon { font-size: 22.8px; margin-right: 6px; } +.EntWatch.Size120 .Status .ReloadIcon { width: 26.4px; height: 26.4px; margin-left: 6px; margin-right: 0px; } +.EntWatch.Size120 .Ammo { margin-right: 14.4px; } +.EntWatch.Size120 .Overflow { font-size: 16.8px; } +.EntWatch.Size121 .Item { width: 580.8px; padding: 9.68px 14.52px; margin-bottom: 6.05px; border-left-width: 3.63px; } +.EntWatch.Size121 .ItemName { font-size: 21.78px; } +.EntWatch.Size121 .Owner { font-size: 19.36px; margin-left: 9.68px; } +.EntWatch.Size121 .Status { margin-left: 14.52px; } +.EntWatch.Size121 .Status Label { font-size: 19.36px; } +.EntWatch.Size121 .Status .Icon { font-size: 22.99px; margin-right: 6.05px; } +.EntWatch.Size121 .Status .ReloadIcon { width: 26.62px; height: 26.62px; margin-left: 6.05px; margin-right: 0px; } +.EntWatch.Size121 .Ammo { margin-right: 14.52px; } +.EntWatch.Size121 .Overflow { font-size: 16.94px; } +.EntWatch.Size122 .Item { width: 585.6px; padding: 9.76px 14.64px; margin-bottom: 6.1px; border-left-width: 3.66px; } +.EntWatch.Size122 .ItemName { font-size: 21.96px; } +.EntWatch.Size122 .Owner { font-size: 19.52px; margin-left: 9.76px; } +.EntWatch.Size122 .Status { margin-left: 14.64px; } +.EntWatch.Size122 .Status Label { font-size: 19.52px; } +.EntWatch.Size122 .Status .Icon { font-size: 23.18px; margin-right: 6.1px; } +.EntWatch.Size122 .Status .ReloadIcon { width: 26.84px; height: 26.84px; margin-left: 6.1px; margin-right: 0px; } +.EntWatch.Size122 .Ammo { margin-right: 14.64px; } +.EntWatch.Size122 .Overflow { font-size: 17.08px; } +.EntWatch.Size123 .Item { width: 590.4px; padding: 9.84px 14.76px; margin-bottom: 6.15px; border-left-width: 3.69px; } +.EntWatch.Size123 .ItemName { font-size: 22.14px; } +.EntWatch.Size123 .Owner { font-size: 19.68px; margin-left: 9.84px; } +.EntWatch.Size123 .Status { margin-left: 14.76px; } +.EntWatch.Size123 .Status Label { font-size: 19.68px; } +.EntWatch.Size123 .Status .Icon { font-size: 23.37px; margin-right: 6.15px; } +.EntWatch.Size123 .Status .ReloadIcon { width: 27.06px; height: 27.06px; margin-left: 6.15px; margin-right: 0px; } +.EntWatch.Size123 .Ammo { margin-right: 14.76px; } +.EntWatch.Size123 .Overflow { font-size: 17.22px; } +.EntWatch.Size124 .Item { width: 595.2px; padding: 9.92px 14.88px; margin-bottom: 6.2px; border-left-width: 3.72px; } +.EntWatch.Size124 .ItemName { font-size: 22.32px; } +.EntWatch.Size124 .Owner { font-size: 19.84px; margin-left: 9.92px; } +.EntWatch.Size124 .Status { margin-left: 14.88px; } +.EntWatch.Size124 .Status Label { font-size: 19.84px; } +.EntWatch.Size124 .Status .Icon { font-size: 23.56px; margin-right: 6.2px; } +.EntWatch.Size124 .Status .ReloadIcon { width: 27.28px; height: 27.28px; margin-left: 6.2px; margin-right: 0px; } +.EntWatch.Size124 .Ammo { margin-right: 14.88px; } +.EntWatch.Size124 .Overflow { font-size: 17.36px; } +.EntWatch.Size125 .Item { width: 600px; padding: 10px 15px; margin-bottom: 6.25px; border-left-width: 3.75px; } +.EntWatch.Size125 .ItemName { font-size: 22.5px; } +.EntWatch.Size125 .Owner { font-size: 20px; margin-left: 10px; } +.EntWatch.Size125 .Status { margin-left: 15px; } +.EntWatch.Size125 .Status Label { font-size: 20px; } +.EntWatch.Size125 .Status .Icon { font-size: 23.75px; margin-right: 6.25px; } +.EntWatch.Size125 .Status .ReloadIcon { width: 27.5px; height: 27.5px; margin-left: 6.25px; margin-right: 0px; } +.EntWatch.Size125 .Ammo { margin-right: 15px; } +.EntWatch.Size125 .Overflow { font-size: 17.5px; } +.EntWatch.Size126 .Item { width: 604.8px; padding: 10.08px 15.12px; margin-bottom: 6.3px; border-left-width: 3.78px; } +.EntWatch.Size126 .ItemName { font-size: 22.68px; } +.EntWatch.Size126 .Owner { font-size: 20.16px; margin-left: 10.08px; } +.EntWatch.Size126 .Status { margin-left: 15.12px; } +.EntWatch.Size126 .Status Label { font-size: 20.16px; } +.EntWatch.Size126 .Status .Icon { font-size: 23.94px; margin-right: 6.3px; } +.EntWatch.Size126 .Status .ReloadIcon { width: 27.72px; height: 27.72px; margin-left: 6.3px; margin-right: 0px; } +.EntWatch.Size126 .Ammo { margin-right: 15.12px; } +.EntWatch.Size126 .Overflow { font-size: 17.64px; } +.EntWatch.Size127 .Item { width: 609.6px; padding: 10.16px 15.24px; margin-bottom: 6.35px; border-left-width: 3.81px; } +.EntWatch.Size127 .ItemName { font-size: 22.86px; } +.EntWatch.Size127 .Owner { font-size: 20.32px; margin-left: 10.16px; } +.EntWatch.Size127 .Status { margin-left: 15.24px; } +.EntWatch.Size127 .Status Label { font-size: 20.32px; } +.EntWatch.Size127 .Status .Icon { font-size: 24.13px; margin-right: 6.35px; } +.EntWatch.Size127 .Status .ReloadIcon { width: 27.94px; height: 27.94px; margin-left: 6.35px; margin-right: 0px; } +.EntWatch.Size127 .Ammo { margin-right: 15.24px; } +.EntWatch.Size127 .Overflow { font-size: 17.78px; } +.EntWatch.Size128 .Item { width: 614.4px; padding: 10.24px 15.36px; margin-bottom: 6.4px; border-left-width: 3.84px; } +.EntWatch.Size128 .ItemName { font-size: 23.04px; } +.EntWatch.Size128 .Owner { font-size: 20.48px; margin-left: 10.24px; } +.EntWatch.Size128 .Status { margin-left: 15.36px; } +.EntWatch.Size128 .Status Label { font-size: 20.48px; } +.EntWatch.Size128 .Status .Icon { font-size: 24.32px; margin-right: 6.4px; } +.EntWatch.Size128 .Status .ReloadIcon { width: 28.16px; height: 28.16px; margin-left: 6.4px; margin-right: 0px; } +.EntWatch.Size128 .Ammo { margin-right: 15.36px; } +.EntWatch.Size128 .Overflow { font-size: 17.92px; } +.EntWatch.Size129 .Item { width: 619.2px; padding: 10.32px 15.48px; margin-bottom: 6.45px; border-left-width: 3.87px; } +.EntWatch.Size129 .ItemName { font-size: 23.22px; } +.EntWatch.Size129 .Owner { font-size: 20.64px; margin-left: 10.32px; } +.EntWatch.Size129 .Status { margin-left: 15.48px; } +.EntWatch.Size129 .Status Label { font-size: 20.64px; } +.EntWatch.Size129 .Status .Icon { font-size: 24.51px; margin-right: 6.45px; } +.EntWatch.Size129 .Status .ReloadIcon { width: 28.38px; height: 28.38px; margin-left: 6.45px; margin-right: 0px; } +.EntWatch.Size129 .Ammo { margin-right: 15.48px; } +.EntWatch.Size129 .Overflow { font-size: 18.06px; } +.EntWatch.Size130 .Item { width: 624px; padding: 10.4px 15.6px; margin-bottom: 6.5px; border-left-width: 3.9px; } +.EntWatch.Size130 .ItemName { font-size: 23.4px; } +.EntWatch.Size130 .Owner { font-size: 20.8px; margin-left: 10.4px; } +.EntWatch.Size130 .Status { margin-left: 15.6px; } +.EntWatch.Size130 .Status Label { font-size: 20.8px; } +.EntWatch.Size130 .Status .Icon { font-size: 24.7px; margin-right: 6.5px; } +.EntWatch.Size130 .Status .ReloadIcon { width: 28.6px; height: 28.6px; margin-left: 6.5px; margin-right: 0px; } +.EntWatch.Size130 .Ammo { margin-right: 15.6px; } +.EntWatch.Size130 .Overflow { font-size: 18.2px; } +.EntWatch.Size131 .Item { width: 628.8px; padding: 10.48px 15.72px; margin-bottom: 6.55px; border-left-width: 3.93px; } +.EntWatch.Size131 .ItemName { font-size: 23.58px; } +.EntWatch.Size131 .Owner { font-size: 20.96px; margin-left: 10.48px; } +.EntWatch.Size131 .Status { margin-left: 15.72px; } +.EntWatch.Size131 .Status Label { font-size: 20.96px; } +.EntWatch.Size131 .Status .Icon { font-size: 24.89px; margin-right: 6.55px; } +.EntWatch.Size131 .Status .ReloadIcon { width: 28.82px; height: 28.82px; margin-left: 6.55px; margin-right: 0px; } +.EntWatch.Size131 .Ammo { margin-right: 15.72px; } +.EntWatch.Size131 .Overflow { font-size: 18.34px; } +.EntWatch.Size132 .Item { width: 633.6px; padding: 10.56px 15.84px; margin-bottom: 6.6px; border-left-width: 3.96px; } +.EntWatch.Size132 .ItemName { font-size: 23.76px; } +.EntWatch.Size132 .Owner { font-size: 21.12px; margin-left: 10.56px; } +.EntWatch.Size132 .Status { margin-left: 15.84px; } +.EntWatch.Size132 .Status Label { font-size: 21.12px; } +.EntWatch.Size132 .Status .Icon { font-size: 25.08px; margin-right: 6.6px; } +.EntWatch.Size132 .Status .ReloadIcon { width: 29.04px; height: 29.04px; margin-left: 6.6px; margin-right: 0px; } +.EntWatch.Size132 .Ammo { margin-right: 15.84px; } +.EntWatch.Size132 .Overflow { font-size: 18.48px; } +.EntWatch.Size133 .Item { width: 638.4px; padding: 10.64px 15.96px; margin-bottom: 6.65px; border-left-width: 3.99px; } +.EntWatch.Size133 .ItemName { font-size: 23.94px; } +.EntWatch.Size133 .Owner { font-size: 21.28px; margin-left: 10.64px; } +.EntWatch.Size133 .Status { margin-left: 15.96px; } +.EntWatch.Size133 .Status Label { font-size: 21.28px; } +.EntWatch.Size133 .Status .Icon { font-size: 25.27px; margin-right: 6.65px; } +.EntWatch.Size133 .Status .ReloadIcon { width: 29.26px; height: 29.26px; margin-left: 6.65px; margin-right: 0px; } +.EntWatch.Size133 .Ammo { margin-right: 15.96px; } +.EntWatch.Size133 .Overflow { font-size: 18.62px; } +.EntWatch.Size134 .Item { width: 643.2px; padding: 10.72px 16.08px; margin-bottom: 6.7px; border-left-width: 4.02px; } +.EntWatch.Size134 .ItemName { font-size: 24.12px; } +.EntWatch.Size134 .Owner { font-size: 21.44px; margin-left: 10.72px; } +.EntWatch.Size134 .Status { margin-left: 16.08px; } +.EntWatch.Size134 .Status Label { font-size: 21.44px; } +.EntWatch.Size134 .Status .Icon { font-size: 25.46px; margin-right: 6.7px; } +.EntWatch.Size134 .Status .ReloadIcon { width: 29.48px; height: 29.48px; margin-left: 6.7px; margin-right: 0px; } +.EntWatch.Size134 .Ammo { margin-right: 16.08px; } +.EntWatch.Size134 .Overflow { font-size: 18.76px; } +.EntWatch.Size135 .Item { width: 648px; padding: 10.8px 16.2px; margin-bottom: 6.75px; border-left-width: 4.05px; } +.EntWatch.Size135 .ItemName { font-size: 24.3px; } +.EntWatch.Size135 .Owner { font-size: 21.6px; margin-left: 10.8px; } +.EntWatch.Size135 .Status { margin-left: 16.2px; } +.EntWatch.Size135 .Status Label { font-size: 21.6px; } +.EntWatch.Size135 .Status .Icon { font-size: 25.65px; margin-right: 6.75px; } +.EntWatch.Size135 .Status .ReloadIcon { width: 29.7px; height: 29.7px; margin-left: 6.75px; margin-right: 0px; } +.EntWatch.Size135 .Ammo { margin-right: 16.2px; } +.EntWatch.Size135 .Overflow { font-size: 18.9px; } +.EntWatch.Size136 .Item { width: 652.8px; padding: 10.88px 16.32px; margin-bottom: 6.8px; border-left-width: 4.08px; } +.EntWatch.Size136 .ItemName { font-size: 24.48px; } +.EntWatch.Size136 .Owner { font-size: 21.76px; margin-left: 10.88px; } +.EntWatch.Size136 .Status { margin-left: 16.32px; } +.EntWatch.Size136 .Status Label { font-size: 21.76px; } +.EntWatch.Size136 .Status .Icon { font-size: 25.84px; margin-right: 6.8px; } +.EntWatch.Size136 .Status .ReloadIcon { width: 29.92px; height: 29.92px; margin-left: 6.8px; margin-right: 0px; } +.EntWatch.Size136 .Ammo { margin-right: 16.32px; } +.EntWatch.Size136 .Overflow { font-size: 19.04px; } +.EntWatch.Size137 .Item { width: 657.6px; padding: 10.96px 16.44px; margin-bottom: 6.85px; border-left-width: 4.11px; } +.EntWatch.Size137 .ItemName { font-size: 24.66px; } +.EntWatch.Size137 .Owner { font-size: 21.92px; margin-left: 10.96px; } +.EntWatch.Size137 .Status { margin-left: 16.44px; } +.EntWatch.Size137 .Status Label { font-size: 21.92px; } +.EntWatch.Size137 .Status .Icon { font-size: 26.03px; margin-right: 6.85px; } +.EntWatch.Size137 .Status .ReloadIcon { width: 30.14px; height: 30.14px; margin-left: 6.85px; margin-right: 0px; } +.EntWatch.Size137 .Ammo { margin-right: 16.44px; } +.EntWatch.Size137 .Overflow { font-size: 19.18px; } +.EntWatch.Size138 .Item { width: 662.4px; padding: 11.04px 16.56px; margin-bottom: 6.9px; border-left-width: 4.14px; } +.EntWatch.Size138 .ItemName { font-size: 24.84px; } +.EntWatch.Size138 .Owner { font-size: 22.08px; margin-left: 11.04px; } +.EntWatch.Size138 .Status { margin-left: 16.56px; } +.EntWatch.Size138 .Status Label { font-size: 22.08px; } +.EntWatch.Size138 .Status .Icon { font-size: 26.22px; margin-right: 6.9px; } +.EntWatch.Size138 .Status .ReloadIcon { width: 30.36px; height: 30.36px; margin-left: 6.9px; margin-right: 0px; } +.EntWatch.Size138 .Ammo { margin-right: 16.56px; } +.EntWatch.Size138 .Overflow { font-size: 19.32px; } +.EntWatch.Size139 .Item { width: 667.2px; padding: 11.12px 16.68px; margin-bottom: 6.95px; border-left-width: 4.17px; } +.EntWatch.Size139 .ItemName { font-size: 25.02px; } +.EntWatch.Size139 .Owner { font-size: 22.24px; margin-left: 11.12px; } +.EntWatch.Size139 .Status { margin-left: 16.68px; } +.EntWatch.Size139 .Status Label { font-size: 22.24px; } +.EntWatch.Size139 .Status .Icon { font-size: 26.41px; margin-right: 6.95px; } +.EntWatch.Size139 .Status .ReloadIcon { width: 30.58px; height: 30.58px; margin-left: 6.95px; margin-right: 0px; } +.EntWatch.Size139 .Ammo { margin-right: 16.68px; } +.EntWatch.Size139 .Overflow { font-size: 19.46px; } +.EntWatch.Size140 .Item { width: 672px; padding: 11.2px 16.8px; margin-bottom: 7px; border-left-width: 4.2px; } +.EntWatch.Size140 .ItemName { font-size: 25.2px; } +.EntWatch.Size140 .Owner { font-size: 22.4px; margin-left: 11.2px; } +.EntWatch.Size140 .Status { margin-left: 16.8px; } +.EntWatch.Size140 .Status Label { font-size: 22.4px; } +.EntWatch.Size140 .Status .Icon { font-size: 26.6px; margin-right: 7px; } +.EntWatch.Size140 .Status .ReloadIcon { width: 30.8px; height: 30.8px; margin-left: 7px; margin-right: 0px; } +.EntWatch.Size140 .Ammo { margin-right: 16.8px; } +.EntWatch.Size140 .Overflow { font-size: 19.6px; } +.EntWatch.Size141 .Item { width: 676.8px; padding: 11.28px 16.92px; margin-bottom: 7.05px; border-left-width: 4.23px; } +.EntWatch.Size141 .ItemName { font-size: 25.38px; } +.EntWatch.Size141 .Owner { font-size: 22.56px; margin-left: 11.28px; } +.EntWatch.Size141 .Status { margin-left: 16.92px; } +.EntWatch.Size141 .Status Label { font-size: 22.56px; } +.EntWatch.Size141 .Status .Icon { font-size: 26.79px; margin-right: 7.05px; } +.EntWatch.Size141 .Status .ReloadIcon { width: 31.02px; height: 31.02px; margin-left: 7.05px; margin-right: 0px; } +.EntWatch.Size141 .Ammo { margin-right: 16.92px; } +.EntWatch.Size141 .Overflow { font-size: 19.74px; } +.EntWatch.Size142 .Item { width: 681.6px; padding: 11.36px 17.04px; margin-bottom: 7.1px; border-left-width: 4.26px; } +.EntWatch.Size142 .ItemName { font-size: 25.56px; } +.EntWatch.Size142 .Owner { font-size: 22.72px; margin-left: 11.36px; } +.EntWatch.Size142 .Status { margin-left: 17.04px; } +.EntWatch.Size142 .Status Label { font-size: 22.72px; } +.EntWatch.Size142 .Status .Icon { font-size: 26.98px; margin-right: 7.1px; } +.EntWatch.Size142 .Status .ReloadIcon { width: 31.24px; height: 31.24px; margin-left: 7.1px; margin-right: 0px; } +.EntWatch.Size142 .Ammo { margin-right: 17.04px; } +.EntWatch.Size142 .Overflow { font-size: 19.88px; } +.EntWatch.Size143 .Item { width: 686.4px; padding: 11.44px 17.16px; margin-bottom: 7.15px; border-left-width: 4.29px; } +.EntWatch.Size143 .ItemName { font-size: 25.74px; } +.EntWatch.Size143 .Owner { font-size: 22.88px; margin-left: 11.44px; } +.EntWatch.Size143 .Status { margin-left: 17.16px; } +.EntWatch.Size143 .Status Label { font-size: 22.88px; } +.EntWatch.Size143 .Status .Icon { font-size: 27.17px; margin-right: 7.15px; } +.EntWatch.Size143 .Status .ReloadIcon { width: 31.46px; height: 31.46px; margin-left: 7.15px; margin-right: 0px; } +.EntWatch.Size143 .Ammo { margin-right: 17.16px; } +.EntWatch.Size143 .Overflow { font-size: 20.02px; } +.EntWatch.Size144 .Item { width: 691.2px; padding: 11.52px 17.28px; margin-bottom: 7.2px; border-left-width: 4.32px; } +.EntWatch.Size144 .ItemName { font-size: 25.92px; } +.EntWatch.Size144 .Owner { font-size: 23.04px; margin-left: 11.52px; } +.EntWatch.Size144 .Status { margin-left: 17.28px; } +.EntWatch.Size144 .Status Label { font-size: 23.04px; } +.EntWatch.Size144 .Status .Icon { font-size: 27.36px; margin-right: 7.2px; } +.EntWatch.Size144 .Status .ReloadIcon { width: 31.68px; height: 31.68px; margin-left: 7.2px; margin-right: 0px; } +.EntWatch.Size144 .Ammo { margin-right: 17.28px; } +.EntWatch.Size144 .Overflow { font-size: 20.16px; } +.EntWatch.Size145 .Item { width: 696px; padding: 11.6px 17.4px; margin-bottom: 7.25px; border-left-width: 4.35px; } +.EntWatch.Size145 .ItemName { font-size: 26.1px; } +.EntWatch.Size145 .Owner { font-size: 23.2px; margin-left: 11.6px; } +.EntWatch.Size145 .Status { margin-left: 17.4px; } +.EntWatch.Size145 .Status Label { font-size: 23.2px; } +.EntWatch.Size145 .Status .Icon { font-size: 27.55px; margin-right: 7.25px; } +.EntWatch.Size145 .Status .ReloadIcon { width: 31.9px; height: 31.9px; margin-left: 7.25px; margin-right: 0px; } +.EntWatch.Size145 .Ammo { margin-right: 17.4px; } +.EntWatch.Size145 .Overflow { font-size: 20.3px; } +.EntWatch.Size146 .Item { width: 700.8px; padding: 11.68px 17.52px; margin-bottom: 7.3px; border-left-width: 4.38px; } +.EntWatch.Size146 .ItemName { font-size: 26.28px; } +.EntWatch.Size146 .Owner { font-size: 23.36px; margin-left: 11.68px; } +.EntWatch.Size146 .Status { margin-left: 17.52px; } +.EntWatch.Size146 .Status Label { font-size: 23.36px; } +.EntWatch.Size146 .Status .Icon { font-size: 27.74px; margin-right: 7.3px; } +.EntWatch.Size146 .Status .ReloadIcon { width: 32.12px; height: 32.12px; margin-left: 7.3px; margin-right: 0px; } +.EntWatch.Size146 .Ammo { margin-right: 17.52px; } +.EntWatch.Size146 .Overflow { font-size: 20.44px; } +.EntWatch.Size147 .Item { width: 705.6px; padding: 11.76px 17.64px; margin-bottom: 7.35px; border-left-width: 4.41px; } +.EntWatch.Size147 .ItemName { font-size: 26.46px; } +.EntWatch.Size147 .Owner { font-size: 23.52px; margin-left: 11.76px; } +.EntWatch.Size147 .Status { margin-left: 17.64px; } +.EntWatch.Size147 .Status Label { font-size: 23.52px; } +.EntWatch.Size147 .Status .Icon { font-size: 27.93px; margin-right: 7.35px; } +.EntWatch.Size147 .Status .ReloadIcon { width: 32.34px; height: 32.34px; margin-left: 7.35px; margin-right: 0px; } +.EntWatch.Size147 .Ammo { margin-right: 17.64px; } +.EntWatch.Size147 .Overflow { font-size: 20.58px; } +.EntWatch.Size148 .Item { width: 710.4px; padding: 11.84px 17.76px; margin-bottom: 7.4px; border-left-width: 4.44px; } +.EntWatch.Size148 .ItemName { font-size: 26.64px; } +.EntWatch.Size148 .Owner { font-size: 23.68px; margin-left: 11.84px; } +.EntWatch.Size148 .Status { margin-left: 17.76px; } +.EntWatch.Size148 .Status Label { font-size: 23.68px; } +.EntWatch.Size148 .Status .Icon { font-size: 28.12px; margin-right: 7.4px; } +.EntWatch.Size148 .Status .ReloadIcon { width: 32.56px; height: 32.56px; margin-left: 7.4px; margin-right: 0px; } +.EntWatch.Size148 .Ammo { margin-right: 17.76px; } +.EntWatch.Size148 .Overflow { font-size: 20.72px; } +.EntWatch.Size149 .Item { width: 715.2px; padding: 11.92px 17.88px; margin-bottom: 7.45px; border-left-width: 4.47px; } +.EntWatch.Size149 .ItemName { font-size: 26.82px; } +.EntWatch.Size149 .Owner { font-size: 23.84px; margin-left: 11.92px; } +.EntWatch.Size149 .Status { margin-left: 17.88px; } +.EntWatch.Size149 .Status Label { font-size: 23.84px; } +.EntWatch.Size149 .Status .Icon { font-size: 28.31px; margin-right: 7.45px; } +.EntWatch.Size149 .Status .ReloadIcon { width: 32.78px; height: 32.78px; margin-left: 7.45px; margin-right: 0px; } +.EntWatch.Size149 .Ammo { margin-right: 17.88px; } +.EntWatch.Size149 .Overflow { font-size: 20.86px; } +.EntWatch.Size150 .Item { width: 720px; padding: 12px 18px; margin-bottom: 7.5px; border-left-width: 4.5px; } +.EntWatch.Size150 .ItemName { font-size: 27px; } +.EntWatch.Size150 .Owner { font-size: 24px; margin-left: 12px; } +.EntWatch.Size150 .Status { margin-left: 18px; } +.EntWatch.Size150 .Status Label { font-size: 24px; } +.EntWatch.Size150 .Status .Icon { font-size: 28.5px; margin-right: 7.5px; } +.EntWatch.Size150 .Status .ReloadIcon { width: 33px; height: 33px; margin-left: 7.5px; margin-right: 0px; } +.EntWatch.Size150 .Ammo { margin-right: 18px; } +.EntWatch.Size150 .Overflow { font-size: 21px; } +.EntWatch.Size151 .Item { width: 724.8px; padding: 12.08px 18.12px; margin-bottom: 7.55px; border-left-width: 4.53px; } +.EntWatch.Size151 .ItemName { font-size: 27.18px; } +.EntWatch.Size151 .Owner { font-size: 24.16px; margin-left: 12.08px; } +.EntWatch.Size151 .Status { margin-left: 18.12px; } +.EntWatch.Size151 .Status Label { font-size: 24.16px; } +.EntWatch.Size151 .Status .Icon { font-size: 28.69px; margin-right: 7.55px; } +.EntWatch.Size151 .Status .ReloadIcon { width: 33.22px; height: 33.22px; margin-left: 7.55px; margin-right: 0px; } +.EntWatch.Size151 .Ammo { margin-right: 18.12px; } +.EntWatch.Size151 .Overflow { font-size: 21.14px; } +.EntWatch.Size152 .Item { width: 729.6px; padding: 12.16px 18.24px; margin-bottom: 7.6px; border-left-width: 4.56px; } +.EntWatch.Size152 .ItemName { font-size: 27.36px; } +.EntWatch.Size152 .Owner { font-size: 24.32px; margin-left: 12.16px; } +.EntWatch.Size152 .Status { margin-left: 18.24px; } +.EntWatch.Size152 .Status Label { font-size: 24.32px; } +.EntWatch.Size152 .Status .Icon { font-size: 28.88px; margin-right: 7.6px; } +.EntWatch.Size152 .Status .ReloadIcon { width: 33.44px; height: 33.44px; margin-left: 7.6px; margin-right: 0px; } +.EntWatch.Size152 .Ammo { margin-right: 18.24px; } +.EntWatch.Size152 .Overflow { font-size: 21.28px; } +.EntWatch.Size153 .Item { width: 734.4px; padding: 12.24px 18.36px; margin-bottom: 7.65px; border-left-width: 4.59px; } +.EntWatch.Size153 .ItemName { font-size: 27.54px; } +.EntWatch.Size153 .Owner { font-size: 24.48px; margin-left: 12.24px; } +.EntWatch.Size153 .Status { margin-left: 18.36px; } +.EntWatch.Size153 .Status Label { font-size: 24.48px; } +.EntWatch.Size153 .Status .Icon { font-size: 29.07px; margin-right: 7.65px; } +.EntWatch.Size153 .Status .ReloadIcon { width: 33.66px; height: 33.66px; margin-left: 7.65px; margin-right: 0px; } +.EntWatch.Size153 .Ammo { margin-right: 18.36px; } +.EntWatch.Size153 .Overflow { font-size: 21.42px; } +.EntWatch.Size154 .Item { width: 739.2px; padding: 12.32px 18.48px; margin-bottom: 7.7px; border-left-width: 4.62px; } +.EntWatch.Size154 .ItemName { font-size: 27.72px; } +.EntWatch.Size154 .Owner { font-size: 24.64px; margin-left: 12.32px; } +.EntWatch.Size154 .Status { margin-left: 18.48px; } +.EntWatch.Size154 .Status Label { font-size: 24.64px; } +.EntWatch.Size154 .Status .Icon { font-size: 29.26px; margin-right: 7.7px; } +.EntWatch.Size154 .Status .ReloadIcon { width: 33.88px; height: 33.88px; margin-left: 7.7px; margin-right: 0px; } +.EntWatch.Size154 .Ammo { margin-right: 18.48px; } +.EntWatch.Size154 .Overflow { font-size: 21.56px; } +.EntWatch.Size155 .Item { width: 744px; padding: 12.4px 18.6px; margin-bottom: 7.75px; border-left-width: 4.65px; } +.EntWatch.Size155 .ItemName { font-size: 27.9px; } +.EntWatch.Size155 .Owner { font-size: 24.8px; margin-left: 12.4px; } +.EntWatch.Size155 .Status { margin-left: 18.6px; } +.EntWatch.Size155 .Status Label { font-size: 24.8px; } +.EntWatch.Size155 .Status .Icon { font-size: 29.45px; margin-right: 7.75px; } +.EntWatch.Size155 .Status .ReloadIcon { width: 34.1px; height: 34.1px; margin-left: 7.75px; margin-right: 0px; } +.EntWatch.Size155 .Ammo { margin-right: 18.6px; } +.EntWatch.Size155 .Overflow { font-size: 21.7px; } +.EntWatch.Size156 .Item { width: 748.8px; padding: 12.48px 18.72px; margin-bottom: 7.8px; border-left-width: 4.68px; } +.EntWatch.Size156 .ItemName { font-size: 28.08px; } +.EntWatch.Size156 .Owner { font-size: 24.96px; margin-left: 12.48px; } +.EntWatch.Size156 .Status { margin-left: 18.72px; } +.EntWatch.Size156 .Status Label { font-size: 24.96px; } +.EntWatch.Size156 .Status .Icon { font-size: 29.64px; margin-right: 7.8px; } +.EntWatch.Size156 .Status .ReloadIcon { width: 34.32px; height: 34.32px; margin-left: 7.8px; margin-right: 0px; } +.EntWatch.Size156 .Ammo { margin-right: 18.72px; } +.EntWatch.Size156 .Overflow { font-size: 21.84px; } +.EntWatch.Size157 .Item { width: 753.6px; padding: 12.56px 18.84px; margin-bottom: 7.85px; border-left-width: 4.71px; } +.EntWatch.Size157 .ItemName { font-size: 28.26px; } +.EntWatch.Size157 .Owner { font-size: 25.12px; margin-left: 12.56px; } +.EntWatch.Size157 .Status { margin-left: 18.84px; } +.EntWatch.Size157 .Status Label { font-size: 25.12px; } +.EntWatch.Size157 .Status .Icon { font-size: 29.83px; margin-right: 7.85px; } +.EntWatch.Size157 .Status .ReloadIcon { width: 34.54px; height: 34.54px; margin-left: 7.85px; margin-right: 0px; } +.EntWatch.Size157 .Ammo { margin-right: 18.84px; } +.EntWatch.Size157 .Overflow { font-size: 21.98px; } +.EntWatch.Size158 .Item { width: 758.4px; padding: 12.64px 18.96px; margin-bottom: 7.9px; border-left-width: 4.74px; } +.EntWatch.Size158 .ItemName { font-size: 28.44px; } +.EntWatch.Size158 .Owner { font-size: 25.28px; margin-left: 12.64px; } +.EntWatch.Size158 .Status { margin-left: 18.96px; } +.EntWatch.Size158 .Status Label { font-size: 25.28px; } +.EntWatch.Size158 .Status .Icon { font-size: 30.02px; margin-right: 7.9px; } +.EntWatch.Size158 .Status .ReloadIcon { width: 34.76px; height: 34.76px; margin-left: 7.9px; margin-right: 0px; } +.EntWatch.Size158 .Ammo { margin-right: 18.96px; } +.EntWatch.Size158 .Overflow { font-size: 22.12px; } +.EntWatch.Size159 .Item { width: 763.2px; padding: 12.72px 19.08px; margin-bottom: 7.95px; border-left-width: 4.77px; } +.EntWatch.Size159 .ItemName { font-size: 28.62px; } +.EntWatch.Size159 .Owner { font-size: 25.44px; margin-left: 12.72px; } +.EntWatch.Size159 .Status { margin-left: 19.08px; } +.EntWatch.Size159 .Status Label { font-size: 25.44px; } +.EntWatch.Size159 .Status .Icon { font-size: 30.21px; margin-right: 7.95px; } +.EntWatch.Size159 .Status .ReloadIcon { width: 34.98px; height: 34.98px; margin-left: 7.95px; margin-right: 0px; } +.EntWatch.Size159 .Ammo { margin-right: 19.08px; } +.EntWatch.Size159 .Overflow { font-size: 22.26px; } +.EntWatch.Size160 .Item { width: 768px; padding: 12.8px 19.2px; margin-bottom: 8px; border-left-width: 4.8px; } +.EntWatch.Size160 .ItemName { font-size: 28.8px; } +.EntWatch.Size160 .Owner { font-size: 25.6px; margin-left: 12.8px; } +.EntWatch.Size160 .Status { margin-left: 19.2px; } +.EntWatch.Size160 .Status Label { font-size: 25.6px; } +.EntWatch.Size160 .Status .Icon { font-size: 30.4px; margin-right: 8px; } +.EntWatch.Size160 .Status .ReloadIcon { width: 35.2px; height: 35.2px; margin-left: 8px; margin-right: 0px; } +.EntWatch.Size160 .Ammo { margin-right: 19.2px; } +.EntWatch.Size160 .Overflow { font-size: 22.4px; } +.EntWatch.Size161 .Item { width: 772.8px; padding: 12.88px 19.32px; margin-bottom: 8.05px; border-left-width: 4.83px; } +.EntWatch.Size161 .ItemName { font-size: 28.98px; } +.EntWatch.Size161 .Owner { font-size: 25.76px; margin-left: 12.88px; } +.EntWatch.Size161 .Status { margin-left: 19.32px; } +.EntWatch.Size161 .Status Label { font-size: 25.76px; } +.EntWatch.Size161 .Status .Icon { font-size: 30.59px; margin-right: 8.05px; } +.EntWatch.Size161 .Status .ReloadIcon { width: 35.42px; height: 35.42px; margin-left: 8.05px; margin-right: 0px; } +.EntWatch.Size161 .Ammo { margin-right: 19.32px; } +.EntWatch.Size161 .Overflow { font-size: 22.54px; } +.EntWatch.Size162 .Item { width: 777.6px; padding: 12.96px 19.44px; margin-bottom: 8.1px; border-left-width: 4.86px; } +.EntWatch.Size162 .ItemName { font-size: 29.16px; } +.EntWatch.Size162 .Owner { font-size: 25.92px; margin-left: 12.96px; } +.EntWatch.Size162 .Status { margin-left: 19.44px; } +.EntWatch.Size162 .Status Label { font-size: 25.92px; } +.EntWatch.Size162 .Status .Icon { font-size: 30.78px; margin-right: 8.1px; } +.EntWatch.Size162 .Status .ReloadIcon { width: 35.64px; height: 35.64px; margin-left: 8.1px; margin-right: 0px; } +.EntWatch.Size162 .Ammo { margin-right: 19.44px; } +.EntWatch.Size162 .Overflow { font-size: 22.68px; } +.EntWatch.Size163 .Item { width: 782.4px; padding: 13.04px 19.56px; margin-bottom: 8.15px; border-left-width: 4.89px; } +.EntWatch.Size163 .ItemName { font-size: 29.34px; } +.EntWatch.Size163 .Owner { font-size: 26.08px; margin-left: 13.04px; } +.EntWatch.Size163 .Status { margin-left: 19.56px; } +.EntWatch.Size163 .Status Label { font-size: 26.08px; } +.EntWatch.Size163 .Status .Icon { font-size: 30.97px; margin-right: 8.15px; } +.EntWatch.Size163 .Status .ReloadIcon { width: 35.86px; height: 35.86px; margin-left: 8.15px; margin-right: 0px; } +.EntWatch.Size163 .Ammo { margin-right: 19.56px; } +.EntWatch.Size163 .Overflow { font-size: 22.82px; } +.EntWatch.Size164 .Item { width: 787.2px; padding: 13.12px 19.68px; margin-bottom: 8.2px; border-left-width: 4.92px; } +.EntWatch.Size164 .ItemName { font-size: 29.52px; } +.EntWatch.Size164 .Owner { font-size: 26.24px; margin-left: 13.12px; } +.EntWatch.Size164 .Status { margin-left: 19.68px; } +.EntWatch.Size164 .Status Label { font-size: 26.24px; } +.EntWatch.Size164 .Status .Icon { font-size: 31.16px; margin-right: 8.2px; } +.EntWatch.Size164 .Status .ReloadIcon { width: 36.08px; height: 36.08px; margin-left: 8.2px; margin-right: 0px; } +.EntWatch.Size164 .Ammo { margin-right: 19.68px; } +.EntWatch.Size164 .Overflow { font-size: 22.96px; } +.EntWatch.Size165 .Item { width: 792px; padding: 13.2px 19.8px; margin-bottom: 8.25px; border-left-width: 4.95px; } +.EntWatch.Size165 .ItemName { font-size: 29.7px; } +.EntWatch.Size165 .Owner { font-size: 26.4px; margin-left: 13.2px; } +.EntWatch.Size165 .Status { margin-left: 19.8px; } +.EntWatch.Size165 .Status Label { font-size: 26.4px; } +.EntWatch.Size165 .Status .Icon { font-size: 31.35px; margin-right: 8.25px; } +.EntWatch.Size165 .Status .ReloadIcon { width: 36.3px; height: 36.3px; margin-left: 8.25px; margin-right: 0px; } +.EntWatch.Size165 .Ammo { margin-right: 19.8px; } +.EntWatch.Size165 .Overflow { font-size: 23.1px; } +.EntWatch.Size166 .Item { width: 796.8px; padding: 13.28px 19.92px; margin-bottom: 8.3px; border-left-width: 4.98px; } +.EntWatch.Size166 .ItemName { font-size: 29.88px; } +.EntWatch.Size166 .Owner { font-size: 26.56px; margin-left: 13.28px; } +.EntWatch.Size166 .Status { margin-left: 19.92px; } +.EntWatch.Size166 .Status Label { font-size: 26.56px; } +.EntWatch.Size166 .Status .Icon { font-size: 31.54px; margin-right: 8.3px; } +.EntWatch.Size166 .Status .ReloadIcon { width: 36.52px; height: 36.52px; margin-left: 8.3px; margin-right: 0px; } +.EntWatch.Size166 .Ammo { margin-right: 19.92px; } +.EntWatch.Size166 .Overflow { font-size: 23.24px; } +.EntWatch.Size167 .Item { width: 801.6px; padding: 13.36px 20.04px; margin-bottom: 8.35px; border-left-width: 5.01px; } +.EntWatch.Size167 .ItemName { font-size: 30.06px; } +.EntWatch.Size167 .Owner { font-size: 26.72px; margin-left: 13.36px; } +.EntWatch.Size167 .Status { margin-left: 20.04px; } +.EntWatch.Size167 .Status Label { font-size: 26.72px; } +.EntWatch.Size167 .Status .Icon { font-size: 31.73px; margin-right: 8.35px; } +.EntWatch.Size167 .Status .ReloadIcon { width: 36.74px; height: 36.74px; margin-left: 8.35px; margin-right: 0px; } +.EntWatch.Size167 .Ammo { margin-right: 20.04px; } +.EntWatch.Size167 .Overflow { font-size: 23.38px; } +.EntWatch.Size168 .Item { width: 806.4px; padding: 13.44px 20.16px; margin-bottom: 8.4px; border-left-width: 5.04px; } +.EntWatch.Size168 .ItemName { font-size: 30.24px; } +.EntWatch.Size168 .Owner { font-size: 26.88px; margin-left: 13.44px; } +.EntWatch.Size168 .Status { margin-left: 20.16px; } +.EntWatch.Size168 .Status Label { font-size: 26.88px; } +.EntWatch.Size168 .Status .Icon { font-size: 31.92px; margin-right: 8.4px; } +.EntWatch.Size168 .Status .ReloadIcon { width: 36.96px; height: 36.96px; margin-left: 8.4px; margin-right: 0px; } +.EntWatch.Size168 .Ammo { margin-right: 20.16px; } +.EntWatch.Size168 .Overflow { font-size: 23.52px; } +.EntWatch.Size169 .Item { width: 811.2px; padding: 13.52px 20.28px; margin-bottom: 8.45px; border-left-width: 5.07px; } +.EntWatch.Size169 .ItemName { font-size: 30.42px; } +.EntWatch.Size169 .Owner { font-size: 27.04px; margin-left: 13.52px; } +.EntWatch.Size169 .Status { margin-left: 20.28px; } +.EntWatch.Size169 .Status Label { font-size: 27.04px; } +.EntWatch.Size169 .Status .Icon { font-size: 32.11px; margin-right: 8.45px; } +.EntWatch.Size169 .Status .ReloadIcon { width: 37.18px; height: 37.18px; margin-left: 8.45px; margin-right: 0px; } +.EntWatch.Size169 .Ammo { margin-right: 20.28px; } +.EntWatch.Size169 .Overflow { font-size: 23.66px; } +.EntWatch.Size170 .Item { width: 816px; padding: 13.6px 20.4px; margin-bottom: 8.5px; border-left-width: 5.1px; } +.EntWatch.Size170 .ItemName { font-size: 30.6px; } +.EntWatch.Size170 .Owner { font-size: 27.2px; margin-left: 13.6px; } +.EntWatch.Size170 .Status { margin-left: 20.4px; } +.EntWatch.Size170 .Status Label { font-size: 27.2px; } +.EntWatch.Size170 .Status .Icon { font-size: 32.3px; margin-right: 8.5px; } +.EntWatch.Size170 .Status .ReloadIcon { width: 37.4px; height: 37.4px; margin-left: 8.5px; margin-right: 0px; } +.EntWatch.Size170 .Ammo { margin-right: 20.4px; } +.EntWatch.Size170 .Overflow { font-size: 23.8px; } +.EntWatch.Size171 .Item { width: 820.8px; padding: 13.68px 20.52px; margin-bottom: 8.55px; border-left-width: 5.13px; } +.EntWatch.Size171 .ItemName { font-size: 30.78px; } +.EntWatch.Size171 .Owner { font-size: 27.36px; margin-left: 13.68px; } +.EntWatch.Size171 .Status { margin-left: 20.52px; } +.EntWatch.Size171 .Status Label { font-size: 27.36px; } +.EntWatch.Size171 .Status .Icon { font-size: 32.49px; margin-right: 8.55px; } +.EntWatch.Size171 .Status .ReloadIcon { width: 37.62px; height: 37.62px; margin-left: 8.55px; margin-right: 0px; } +.EntWatch.Size171 .Ammo { margin-right: 20.52px; } +.EntWatch.Size171 .Overflow { font-size: 23.94px; } +.EntWatch.Size172 .Item { width: 825.6px; padding: 13.76px 20.64px; margin-bottom: 8.6px; border-left-width: 5.16px; } +.EntWatch.Size172 .ItemName { font-size: 30.96px; } +.EntWatch.Size172 .Owner { font-size: 27.52px; margin-left: 13.76px; } +.EntWatch.Size172 .Status { margin-left: 20.64px; } +.EntWatch.Size172 .Status Label { font-size: 27.52px; } +.EntWatch.Size172 .Status .Icon { font-size: 32.68px; margin-right: 8.6px; } +.EntWatch.Size172 .Status .ReloadIcon { width: 37.84px; height: 37.84px; margin-left: 8.6px; margin-right: 0px; } +.EntWatch.Size172 .Ammo { margin-right: 20.64px; } +.EntWatch.Size172 .Overflow { font-size: 24.08px; } +.EntWatch.Size173 .Item { width: 830.4px; padding: 13.84px 20.76px; margin-bottom: 8.65px; border-left-width: 5.19px; } +.EntWatch.Size173 .ItemName { font-size: 31.14px; } +.EntWatch.Size173 .Owner { font-size: 27.68px; margin-left: 13.84px; } +.EntWatch.Size173 .Status { margin-left: 20.76px; } +.EntWatch.Size173 .Status Label { font-size: 27.68px; } +.EntWatch.Size173 .Status .Icon { font-size: 32.87px; margin-right: 8.65px; } +.EntWatch.Size173 .Status .ReloadIcon { width: 38.06px; height: 38.06px; margin-left: 8.65px; margin-right: 0px; } +.EntWatch.Size173 .Ammo { margin-right: 20.76px; } +.EntWatch.Size173 .Overflow { font-size: 24.22px; } +.EntWatch.Size174 .Item { width: 835.2px; padding: 13.92px 20.88px; margin-bottom: 8.7px; border-left-width: 5.22px; } +.EntWatch.Size174 .ItemName { font-size: 31.32px; } +.EntWatch.Size174 .Owner { font-size: 27.84px; margin-left: 13.92px; } +.EntWatch.Size174 .Status { margin-left: 20.88px; } +.EntWatch.Size174 .Status Label { font-size: 27.84px; } +.EntWatch.Size174 .Status .Icon { font-size: 33.06px; margin-right: 8.7px; } +.EntWatch.Size174 .Status .ReloadIcon { width: 38.28px; height: 38.28px; margin-left: 8.7px; margin-right: 0px; } +.EntWatch.Size174 .Ammo { margin-right: 20.88px; } +.EntWatch.Size174 .Overflow { font-size: 24.36px; } +.EntWatch.Size175 .Item { width: 840px; padding: 14px 21px; margin-bottom: 8.75px; border-left-width: 5.25px; } +.EntWatch.Size175 .ItemName { font-size: 31.5px; } +.EntWatch.Size175 .Owner { font-size: 28px; margin-left: 14px; } +.EntWatch.Size175 .Status { margin-left: 21px; } +.EntWatch.Size175 .Status Label { font-size: 28px; } +.EntWatch.Size175 .Status .Icon { font-size: 33.25px; margin-right: 8.75px; } +.EntWatch.Size175 .Status .ReloadIcon { width: 38.5px; height: 38.5px; margin-left: 8.75px; margin-right: 0px; } +.EntWatch.Size175 .Ammo { margin-right: 21px; } +.EntWatch.Size175 .Overflow { font-size: 24.5px; } +.EntWatch.Size176 .Item { width: 844.8px; padding: 14.08px 21.12px; margin-bottom: 8.8px; border-left-width: 5.28px; } +.EntWatch.Size176 .ItemName { font-size: 31.68px; } +.EntWatch.Size176 .Owner { font-size: 28.16px; margin-left: 14.08px; } +.EntWatch.Size176 .Status { margin-left: 21.12px; } +.EntWatch.Size176 .Status Label { font-size: 28.16px; } +.EntWatch.Size176 .Status .Icon { font-size: 33.44px; margin-right: 8.8px; } +.EntWatch.Size176 .Status .ReloadIcon { width: 38.72px; height: 38.72px; margin-left: 8.8px; margin-right: 0px; } +.EntWatch.Size176 .Ammo { margin-right: 21.12px; } +.EntWatch.Size176 .Overflow { font-size: 24.64px; } +.EntWatch.Size177 .Item { width: 849.6px; padding: 14.16px 21.24px; margin-bottom: 8.85px; border-left-width: 5.31px; } +.EntWatch.Size177 .ItemName { font-size: 31.86px; } +.EntWatch.Size177 .Owner { font-size: 28.32px; margin-left: 14.16px; } +.EntWatch.Size177 .Status { margin-left: 21.24px; } +.EntWatch.Size177 .Status Label { font-size: 28.32px; } +.EntWatch.Size177 .Status .Icon { font-size: 33.63px; margin-right: 8.85px; } +.EntWatch.Size177 .Status .ReloadIcon { width: 38.94px; height: 38.94px; margin-left: 8.85px; margin-right: 0px; } +.EntWatch.Size177 .Ammo { margin-right: 21.24px; } +.EntWatch.Size177 .Overflow { font-size: 24.78px; } +.EntWatch.Size178 .Item { width: 854.4px; padding: 14.24px 21.36px; margin-bottom: 8.9px; border-left-width: 5.34px; } +.EntWatch.Size178 .ItemName { font-size: 32.04px; } +.EntWatch.Size178 .Owner { font-size: 28.48px; margin-left: 14.24px; } +.EntWatch.Size178 .Status { margin-left: 21.36px; } +.EntWatch.Size178 .Status Label { font-size: 28.48px; } +.EntWatch.Size178 .Status .Icon { font-size: 33.82px; margin-right: 8.9px; } +.EntWatch.Size178 .Status .ReloadIcon { width: 39.16px; height: 39.16px; margin-left: 8.9px; margin-right: 0px; } +.EntWatch.Size178 .Ammo { margin-right: 21.36px; } +.EntWatch.Size178 .Overflow { font-size: 24.92px; } +.EntWatch.Size179 .Item { width: 859.2px; padding: 14.32px 21.48px; margin-bottom: 8.95px; border-left-width: 5.37px; } +.EntWatch.Size179 .ItemName { font-size: 32.22px; } +.EntWatch.Size179 .Owner { font-size: 28.64px; margin-left: 14.32px; } +.EntWatch.Size179 .Status { margin-left: 21.48px; } +.EntWatch.Size179 .Status Label { font-size: 28.64px; } +.EntWatch.Size179 .Status .Icon { font-size: 34.01px; margin-right: 8.95px; } +.EntWatch.Size179 .Status .ReloadIcon { width: 39.38px; height: 39.38px; margin-left: 8.95px; margin-right: 0px; } +.EntWatch.Size179 .Ammo { margin-right: 21.48px; } +.EntWatch.Size179 .Overflow { font-size: 25.06px; } +.EntWatch.Size180 .Item { width: 864px; padding: 14.4px 21.6px; margin-bottom: 9px; border-left-width: 5.4px; } +.EntWatch.Size180 .ItemName { font-size: 32.4px; } +.EntWatch.Size180 .Owner { font-size: 28.8px; margin-left: 14.4px; } +.EntWatch.Size180 .Status { margin-left: 21.6px; } +.EntWatch.Size180 .Status Label { font-size: 28.8px; } +.EntWatch.Size180 .Status .Icon { font-size: 34.2px; margin-right: 9px; } +.EntWatch.Size180 .Status .ReloadIcon { width: 39.6px; height: 39.6px; margin-left: 9px; margin-right: 0px; } +.EntWatch.Size180 .Ammo { margin-right: 21.6px; } +.EntWatch.Size180 .Overflow { font-size: 25.2px; } +.EntWatch.Size181 .Item { width: 868.8px; padding: 14.48px 21.72px; margin-bottom: 9.05px; border-left-width: 5.43px; } +.EntWatch.Size181 .ItemName { font-size: 32.58px; } +.EntWatch.Size181 .Owner { font-size: 28.96px; margin-left: 14.48px; } +.EntWatch.Size181 .Status { margin-left: 21.72px; } +.EntWatch.Size181 .Status Label { font-size: 28.96px; } +.EntWatch.Size181 .Status .Icon { font-size: 34.39px; margin-right: 9.05px; } +.EntWatch.Size181 .Status .ReloadIcon { width: 39.82px; height: 39.82px; margin-left: 9.05px; margin-right: 0px; } +.EntWatch.Size181 .Ammo { margin-right: 21.72px; } +.EntWatch.Size181 .Overflow { font-size: 25.34px; } +.EntWatch.Size182 .Item { width: 873.6px; padding: 14.56px 21.84px; margin-bottom: 9.1px; border-left-width: 5.46px; } +.EntWatch.Size182 .ItemName { font-size: 32.76px; } +.EntWatch.Size182 .Owner { font-size: 29.12px; margin-left: 14.56px; } +.EntWatch.Size182 .Status { margin-left: 21.84px; } +.EntWatch.Size182 .Status Label { font-size: 29.12px; } +.EntWatch.Size182 .Status .Icon { font-size: 34.58px; margin-right: 9.1px; } +.EntWatch.Size182 .Status .ReloadIcon { width: 40.04px; height: 40.04px; margin-left: 9.1px; margin-right: 0px; } +.EntWatch.Size182 .Ammo { margin-right: 21.84px; } +.EntWatch.Size182 .Overflow { font-size: 25.48px; } +.EntWatch.Size183 .Item { width: 878.4px; padding: 14.64px 21.96px; margin-bottom: 9.15px; border-left-width: 5.49px; } +.EntWatch.Size183 .ItemName { font-size: 32.94px; } +.EntWatch.Size183 .Owner { font-size: 29.28px; margin-left: 14.64px; } +.EntWatch.Size183 .Status { margin-left: 21.96px; } +.EntWatch.Size183 .Status Label { font-size: 29.28px; } +.EntWatch.Size183 .Status .Icon { font-size: 34.77px; margin-right: 9.15px; } +.EntWatch.Size183 .Status .ReloadIcon { width: 40.26px; height: 40.26px; margin-left: 9.15px; margin-right: 0px; } +.EntWatch.Size183 .Ammo { margin-right: 21.96px; } +.EntWatch.Size183 .Overflow { font-size: 25.62px; } +.EntWatch.Size184 .Item { width: 883.2px; padding: 14.72px 22.08px; margin-bottom: 9.2px; border-left-width: 5.52px; } +.EntWatch.Size184 .ItemName { font-size: 33.12px; } +.EntWatch.Size184 .Owner { font-size: 29.44px; margin-left: 14.72px; } +.EntWatch.Size184 .Status { margin-left: 22.08px; } +.EntWatch.Size184 .Status Label { font-size: 29.44px; } +.EntWatch.Size184 .Status .Icon { font-size: 34.96px; margin-right: 9.2px; } +.EntWatch.Size184 .Status .ReloadIcon { width: 40.48px; height: 40.48px; margin-left: 9.2px; margin-right: 0px; } +.EntWatch.Size184 .Ammo { margin-right: 22.08px; } +.EntWatch.Size184 .Overflow { font-size: 25.76px; } +.EntWatch.Size185 .Item { width: 888px; padding: 14.8px 22.2px; margin-bottom: 9.25px; border-left-width: 5.55px; } +.EntWatch.Size185 .ItemName { font-size: 33.3px; } +.EntWatch.Size185 .Owner { font-size: 29.6px; margin-left: 14.8px; } +.EntWatch.Size185 .Status { margin-left: 22.2px; } +.EntWatch.Size185 .Status Label { font-size: 29.6px; } +.EntWatch.Size185 .Status .Icon { font-size: 35.15px; margin-right: 9.25px; } +.EntWatch.Size185 .Status .ReloadIcon { width: 40.7px; height: 40.7px; margin-left: 9.25px; margin-right: 0px; } +.EntWatch.Size185 .Ammo { margin-right: 22.2px; } +.EntWatch.Size185 .Overflow { font-size: 25.9px; } +.EntWatch.Size186 .Item { width: 892.8px; padding: 14.88px 22.32px; margin-bottom: 9.3px; border-left-width: 5.58px; } +.EntWatch.Size186 .ItemName { font-size: 33.48px; } +.EntWatch.Size186 .Owner { font-size: 29.76px; margin-left: 14.88px; } +.EntWatch.Size186 .Status { margin-left: 22.32px; } +.EntWatch.Size186 .Status Label { font-size: 29.76px; } +.EntWatch.Size186 .Status .Icon { font-size: 35.34px; margin-right: 9.3px; } +.EntWatch.Size186 .Status .ReloadIcon { width: 40.92px; height: 40.92px; margin-left: 9.3px; margin-right: 0px; } +.EntWatch.Size186 .Ammo { margin-right: 22.32px; } +.EntWatch.Size186 .Overflow { font-size: 26.04px; } +.EntWatch.Size187 .Item { width: 897.6px; padding: 14.96px 22.44px; margin-bottom: 9.35px; border-left-width: 5.61px; } +.EntWatch.Size187 .ItemName { font-size: 33.66px; } +.EntWatch.Size187 .Owner { font-size: 29.92px; margin-left: 14.96px; } +.EntWatch.Size187 .Status { margin-left: 22.44px; } +.EntWatch.Size187 .Status Label { font-size: 29.92px; } +.EntWatch.Size187 .Status .Icon { font-size: 35.53px; margin-right: 9.35px; } +.EntWatch.Size187 .Status .ReloadIcon { width: 41.14px; height: 41.14px; margin-left: 9.35px; margin-right: 0px; } +.EntWatch.Size187 .Ammo { margin-right: 22.44px; } +.EntWatch.Size187 .Overflow { font-size: 26.18px; } +.EntWatch.Size188 .Item { width: 902.4px; padding: 15.04px 22.56px; margin-bottom: 9.4px; border-left-width: 5.64px; } +.EntWatch.Size188 .ItemName { font-size: 33.84px; } +.EntWatch.Size188 .Owner { font-size: 30.08px; margin-left: 15.04px; } +.EntWatch.Size188 .Status { margin-left: 22.56px; } +.EntWatch.Size188 .Status Label { font-size: 30.08px; } +.EntWatch.Size188 .Status .Icon { font-size: 35.72px; margin-right: 9.4px; } +.EntWatch.Size188 .Status .ReloadIcon { width: 41.36px; height: 41.36px; margin-left: 9.4px; margin-right: 0px; } +.EntWatch.Size188 .Ammo { margin-right: 22.56px; } +.EntWatch.Size188 .Overflow { font-size: 26.32px; } +.EntWatch.Size189 .Item { width: 907.2px; padding: 15.12px 22.68px; margin-bottom: 9.45px; border-left-width: 5.67px; } +.EntWatch.Size189 .ItemName { font-size: 34.02px; } +.EntWatch.Size189 .Owner { font-size: 30.24px; margin-left: 15.12px; } +.EntWatch.Size189 .Status { margin-left: 22.68px; } +.EntWatch.Size189 .Status Label { font-size: 30.24px; } +.EntWatch.Size189 .Status .Icon { font-size: 35.91px; margin-right: 9.45px; } +.EntWatch.Size189 .Status .ReloadIcon { width: 41.58px; height: 41.58px; margin-left: 9.45px; margin-right: 0px; } +.EntWatch.Size189 .Ammo { margin-right: 22.68px; } +.EntWatch.Size189 .Overflow { font-size: 26.46px; } +.EntWatch.Size190 .Item { width: 912px; padding: 15.2px 22.8px; margin-bottom: 9.5px; border-left-width: 5.7px; } +.EntWatch.Size190 .ItemName { font-size: 34.2px; } +.EntWatch.Size190 .Owner { font-size: 30.4px; margin-left: 15.2px; } +.EntWatch.Size190 .Status { margin-left: 22.8px; } +.EntWatch.Size190 .Status Label { font-size: 30.4px; } +.EntWatch.Size190 .Status .Icon { font-size: 36.1px; margin-right: 9.5px; } +.EntWatch.Size190 .Status .ReloadIcon { width: 41.8px; height: 41.8px; margin-left: 9.5px; margin-right: 0px; } +.EntWatch.Size190 .Ammo { margin-right: 22.8px; } +.EntWatch.Size190 .Overflow { font-size: 26.6px; } +.EntWatch.Size191 .Item { width: 916.8px; padding: 15.28px 22.92px; margin-bottom: 9.55px; border-left-width: 5.73px; } +.EntWatch.Size191 .ItemName { font-size: 34.38px; } +.EntWatch.Size191 .Owner { font-size: 30.56px; margin-left: 15.28px; } +.EntWatch.Size191 .Status { margin-left: 22.92px; } +.EntWatch.Size191 .Status Label { font-size: 30.56px; } +.EntWatch.Size191 .Status .Icon { font-size: 36.29px; margin-right: 9.55px; } +.EntWatch.Size191 .Status .ReloadIcon { width: 42.02px; height: 42.02px; margin-left: 9.55px; margin-right: 0px; } +.EntWatch.Size191 .Ammo { margin-right: 22.92px; } +.EntWatch.Size191 .Overflow { font-size: 26.74px; } +.EntWatch.Size192 .Item { width: 921.6px; padding: 15.36px 23.04px; margin-bottom: 9.6px; border-left-width: 5.76px; } +.EntWatch.Size192 .ItemName { font-size: 34.56px; } +.EntWatch.Size192 .Owner { font-size: 30.72px; margin-left: 15.36px; } +.EntWatch.Size192 .Status { margin-left: 23.04px; } +.EntWatch.Size192 .Status Label { font-size: 30.72px; } +.EntWatch.Size192 .Status .Icon { font-size: 36.48px; margin-right: 9.6px; } +.EntWatch.Size192 .Status .ReloadIcon { width: 42.24px; height: 42.24px; margin-left: 9.6px; margin-right: 0px; } +.EntWatch.Size192 .Ammo { margin-right: 23.04px; } +.EntWatch.Size192 .Overflow { font-size: 26.88px; } +.EntWatch.Size193 .Item { width: 926.4px; padding: 15.44px 23.16px; margin-bottom: 9.65px; border-left-width: 5.79px; } +.EntWatch.Size193 .ItemName { font-size: 34.74px; } +.EntWatch.Size193 .Owner { font-size: 30.88px; margin-left: 15.44px; } +.EntWatch.Size193 .Status { margin-left: 23.16px; } +.EntWatch.Size193 .Status Label { font-size: 30.88px; } +.EntWatch.Size193 .Status .Icon { font-size: 36.67px; margin-right: 9.65px; } +.EntWatch.Size193 .Status .ReloadIcon { width: 42.46px; height: 42.46px; margin-left: 9.65px; margin-right: 0px; } +.EntWatch.Size193 .Ammo { margin-right: 23.16px; } +.EntWatch.Size193 .Overflow { font-size: 27.02px; } +.EntWatch.Size194 .Item { width: 931.2px; padding: 15.52px 23.28px; margin-bottom: 9.7px; border-left-width: 5.82px; } +.EntWatch.Size194 .ItemName { font-size: 34.92px; } +.EntWatch.Size194 .Owner { font-size: 31.04px; margin-left: 15.52px; } +.EntWatch.Size194 .Status { margin-left: 23.28px; } +.EntWatch.Size194 .Status Label { font-size: 31.04px; } +.EntWatch.Size194 .Status .Icon { font-size: 36.86px; margin-right: 9.7px; } +.EntWatch.Size194 .Status .ReloadIcon { width: 42.68px; height: 42.68px; margin-left: 9.7px; margin-right: 0px; } +.EntWatch.Size194 .Ammo { margin-right: 23.28px; } +.EntWatch.Size194 .Overflow { font-size: 27.16px; } +.EntWatch.Size195 .Item { width: 936px; padding: 15.6px 23.4px; margin-bottom: 9.75px; border-left-width: 5.85px; } +.EntWatch.Size195 .ItemName { font-size: 35.1px; } +.EntWatch.Size195 .Owner { font-size: 31.2px; margin-left: 15.6px; } +.EntWatch.Size195 .Status { margin-left: 23.4px; } +.EntWatch.Size195 .Status Label { font-size: 31.2px; } +.EntWatch.Size195 .Status .Icon { font-size: 37.05px; margin-right: 9.75px; } +.EntWatch.Size195 .Status .ReloadIcon { width: 42.9px; height: 42.9px; margin-left: 9.75px; margin-right: 0px; } +.EntWatch.Size195 .Ammo { margin-right: 23.4px; } +.EntWatch.Size195 .Overflow { font-size: 27.3px; } +.EntWatch.Size196 .Item { width: 940.8px; padding: 15.68px 23.52px; margin-bottom: 9.8px; border-left-width: 5.88px; } +.EntWatch.Size196 .ItemName { font-size: 35.28px; } +.EntWatch.Size196 .Owner { font-size: 31.36px; margin-left: 15.68px; } +.EntWatch.Size196 .Status { margin-left: 23.52px; } +.EntWatch.Size196 .Status Label { font-size: 31.36px; } +.EntWatch.Size196 .Status .Icon { font-size: 37.24px; margin-right: 9.8px; } +.EntWatch.Size196 .Status .ReloadIcon { width: 43.12px; height: 43.12px; margin-left: 9.8px; margin-right: 0px; } +.EntWatch.Size196 .Ammo { margin-right: 23.52px; } +.EntWatch.Size196 .Overflow { font-size: 27.44px; } +.EntWatch.Size197 .Item { width: 945.6px; padding: 15.76px 23.64px; margin-bottom: 9.85px; border-left-width: 5.91px; } +.EntWatch.Size197 .ItemName { font-size: 35.46px; } +.EntWatch.Size197 .Owner { font-size: 31.52px; margin-left: 15.76px; } +.EntWatch.Size197 .Status { margin-left: 23.64px; } +.EntWatch.Size197 .Status Label { font-size: 31.52px; } +.EntWatch.Size197 .Status .Icon { font-size: 37.43px; margin-right: 9.85px; } +.EntWatch.Size197 .Status .ReloadIcon { width: 43.34px; height: 43.34px; margin-left: 9.85px; margin-right: 0px; } +.EntWatch.Size197 .Ammo { margin-right: 23.64px; } +.EntWatch.Size197 .Overflow { font-size: 27.58px; } +.EntWatch.Size198 .Item { width: 950.4px; padding: 15.84px 23.76px; margin-bottom: 9.9px; border-left-width: 5.94px; } +.EntWatch.Size198 .ItemName { font-size: 35.64px; } +.EntWatch.Size198 .Owner { font-size: 31.68px; margin-left: 15.84px; } +.EntWatch.Size198 .Status { margin-left: 23.76px; } +.EntWatch.Size198 .Status Label { font-size: 31.68px; } +.EntWatch.Size198 .Status .Icon { font-size: 37.62px; margin-right: 9.9px; } +.EntWatch.Size198 .Status .ReloadIcon { width: 43.56px; height: 43.56px; margin-left: 9.9px; margin-right: 0px; } +.EntWatch.Size198 .Ammo { margin-right: 23.76px; } +.EntWatch.Size198 .Overflow { font-size: 27.72px; } +.EntWatch.Size199 .Item { width: 955.2px; padding: 15.92px 23.88px; margin-bottom: 9.95px; border-left-width: 5.97px; } +.EntWatch.Size199 .ItemName { font-size: 35.82px; } +.EntWatch.Size199 .Owner { font-size: 31.84px; margin-left: 15.92px; } +.EntWatch.Size199 .Status { margin-left: 23.88px; } +.EntWatch.Size199 .Status Label { font-size: 31.84px; } +.EntWatch.Size199 .Status .Icon { font-size: 37.81px; margin-right: 9.95px; } +.EntWatch.Size199 .Status .ReloadIcon { width: 43.78px; height: 43.78px; margin-left: 9.95px; margin-right: 0px; } +.EntWatch.Size199 .Ammo { margin-right: 23.88px; } +.EntWatch.Size199 .Overflow { font-size: 27.86px; } +.EntWatch.Size200 .Item { width: 960px; padding: 16px 24px; margin-bottom: 10px; border-left-width: 6px; } +.EntWatch.Size200 .ItemName { font-size: 36px; } +.EntWatch.Size200 .Owner { font-size: 32px; margin-left: 16px; } +.EntWatch.Size200 .Status { margin-left: 24px; } +.EntWatch.Size200 .Status Label { font-size: 32px; } +.EntWatch.Size200 .Status .Icon { font-size: 38px; margin-right: 10px; } +.EntWatch.Size200 .Status .ReloadIcon { width: 44px; height: 44px; margin-left: 10px; margin-right: 0px; } +.EntWatch.Size200 .Ammo { margin-right: 24px; } +.EntWatch.Size200 .Overflow { font-size: 28px; } diff --git a/src/entwatch.cpp b/src/entwatch.cpp index 469a49f1..6e61dccb 100644 --- a/src/entwatch.cpp +++ b/src/entwatch.cpp @@ -2568,7 +2568,7 @@ CON_COMMAND_CHAT(hud, "- Toggle EntWatch HUD") ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "EntWatch HUD\x04 enabled\x10 (Item names only)."); } -CON_COMMAND_CHAT(hudpos, " - Sets the position of the EntWatch hud.") +CON_COMMAND_CHAT(hudpos, "[x y|reset] - Position the active EntWatch HUD style") { if (!g_cvarEnableEntWatch.Get()) return; @@ -2592,15 +2592,30 @@ CON_COMMAND_CHAT(hudpos, " - Sets the position of the EntWatch hud.") return; } - if (args.ArgC() < 3) + if (zpPlayer->GetEntwatchHudStyle() == 1) + { + EW_ConfigurePanoramaHudPos(player, args); + return; + } + if (args.ArgC() == 2 && !V_stricmp(args[1], "reset")) + { + zpPlayer->SetEntwatchHudPos(EW_HUDPOS_X_DEFAULT, EW_HUDPOS_Y_DEFAULT); + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "World-text HUD position reset."); + return; + } + if (args.ArgC() != 3) { ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Usage: !hudpos "); ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Current hudpos: %.1fx %.1fy", zpPlayer->GetEntwatchHudX(), zpPlayer->GetEntwatchHudY()); return; } - float x = std::atof(args[1]); - float y = std::atof(args[2]); + float x, y; + if (!EW_ParseHudFloat(args[1], x) || !EW_ParseHudFloat(args[2], y) || std::abs(x) > 1000.0f || std::abs(y) > 1000.0f) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "World-text position must contain two numbers between -1000 and 1000."); + return; + } zpPlayer->SetEntwatchHudPos(x, y); ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Set hudpos to: %.1fx %.1fy", x, y); @@ -2658,7 +2673,7 @@ CON_COMMAND_CHAT(hudcolor, " [a] - Set color (and transparency) of th zpPlayer->SetEntwatchHudColor(newColor); } -CON_COMMAND_CHAT(hudsize, " - Set font size of the EntWatch hud") +CON_COMMAND_CHAT(hudsize, "[size|reset] - Size the active HUD: world-text font size or Panorama percentage") { if (!g_cvarEnableEntWatch.Get()) return; @@ -2682,7 +2697,18 @@ CON_COMMAND_CHAT(hudsize, " - Set font size of the EntWatch hud") return; } - if (args.ArgC() < 2) + if (zpPlayer->GetEntwatchHudStyle() == 1) + { + EW_ConfigurePanoramaHudSize(player, args); + return; + } + if (args.ArgC() == 2 && !V_stricmp(args[1], "reset")) + { + zpPlayer->SetEntwatchHudSize(EW_HUDSIZE_DEFAULT); + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "World-text HUD font size reset."); + return; + } + if (args.ArgC() != 2) { ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Usage: !hudsize "); float flSize = zpPlayer->GetEntwatchHudSize(); @@ -2690,7 +2716,12 @@ CON_COMMAND_CHAT(hudsize, " - Set font size of the EntWatch hud") return; } - float size = std::atof(args[1]); + float size; + if (!EW_ParseHudFloat(args[1], size)) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "HUD size must be a finite number."); + return; + } if (size < 20.0f) // size 20 with 0.005 units per pixel is small size = 20.0f; else if (size > 255.0f) // game has a max of 255 diff --git a/src/entwatch.h b/src/entwatch.h index 1526bb2f..1f1d29a6 100644 --- a/src/entwatch.h +++ b/src/entwatch.h @@ -37,6 +37,10 @@ extern CConVar g_cvarEnableEntwatchHud; #define EW_PREFIX " \4[EntWatch]\1 " #define EW_PREF_HUD_MODE "entwatch_hud" +#define EW_PREF_HUD_STYLE "entwatch_hud_style" +#define EW_PREF_PANORAMA_X "entwatch_panorama_hudpos_x" +#define EW_PREF_PANORAMA_Y "entwatch_panorama_hudpos_y" +#define EW_PREF_PANORAMA_SIZE "entwatch_panorama_hudsize" #define EW_PREF_HUDPOS_X "entwatch_hudpos_x" #define EW_PREF_HUDPOS_Y "entwatch_hudpos_y" #define EW_PREF_HUDCOLOR "entwatch_hudcolor" @@ -317,4 +321,4 @@ void EW_PlayerDeathPre(CCSPlayerController* pController); void EW_PlayerDisconnect(int slot); void EW_FireOutput(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, float flDelay); int GetTemplateSuffixNumber(const char* szName); -float EW_UpdateHud(); \ No newline at end of file +float EW_UpdateHud(); diff --git a/src/entwatch_hud.cpp b/src/entwatch_hud.cpp index 369c3601..4eb49f6f 100644 --- a/src/entwatch_hud.cpp +++ b/src/entwatch_hud.cpp @@ -24,8 +24,12 @@ #include "entwatch.h" #include "filesystem.h" #include "playermanager.h" +#include "user_preferences.h" #include "utils/entity.h" #include +#include +#include +#include CConVar g_cvarEntwatchHudStyle("entwatch_hud_style", FCVAR_NONE, "Default HUD renderer: 0 = world text, 1 = Panorama", 1, true, 0, true, 1); CConVar g_cvarEntwatchPanoramaDebug("cs2f_entwatch_panorama_debug", FCVAR_NONE, "Log EntWatch HUD creation and Panorama resource diagnostics", false); @@ -36,6 +40,9 @@ namespace CHandle s_layout; std::array s_previous; std::array s_initialized{}; + std::array s_positionX{}; + std::array s_positionY{}; + std::array s_size{}; std::array, MAXPLAYERS> s_rows; std::array s_mode{}; double s_flNextCreateAttempt = 0.0; @@ -77,6 +84,10 @@ namespace if (slot < 0 || slot >= MAXPLAYERS) return false; std::string signature = visible ? "on" : "off"; signature += std::to_string(player->GetEntwatchHudMode()); + const int x = player->GetEntwatchPanoramaHudX(); + const int y = player->GetEntwatchPanoramaHudY(); + const int size = player->GetEntwatchPanoramaHudSize(); + signature += ":" + std::to_string(x) + ":" + std::to_string(y) + ":" + std::to_string(size) + ":"; if (visible) { signature += std::to_string(rows.size()) + ":"; @@ -85,6 +96,25 @@ namespace signature += std::to_string(value.size()) + ":" + value; } if (s_initialized[slot] && s_previous[slot] == signature) return true; + // Remove the previous per-player position before applying the new CSS classes. + if (s_initialized[slot]) + { + if (s_positionX[slot] != x) + layout->SetHasClass("entwatch", "PosX" + std::to_string(s_positionX[slot]), false, slot); + if (s_positionY[slot] != y) + layout->SetHasClass("entwatch", "PosY" + std::to_string(s_positionY[slot]), false, slot); + if (s_size[slot] != size) + layout->SetHasClass("entwatch", "Size" + std::to_string(s_size[slot]), false, slot); + } + if (!s_initialized[slot] || s_positionX[slot] != x) + layout->SetHasClass("entwatch", "PosX" + std::to_string(x), true, slot); + if (!s_initialized[slot] || s_positionY[slot] != y) + layout->SetHasClass("entwatch", "PosY" + std::to_string(y), true, slot); + if (!s_initialized[slot] || s_size[slot] != size) + layout->SetHasClass("entwatch", "Size" + std::to_string(size), true, slot); + s_positionX[slot] = x; + s_positionY[slot] = y; + s_size[slot] = size; s_initialized[slot] = true; s_previous[slot] = signature; layout->SetHasClass("entwatch", "Hidden", !visible, slot); @@ -117,6 +147,106 @@ namespace int EW_DefaultHudStyle() { return g_cvarEntwatchHudStyle.Get(); } +bool EW_ParseHudFloat(const char* pszValue, float& flValue) +{ + if (!pszValue || !*pszValue) + return false; + char* pszEnd; + errno = 0; + flValue = std::strtof(pszValue, &pszEnd); + return pszEnd != pszValue && !*pszEnd && errno != ERANGE && std::isfinite(flValue); +} + +void ZEPlayer::SetEntwatchPanoramaHudPos(int x, int y) +{ + m_iEntwatchPanoramaX = x >= 0 && x <= 100 ? x : EW_PANORAMA_X_DEFAULT; + m_iEntwatchPanoramaY = y >= 0 && y <= 100 ? y : EW_PANORAMA_Y_DEFAULT; + g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_PANORAMA_X, m_iEntwatchPanoramaX); + g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_PANORAMA_Y, m_iEntwatchPanoramaY); +} + +void EW_ConfigurePanoramaHudPos(CCSPlayerController* player, const CCommand& args) +{ + if (!player) return; + auto zePlayer = player->GetZEPlayer(); + if (!zePlayer) return; + int x = zePlayer->GetEntwatchPanoramaHudX(); + int y = zePlayer->GetEntwatchPanoramaHudY(); + if (args.ArgC() == 2 && !V_stricmp(args[1], "reset")) + { + x = EW_PANORAMA_X_DEFAULT; + y = EW_PANORAMA_Y_DEFAULT; + } + else if (args.ArgC() == 3) + { + char* endX; + char* endY; + const long parsedX = std::strtol(args[1], &endX, 10); + const long parsedY = std::strtol(args[2], &endY, 10); + if (!*args[1] || !*args[2] || *endX || *endY || parsedX < 0 || parsedX > 100 || parsedY < 0 || parsedY > 100) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Use whole screen percentages from 0 to 100: !hudpos "); + return; + } + x = static_cast(parsedX); + y = static_cast(parsedY); + } + else if (args.ArgC() != 1) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Usage: !hudpos [x y|reset]"); + return; + } + if (args.ArgC() > 1) + { + zePlayer->SetEntwatchPanoramaHudPos(x, y); + EW_UpdateHud(); + } + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Panorama HUD position: %d%% from left, %d%% from top.", x, y); +} + +CON_COMMAND_CHAT(hudpos2, "[x y|reset] - Alias to configure Panorama position regardless of active style") +{ + EW_ConfigurePanoramaHudPos(player, args); +} + +void ZEPlayer::SetEntwatchPanoramaHudSize(int size) +{ + m_iEntwatchPanoramaSize = size >= EW_PANORAMA_SIZE_MIN && size <= EW_PANORAMA_SIZE_MAX ? size : EW_PANORAMA_SIZE_DEFAULT; + g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_PANORAMA_SIZE, m_iEntwatchPanoramaSize); +} + +void EW_ConfigurePanoramaHudSize(CCSPlayerController* player, const CCommand& args) +{ + if (!player) return; + auto zePlayer = player->GetZEPlayer(); + if (!zePlayer) return; + int size = zePlayer->GetEntwatchPanoramaHudSize(); + if (args.ArgC() == 2) + { + if (!V_stricmp(args[1], "reset")) + size = EW_PANORAMA_SIZE_DEFAULT; + else + { + char* end; + const long parsed = std::strtol(args[1], &end, 10); + if (!*args[1] || *end || parsed < EW_PANORAMA_SIZE_MIN || parsed > EW_PANORAMA_SIZE_MAX) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Panorama size must be a whole percentage from 50 to 200. Default: 100."); + return; + } + size = static_cast(parsed); + } + zePlayer->SetEntwatchPanoramaHudSize(size); + EW_UpdateHud(); + } + else if (args.ArgC() != 1) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Usage: !hudsize [50-200|reset]"); + return; + } + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Panorama HUD size: %d%%.", size); +} + void EW_DestroyHud() { if (auto layout = s_layout.Get()) layout->Remove(); @@ -153,3 +283,37 @@ void EW_RenderHud(ZEPlayer* player, const std::vector& rows) const bool bPanoramaReady = RenderPanorama(player, rows, visible && panorama); EW_RenderWorldText(player, rows, visible && (!panorama || !bPanoramaReady)); } + +CON_COMMAND_CHAT(hudstyle, "[old|new|default] - Switch EntWatch world-text/Panorama renderer") +{ + if (!player) + { + ClientPrint(player, HUD_PRINTCONSOLE, "Use entwatch_hud_style 0/1 for the server default."); + return; + } + auto zePlayer = player->GetZEPlayer(); + if (!zePlayer) return; + int style = zePlayer->GetEntwatchHudStyle() == 0 ? 1 : 0; + if (args.ArgC() > 2) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Usage: !hudstyle [old|new|default]"); + return; + } + if (args.ArgC() > 1) + { + if (!V_stricmp(args[1], "old")) + style = 0; + else if (!V_stricmp(args[1], "new")) + style = 1; + else if (!V_stricmp(args[1], "default")) + style = -1; + else + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Usage: !hudstyle [old|new|default]"); + return; + } + } + zePlayer->SetEntwatchHudStyle(style); + EW_UpdateHud(); + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "HUD renderer: %s. Use !hud to toggle visibility.", zePlayer->GetEntwatchHudStyle() ? "Panorama" : "world text"); +} diff --git a/src/entwatch_hud.h b/src/entwatch_hud.h index 3b089502..85f713c0 100644 --- a/src/entwatch_hud.h +++ b/src/entwatch_hud.h @@ -26,6 +26,12 @@ class ZEPlayer; class CCSPlayerController; class CCommand; +constexpr int EW_PANORAMA_X_DEFAULT = 2; +constexpr int EW_PANORAMA_Y_DEFAULT = 15; +constexpr int EW_PANORAMA_SIZE_DEFAULT = 100; +constexpr int EW_PANORAMA_SIZE_MIN = 50; +constexpr int EW_PANORAMA_SIZE_MAX = 200; + struct EntwatchHudRow { std::string name; @@ -43,3 +49,6 @@ void EW_RenderWorldText(ZEPlayer* player, const std::vector& row void EW_ForgetHudPlayer(int slot); void EW_DestroyHud(); int EW_DefaultHudStyle(); +bool EW_ParseHudFloat(const char* pszValue, float& flValue); +void EW_ConfigurePanoramaHudPos(CCSPlayerController* player, const CCommand& args); +void EW_ConfigurePanoramaHudSize(CCSPlayerController* player, const CCommand& args); diff --git a/src/playermanager.cpp b/src/playermanager.cpp index a8ad2c42..ef228a0b 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -39,6 +39,7 @@ #include "votemanager.h" #include "zombiereborn.h" #include <../cs2fixes.h> +#include #include "tier0/memdbgon.h" @@ -755,7 +756,14 @@ void ZEPlayer::CreateEntwatchHud() int ZEPlayer::GetEntwatchHudStyle() { - return EW_DefaultHudStyle(); + return m_iEntwatchHudStyle < 0 ? EW_DefaultHudStyle() : m_iEntwatchHudStyle; +} + +void ZEPlayer::SetEntwatchHudStyle(int style) +{ + m_iEntwatchHudStyle = style >= -1 && style <= 1 ? style : -1; + g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_HUD_STYLE, m_iEntwatchHudStyle); + CreateEntwatchHud(); } int ZEPlayer::GetEntwatchHudMode() @@ -767,7 +775,7 @@ int ZEPlayer::GetEntwatchHudMode() void ZEPlayer::SetEntwatchHudMode(int iMode) { - m_iEntwatchHudMode = iMode; + m_iEntwatchHudMode = iMode >= Hud_None && iMode <= Hud_ItemOnly ? iMode : Hud_None; g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_HUD_MODE, m_iEntwatchHudMode); } @@ -791,8 +799,8 @@ void ZEPlayer::SetEntwatchHudColor(Color colorHud) void ZEPlayer::SetEntwatchHudPos(float x, float y) { - m_flEntwatchHudX = x; - m_flEntwatchHudY = y; + m_flEntwatchHudX = std::isfinite(x) && std::abs(x) <= 1000.0f ? x : EW_HUDPOS_X_DEFAULT; + m_flEntwatchHudY = std::isfinite(y) && std::abs(y) <= 1000.0f ? y : EW_HUDPOS_Y_DEFAULT; g_pUserPreferencesSystem->SetPreferenceFloat(m_slot.Get(), EW_PREF_HUDPOS_X, m_flEntwatchHudX); g_pUserPreferencesSystem->SetPreferenceFloat(m_slot.Get(), EW_PREF_HUDPOS_Y, m_flEntwatchHudY); @@ -801,7 +809,7 @@ void ZEPlayer::SetEntwatchHudPos(float x, float y) void ZEPlayer::SetEntwatchHudSize(float flSize) { - m_flEntwatchHudSize = flSize; + m_flEntwatchHudSize = std::isfinite(flSize) ? std::clamp(flSize, 20.0f, 255.0f) : EW_HUDSIZE_DEFAULT; g_pUserPreferencesSystem->SetPreferenceFloat(m_slot.Get(), EW_PREF_HUDSIZE, m_flEntwatchHudSize); CPointWorldText* pText = GetEntwatchHud(); @@ -1950,4 +1958,4 @@ void CPlayerManager::FullUpdateAllClients() FOR_EACH_VEC(*pClients, i) (*pClients)[i]->ForceFullUpdate(); -} \ No newline at end of file +} diff --git a/src/playermanager.h b/src/playermanager.h index 0760f526..b5ce403d 100644 --- a/src/playermanager.h +++ b/src/playermanager.h @@ -25,6 +25,7 @@ #include "entity/cpointworldtext.h" #include "entity/customplayercamera.h" #include "entity/lights.h" +#include "entwatch_hud.h" #include "gamesystem.h" #include "in_buttons.h" #include "steam/isteamuser.h" @@ -198,6 +199,10 @@ class ZEPlayer m_pActiveZRModel = nullptr; m_iButtonWatchMode = 0; m_iEntwatchHudMode = 0; + m_iEntwatchHudStyle = -1; + m_iEntwatchPanoramaX = EW_PANORAMA_X_DEFAULT; + m_iEntwatchPanoramaY = EW_PANORAMA_Y_DEFAULT; + m_iEntwatchPanoramaSize = EW_PANORAMA_SIZE_DEFAULT; m_colorEntwatchHud = Color(255, 255, 255, 255); m_flEntwatchHudX = -7.5f; m_flEntwatchHudY = -2.0f; @@ -271,12 +276,18 @@ class ZEPlayer void SetActiveZRClass(std::shared_ptr pZRModel) { m_pActiveZRClass = pZRModel; } void SetActiveZRModel(std::shared_ptr pZRClass) { m_pActiveZRModel = pZRClass; } void SetEntwatchHudMode(int iMode); - void CreateEntwatchWorldHud(); + void SetEntwatchHudStyle(int style); int GetEntwatchHudStyle(); + void CreateEntwatchWorldHud(); void SetPointOrient(CPointOrient* pOrient) { m_hPointOrient.Set(pOrient); } void SetEntwatchHud(CPointWorldText* pWorldText) { m_hEntwatchHud.Set(pWorldText); } void SetEntwatchHudColor(Color colorHud); void SetEntwatchHudPos(float x, float y); + void SetEntwatchPanoramaHudPos(int x, int y); + int GetEntwatchPanoramaHudX() const { return m_iEntwatchPanoramaX; } + int GetEntwatchPanoramaHudY() const { return m_iEntwatchPanoramaY; } + void SetEntwatchPanoramaHudSize(int size); + int GetEntwatchPanoramaHudSize() const { return m_iEntwatchPanoramaSize; } void SetEntwatchHudSize(float flSize); void SetTopDefenderStatus(bool bStatus) { m_bTopDefender = bStatus; } void SetLastVoiceTime(float flTime) { m_flLastVoiceTime = flTime; } @@ -411,6 +422,10 @@ class ZEPlayer CHandle m_hEntwatchHud; CHandle m_hCustomCamera; int m_iEntwatchHudMode; + int m_iEntwatchHudStyle; + int m_iEntwatchPanoramaX; + int m_iEntwatchPanoramaY; + int m_iEntwatchPanoramaSize; Color m_colorEntwatchHud; float m_flEntwatchHudX; float m_flEntwatchHudY; @@ -498,4 +513,4 @@ class CPlayerManager extern CPlayerManager* g_playerManager; -void PrecacheBeaconParticle(IEntityResourceManifest* pResourceManifest); \ No newline at end of file +void PrecacheBeaconParticle(IEntityResourceManifest* pResourceManifest); diff --git a/src/user_preferences.cpp b/src/user_preferences.cpp index 27f41e47..d603f94a 100644 --- a/src/user_preferences.cpp +++ b/src/user_preferences.cpp @@ -21,6 +21,7 @@ #include "commands.h" #include "common.h" #include "entwatch.h" +#include "entwatch_hud.h" #include "httpmanager.h" #include "playermanager.h" #include "strtools.h" @@ -137,9 +138,13 @@ void CUserPreferencesSystem::OnPutPreferences(int iSlot) // Set EntWatch player->SetEntwatchHudMode(iEntwatchMode); + player->SetEntwatchHudStyle(GetPreferenceInt(iSlot, EW_PREF_HUD_STYLE, -1)); player->SetEntwatchHudPos(flEntwatchHudposX, flEntwatchHudposY); + player->SetEntwatchPanoramaHudPos(GetPreferenceInt(iSlot, EW_PREF_PANORAMA_X, EW_PANORAMA_X_DEFAULT), GetPreferenceInt(iSlot, EW_PREF_PANORAMA_Y, EW_PANORAMA_Y_DEFAULT)); + player->SetEntwatchPanoramaHudSize(GetPreferenceInt(iSlot, EW_PREF_PANORAMA_SIZE, EW_PANORAMA_SIZE_DEFAULT)); player->SetEntwatchHudColor(ewHudColor); player->SetEntwatchHudSize(flEntwatchHudSize); + EW_UpdateHud(); } void CUserPreferencesSystem::PullPreferences(int iSlot) @@ -316,4 +321,4 @@ void CUserPreferencesREST::StorePreferences(uint64 iSteamId, UserPrefsMap_t& pre cb(iSteamId, preferencesMap); preferencesMap.clear(); }); -} \ No newline at end of file +} From 2f4c6e937a0588e9580af36126dec747e5af3c55 Mon Sep 17 00:00:00 2001 From: tojba <1348625+tojba@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:31:43 +0000 Subject: [PATCH 4/5] Panorama HUD review fixes, generator and checked-in assets - Only start the 30s layout retry cooldown on failure - Compare per-player Panorama state directly instead of building signature strings, and cache the last world-text message per player - Gate !hudstyle on entwatch/entwatch_hud, remove stale world-text entities once a player renders with Panorama - Don't write default HUD style/position/size back to preferences on load - Cap Panorama HUD position at 95% - Generate hud.xml/hud.css from templates (scripts/generate-panorama.py) - Replace compile-panorama.ps1 with a cross-platform Python script - Check in compiled Panorama resources and drop the CI Workshop Tools download - Revert whitespace-only churn in unrelated files Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01XagcvZZBfqEnBVSzXh88yb --- .gitignore | 3 +- assets/panorama/layout/custom_game/hud.vxml_c | Bin 0 -> 5941 bytes assets/panorama/styles/entwatch/hud.vcss_c | Bin 0 -> 188083 bytes assets_source/panorama/README.md | 17 +- .../panorama/styles/entwatch/hud.css | 10 -- assets_source/panorama/templates/hud.base.css | 31 ++++ assets_source/panorama/templates/hud.base.xml | 9 ++ assets_source/panorama/templates/item.xml | 11 ++ cfg/cs2fixes/cs2fixes.cfg | 2 +- scripts/compile-panorama.ps1 | 31 ---- scripts/compile-panorama.py | 95 ++++++++++++ scripts/generate-panorama.py | 146 ++++++++++++++++++ src/cs2_sdk/entity/customhudlayout.cpp | 1 + src/entwatch.h | 2 +- src/entwatch_hud.cpp | 85 ++++++---- src/entwatch_hud.h | 1 + src/entwatch_hud_worldtext.cpp | 22 +++ src/playermanager.cpp | 7 +- src/playermanager.h | 8 +- src/user_preferences.cpp | 8 +- 20 files changed, 399 insertions(+), 90 deletions(-) create mode 100644 assets/panorama/layout/custom_game/hud.vxml_c create mode 100644 assets/panorama/styles/entwatch/hud.vcss_c create mode 100644 assets_source/panorama/templates/hud.base.css create mode 100644 assets_source/panorama/templates/hud.base.xml create mode 100644 assets_source/panorama/templates/item.xml delete mode 100644 scripts/compile-panorama.ps1 create mode 100644 scripts/compile-panorama.py create mode 100644 scripts/generate-panorama.py diff --git a/.gitignore b/.gitignore index f8e77785..1a128a64 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,4 @@ bld/ /dockerbuild .idea/* -# Compiled Panorama resources; regenerate with scripts/compile-panorama.ps1. -/assets/panorama/**/*_c +__pycache__/ diff --git a/assets/panorama/layout/custom_game/hud.vxml_c b/assets/panorama/layout/custom_game/hud.vxml_c new file mode 100644 index 0000000000000000000000000000000000000000..8200bafecccea55097b5cdc78c603c9b5d779e21 GIT binary patch literal 5941 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

Cz$iQnri*c+w8NY|`SFAcN@T zu}d!7DzD8_4d9oU!HTtLdW=7(OxLi@?z;J6Sp6EqYgr&?3PzVoj0rMmW3 zqX$bsGoHw$C9!A~k;{8gW9&{rbR0WH^jQ?0(1uxBc~&|v+eB=hJQXPk?!-JXQ=O>1 z$Z*h3JMDp}W4aeORfgAiPUFkYPG(Wo;3gKC$;lYU6p&0LFu~cVtd^OntQLaHF&S5Y zV3OTMSc!{EP=S@mCjW9+gRZ8Lp+HKTb2-RkuMC=v_F?hyJJgjAsf}2W^F@CUu<2RnuJK~m3L9r}Qf*e~6sZr}AQI)!p1TLrHIe<%PDAvBH#FKa` zL+B#NhKteI8UCL4NMGa0hKDhpM?h0%S9^=NQh^irD-$P9YafGRda=HGZRJ90y62{z z7?<2^WBSTV>kPE!MLgWH7xH5SgV}SIjJN>LXAz{1!7an%x{=^~c35H-RT!MB!Qf6_-foKYH1HPaQmFVmf_UHK$Uiw@ywxk$Pxp?xW6*UD2m1kht+bAb7&zrVi5|??Jgb) zW|O*=$NEFugQD%Q2>L@jfsA%o1mDlUpr(2i&90Ya-+|KD`;ZSGps{j=EnO!||6Un< zWPfiRiXZQ8v`bgxIn!bh<3%?%jIZ8yp;S`{ra1u=XIZA%`)8@ZhJH2emf_AoksbOS z5Er;qQE6JlFTt#OK?FoK3JoW8bSmG~@x)lJK!)|OJDa=Re122>PVhrL8m{oK&`uSp zeBdu3A+;<(F|Un&>FS!gQ3&LQ?;lEshcFp>zy!Nt4gKA!JX5=LGaekcB%~m}x5hjh z{uVtUBR?K?TvKw1h=pMW&zehXMv;wBnxOKXC(HMwsINIt+z<&arYqll8;h5 z&p`->l!eo6#Um(N*-;gkiMc4 z6pQ`c2Fv0qkj>x*CtZV~<6->8Pzz!iFOUdaE3^*vl>2Op#nhFFh3N6*vzsZ62_ ztau3-vur$hgI2RN*(+`D1Vem;wyXTRMKm}m^(v%xJQX+s|7Aye1dqTtyB&cwIs6FY zsU{eftW>yoOr)%9SDb*Z_bkxf5HB6Bx2uN6VNFg&*(H8@O7&J341Tp4ztRf`p^A$^ zvechdDHUWeTrhW*nlE__p?VyBcmhPr)Thd5;Pyp`0bw| zBo3hLIo$^ajzmA*0}ZLd0+ukh+Y1T(1dN_OQb?HP3cQ`6_`KYc?abvpvQN%x(OW=st`!nwxd;=>7_VYl{sNjB|D-Kik8atq zazf6C`%@1dxQv{^WEd69y(z)&;0!4~nn7SwnP5IJ_4+-fnR-{cQ%&!cB?>5p2XqH( z4D4<^=lOe%mf|V=peVkkDF4|nUg*mTqVw6cxW}MiUQ@JD3Ki3TbU3dxScgS<0A(*w z2W6)>Bja~`tJSMdR|s(@(f2{Jye$Zkn(O)EFi{S~Yw9Rr&!dDrk20PM8I02om!fhB ztI-te78@J9F$ukxjItN)Q50g$ozi@Mg9^BU-Exzw-2LqgVN{=MYbd0w_u`IYMyyH! z{Vu*r@d8+56I#32UvwrKicu-dCUud)5r4(EAX(wxKP&(|(NG1n!CvZ>6z+92Mx1oC z@mx}@?`y1clJxl`6pVc;&ACrRSj=qmKl7vm1s zvZ_w{vnOsbvG#vMvD(_>1INUp23@vW!nPo-!c<8!RRj6-mj1H$3(epv@M-_=?pQ6}qJ<`p)I>J2H6 zf#AB>tV0cd-=V|709L^lK-2z!@vQ2sAdVzDb|_(N+^4hRJ(Z(~=u$LsJ)0o5=r$+A z$3aB&ZV=qyK8#r<5a=lc2yX27M)TnP-;gOCki|d(o*r_83?^W`v2&YUEvVmd&$4-4 zaVnm~gBHU>6R_&T5{zfHDs-(uH&O+m#n3`@e-S8d;@vbcz#{BRVMKY&ihhwY7FSd^ zbWzEokD%nu>iB5U12t#Ofvqw#J5lvVAh^XwSpk+$L{&XC3?y%z2_|9m zYy8fQ(ndy&o_^(S6yFyouQ4oL7=b?rGYY1ZA3wHkkWqAE8cN@4gR!;+rBp1ecnzKu z9qcI?7FHau$J^rd8y8k=L`Ga#@g*?B%V_O3sxh&CkgM*JL90;&lH2`92YR5M6b+U( zWh13|>jRb417l9^VLWU7D}KatV@*f(gmjU`QJ|+QWb5scbc!XiXmA+_SOQGjiYwNS zk-8`vA?+=$=u|6!Vu3{pd^CMWXSkxij3D?^EbelsY7zLcc`|Ml_$YQKfSF)Cig0ca z{E!zkp8D9*tu<5NgW#@C2$U0J@|H@|%7`d-cSp;HFW4v2AJGt6e}$(+sI+;CFC(S| zLwGI<$Q(M7FK$XhDeDFqP7Gm>?-4Sdd#n*cVL+9WK@_7f#8OZ+M0G9tPL@Uw+%AYJ6}j%M6esu z;0v^UUs+C|Cx~3P=(fI);l!TkVUM21bHDERt=B&=ipqLJjzsAKJ%cd&Yo%-U8+fNz z!Knmg*ZDUQ1kzb=(dZTnDgF_>e>F%R@K^C5+FlM4gDF0bKD+>;2jluWQSbW~nk8;v zQuRo%ynFCC*%gk1OzO=&Pe74Kock+Wc{he|4+tKn0^nvzFQ@>#1%kIh@CY}KjtYRBEyQjr0RTmRm=5^$=}O4iz7_{3gvrqIiH9*wQFm4asqAZYAN1CTQX7N%<_N3sDE{v?V$)>*xJ zrT~J+v$_P5PzA9;mm0GbPD~Q6OER7(s6}+3&@%&^^K_fHzO`G@ zO~GbkN5{_EE@P!}c+ieQ%Hiao<5ONWh~}C))9SaPKifd?=gzeH{aSCJcbn>iy|GS* z_r`=D(c5^QiPu~7D1;+}=ui+m+ZlnL7l2?R0l`=@852$m;*9ATH2f@zJr`Tx(3;9w zL2RB>c8~+<(_$jCh`lp>Obde~Xr1?Aa#(l&-DgqUm`# z`W8Me1)b}aVmvR=sgam!tlOfX>~vd%X(qGVP$R>dj_IF)k}r4kSv0k4ghFq90>x&3 zt;kC}J@iWmQdJ93ywY)_rq&`NJ)W~-*prIpO{(#{+QwPY?%w=R`Uxl+*H^I=8F76T zry(P*ui^smKqcDxOIue(C#z2P;K=r4Ww5tm7rPBKTl`JWVwkS4qN;gj{cIsoM{<-vQQ`5oRIYkIioMBVar_joMO*F8 z28f~m2^leG12{H8l?jjIIlUAm5Kad5|4KXaIH{^*kM~t>i-Pgm!|NV|$RIQmJuc{2DSXd7~+)G`p3Q}~JESuyy!g3bgrw<=M z@E9kYUi#G1$`r*Oy%_A8UP0#Z4tI$(*uIdeu{<54uZ$KQ4NZe5&VtCUFD99m+`$u1 zODj@51(q(N(kE2Um#EWFFKPn^!IQS%$E0EFnclzpp3>}|jhVX}L#8dL<$c_)Hpo2X zK#4Et{nI)*oU*LS4C#dc6n|-V>KFB%P$&aJ@pOke)q+-N_Y9JFMY+cg(5{nJxQ_a- zC+{jGSYZD=A)Cz+D#Fj5#D?u<}LO7S_>F!y!hK zOsDLCh>w$y21G2p0~h?AnqSyFG*_gCYF*X+ClgVuF4DNJ#US&diUY~;#!hBtTL`-A zU3LJ$WmEz2w6lh*hWDyh_M~#yqPJYU} z$=y`>X|9j{lkY>zcjyBjbnFvkUN-b$ET>ohHSFkb^2xi#De(BdK!vNhCj42k`RK= zXz-YebA4&Xkg~nB3}+kuFy9wWKtbf!0*5~wA~!!(k}(Z`SUjLFivI)q2ANkotUFc4 zS&?9Y{*D~}a0%@@1(Mgcq4tMOE3KvV;-qj3lW{AVUw4aw9T3+HS6(nQvls=x3CSCr z1o}}<8v3wU-H+9>Yri1#W{1_+OXiA|!Qh7z=s}v^e-^EnP3E@@eK_%aDZyDltyk~W zmy)yeD|zg-{sun$O?gCWV#s2*v8PGq-{9Ts@H>W)f$zuwPi8P>{hEUqyrXZBHVLne%v4@-zQWb=DP@w96 zwBLQ#+%6pbAZ`0I1plSD!(feg+Hjv{Gb(Rp>}iCFbbbK6$_`)}b{G(3Hk*3TcujX0 zZ!EDlvpfuncRO4wu8Q0-+ha`4MtTADFNEejXGgtJ?sB3e=x{Z84b(WszMO9G547MW z^1g3~!)UE!O{xap;z=6f@FR*`etWKt$h?LN)Ee*dux5lk20^7Cau?2JX+jC2a(S_OAPw(2Fvx6)D@gorX_ssd{(tF| z<}0u{l%|pGqhwMWfo=^D{CjHzx-&rV@m2_QXYgscdisX<;C#I>V7)M4eUSM?MT8{S z(3!k7K%a^=l(og=EWZ*M*l;Epjy2##5^Z=glfQ(@J~eG%d(Ge)M(~#qd}f+K0~)US zi44W6pU9i`Bm_@E@VTu5NyVU{3_t0dsTq*DYN%)^&4?wKrI+PxioyIK=6_cihNP9W z;SAY1on|mF1eL)Ii=zi2BOEX&$b2zowzNpOB>3bW`K>2MGu?;aOO+4;U7TDLDsLhE z3ko-#VA;KjVK;7OB5on?R|+%4`@CLS`!G~yBmFwPe*>DY!4eIopkAi__x@EZG-zQk zD@OI;04v6A=mp1Hn>B$!mZ69)G*ps51t#sXQsMy~V3_yl%uG=%nbO=?j zOt+PuMEl~9!>Gbm+AxPLP`Q&s0&;i`)uloX6;VXpVQ4~?Ar9^LvI~V{A7##3p~!AS zR)A&ISYa=!FQX3gd+~nmychHFjlF`*4&m^h%V=+WKt2<&!$$hQA0!<^J4C2fu)?tE zWN4N^vtwuu;vLPoDrP(2;Z^0%Cm{m2(}X+7yHglbA39mVqYk+yaHzwwv|zBqueH$J z5Yqi3!C_(u9FyZwn!He~9RhFk9uj0ag%iIez14NX`C;;hiAi**1Wjj~^uR6=ViJS- zB7$P)2I-`~J<=5;FbU@xTHx`>+rS-efUIJnFoWrrNJs-77PcTleni#Z2&>P@4W)7e z9>z}-wSeGCy@v*wU0Sqx29xzp9u3cP1mzp>(1Mypjb{Ebj|rJi)+p5b18>qaS8mDt zapF?O=Q3z^4edO!`V~p^D}@#FADA&{IJxK1Rru=P^n5N(!R?(6dF~;5ti`CWnVen=L8kdA0nr*Uo z@`%9+JBTQjDwL0ZQVg!F%?T%uk;O7B9x@Eh7&k1)6vB3Q&D=Xn50=3fXFySHSi4jw zk83I4FgoVtG02Efwgl8}zMZUHLp@pqD?b*-&j@^pEl?=lrt|MWv0GTzJ-3fOwnX_{ z`7tEL-S&Z|+de_2TNo+YMelW7SxO?Yw9EgOGZto3`yBFh4>LpLscD<64W_u1ox}e3 zpHwJOv{RmPf^Yw{@CZEcD0O@@v=SyN9MsjJ*PNKQHGc}l?jiQk!zm;tQrl}^>@ysi zzQcn|k8r)b6+DiAN}CQ(K8;cxIxb)q4!T8e%nfads#P+d&GYH@+&gKrEgsXh<}0YT zhS8TA<4w~eOab_5^TSZ|3{65Z3j1w^i_DF0lo5QXp#pX0M=)(WjX-|rG$P3Cp;wTJ zvQ3ROlCt-OpjT*?N%7i^;zTG;f}%Dw9alRFy%CD*zYK%?M`nH<`Fe+IM9mo}*t+be z&s;;l%b-*!8qI;@mn5KJ$c^ONuLKjT@*^2YkD_QHg1q~pOC|X-zPX@G{Bls0}a`=A;{D_{!qRu^GDe?pYd#2epo+H25>UvjWdrC zZSsR8EF>XKd?=g+Z!D*_L1BB0p_d+h&(vQ7&EW8Y9*jot#Xscpp?h>>%=7C@jLcsl z*|S0SXQe1RX8RzUZ=?+zF+6iP`62GiF>?M^WSdC!<|qS)^tuUi<#-gWLV%FQIo-4^ z8pqR!MdaNlG=F@l9-=wOSFReyE;o{ps+SaDtwMY-wcB&B#q-oRJk(92eBdzKN_?{C z_lH-*{pojh{~$BM2@nc#an=i}Q7foI28xkklfYLhmkqO^n89ecWh1Vgbn%*S<|y*R zQgZuMW8)Yp%UL*`&(Abpj)kk>i{DW9zTu{!LSNy^apNFnz3?nucn+e5tt=Y(QO3IE zRm03=8_gA1VH6WnJu1jFhH-a}K}o^i&eCZtRWw1f-!_&FkjRBqH;wt0ZGKk3l% zW}Z|iDhckB_N*OgQ|& z+yV3=X5bR_SBE>r-UrZ&;sJ<-5J}s*n@3`EKw7ZlftYeC4lpoP=OFcCuOmPZzjSHvt5~ffMY}8ld1eigM0GOJugk-!^ z0Jx*Sj*iK6k3sP`6ce0GXJckEouQ{hri&w=YF6dO#2)3xzzpArJ&;)|)r#pzRWE*~ z#i}Vbj)52U8-vwoIAOG8@WCg{IHkW~-A-V(PK4;NHPXMR`{teGt7xOs=b1pN_$f~; zT1_xi?)H4Jnj3gWZzS*Gp*q%ZNCsyZdzU!jDg2GDZ-QiEIALuLCz3NxQ%?%!pp5Ul_jf_P@ls}7Vh|*=C6Jw z*QC9W$2F_+O+4SF{J`gdy4bS`9@wJ^qfZM!V(sv6uk>&tlY0aNGwk5eo?s;e=Rk1m z7u}?~IDwt7MQnRRB~q<98fxw=EFMkNVD5hJm8tJoPYKZ^`*K&@&ym{>6DN!+NV0{a zDTv3me^Twt@baZO)H0^-3D!R=jadJzbgo9OUV0vafv1WNP9cI<4V+YlRIzve$f(;TkXQ(48Wrp2Q9jN0+wH;%T% z4jbd>!Z*gzj$OuK!5MyXr1ZYuI=u|@j#W%S!}3}gj;2OY#U&Cf98FAJDO@t2gfz*a za0dKvCiNX>TSVHLa5Y`}9VGKYvmH-(f(|;)7Or`Lk$(}I`3*9(sUd0h$cWOuLSbos zarU(@w<>gHbc_Qgt=7X{$)eH>DnCEbIKw$%I%GT-8{@`fH(JwM<~9DQjA7xWAXunt zLZz9shH;P^02h)b&4MI17m3y3r+7 zmA|0O3KfMNHm)z1=@k?vF~lf5)0%01mfB7XH_VX%)mOZ%sob2;9}1^# ze<Rm)j`xW&@HXu`PlmnHuNZ@ne31 zlFS{(7;MtRHO?LLhtc^?hcO|Y55oX7ft1`JC zQPU(Urz_L_T~3c_K*_>QRDLr#ml{seoLHC-ioxch@ok!6x4`DpF|eQ#|JKJjQMt6a zbj%;lJnXZc7ghpFZ!2$m&8NE0MieI-M& zl%Y5siZfP)l6kW(Y&{boNnzeJe~$jdY3>~V2vsUZ@-Y(3oufq?^xhobh7I1K<}>Gp zxrtP*8vDTafwmRZZB+F{Y&ye^6WY2KBN3O(#WFK5 zj)m_tG(Ui3Md-{R49sQdNPnQXo6)%kqO%`TRiWQ7+<{`KI!*c~O_;6%f%>Jxi+279 z8lOFaHtcW&hMS=|;x?sq%qe#j3az-$ZGOvZ$08Mf8ci`6<}7;Wd^mQI8TQ~v4icqP zsAgq*1c~v$FX_XtAUMa?f)1*A@BD@oVcro7PeJh)D88-Xd(0BD?32yBH*zA523)*b z?nu73=DsnHUR18$9CsT)(sim2`O@4s7Dpc`H{VBMEn2&~OtBvy`z;*G{bFee1m~LI z(2k%A{!GbsGcV#TWc#jNShUMl&>L?Ez6TOYmiBfO#R4~hrRqu8Y$nsnZL4C}jOX(w zhnYHfN2pB^*zBDn@c835JpMYk@iO{3%TEGittIovzYbUY8n@jvBd9EIkUz zg)J(@q&aGoJpo6JIrM^FPAGNGAH~bq`6y;&=c6zZ4PTfcWjj&9tq3M6G%!ew(EO-k zMTom-eXT@+stf?C~L>#rUr6S$V@yN{DvoSa}j`frCJ?;z)o4JnyqDarRf`Px5~ zTkcJbxye3J5wnvaucCqq5y8}Ky(hyD#mN|kngDc-3gO>~mEJ_?%uOj#AwRb$~? zD838D#fp?n*F|1StDJY8xGpk=loWP&04m$@%uyr#k^a6!2hwnoa>rfzh?+0iFeo?0 z_q#kaWG&WCp>e&ZUc3FH;Fv-9siM#F6We{Ah$B2{?lno)c zB3U@I?Rxc<{>n`)*B^Z^Kb0ourc!s+RO~tp7U|Xm7s}F{GICIiMyM@ac}-X>UcEIi zM5@+t5jj%VgcYrs=Ci5oXHHH`J3L%VXRm{1b*}T`J-u?9MR8Jhd$eiAS34nV*xKC+OEdAAr%-|JmhGYVBFEEMx{1Y%V_-> z5L{`<$mD#;pvimK?y1~lmu@H98cVV}3{NI~ew%XNf#8?Cb;qO?QQYkqNV*+^9j9G) z`rI-&_2!3B#8Q)qlaR<}YM)EaUmGNH;(L)y3DOLzRPz{im@e4w!}= zsM9cN$QTo+yqz>6fvFTy&7^(I7-7^j|BJFCnE%BJP^4}N)co76*-7i02*K4cY*-m5 zCL_sq!2h}F`bFpYCqG>_gXv7d&eO3B-Ac{^J3*-tg5PhAU@-(ILvYPj2$c6?X*Cl7VMeVRpUBhTwX8XsF0I0XNyD??7;atpJ8`iV;-FEw=w(>PY^U<^TTV)2L)v z$QNmKg_X4VT>KDi(iW<`5j|q=STdI`l!8r>xbAtHUF>x%&8j^Xn@}eWSd};n}(2#|Pp?L(FTT*YK%trc4+Q2PT zZYJMO8h{ID%6@>5SgM+d322N@68tM_!(^IpwQMZ0rydR2LIoxbxK+SKjX4_*_!hO? zW{Bq&#Ze`pkk`?V>mm80iUJ-8`Orog^oKSIm%I$cD^RR6^BNa7%I*LOGMAr4yFwb^ zy*8`o#dH|t?vNd{awKI}xLzE>lQbM;@z7cD!(p>9JPqGaymm>2EejeGtb9)zxPk_r z4aptWrc^KkjOw+EWgw*F{S%_$dh*^GuKtxYE6x3)8kj+I7iWdp3`+_Qve;`jji{ZC z`KM|ZJ^ zs$}pS9PvDL{V8ot$j^Z_!#VUMI|oZro9~KOn)Y&0T^a_#y<1xqO}NQFkyT-7 z?0*^dk^vtt;AblE@i%b6Z>jRWaP<{Zmf{|xM4*_$b2RIDXzq8bLS>kkd@}_G zjbut*PA^sr`UCL6gJk`)p&mbYRZ2HiqT_?ld4MJ{H<#}=d#e0g3hl(BRNz7n5|V3! z!XArz&V?2Bnu`(XHeipl=*?_s9(Jok4E7lHSF@eMMUea$l1EZO(gt?AjVb$|VUMCK zs(?LiR7aezk&p&^EPRfb_yu)8N?7aTs3VDeWUPz*F>@>pI1ckslO)XiEg9OH(^VSk z@pz_V5jh{z<3jXJci8y0%!)JOy@JAj3d!TTab)fFG zkqd3jDK8o}ch{WUy0rzj&d;O$RdQ(QG7lrsIQTKHjFe+TYHVv+Zc<}g%K?45vFAej zve?#z<#5Cb>UwIK08qT!Zi^LTrh?#`O4mT~7dIYZ6vNpd2!PBAH&8SMz z`Mn)=U4A~C8c?)1s*!4vzh!mUji+Y4=hNi18Qh+h0U9?S9vD9#ThuuAanxEZc`fL%*S;rWVo8G}+g%L&-DG<%j(fBlM#W>srelWVeD`YUPj^(E07c#UR7Sh9TA*Q3ICb0UNu4!v0So7w+A=v2pH$jv}R)}}E zfB^o#iBx?WWFE4V06PAFgjAs8TDF9%sQcw`!V0NXFQ$U{#6LsxpM~NTdvmqK9 zpUhL+c@M$XFO@SRgE$uR^70ps$ClI}j+QqGag@vUv5;&sZGn*_!@ise$yt!Rs;`-w zum!)9<}Uc1Od~fy$*sVj74D<{`^ov5UN*YZWHLhaCzPTLRWmB{^Bp;fN2Avd%rBzU zj{Hu=Hg+Q+O)Mx5T+~WbqeU2xhHKTdK22jVo!-oV<_*I(+OVm@AaYUdFM#4gDBd*5 zz=p(Qls?Exk8hy~6<3XE*hbk4Qn8J%laPjOEPTm2@D+8xg)dU%VfRLFx=aRplOT7C z16ycbeG3MoDj~Q*O(GlR%x`b06AuiYbQ06Cn4Is#fQ|mlVEV%=DSHhRe~*En%c6nd zf}e)u8A$$-4r`jjLdW?^D<2P}O^`RI{~?Kr~XSMcanv-T2yI&X^6(sG1ZA-fL>g zok&d;C}_Ls+=T>xZb;Q38lbT+WPWu>02+a0r2-m@Q%-~(rk;rTX&lg)SRT$}I#xmP z!8VQ!!mSRJpn#Uhz>I~5nTvmpF#64jtwXAIMvvC;7L%` zpM?3REfF2n7|Vak^l{>d_Bm@iDcGGM4a#^LO;}3CEe?*LQK^$i#%suv8kPD^5>hpa zkCTwLKomB$5|@J7KC+AFi?+`#hSWk$3ivs{7$)6CG$YYs3`$KcoWLVQ{SC+{K-f{x ze5`9kI*?IhxeH{OjJBm#Tuyq0!Lf92(+rm@lm(aDHcx0N!V9U)i1B9m*Hk6}#s^#_IC9uYxOE55XQREWgsW<;nS|kda znUH*KHklTlI#_U%OoH9HUr2|42t_7qvTdt6WYynZ)p#q!ieB2Ls!=%Ds~Y3ssbA-L zs;ZHFqxmap4zd_vpF$lm{R+QjS_hs&>*`Ozs5F~Ql=hnmlI$DFH0d|nM)P9wZNIgA z5(cMv4HO-=O2Mwt{0tOfDnpmz64GC%d{Rr zyLG=S-#Hi*m{rHwb$IItjn7$iD#K_&s-s2Dg2tj$e~&%mJnGsZJ9n}SOPT<2D_yw_ znvPjBqIae#rU7*x8sCIf-hyVw22q`0U6~Wn(4x^sd#u_me;TdcnMYoTFc(XyJ{pUV zRTx-Wyy^xLDzuMwdp7wrxM9j^*raA#_Lusd#2!0Ne2)g62SukAZJ-TaQulasIb%8I zi*Un3Ovl6I?3~T0Le|PoM11*#5&9I8owKE$Ire8aH{QI`46*BgZ8Q&DiWz9uHVtco zUqMXwIEyYO1qrjmX4`09O5R;k*-2P}T_es-j=|Y7;!nNi@d>J_xQ8^@-mCD#Yt$2E z%XZkg(;+tPV{q-5{OP<|kvQhr^>oZhor1xXbNw!o!FPt(g;8{OG&H$vsy&rS5}d%w zlEjowlDonXo28tiK4c?ev=6KeL5^)V=agSxpNUvp>mS**=;Z%?jak6v_%yWyX>LJS8VIxHaS%5K{ z&x53pjRmgeoFQy%r;R&kRgxzyKhcYvIn+UVR?n0Rf z4W#FcJ|v`x62%c`z#1dZz??K&eW^4qzElL$&zBa-!FeGhyJh2XtIb@-3lf(z>{me3 zt--AnGF*P4u*1fBp7?cQ8;00&8If2gTmYE&d5$_VcP8I$5n%FX!nix030v%RCRVAo zP`KFD3BDLX14lyg%@)-Hr^bL0m5=Eo%WfOY7W*vbWI364&uZN2^cXPLFih7%)FWGW zxb!|P28@B_A*x}u$eqP_`|vL^_I+o{D_=$46vim_l~(jS3%k+m)%QyU31cd^g>Xre z4sR5x-yb~Q&q#J>iv4YVCKe4BocdxI;}UAyBb%a$RJktK>Mn<5ZZ^6VW + + + + + diff --git a/assets_source/panorama/templates/item.xml b/assets_source/panorama/templates/item.xml new file mode 100644 index 00000000..a0f7f1aa --- /dev/null +++ b/assets_source/panorama/templates/item.xml @@ -0,0 +1,11 @@ + diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index aca4ce08..076067ed 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -181,4 +181,4 @@ cs2f_mapmigrations_20260922 2 // Current mode for 2026-09-22 CS2 update map mi cs2f_thirdperson_enable 0 // Whether to enable thirdperson cs2f_thirdperson_distance_default 65.0 // Default distance for thirdperson cs2f_thirdperson_distance_min 15.0 // Minimum distance allowed for thirdperson -cs2f_thirdperson_distance_max 150.0 // Maximum distance allowed for thirdperson +cs2f_thirdperson_distance_max 150.0 // Maximum distance allowed for thirdperson \ No newline at end of file diff --git a/scripts/compile-panorama.ps1 b/scripts/compile-panorama.ps1 deleted file mode 100644 index 03c653fb..00000000 --- a/scripts/compile-panorama.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -param( - [Parameter(Mandatory = $true)] - [string]$Cs2Root -) -$ErrorActionPreference = 'Stop' -$repo = Split-Path $PSScriptRoot -Parent -$content = Join-Path $Cs2Root 'content\csgo_addons\cs2fixes_hud' -$output = Join-Path $Cs2Root 'game\csgo_addons\cs2fixes_hud' -$compiler = Join-Path $Cs2Root 'game\bin\win64\resourcecompiler.exe' -if (-not (Test-Path -LiteralPath $compiler)) { throw 'Install CS2 Workshop Tools to obtain resourcecompiler.exe.' } -$layout = Join-Path $content 'panorama\layout\custom_game\hud.xml' -$style = Join-Path $content 'panorama\styles\entwatch\hud.css' -New-Item -ItemType Directory -Force (Split-Path $layout), (Split-Path $style) | Out-Null -Copy-Item -LiteralPath (Join-Path $repo 'assets_source\panorama\layout\custom_game\hud.xml') -Destination $layout -Force -Copy-Item -LiteralPath (Join-Path $repo 'assets_source\panorama\styles\entwatch\hud.css') -Destination $style -Force -Set-Content -LiteralPath (Join-Path $content 'panorama\preprocessor_config.txt') -Encoding ascii -Value '"PanzipCfg" { "BlockDefs" {} }' -Set-Content -LiteralPath (Join-Path $content 'addoninfo.txt') -Encoding utf8 -Value @' - -{ IsPlayable = false } -'@ -& $compiler -game (Join-Path $Cs2Root 'game\csgo') -i $style -i $layout -f -nop4 -if ($LASTEXITCODE -ne 0) { throw "Panorama compiler failed: $LASTEXITCODE" } -foreach ($relative in @('panorama\layout\custom_game\hud.vxml_c', 'panorama\styles\entwatch\hud.vcss_c')) { - $compiled = Join-Path $output $relative - if (-not (Test-Path -LiteralPath $compiled)) { throw "Missing compiled resource: $compiled" } - $destination = Join-Path $repo ('assets\' + $relative) - New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null - Copy-Item -LiteralPath $compiled -Destination $destination -Force -} -Copy-Item -LiteralPath (Join-Path $content 'addoninfo.txt') -Destination (Join-Path $output 'addoninfo.txt') -Force -Write-Host 'Compiled Panorama resources copied into assets/panorama.' diff --git a/scripts/compile-panorama.py b/scripts/compile-panorama.py new file mode 100644 index 00000000..d7575a08 --- /dev/null +++ b/scripts/compile-panorama.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +"""Compile the EntWatch Panorama HUD with the CS2 Workshop Tools resource compiler. + +Regenerates the HUD sources first (see generate-panorama.py), stages them in a +local addon under the CS2 install, compiles them and copies the results into +assets/panorama. Commit those compiled files; clients and servers need them. + +Usage: + python scripts/compile-panorama.py --cs2-root "" +The root can also come from the CS2_ROOT environment variable. +""" + +import argparse +import importlib.util +import os +import shutil +import subprocess +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +REPO = HERE.parent +RESOURCES = [Path("panorama/layout/custom_game/hud.vxml_c"), Path("panorama/styles/entwatch/hud.vcss_c")] +ADDON_INFO = ( + "\n" + "{ IsPlayable = false }\n" +) + + +def write_text(path, text): + path.parent.mkdir(parents=True, exist_ok=True) + with open(path, "w", encoding="utf-8", newline="\n") as f: + f.write(text) + + +def find_compiler(cs2_root): + if sys.platform == "win32": + candidates = [cs2_root / "game" / "bin" / "win64" / "resourcecompiler.exe"] + else: + candidates = [cs2_root / "game" / "bin" / "linuxsteamrt64" / "resourcecompiler"] + for candidate in candidates: + if candidate.is_file(): + return candidate + sys.exit("resourcecompiler not found (looked for %s). Install the CS2 Workshop Tools." % ", ".join(map(str, candidates))) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + parser.add_argument("--cs2-root", default=os.environ.get("CS2_ROOT"), help="CS2 install directory (default: $CS2_ROOT)") + parser.add_argument("--destination", default=str(REPO / "assets"), help="where to copy compiled resources (default: /assets)") + args = parser.parse_args() + if not args.cs2_root: + parser.error("--cs2-root or CS2_ROOT is required") + + cs2_root = Path(args.cs2_root) + destination = Path(args.destination) + compiler = find_compiler(cs2_root) + + spec = importlib.util.spec_from_file_location("generate_panorama", HERE / "generate-panorama.py") + generator = importlib.util.module_from_spec(spec) + spec.loader.exec_module(generator) + if generator.main([]) != 0: + sys.exit("Panorama source generation failed") + + content = cs2_root / "content" / "csgo_addons" / "cs2fixes_hud" + output = cs2_root / "game" / "csgo_addons" / "cs2fixes_hud" + layout = content / "panorama" / "layout" / "custom_game" / "hud.xml" + style = content / "panorama" / "styles" / "entwatch" / "hud.css" + for src, dst in ((generator.OUTPUTS["xml"], layout), (generator.OUTPUTS["css"], style)): + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(src, dst) + write_text(content / "panorama" / "preprocessor_config.txt", '"PanzipCfg" { "BlockDefs" {} }\n') + write_text(content / "addoninfo.txt", ADDON_INFO) + + # Do not accept outputs left over from a previous compilation. + for relative in RESOURCES: + (output / relative).unlink(missing_ok=True) + + subprocess.run([str(compiler), "-game", str(cs2_root / "game" / "csgo"), "-i", str(style), "-i", str(layout), "-f", "-nop4"], check=True) + + for relative in RESOURCES: + compiled = output / relative + if not compiled.is_file() or compiled.stat().st_size == 0: + sys.exit("Missing or empty compiled resource: %s" % compiled) + for relative in RESOURCES: + target = destination / relative + target.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(output / relative, target) + shutil.copyfile(content / "addoninfo.txt", output / "addoninfo.txt") + print("Compiled Panorama resources copied into %s." % destination) + + +if __name__ == "__main__": + main() diff --git a/scripts/generate-panorama.py b/scripts/generate-panorama.py new file mode 100644 index 00000000..6f8b36db --- /dev/null +++ b/scripts/generate-panorama.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +"""Generate the EntWatch Panorama HUD layout and stylesheet. + +Reads the hand-edited templates in assets_source/panorama/templates and writes + assets_source/panorama/layout/custom_game/hud.xml + assets_source/panorama/styles/entwatch/hud.css + +Limits (row count, position cap, size range) are read from the C++ sources so +the generated classes always match what the server will actually send. + +Usage: + python scripts/generate-panorama.py # (re)generate + python scripts/generate-panorama.py --check # exit 1 if generated files are stale + +After regenerating, recompile with scripts/compile-panorama.py and commit the +compiled resources in assets/panorama. +""" + +import argparse +import re +import sys +from collections import namedtuple +from decimal import Decimal +from pathlib import Path + +REPO = Path(__file__).resolve().parent.parent +PANORAMA = REPO / "assets_source" / "panorama" +TEMPLATES = PANORAMA / "templates" +OUTPUTS = { + "xml": PANORAMA / "layout" / "custom_game" / "hud.xml", + "css": PANORAMA / "styles" / "entwatch" / "hud.css", +} + +Limits = namedtuple("Limits", "pos_max size_min size_max size_default max_rows") + +# Geometry at 100% size. Every other size class is these values scaled by N/100. +# (selector, [(property, (px values...)), ...]) +SIZE_RULES = [ + (".Item", [("width", (480,)), ("padding", (8, 12)), ("margin-bottom", (5,)), ("border-left-width", (3,))]), + (".ItemName", [("font-size", (18,))]), + (".Owner", [("font-size", (16,)), ("margin-left", (8,))]), + (".Status", [("margin-left", (12,))]), + (".Status Label", [("font-size", (16,))]), + (".Status .Icon", [("font-size", (19,)), ("margin-right", (5,))]), + (".Status .ReloadIcon", [("width", (22,)), ("height", (22,)), ("margin-left", (5,)), ("margin-right", (0,))]), + (".Ammo", [("margin-right", (12,))]), + (".Overflow", [("font-size", (14,))]), +] + + +def read_constexpr(path, name): + match = re.search(r"constexpr\s+(?:int|size_t)\s+%s\s*=\s*(\d+)\s*;" % re.escape(name), path.read_text(encoding="utf-8")) + if not match: + sys.exit("Could not find constexpr %s in %s" % (name, path)) + return int(match.group(1)) + + +def read_limits(): + header = REPO / "src" / "entwatch_hud.h" + source = REPO / "src" / "entwatch_hud.cpp" + return Limits( + pos_max=read_constexpr(header, "EW_PANORAMA_POS_MAX"), + size_min=read_constexpr(header, "EW_PANORAMA_SIZE_MIN"), + size_max=read_constexpr(header, "EW_PANORAMA_SIZE_MAX"), + size_default=read_constexpr(header, "EW_PANORAMA_SIZE_DEFAULT"), + max_rows=read_constexpr(source, "MaxRows"), + ) + + +def scale(value, percent): + """value * percent / 100 as a short decimal string (no float rounding noise).""" + return format((Decimal(value * percent) / 100).normalize(), "f") + + +def size_section(limits): + lines = [] + for percent in range(limits.size_min, limits.size_max + 1): + for selector, props in SIZE_RULES: + decls = "; ".join( + "%s: %s" % (prop, " ".join(scale(v, percent) + "px" for v in values)) for prop, values in props + ) + lines.append(".EntWatch.Size%d %s { %s; }" % (percent, selector, decls)) + return "\n".join(lines) + "\n" + + +def position_section(limits): + lines = [] + for n in range(limits.pos_max + 1): + lines.append(".EntWatch.PosX%d { margin-left: %d%%; }" % (n, n)) + lines.append(".EntWatch.PosY%d { margin-top: %d%%; }" % (n, n)) + return "\n".join(lines) + "\n" + + +def fill(template, marker, content): + lines = template.split("\n") + hits = [i for i, line in enumerate(lines) if marker in line] + if len(hits) != 1: + sys.exit("Template must contain exactly one '%s' marker (found %d)" % (marker, len(hits))) + lines[hits[0]] = content.rstrip("\n") + return "\n".join(lines) + + +def generate(limits): + """Return {"xml": text, "css": text}.""" + if limits.size_default != 100: + sys.exit("The base geometry in SIZE_RULES is the 100%% size; EW_PANORAMA_SIZE_DEFAULT is %d." % limits.size_default) + read = lambda name: (TEMPLATES / name).read_text(encoding="utf-8") + + item = read("item.xml").rstrip("\n") + items = "\n".join(item.replace("@INDEX@", str(i)) for i in range(limits.max_rows)) + xml = fill(read("hud.base.xml"), "@generate: items", items) + + css = fill(read("hud.base.css"), "@generate: positions", position_section(limits)) + css = fill(css, "@generate: sizes", size_section(limits)) + return {"xml": xml, "css": css} + + +def normalized(path): + return path.read_bytes().replace(b"\r\n", b"\n").decode("utf-8") if path.exists() else None + + +def main(argv=None): + parser = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + parser.add_argument("--check", action="store_true", help="fail if the generated files on disk are out of date") + args = parser.parse_args(argv) + + generated = generate(read_limits()) + stale = [key for key, text in generated.items() if normalized(OUTPUTS[key]) != text] + if args.check: + if stale: + print("Out of date, run scripts/generate-panorama.py: " + ", ".join(str(OUTPUTS[k].relative_to(REPO)) for k in stale)) + return 1 + print("Generated Panorama sources are up to date.") + return 0 + for key, text in generated.items(): + if key in stale: + with open(OUTPUTS[key], "w", encoding="utf-8", newline="\n") as f: + f.write(text) + print("Wrote " + str(OUTPUTS[key].relative_to(REPO))) + if not stale: + print("Already up to date.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/cs2_sdk/entity/customhudlayout.cpp b/src/cs2_sdk/entity/customhudlayout.cpp index 9d35e94c..eeb7f224 100644 --- a/src/cs2_sdk/entity/customhudlayout.cpp +++ b/src/cs2_sdk/entity/customhudlayout.cpp @@ -25,6 +25,7 @@ std::unordered_map CCSCustomHudLayout::sm_mapCu CCSCustomHudLayout* CCSCustomHudLayout::Create(std::string sLayout, std::string sTargetName) { CCSCustomHudLayout* pLayout = CreateEntityByName("custom_hud_layout"); + if (!pLayout) return nullptr; diff --git a/src/entwatch.h b/src/entwatch.h index 1f1d29a6..cd0bbe9b 100644 --- a/src/entwatch.h +++ b/src/entwatch.h @@ -321,4 +321,4 @@ void EW_PlayerDeathPre(CCSPlayerController* pController); void EW_PlayerDisconnect(int slot); void EW_FireOutput(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, float flDelay); int GetTemplateSuffixNumber(const char* szName); -float EW_UpdateHud(); +float EW_UpdateHud(); \ No newline at end of file diff --git a/src/entwatch_hud.cpp b/src/entwatch_hud.cpp index 4eb49f6f..5a556d70 100644 --- a/src/entwatch_hud.cpp +++ b/src/entwatch_hud.cpp @@ -26,6 +26,7 @@ #include "playermanager.h" #include "user_preferences.h" #include "utils/entity.h" +#include #include #include #include @@ -38,7 +39,19 @@ namespace { constexpr size_t MaxRows = 64; CHandle s_layout; - std::array s_previous; + struct PanoramaState + { + bool visible = false; + int mode = 0; + int x = 0; + int y = 0; + int size = 0; + size_t totalRows = 0; + + bool operator==(const PanoramaState&) const = default; + }; + + std::array s_previous; std::array s_initialized{}; std::array s_positionX{}; std::array s_positionY{}; @@ -53,16 +66,17 @@ namespace return s_layout.Get(); if (g_flUniversalTime < s_flNextCreateAttempt) return nullptr; - s_flNextCreateAttempt = g_flUniversalTime + 30.0; if (!g_pFullFileSystem || !g_pFullFileSystem->FileExists("panorama/layout/custom_game/hud.vxml_c", "GAME") || !g_pFullFileSystem->FileExists("panorama/styles/entwatch/hud.vcss_c", "GAME")) { Warning("[EntWatch HUD] Missing compiled Panorama resources; using world text. Install the packaged panorama directory on server and clients. Retrying in 30 seconds.\n"); + s_flNextCreateAttempt = g_flUniversalTime + 30.0; return nullptr; } auto layout = CCSCustomHudLayout::Create("hud", "entwatchHud"); if (!layout) { Warning("[EntWatch HUD] Failed to create custom_hud_layout; using world text. Retrying in 30 seconds.\n"); + s_flNextCreateAttempt = g_flUniversalTime + 30.0; return nullptr; } s_layout = layout->GetHandle(); @@ -82,20 +96,14 @@ namespace return !visible; const int slot = player->GetPlayerSlot().Get(); if (slot < 0 || slot >= MAXPLAYERS) return false; - std::string signature = visible ? "on" : "off"; - signature += std::to_string(player->GetEntwatchHudMode()); const int x = player->GetEntwatchPanoramaHudX(); const int y = player->GetEntwatchPanoramaHudY(); const int size = player->GetEntwatchPanoramaHudSize(); - signature += ":" + std::to_string(x) + ":" + std::to_string(y) + ":" + std::to_string(size) + ":"; - if (visible) - { - signature += std::to_string(rows.size()) + ":"; - for (size_t i = 0; i < std::min(rows.size(), MaxRows); ++i) - for (const auto& value : {rows[i].name, rows[i].owner, rows[i].state, rows[i].cooldown, rows[i].ammo}) - signature += std::to_string(value.size()) + ":" + value; - } - if (s_initialized[slot] && s_previous[slot] == signature) return true; + const PanoramaState state{visible, player->GetEntwatchHudMode(), x, y, size, visible ? rows.size() : 0}; + const size_t visibleRows = visible ? std::min(rows.size(), MaxRows) : 0; + // Compare against the last rendered state directly instead of building a signature string per player per tick. + if (s_initialized[slot] && s_previous[slot] == state && s_rows[slot].size() == visibleRows && std::equal(rows.begin(), rows.begin() + visibleRows, s_rows[slot].begin())) + return true; // Remove the previous per-player position before applying the new CSS classes. if (s_initialized[slot]) { @@ -116,7 +124,7 @@ namespace s_positionY[slot] = y; s_size[slot] = size; s_initialized[slot] = true; - s_previous[slot] = signature; + s_previous[slot] = state; layout->SetHasClass("entwatch", "Hidden", !visible, slot); for (size_t i = 0; i < MaxRows; ++i) { @@ -157,10 +165,12 @@ bool EW_ParseHudFloat(const char* pszValue, float& flValue) return pszEnd != pszValue && !*pszEnd && errno != ERANGE && std::isfinite(flValue); } -void ZEPlayer::SetEntwatchPanoramaHudPos(int x, int y) +void ZEPlayer::SetEntwatchPanoramaHudPos(int x, int y, bool bSave) { - m_iEntwatchPanoramaX = x >= 0 && x <= 100 ? x : EW_PANORAMA_X_DEFAULT; - m_iEntwatchPanoramaY = y >= 0 && y <= 100 ? y : EW_PANORAMA_Y_DEFAULT; + m_iEntwatchPanoramaX = x >= 0 && x <= EW_PANORAMA_POS_MAX ? x : EW_PANORAMA_X_DEFAULT; + m_iEntwatchPanoramaY = y >= 0 && y <= EW_PANORAMA_POS_MAX ? y : EW_PANORAMA_Y_DEFAULT; + if (!bSave) + return; g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_PANORAMA_X, m_iEntwatchPanoramaX); g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_PANORAMA_Y, m_iEntwatchPanoramaY); } @@ -183,9 +193,9 @@ void EW_ConfigurePanoramaHudPos(CCSPlayerController* player, const CCommand& arg char* endY; const long parsedX = std::strtol(args[1], &endX, 10); const long parsedY = std::strtol(args[2], &endY, 10); - if (!*args[1] || !*args[2] || *endX || *endY || parsedX < 0 || parsedX > 100 || parsedY < 0 || parsedY > 100) + if (!*args[1] || !*args[2] || *endX || *endY || parsedX < 0 || parsedX > EW_PANORAMA_POS_MAX || parsedY < 0 || parsedY > EW_PANORAMA_POS_MAX) { - ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Use whole screen percentages from 0 to 100: !hudpos "); + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Use whole screen percentages from 0 to %d: !hudpos ", EW_PANORAMA_POS_MAX); return; } x = static_cast(parsedX); @@ -204,15 +214,11 @@ void EW_ConfigurePanoramaHudPos(CCSPlayerController* player, const CCommand& arg ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "Panorama HUD position: %d%% from left, %d%% from top.", x, y); } -CON_COMMAND_CHAT(hudpos2, "[x y|reset] - Alias to configure Panorama position regardless of active style") -{ - EW_ConfigurePanoramaHudPos(player, args); -} - -void ZEPlayer::SetEntwatchPanoramaHudSize(int size) +void ZEPlayer::SetEntwatchPanoramaHudSize(int size, bool bSave) { m_iEntwatchPanoramaSize = size >= EW_PANORAMA_SIZE_MIN && size <= EW_PANORAMA_SIZE_MAX ? size : EW_PANORAMA_SIZE_DEFAULT; - g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_PANORAMA_SIZE, m_iEntwatchPanoramaSize); + if (bSave) + g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_PANORAMA_SIZE, m_iEntwatchPanoramaSize); } void EW_ConfigurePanoramaHudSize(CCSPlayerController* player, const CCommand& args) @@ -253,16 +259,19 @@ void EW_DestroyHud() s_layout = nullptr; s_flNextCreateAttempt = 0.0; s_initialized.fill(false); - for (auto& previous : s_previous) previous.clear(); + for (auto& previous : s_previous) + previous = {}; + s_mode.fill(0); for (auto& vecRows : s_rows) vecRows.clear(); } void EW_ForgetHudPlayer(int slot) { - if (slot >= 0 && slot < 64) + if (slot >= 0 && slot < MAXPLAYERS) { s_initialized[slot] = false; - s_previous[slot].clear(); + s_previous[slot] = {}; + s_mode[slot] = 0; s_rows[slot].clear(); auto pPlayer = g_playerManager ? g_playerManager->GetPlayer(CPlayerSlot(slot)) : nullptr; if (pPlayer) @@ -281,11 +290,29 @@ void EW_RenderHud(ZEPlayer* player, const std::vector& rows) const bool visible = g_cvarEnableEntWatch.Get() && g_cvarEnableEntwatchHud.Get() && player->GetEntwatchHudMode() != Hud_None && !rows.empty(); const bool panorama = player->GetEntwatchHudStyle() == 1; const bool bPanoramaReady = RenderPanorama(player, rows, visible && panorama); + if (panorama && bPanoramaReady) + { + // Remove a world-text entity left over from before this player (or the server default) switched to Panorama. + if (auto text = player->GetEntwatchHud()) + { + text->Remove(); + player->SetEntwatchHud(nullptr); + } + } EW_RenderWorldText(player, rows, visible && (!panorama || !bPanoramaReady)); } CON_COMMAND_CHAT(hudstyle, "[old|new|default] - Switch EntWatch world-text/Panorama renderer") { + if (!g_cvarEnableEntWatch.Get()) + return; + + if (!g_cvarEnableEntwatchHud.Get()) + { + ClientPrint(player, HUD_PRINTTALK, EW_PREFIX "The EntWatch hud is currently disabled."); + return; + } + if (!player) { ClientPrint(player, HUD_PRINTCONSOLE, "Use entwatch_hud_style 0/1 for the server default."); diff --git a/src/entwatch_hud.h b/src/entwatch_hud.h index 85f713c0..23e4687f 100644 --- a/src/entwatch_hud.h +++ b/src/entwatch_hud.h @@ -28,6 +28,7 @@ class CCommand; constexpr int EW_PANORAMA_X_DEFAULT = 2; constexpr int EW_PANORAMA_Y_DEFAULT = 15; +constexpr int EW_PANORAMA_POS_MAX = 95; constexpr int EW_PANORAMA_SIZE_DEFAULT = 100; constexpr int EW_PANORAMA_SIZE_MIN = 50; constexpr int EW_PANORAMA_SIZE_MAX = 200; diff --git a/src/entwatch_hud_worldtext.cpp b/src/entwatch_hud_worldtext.cpp index 5b72d944..7f465a1c 100644 --- a/src/entwatch_hud_worldtext.cpp +++ b/src/entwatch_hud_worldtext.cpp @@ -22,9 +22,21 @@ #include "entwatch_hud.h" #include "playermanager.h" #include "utils/entity.h" +#include extern CConVar g_cvarEntwatchPanoramaDebug; +namespace +{ + // Last message sent to each player's world-text entity, so unchanged text isn't re-sent every tick. + struct WorldTextCache + { + int handle = -1; + std::string message; + }; + std::array s_cache; +} // namespace + void EW_RenderWorldText(ZEPlayer* player, const std::vector& rows, bool visible) { if (!player) @@ -45,6 +57,16 @@ void EW_RenderWorldText(ZEPlayer* player, const std::vector& row message += "[" + row.state + "]" + row.name; if (player->GetEntwatchHudMode() == Hud_On) message += ": " + row.owner; } + const int slot = player->GetPlayerSlot().Get(); + if (slot >= 0 && slot < MAXPLAYERS) + { + auto& cache = s_cache[slot]; + const int handle = text->GetHandle().ToInt(); + if (cache.handle == handle && cache.message == message) + return; + cache.handle = handle; + cache.message = message; + } text->AcceptInput("SetMessage", message.c_str()); } diff --git a/src/playermanager.cpp b/src/playermanager.cpp index ef228a0b..3acc16d4 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -759,10 +759,11 @@ int ZEPlayer::GetEntwatchHudStyle() return m_iEntwatchHudStyle < 0 ? EW_DefaultHudStyle() : m_iEntwatchHudStyle; } -void ZEPlayer::SetEntwatchHudStyle(int style) +void ZEPlayer::SetEntwatchHudStyle(int style, bool bSave) { m_iEntwatchHudStyle = style >= -1 && style <= 1 ? style : -1; - g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_HUD_STYLE, m_iEntwatchHudStyle); + if (bSave) + g_pUserPreferencesSystem->SetPreferenceInt(m_slot.Get(), EW_PREF_HUD_STYLE, m_iEntwatchHudStyle); CreateEntwatchHud(); } @@ -1958,4 +1959,4 @@ void CPlayerManager::FullUpdateAllClients() FOR_EACH_VEC(*pClients, i) (*pClients)[i]->ForceFullUpdate(); -} +} \ No newline at end of file diff --git a/src/playermanager.h b/src/playermanager.h index b5ce403d..f15deedc 100644 --- a/src/playermanager.h +++ b/src/playermanager.h @@ -276,17 +276,17 @@ class ZEPlayer void SetActiveZRClass(std::shared_ptr pZRModel) { m_pActiveZRClass = pZRModel; } void SetActiveZRModel(std::shared_ptr pZRClass) { m_pActiveZRModel = pZRClass; } void SetEntwatchHudMode(int iMode); - void SetEntwatchHudStyle(int style); + void SetEntwatchHudStyle(int style, bool bSave = true); int GetEntwatchHudStyle(); void CreateEntwatchWorldHud(); void SetPointOrient(CPointOrient* pOrient) { m_hPointOrient.Set(pOrient); } void SetEntwatchHud(CPointWorldText* pWorldText) { m_hEntwatchHud.Set(pWorldText); } void SetEntwatchHudColor(Color colorHud); void SetEntwatchHudPos(float x, float y); - void SetEntwatchPanoramaHudPos(int x, int y); + void SetEntwatchPanoramaHudPos(int x, int y, bool bSave = true); int GetEntwatchPanoramaHudX() const { return m_iEntwatchPanoramaX; } int GetEntwatchPanoramaHudY() const { return m_iEntwatchPanoramaY; } - void SetEntwatchPanoramaHudSize(int size); + void SetEntwatchPanoramaHudSize(int size, bool bSave = true); int GetEntwatchPanoramaHudSize() const { return m_iEntwatchPanoramaSize; } void SetEntwatchHudSize(float flSize); void SetTopDefenderStatus(bool bStatus) { m_bTopDefender = bStatus; } @@ -513,4 +513,4 @@ class CPlayerManager extern CPlayerManager* g_playerManager; -void PrecacheBeaconParticle(IEntityResourceManifest* pResourceManifest); +void PrecacheBeaconParticle(IEntityResourceManifest* pResourceManifest); \ No newline at end of file diff --git a/src/user_preferences.cpp b/src/user_preferences.cpp index d603f94a..d4121f07 100644 --- a/src/user_preferences.cpp +++ b/src/user_preferences.cpp @@ -138,10 +138,10 @@ void CUserPreferencesSystem::OnPutPreferences(int iSlot) // Set EntWatch player->SetEntwatchHudMode(iEntwatchMode); - player->SetEntwatchHudStyle(GetPreferenceInt(iSlot, EW_PREF_HUD_STYLE, -1)); + player->SetEntwatchHudStyle(GetPreferenceInt(iSlot, EW_PREF_HUD_STYLE, -1), false); player->SetEntwatchHudPos(flEntwatchHudposX, flEntwatchHudposY); - player->SetEntwatchPanoramaHudPos(GetPreferenceInt(iSlot, EW_PREF_PANORAMA_X, EW_PANORAMA_X_DEFAULT), GetPreferenceInt(iSlot, EW_PREF_PANORAMA_Y, EW_PANORAMA_Y_DEFAULT)); - player->SetEntwatchPanoramaHudSize(GetPreferenceInt(iSlot, EW_PREF_PANORAMA_SIZE, EW_PANORAMA_SIZE_DEFAULT)); + player->SetEntwatchPanoramaHudPos(GetPreferenceInt(iSlot, EW_PREF_PANORAMA_X, EW_PANORAMA_X_DEFAULT), GetPreferenceInt(iSlot, EW_PREF_PANORAMA_Y, EW_PANORAMA_Y_DEFAULT), false); + player->SetEntwatchPanoramaHudSize(GetPreferenceInt(iSlot, EW_PREF_PANORAMA_SIZE, EW_PANORAMA_SIZE_DEFAULT), false); player->SetEntwatchHudColor(ewHudColor); player->SetEntwatchHudSize(flEntwatchHudSize); EW_UpdateHud(); @@ -321,4 +321,4 @@ void CUserPreferencesREST::StorePreferences(uint64 iSteamId, UserPrefsMap_t& pre cb(iSteamId, preferencesMap); preferencesMap.clear(); }); -} +} \ No newline at end of file From 6c5280eff27a75578e123f75a03da94f670caa32 Mon Sep 17 00:00:00 2001 From: tojba <1348625+tojba@users.noreply.github.com> Date: Sun, 18 Oct 2026 17:38:17 +0000 Subject: [PATCH 5/5] Default entwatch_hud_style to world text Panorama still needs more testing on real servers and maps, and requires the packaged panorama resources on server and clients, so keep the existing world-text renderer as the default. Panorama stays opt-in via entwatch_hud_style 1 or !hudstyle new. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01XagcvZZBfqEnBVSzXh88yb --- cfg/cs2fixes/cs2fixes.cfg | 2 +- src/entwatch_hud.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cfg/cs2fixes/cs2fixes.cfg b/cfg/cs2fixes/cs2fixes.cfg index 076067ed..0cd747a8 100644 --- a/cfg/cs2fixes/cs2fixes.cfg +++ b/cfg/cs2fixes/cs2fixes.cfg @@ -162,7 +162,7 @@ entwatch_enable 0 // Whether to enable EntWatch features entwatch_auto_filter 1 // Whether to automatically block non-item holders from triggering uses entwatch_clantag 1 // Whether to set item holder's clantag and set 9999 score entwatch_hud 1 // Whether to enable the EntWatch hud and related commands -entwatch_hud_style 1 // Default renderer: 0 = world text, 1 = Panorama; players can use !hudstyle +entwatch_hud_style 0 // Default renderer: 0 = world text, 1 = Panorama (experimental, needs the packaged panorama files on server and clients, still being tested on more servers/maps); players can use !hudstyle entwatch_score 9999 // Score to give item holders (0 = dont change score at all) Requires entwatch_clantag 1 entwatch_glow 1000 // Distance that dropped item weapon glow will be visible (0 = glow disabled) entwatch_glow_team 0 // Whether dropped item glow is only visible to the team the item belongs to (0 = glow to all players) diff --git a/src/entwatch_hud.cpp b/src/entwatch_hud.cpp index 5a556d70..56bc7e97 100644 --- a/src/entwatch_hud.cpp +++ b/src/entwatch_hud.cpp @@ -32,7 +32,7 @@ #include #include -CConVar g_cvarEntwatchHudStyle("entwatch_hud_style", FCVAR_NONE, "Default HUD renderer: 0 = world text, 1 = Panorama", 1, true, 0, true, 1); +CConVar g_cvarEntwatchHudStyle("entwatch_hud_style", FCVAR_NONE, "Default HUD renderer: 0 = world text, 1 = Panorama", 0, true, 0, true, 1); CConVar g_cvarEntwatchPanoramaDebug("cs2f_entwatch_panorama_debug", FCVAR_NONE, "Log EntWatch HUD creation and Panorama resource diagnostics", false); namespace