Dodaje na minimapie dodatkowy okrąg pokazujący odległość, z jakiej Twój czołg może zostać zauważony przez przeciwnika.
Granica jest prosta: wszystko co jest w descriptorze pojazdu (transmitowanym przez serwer w strCompactDescr) bierzemy automatycznie. Reszta jest manualnym toggle.
| Element | Auto / manualne | Skąd |
|---|---|---|
| Hull / turret / gun / engine / radio | ✅ auto | descr.turret.circularVisionRadius itd. |
| Coated Optics przeciwnika | ✅ auto | descr.miscAttrs.circularVisionRadiusFactor (już z optyką) |
| Stereoscope przeciwnika | ✅ auto | descr.optionalDevices (Stereoscope class) |
| Enhancements / dyrektywy w slotach equipment | ❌ manual toggle (Numpad 1) | proste *1.025 na auto-wykryte sprzęty |
| Ulepszenia polowe (post-progression) WŁASNE | ✅ auto | Vehicle.getDescr woła VehicleDescr(..., extData=self) → __applyExternalData woła installModifications |
| Ulepszenia polowe ENEMY (VR) | ❌ manual toggle (Numpad 0) — BETA | per-czołg tabelka w configu (pickerFieldUpgradeVR); server transmituje vehPostProgression tylko właścicielowi |
| Camo net na własnym czołgu | ✅ auto, aktywne po 3s | descr.optionalDevices (CamouflageNet class) |
| Tryby siege (CS-63 itp.) | ✅ auto | CompositeVehicleDescriptor w silniku |
| Kara za strzał | ✅ auto | hook na Avatar.shoot + miscAttrs.invisibilityFactorAtShot |
| Skille załogi (BIA+Recon+SitAware bundled) | ❌ manual toggle (Numpad 4) | serwer nie wysyła |
| Combat Rations | ❌ manual toggle (Numpad 7) | serwer nie wysyła aktywnego stanu |
W praktyce: po wybraniu enemy pickerem, jego VR od razu zawiera Coated Optics + Stereoscope (jeśli są na tym czołgu — odczytane z descriptora). Toggle perków / consumables / dyrektyw / field-upgradów nakładasz tylko gdy zakładasz że enemy je faktycznie ma.
Weryfikacja własnych field upgrades: naciśnij NumpadEnter (status snapshot) — w chacie pojawi się m.in. linia
myVR: base=410m * factor=1.103imyCamo: base(...) + add=0.025. Jeślifactor>1.0lubadd>0.0, ulepszenia polowe są naliczone w descriptorze.
- Czerwony w ruchu (camo
invMoving) - Zielony w postoju (camo
invStill) - Ciemnozielony w postoju 3s+ z aktywną siatką maskującą (camo
invStill + camoNetBonus) - Pomarańczowy ~3s po strzale (camo
* invisibilityFactorAtShot) - Czołgi lekkie / niektóre kołowe — w XML mają
invMoving == invStill, więc okrąg po prostu nie zmienia rozmiaru. Bez specjalnego case'u. - Czołgi z trybem siege (CS-63, S-Conqueror, italian heavies) — silnik gry sam podmienia descriptor (
CompositeVehicleDescriptor) na właściwy tryb, więc mod automatycznie używa odpowiedniego camo dla obecnego trybu.
camo = max(0, (base * vehicleFactor * crewBonus
+ invisibilityBaseAdditive + invisibilityAdditiveTerm)
* invisibilityMultFactor)
spot_distance = enemyViewRange * (1 - camo)
spot_distance ∈ [50 m, 445 m]
base = vehicle.typeDescriptor.type.invisibility[moving|still] (z XML czołgu).
vehicleFactor, invisibilityBaseAdditive, invisibilityAdditiveTerm, invisibilityMultFactor — z vehicle.typeDescriptor.miscAttrs (zbiorcze modyfikatory wieży / sprzętu / perków).
crewBonus — przybliżona poprawka na skill Camouflage załogi (configurable, domyślnie 1.05).
Trzy źródła w kolejności priorytetu:
- Picker aktywny — bierzemy descriptor wybranego enemy (
strCompactDescr), liczymy bazowy VR z wieży, dodajemy auto-wykryte (Optics, Stereoscope) i opcjonalnie zaznaczone toggle (Rations, Crew Perks, Directives, Field Upgrades). useOwnViewRange: true(default, picker nieaktywny) — bierzemy własny VR zfeedback.getVehicleAttrs()['circularVisionRadius']. Serwer go syncuje (VEHICLE_ATTRS_TO_SYNC). Ten VR ma już naliczoną załogę, optykę, lornę itd.useOwnViewRange: false— używamyenemyViewRangeFallback(domyślnie 445 m = max w grze).
Gra w UI dodaje wszystkie bonusy addytywnie wobec baseline (base_VR × rations). Mod robi tak samo:
1. base_vr ← descr.turret.circularVisionRadius
2. JEŚLI Field Upgrades ON i czołg w tabelce:
base_vr ← min(base_vr * (1 + upgrade%), 445m)
3. baseline ← base_vr * (Rations ? 1.0430 : 1.0)
4. final ← baseline
+ baseline * (optics_factor * directive_factor - 1) # auto z descriptora
+ baseline * (stereo_factor * directive_factor - 1) # auto z descriptora (jeśli ma)
+ baseline * (CrewPerks_factor - 1) # toggle, ON default
Mnożniki (skalibrowane empirycznie wobec UI gry):
| toggle | klawisz | config | default | znaczenie |
|---|---|---|---|---|
| Rations | Numpad 7 | pickerVRBonusRations |
1.0430 |
default ON — racje +4.30% |
| CrewPerks bundled (BIA+Recon+SitAware) | Numpad 4 | pickerVRBonusCrewPerks |
1.0953 |
default ON — łącznie +9.53% |
| Directives na sprzęt | Numpad 1 | pickerVRBonusDirective |
1.0250 |
default OFF — mnożnik na auto-wykryte (optics, stereo) |
| Field Upgrades VR | Numpad 0 | pickerFieldUpgradeVR |
per-czołg tabelka | default OFF — BETA |
Plus auto-detekcja z descriptora przeciwnika (zawsze, niezależnie od toggle):
- Coated Optics (basic): ×1.10
- Coated Optics (deluxe / fioletowa): ×1.135
- Coated Optics (bond / improved): ~×1.14 (tank-zależne)
- Stereoscope (basic): ×1.25 (założenie: zawsze aktywna; toggle przez
pickerAssumeStereoscope)
Verifikacja na czołgu z bazowym VR 340m, 100% załoga:
- BIA alone: +8.6m ✓
- Recon: +9.79m ≈ +9.81 (gra) ✓
- SitAware: +15.33m ≈ +15.34 (gra) ✓
- Rations: +14.6m ✓
- Optyka deluxe: +47.87m (liczona z
(340+rations)*0.135) ✓
Server NIE wysyła vehPostProgression przeciwnika (jest to MY_VEHICLE scope). Mod używa ręcznie utrzymywanej tabelki per-czołg w configu:
"pickerFieldUpgradeVR": {
"Rhm.-B. WT": 0.02,
"Obj. 907": 0.03,
"Jg.Pz. E 100": 0.02
},
"pickerFieldUpgradeCap": 445.0Mechanika: po wciśnięciu Numpad 0 (toggle ON), mod szuka czołgu po shortName w tabelce. Jeśli znajdzie, mnoży base_vr przez (1 + %) z capem 445m, przed dodaniem rations/perks/directives. Czołgi spoza tabelki = 0% (toggle nie robi nic). EBR 105 nie ma w post-progression żadnego upgradeu na VR, więc go w tabelce nie ma.
Dopisuj własne wpisy — sprawdź shortName przez Numpad * (dump descryptora wybranego enemy do python.log), znajdź wpis i dodaj do tabelki w spotmeter.json. Np. dla czołgu z +2.5% upgradeu na VR: "NazwaCzolgu": 0.025.
Dlaczego BETA: lista czołgów z VR upgrades w post-progression nie jest wyczerpująco udokumentowana publicznie, więc tabelka jest aktualnie bardzo skromna. Jeśli zauważysz zaniżony radius na konkretnym czołgu enemy, to znak że ma upgradeu na VR i trzeba go dopisać.
Pobierz spotmeter-v<wersja>.zip z GitHub Releases. W środku:
spotmeter-v<wersja>.wotmod→ wrzuć do<WoT>/mods/2.2.1.3/spotmeter.json(opcjonalny) → wrzuć do<WoT>/mods/configs/INSTALL.txt— szczegółowa instrukcja krok po kroku
Gra automatycznie ładuje wszystkie .wotmod z mods/<wersja>/ po starcie. Bez configu mod używa sensownych domyślnych wartości.
+-----+-----+-----+-----+
| | / | * | - | *=dump descryptor enemy do log
+-----+-----+-----+-----+
| 7 | 8 | 9 | + | 7=rations 8=prev 9=overlay-toggle
+-----+-----+-----+-----+
| 4 | 5 | 6 | | 4=crew-perks 5=clear-picker
+-----+-----+-----+-----+
| 1 | 2 | 3 |Enter| 1=directives 2=next Enter=full-status
+-----+-----+-----+-----+
| 0 | . | 0=field-upgrades .=reload-config
+-----+-----+-----+-----+
| akcja | klawisz | config | default state |
|---|---|---|---|
| następny przeciwnik | Numpad 2 | pickerNextKey |
— |
| poprzedni przeciwnik | Numpad 8 | pickerPrevKey |
— |
| wyczyść picker | Numpad 5 | pickerClearKey |
— |
| toggle Rations | Numpad 7 | pickerRationsKey |
ON |
| toggle Crew Perks (BIA+Recon+SitAware) | Numpad 4 | pickerCrewPerksKey |
ON |
| toggle Directives na sprzęt | Numpad 1 | pickerDirectivesKey |
OFF |
| toggle Field Upgrades VR (BETA) | Numpad 0 | pickerFieldUpgradesKey |
OFF |
| toggle overlay tekstu (auto) | Numpad 9 | overlayToggleKey |
(config) |
| pełen status snapshot | NumpadEnter | overlayPrintNowKey |
— |
| dump descriptor enemy do logu | Numpad * | pickerDiagDumpKey |
— |
| reload configu | NumpadPeriod | reloadKey |
— |
Działa przy NumLock włączonym i wyłączonym.
| pole | default | opis |
|---|---|---|
enabled |
true |
wyłącza moda bez odinstalowywania |
useOwnViewRange |
true |
używa Twojego VR jako założonego VR przeciwnika (gdy picker nieaktywny) |
enemyViewRangeFallback |
445.0 |
VR używany kiedy useOwnViewRange = false |
crewCamoBonus |
1.05 |
przybliżenie bonusu skilla Camouflage załogi |
colorMoving |
0xFF6347 |
kolor okręgu w ruchu (tomato) |
colorStill |
0x32CD32 |
kolor okręgu w postoju (lime) |
colorAfterShot |
0xFFA500 |
kolor okręgu po strzale (orange) |
colorCamoNet |
0x228B22 |
kolor okręgu gdy siatka aktywna (forestGreen) |
alpha |
70 |
przezroczystość 0–100 |
tickInterval |
0.2 |
jak często aktualizować (s) |
movingSpeedThreshold |
0.5 |
prędkość uznawana za ruch (m/s) |
applyFirePenalty |
true |
po strzale aplikuje * invisibilityFactorAtShot |
fireRevealDuration |
3.0 |
czas trwania kary za strzał (s) |
applyCamoNet |
true |
uwzględnia siatkę maskującą po camoNetActivateSec w postoju |
camoNetActivateSec |
3.0 |
czas postoju do aktywacji siatki (s) |
camoNetFallbackBonus |
0.05 |
bonus jeśli odczyt z descriptora padnie |
pickerEnabled |
true |
włącza picker przeciwnika |
pickerVRBonusRations |
1.0430 |
mnożnik gdy toggle Rations ON |
pickerVRBonusCrewPerks |
1.0953 |
mnożnik gdy toggle Crew Perks ON (BIA+Recon+SitAware bundled) |
pickerVRBonusDirective |
1.0250 |
mnożnik na auto-wykryte sprzęty gdy toggle Directives ON |
pickerFieldUpgradeVR |
per-tank dict | BETA, mapuje shortName → % VR upgrade |
pickerFieldUpgradeCap |
445.0 |
cap na base_vr po zastosowaniu upgrade'u (m) |
pickerAssumeStereoscope |
true |
jeśli enemy ma lornetkę, zakłada że jest aktywna |
pickerStereoscopeFallback |
1.25 |
mnożnik VR jeśli odczyt z descriptora padnie |
pickerMarker |
"● " |
prefix nazwy wybranego przeciwnika |
pickerIncludeDeadEnemies |
false |
czy uwzględniać martwych w cyklu |
overlayEnabled |
true |
włącza overlay tekstu (chat-line nad minimapą) |
overlayShowOnTickChange |
true |
automatycznie pokazuje przy istotnej zmianie radiusa |
overlayMinRadiusDelta |
15.0 |
próg zmiany w m do auto-display |
pickerNextKey |
KEY_NUMPAD2 |
następny przeciwnik |
pickerPrevKey |
KEY_NUMPAD8 |
poprzedni przeciwnik |
pickerClearKey |
KEY_NUMPAD5 |
wyczyść picker |
pickerRationsKey |
KEY_NUMPAD7 |
toggle Rations |
pickerCrewPerksKey |
KEY_NUMPAD4 |
toggle Crew Perks (BIA+Recon+SitAware) |
pickerDirectivesKey |
KEY_NUMPAD1 |
toggle Directives |
pickerFieldUpgradesKey |
KEY_NUMPAD0 |
toggle Field Upgrades (BETA) |
pickerDiagDumpKey |
KEY_NUMPADSTAR |
dump enemy descriptor do python.log |
overlayToggleKey |
KEY_NUMPAD9 |
toggle overlay tekstu |
overlayPrintNowKey |
KEY_NUMPADENTER |
pokaż pełen status snapshot |
reloadKey |
KEY_NUMPADPERIOD |
reload configu |
logCalcDetails |
false |
wypisuje camo/radius/state do python.log |
Nazwy klawiszy: nazwy z modułu Keys (np. KEY_F8, KEY_F7, KEY_HOME, KEY_INSERT). Pusty string = bez hotkeya.
Sprawdziłem w zdekompilowanych plikach scripts/common/constants.py i scripts/client/Avatar.py:
- View range własny: tak,
circularVisionRadius(m) jest jawnie syncowany z serwerem (VEHICLE_ATTRS_TO_SYNC). Mamy go wfeedback.getVehicleAttrs()w trakcie bitwy. - Camouflage / invisibility: NIE jest syncowane jako pojedyncza liczba. Klient liczy go sam z deskryptora pojazdu (
computeBaseInvisibility+getInvisibilitywscripts/common/items/utils.py). Wszystkie składniki potrzebne do tego są w pełni dostępne klientowi z deskryptora czołgu. strCompactDescrprzeciwnika: tak, pełny binarny descriptor każdego pojazdu (gui/battle_control/arena_info/arena_vos.py). Po dekodowaniu mamy: hull/turret/gun/engine/radio, zainstalowany sprzęt (binokle, optyka, dyrektywy w slotach), camouflage skin/styl, tier/klasa/rola/max HP.vehPostProgressionprzeciwnika: NIE — server-side tagged jakoMY_VEHICLEwVehicle.def. Ulepszenia polowe enemy są niewidoczne dla klienta. Stąd toggle Numpad 0 + ręczna tabelka.- Skille załogi przeciwnika (BIA, Recon, SitAware): NIE — stąd toggle Numpad 4.
- Aktywne consumables przeciwnika (Rations): NIE — stąd toggle Numpad 7.
Innymi słowy: mod nie odczytuje żadnej informacji do której nie miałby normalnie dostępu. Przy własnym czołgu liczy ze wszystkiego co dostarcza descriptor + sync. Przy enemy: descriptor + manualne toggle dla rzeczy server-private.
- Mod jest legalny w świetle Wargaming Fair Play Policy. WG od dawna toleruje (i zalicza do oficjalnych przykładów) okręgi widoczności na minimapie — patrz np. domyślne ustawienia gry
MINIMAP_VIEW_RANGE/MINIMAP_MAX_VIEW_RANGE/MINIMAP_MIN_SPOTTING_RANGE(są to opcje wbudowane). XVM, Aslain's modpack i inne ogólnodostępne packi zawierają od lat funkcję "Spot Range Circle" — działa to dokładnie tak jak ten mod. - Zakazane są mody, które (a) pokazują pozycje przeciwników, których normalnie nie widzisz, (b) automatyzują celowanie / poruszanie się, (c) odczytują dane serwerowe, do których klient nie ma normalnie dostępu, (d) omijają płatne funkcje gry. Ten mod NIC z tej listy nie robi.
- Linki: WG EU Fair Play Policy — kategoria "Allowed mods" obejmuje minimap improvements/markers.
W bitwie naciśnij NumpadPeriod (lub klawisz z reloadKey) — config wczytuje się ponownie i okrąg uwzględnia nowe wartości w czasie 1 ticka (0.2 s). Pozwala iterować nad kolorami / VR / crewCamoBonus bez zamykania bitwy. Wymaga NumLock ON.
- Loader gry (
scripts/client/gui/mods/__init__.py) ładuje modułmod_spotmeter. - Monkey-patchuje
PersonalEntriesPlugin._invalidateMarkupzgui/Scaleform/daapi/view/battle/shared/minimap/plugins.py. - Tworzy drugi entry typu
VIEW_RANGE_CIRCLES(silnik nie limituje liczby; każdy ma własny ID) i steruje nim niezależnie od Twoich istniejących okręgów. - Co
tickIntervalsekund:- czyta
vehicle.getSpeed()→ moving/still - czyta
vehicle.typeDescriptor.miscAttrs→ modyfikatory invisibility - czyta
feedback.getVehicleAttrs()['circularVisionRadius']→ własny VR (jeśliuseOwnViewRange) - liczy camo i radius spotu
- wywołuje na Flashu
as_addDynamicViewRange/as_updateDynRangez (color, alpha, radius)
- czyta
- Sprząta entry i callbacki w
_hideMarkup,__onPostMortemSwitched,stop.
- Numpad 0 toggle = ulepszenia polowe na VR (BETA)
- per-czołg tabelka
pickerFieldUpgradeVRw configu (shortName→ %) - pre-fill: Rhm.-B. WT (+2%), Obj. 907 (+3%), Jg.Pz. E 100 (+2%)
- cap 445m
- EBR 105 = brak (nie ma takiego upgradeu)
- Mnożniki dla rations/crew/directive zmierzone wobec UI gry (czołg z bazowym VR 340m)
- Game-UI matching additive model: wszystko addytywne wobec
(base_vr × rations)baseline - BIA+Recon+SitAware bundled w jeden toggle (nie da się ich w grze rozdzielić w UI VR)
- Cały picker przeniesiony na klawiaturę numeryczną (działa NumLock ON i OFF)
- 4 toggle'e dla VR enemy: Rations / Crew Perks bundle / Directives / Field Upgrades
- Overlay tekstu nad minimapą (chat-line w battle-message-feed)
- NumpadEnter — pełen status snapshot
- Numpad
*— dump descryptora enemy dopython.log - NumpadPeriod — hot-reload configu
- Stereoscope (lornetka) w pickerze — gdy wykryta w
descr.optionalDevices, automatycznie aplikuje czynnikcircularVisionRadiusFactor.getActiveValue(level). Worst-case assumption: lorna jest zawsze aktywna. Toggle przezpickerAssumeStereoscope. - CamouflageNet (siatka) dla własnego czołgu — silnik gry trackuje
_LAST_MOVEMENT_TIME. PocamoNetActivateSec(default3.0s) bez ruchu siatka się aktywuje i bonusinvisibilityBonusjest dodawany. Kolor okręgu zmienia się na ciemnozielony.
W bitwie wybierasz konkretnego przeciwnika hotkeyami i okrąg dostosowuje się do jego VR. Server wysyła pełny strCompactDescr każdego pojazdu od początku bitwy, więc dekodujemy lokalnie.
- Kara za strzał — hook na
PlayerAvatar.shoot()ishootDualGun(). PrzezfireRevealDuration(3 s) po strzale aplikujemycamo *= invisibilityFactorAtShot. - Tryby (CS-63, S-Conqueror itp.) — silnik gry obsługuje to automatycznie przez
CompositeVehicleDescriptor. - EBR / wheeled — bez specjalnego case'u; XML czołgu ma
invMoving == invStill.
- Bonus za roślinność (foliage) — częściowo obliczany serwerowo, wymaga raycastów do każdego krzaka. Złożoność niewspółmierna do zysku.
- Pokazywanie czyjegoś camo / VR jako liczby na ekranie — to "softcheat" w niektórych interpretacjach. Mod liczy tylko własne wartości i pokazuje wynik geometrycznie.
Wymaga Python 2.7 (do kompilacji .pyc zgodnego z silnikiem WoT-a, Anaconda env py27) i Python 3.10 (do uruchomienia build skryptu).
<python2.7> -c "import py_compile; py_compile.compile('src/mod_spotmeter.py', cfile='build/mod_spotmeter.pyc', dfile='mod_spotmeter.py', doraise=True)"Gdzie <python2.7> to ścieżka do Pythona 2.7 (np. python2.7 na systemach gdzie jest w PATH, albo pełna ścieżka do python.exe z conda/miniforge env-u o Python 2.7). Parametr dfile='mod_spotmeter.py' jest ważny — bez niego ścieżka source (zawierająca lokalną strukturę katalogów) zostaje zaszyta w .pyc i jest widoczna po unzipowaniu .wotmod.
py -3.10 packaging/build_wotmod.pyOutput do dist/:
spotmeter-v<wersja>.wotmod— sam mod (domods/<wersja>/)spotmeter.json— domyślny config (domods/configs/)INSTALL.txt— instrukcjaspotmeter-v<wersja>.zip— wszystko w jednym do dystrybucji
Wersja jest czytana z packaging/meta.xml — zaktualizuj tam przed kolejnym buildem.
cp build/mod_spotmeter.pyc "<WoT>/res_mods/2.2.1.3/scripts/client/gui/mods/"
cp src/spotmeter.json "<WoT>/mods/configs/"res_mods/ ma priorytet nad mods/<wersja>/*.wotmod więc lokalna zmiana w res_mods/ wygrywa nad zainstalowaną wersją release'ową.