merge
This commit is contained in:
commit
6cfd47e80d
19 files changed
+1564
-255
No files matched your search
+16
-6
@@ -144,14 +144,15 @@ Networking is enabled for Windows and the Emscripten web client:
|
|||||||
- `proj-web/CMakeLists.txt` defines `NETWORK`, compiles the shared protocol,
|
- `proj-web/CMakeLists.txt` defines `NETWORK`, compiles the shared protocol,
|
||||||
replica, and remote-host code, and links Emscripten's `websocket.js` library.
|
replica, and remote-host code, and links Emscripten's `websocket.js` library.
|
||||||
`WebsocketGameClient.cpp` selects the browser WebSocket API on Emscripten; it
|
`WebsocketGameClient.cpp` selects the browser WebSocket API on Emscripten; it
|
||||||
does not use Boost.Asio or Boost.Beast there.
|
does not use Boost.Asio, Boost.Beast, or OpenSSL there. The browser performs
|
||||||
- `wss://` (TLS) is supported by the Windows client only. `proj-windows` also defines
|
the TLS handshake and certificate/hostname validation for `wss://`.
|
||||||
|
- `proj-windows` defines
|
||||||
`NETWORK_TLS` and links static OpenSSL 3.4.1, which CMake downloads and builds
|
`NETWORK_TLS` and links static OpenSSL 3.4.1, which CMake downloads and builds
|
||||||
automatically at configure time (`cmake/ThirdParty.cmake`, section 12) using a
|
automatically at configure time (`cmake/ThirdParty.cmake`, section 12) using a
|
||||||
downloaded portable Strawberry Perl and the nmake from the installed Visual Studio
|
downloaded portable Strawberry Perl and the nmake from the installed Visual Studio
|
||||||
(located through `vswhere`). Builds go to `thirdparty/openssl-3.4.1/install-Debug`
|
(located through `vswhere`). Builds go to `thirdparty/openssl-3.4.1/install-Debug`
|
||||||
and `install-Release`; later configures skip them. `NETWORK_TLS` unset (server tests)
|
and `install-Release`; later configures skip them. `NETWORK_TLS` unset (server tests)
|
||||||
means `wss://` endpoints fail with a logged error.
|
means native `wss://` endpoints fail with a logged error.
|
||||||
- Linux and Android builds do not define `NETWORK` and do not compile the
|
- Linux and Android builds do not define `NETWORK` and do not compile the
|
||||||
network transport.
|
network transport.
|
||||||
|
|
||||||
@@ -170,15 +171,24 @@ Run it from the repository root:
|
|||||||
.\server\build\Debug\GameServer.exe --campaign battle_zone_multiplayer --location uni_exterior
|
.\server\build\Debug\GameServer.exe --campaign battle_zone_multiplayer --location uni_exterior
|
||||||
```
|
```
|
||||||
|
|
||||||
The listener defaults to `0.0.0.0:8080`. It can be changed with:
|
The listener defaults to `0.0.0.0:8080` and serves plain WebSocket traffic. It can be changed with:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
--address IP
|
--address IP
|
||||||
--port N
|
--port N
|
||||||
```
|
```
|
||||||
|
|
||||||
Launch the Windows game and select `battle_zone_multiplayer`. The client connects to
|
Launch the Windows game and select `battle_zone_multiplayer`. The production client
|
||||||
`127.0.0.1:8080`. Selecting another campaign continues to use the local server.
|
default is `wss://api.shadowoverbishkek.com/server001/`; the endpoint is currently
|
||||||
|
configured in `Game.cpp`. Selecting another campaign continues to use the local
|
||||||
|
server.
|
||||||
|
|
||||||
|
For the Web build, serve the page over HTTPS and ensure the TLS-terminating reverse
|
||||||
|
proxy presents a valid certificate for `api.shadowoverbishkek.com`, accepts the
|
||||||
|
WebSocket upgrade at `/server001/`, and forwards the upgraded connection to the
|
||||||
|
plain server listener. A page served over HTTPS cannot connect to a `ws://` endpoint
|
||||||
|
because browsers block that mixed-content request. Certificate and hostname errors
|
||||||
|
are enforced by the browser and cannot be bypassed by the C++ client.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# Hostile NPC Behavior
|
||||||
|
|
||||||
|
## Authority and update order
|
||||||
|
|
||||||
|
Hostile NPC behavior is simulated by `LocationGameState` and
|
||||||
|
`CharacterState`. Rendering objects do not select targets and do not change
|
||||||
|
NPC combat state.
|
||||||
|
|
||||||
|
During each authoritative simulation tick:
|
||||||
|
|
||||||
|
1. The location gathers the enabled players and NPCs visible to the
|
||||||
|
simulation.
|
||||||
|
2. Each hostile NPC selects or retains a player target.
|
||||||
|
3. Every character advances using the same tick-start observations.
|
||||||
|
4. Movement reservations and attack damage are resolved deterministically.
|
||||||
|
5. Navigation recovery events are applied by `InternalGameServer`.
|
||||||
|
|
||||||
|
The resulting state and recovery decisions are replicated through the existing
|
||||||
|
WebSocket lockstep stream. NPC target changes are simulation consequences, not
|
||||||
|
client commands.
|
||||||
|
|
||||||
|
## Eligible players and nearest selection
|
||||||
|
|
||||||
|
An eligible target must:
|
||||||
|
|
||||||
|
- exist in the campaign player map;
|
||||||
|
- be enabled;
|
||||||
|
- have positive health; and
|
||||||
|
- be within the NPC's `visibleRange` when a new target is selected.
|
||||||
|
|
||||||
|
Distance is measured in the X/Z plane. If two players are equally close,
|
||||||
|
their stable player IDs are compared lexicographically. This gives every
|
||||||
|
lockstep replica the same result regardless of hash-map iteration order.
|
||||||
|
|
||||||
|
## Ordinary target locking
|
||||||
|
|
||||||
|
Once a hostile NPC has a valid target, it keeps that target during ordinary
|
||||||
|
ticks. The target remains locked even if it moves outside `visibleRange`.
|
||||||
|
The lock ends when the player dies or becomes disabled.
|
||||||
|
|
||||||
|
When a lock ends, the NPC selects the nearest eligible player in range. If no
|
||||||
|
player qualifies, it clears the attack target, leaves combat state, and
|
||||||
|
requests a route to its `homePosition`.
|
||||||
|
|
||||||
|
## Movement blockage and target reconsideration
|
||||||
|
|
||||||
|
NPC movement uses a retry schedule after a character blocks its path. The
|
||||||
|
blocked NPC first stops and waits for its deterministic navigation retry
|
||||||
|
cooldown. When the retry event emits `forceNavigationReplan`, the authoritative
|
||||||
|
location state performs a fresh target selection across all eligible players.
|
||||||
|
|
||||||
|
This blocked-replan selection differs from ordinary target locking:
|
||||||
|
|
||||||
|
- the current target is not privileged;
|
||||||
|
- the nearest eligible player may remain the target;
|
||||||
|
- a nearer eligible player replaces the current target;
|
||||||
|
- the route is rebuilt from the NPC's current position toward the selected
|
||||||
|
player's current position.
|
||||||
|
|
||||||
|
If no eligible player is in range during blocked recovery, the NPC clears its
|
||||||
|
stale chase target and returns toward its home position instead. The blocker is
|
||||||
|
still passed to path planning so the immediate replan does not route through
|
||||||
|
the character that caused the recovery event.
|
||||||
|
|
||||||
|
## Death, disconnect, and attack safety
|
||||||
|
|
||||||
|
Dead or disabled players are excluded from target acquisition. A target that
|
||||||
|
dies or disconnects is therefore invalidated on the next authoritative
|
||||||
|
selection pass, and the NPC either switches to another player or returns home.
|
||||||
|
|
||||||
|
Attack impacts are also validated at application time. Damage is ignored if
|
||||||
|
the recorded target no longer exists, is disabled, or has already reached
|
||||||
|
zero health. This prevents a queued animation impact from damaging a stale
|
||||||
|
target.
|
||||||
|
|
||||||
|
## Regression expectations
|
||||||
|
|
||||||
|
The state and pathfinding tests should preserve these guarantees:
|
||||||
|
|
||||||
|
- nearest in-range player selection is deterministic;
|
||||||
|
- a valid ordinary lock is retained;
|
||||||
|
- blocked NPC recovery can replace the target and rebuild the chase route;
|
||||||
|
- no-target blocked recovery clears combat and routes home;
|
||||||
|
- dead and disabled players cannot be selected or damaged;
|
||||||
|
- retry cooldowns and blocker identity remain deterministic.
|
||||||
@@ -174,6 +174,11 @@ if(WIN32)
|
|||||||
../src/game_server/RemoteGameServerHost.h
|
../src/game_server/RemoteGameServerHost.h
|
||||||
../src/game_server/RemoteGameServerHost.cpp
|
../src/game_server/RemoteGameServerHost.cpp
|
||||||
)
|
)
|
||||||
|
if(MSVC)
|
||||||
|
set_source_files_properties(
|
||||||
|
../src/game_server/WebsocketGameClient.cpp
|
||||||
|
PROPERTIES COMPILE_OPTIONS "/bigobj")
|
||||||
|
endif()
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
ShadowOverBishkekDemo PRIVATE opengl32 ws2_32 mswsock)
|
ShadowOverBishkekDemo PRIVATE opengl32 ws2_32 mswsock)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
"campaigns": [
|
"campaigns": [
|
||||||
{
|
{
|
||||||
"id": "main",
|
"id": "main",
|
||||||
"title": { "ru": "Основная игра", "en": "Main Game" },
|
"title": {
|
||||||
|
"ru": "Основная игра",
|
||||||
|
"en": "Main Game"
|
||||||
|
},
|
||||||
"locations": [
|
"locations": [
|
||||||
"resources/config/locations/location_dorm.json",
|
"resources/config/locations/location_dorm.json",
|
||||||
"resources/config/locations/uni_exterior.json",
|
"resources/config/locations/uni_exterior.json",
|
||||||
@@ -17,12 +20,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "battle_zone",
|
"id": "battle_zone",
|
||||||
"title": { "ru": "Зона боя (одиночная)", "en": "Battle Zone (Single Player)" },
|
"title": {
|
||||||
|
"ru": "Зона боя (одиночная)",
|
||||||
|
"en": "Battle Zone (Single Player)"
|
||||||
|
},
|
||||||
"locations": [
|
"locations": [
|
||||||
"resources/config/locations/battle_zone_uni_exterior.json"
|
"resources/config/locations/battle_zone_korea.json"
|
||||||
],
|
],
|
||||||
"startLocation": "uni_exterior",
|
"startLocation": "park_korea",
|
||||||
"startMusic": "music/bishkek univer day.ogg",
|
"startMusic": "music/bishkek fight calm.ogg",
|
||||||
"startState": "resources/config/start_state_battle_zone_singleplayer.json",
|
"startState": "resources/config/start_state_battle_zone_singleplayer.json",
|
||||||
"quests": "resources/config/quests_battle_zone.json",
|
"quests": "resources/config/quests_battle_zone.json",
|
||||||
"tutorial": false,
|
"tutorial": false,
|
||||||
@@ -30,16 +36,24 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "battle_zone_multiplayer",
|
"id": "battle_zone_multiplayer",
|
||||||
"title": { "ru": "Зона боя (сетевая)", "en": "Battle Zone (Multiplayer)" },
|
"title": {
|
||||||
|
"ru": "Зона боя (сетевая)",
|
||||||
|
"en": "Battle Zone (Multiplayer)"
|
||||||
|
},
|
||||||
"locations": [
|
"locations": [
|
||||||
"resources/config/locations/battle_zone_uni_exterior.json"
|
"resources/config/locations/battle_zone_korea.json"
|
||||||
],
|
],
|
||||||
"startLocation": "uni_exterior",
|
"startLocation": "park_korea",
|
||||||
"startMusic": "music/bishkek univer day.ogg",
|
"startMusic": "music/bishkek fight calm.ogg",
|
||||||
"startState": "resources/config/start_state_battle_zone.json",
|
"startState": "resources/config/start_state_battle_zone.json",
|
||||||
"quests": "resources/config/quests_battle_zone.json",
|
"quests": "resources/config/quests_battle_zone.json",
|
||||||
"tutorial": false,
|
"tutorial": false,
|
||||||
"networkPlayerSlots": ["player", "player2"],
|
"networkPlayerSlots": [
|
||||||
|
"player1",
|
||||||
|
"player2",
|
||||||
|
"player3",
|
||||||
|
"player4"
|
||||||
|
],
|
||||||
"networkCompatibility": "battle-zone-lockstep-v5",
|
"networkCompatibility": "battle-zone-lockstep-v5",
|
||||||
"loadingScreen": "resources/w/ui/screen_loading.json"
|
"loadingScreen": "resources/w/ui/screen_loading.json"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"id": "uni_exterior",
|
"id": "park_korea",
|
||||||
"gameObjects": "resources/w/shelter/game_objects.json",
|
"gameObjects": "resources/w/shelter/game_objects.json",
|
||||||
"interactiveObjects": "resources/w/shelter/interactive_objects.json",
|
"interactiveObjects": "resources/w/shelter/interactive_objects.json",
|
||||||
"npcs": "resources/config/npcs_battle_zone.json",
|
"npcs": "resources/config/npcs_battle_zone.json",
|
||||||
@@ -161,6 +161,168 @@
|
|||||||
"hp": 35,
|
"hp": 35,
|
||||||
"visibleRange" : 6.5,
|
"visibleRange" : 6.5,
|
||||||
"canAttack": true
|
"canAttack": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ghost_07x",
|
||||||
|
"name": "Тень",
|
||||||
|
"meshTextures": {
|
||||||
|
"Shadow_NPC_Rigged": "resources/w/shadow/Shadow_BaseColor.png"
|
||||||
|
},
|
||||||
|
"animationIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationWalkPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionAttackPath": "resources/w/shadow/shadow_attack003.anim",
|
||||||
|
"animationStandToActionPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToStandPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToDeathPath": "resources/w/shadow/shadow_die003.anim",
|
||||||
|
"animationDeathIdlePath": "resources/w/shadow/shadow_dead003.anim",
|
||||||
|
"positionX": -5.6,
|
||||||
|
"positionY": 0.0,
|
||||||
|
"positionZ": -14.0,
|
||||||
|
"walkSpeed": 1.5,
|
||||||
|
"rotationSpeed": 8.0,
|
||||||
|
"modelScale": 1.0,
|
||||||
|
"modelCorrectionRotX": -90.0,
|
||||||
|
"modelCorrectionRotY": 180.0,
|
||||||
|
"modelCorrectionRotZ": 0.0,
|
||||||
|
"hp": 35,
|
||||||
|
"visibleRange" : 6.5,
|
||||||
|
"canAttack": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ghost_08x",
|
||||||
|
"name": "Тень",
|
||||||
|
"meshTextures": {
|
||||||
|
"Shadow_NPC_Rigged": "resources/w/shadow/Shadow_BaseColor.png"
|
||||||
|
},
|
||||||
|
"animationIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationWalkPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionAttackPath": "resources/w/shadow/shadow_attack003.anim",
|
||||||
|
"animationStandToActionPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToStandPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToDeathPath": "resources/w/shadow/shadow_die003.anim",
|
||||||
|
"animationDeathIdlePath": "resources/w/shadow/shadow_dead003.anim",
|
||||||
|
"positionX": -6.4,
|
||||||
|
"positionY": 0.0,
|
||||||
|
"positionZ": -14.0,
|
||||||
|
"walkSpeed": 1.5,
|
||||||
|
"rotationSpeed": 8.0,
|
||||||
|
"modelScale": 1.0,
|
||||||
|
"modelCorrectionRotX": -90.0,
|
||||||
|
"modelCorrectionRotY": 180.0,
|
||||||
|
"modelCorrectionRotZ": 0.0,
|
||||||
|
"hp": 35,
|
||||||
|
"visibleRange" : 6.5,
|
||||||
|
"canAttack": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ghost_09x",
|
||||||
|
"name": "Тень",
|
||||||
|
"meshTextures": {
|
||||||
|
"Shadow_NPC_Rigged": "resources/w/shadow/Shadow_BaseColor.png"
|
||||||
|
},
|
||||||
|
"animationIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationWalkPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionAttackPath": "resources/w/shadow/shadow_attack003.anim",
|
||||||
|
"animationStandToActionPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToStandPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToDeathPath": "resources/w/shadow/shadow_die003.anim",
|
||||||
|
"animationDeathIdlePath": "resources/w/shadow/shadow_dead003.anim",
|
||||||
|
"positionX": -5.6,
|
||||||
|
"positionY": 0.0,
|
||||||
|
"positionZ": -14.5,
|
||||||
|
"walkSpeed": 1.5,
|
||||||
|
"rotationSpeed": 8.0,
|
||||||
|
"modelScale": 1.0,
|
||||||
|
"modelCorrectionRotX": -90.0,
|
||||||
|
"modelCorrectionRotY": 180.0,
|
||||||
|
"modelCorrectionRotZ": 0.0,
|
||||||
|
"hp": 35,
|
||||||
|
"visibleRange" : 6.5,
|
||||||
|
"canAttack": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ghost_10x",
|
||||||
|
"name": "Тень",
|
||||||
|
"meshTextures": {
|
||||||
|
"Shadow_NPC_Rigged": "resources/w/shadow/Shadow_BaseColor.png"
|
||||||
|
},
|
||||||
|
"animationIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationWalkPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionAttackPath": "resources/w/shadow/shadow_attack003.anim",
|
||||||
|
"animationStandToActionPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToStandPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToDeathPath": "resources/w/shadow/shadow_die003.anim",
|
||||||
|
"animationDeathIdlePath": "resources/w/shadow/shadow_dead003.anim",
|
||||||
|
"positionX": -6.4,
|
||||||
|
"positionY": 0.0,
|
||||||
|
"positionZ": -14.5,
|
||||||
|
"walkSpeed": 1.5,
|
||||||
|
"rotationSpeed": 8.0,
|
||||||
|
"modelScale": 1.0,
|
||||||
|
"modelCorrectionRotX": -90.0,
|
||||||
|
"modelCorrectionRotY": 180.0,
|
||||||
|
"modelCorrectionRotZ": 0.0,
|
||||||
|
"hp": 35,
|
||||||
|
"visibleRange" : 6.5,
|
||||||
|
"canAttack": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ghost_11x",
|
||||||
|
"name": "Тень",
|
||||||
|
"meshTextures": {
|
||||||
|
"Shadow_NPC_Rigged": "resources/w/shadow/Shadow_BaseColor.png"
|
||||||
|
},
|
||||||
|
"animationIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationWalkPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionAttackPath": "resources/w/shadow/shadow_attack003.anim",
|
||||||
|
"animationStandToActionPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToStandPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToDeathPath": "resources/w/shadow/shadow_die003.anim",
|
||||||
|
"animationDeathIdlePath": "resources/w/shadow/shadow_dead003.anim",
|
||||||
|
"positionX": -5.6,
|
||||||
|
"positionY": 0.0,
|
||||||
|
"positionZ": -15.0,
|
||||||
|
"walkSpeed": 1.5,
|
||||||
|
"rotationSpeed": 8.0,
|
||||||
|
"modelScale": 1.0,
|
||||||
|
"modelCorrectionRotX": -90.0,
|
||||||
|
"modelCorrectionRotY": 180.0,
|
||||||
|
"modelCorrectionRotZ": 0.0,
|
||||||
|
"hp": 35,
|
||||||
|
"visibleRange" : 6.5,
|
||||||
|
"canAttack": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ghost_12x",
|
||||||
|
"name": "Тень",
|
||||||
|
"meshTextures": {
|
||||||
|
"Shadow_NPC_Rigged": "resources/w/shadow/Shadow_BaseColor.png"
|
||||||
|
},
|
||||||
|
"animationIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationWalkPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionIdlePath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionAttackPath": "resources/w/shadow/shadow_attack003.anim",
|
||||||
|
"animationStandToActionPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToStandPath": "resources/w/shadow/shadow_idle003.anim",
|
||||||
|
"animationActionToDeathPath": "resources/w/shadow/shadow_die003.anim",
|
||||||
|
"animationDeathIdlePath": "resources/w/shadow/shadow_dead003.anim",
|
||||||
|
"positionX": -6.4,
|
||||||
|
"positionY": 0.0,
|
||||||
|
"positionZ": -15.0,
|
||||||
|
"walkSpeed": 1.5,
|
||||||
|
"rotationSpeed": 8.0,
|
||||||
|
"modelScale": 1.0,
|
||||||
|
"modelCorrectionRotX": -90.0,
|
||||||
|
"modelCorrectionRotY": 180.0,
|
||||||
|
"modelCorrectionRotZ": 0.0,
|
||||||
|
"hp": 35,
|
||||||
|
"visibleRange" : 6.5,
|
||||||
|
"canAttack": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,13 @@
|
|||||||
{
|
{
|
||||||
|
"localState": {
|
||||||
|
"locations": {
|
||||||
|
"location_dorm": {
|
||||||
|
"cameraAzimuth": -2.3499999046325684,
|
||||||
|
"cameraInclination": 1.103600025177002
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"networkState": {
|
||||||
"campaignId": "main",
|
"campaignId": "main",
|
||||||
"chatHistory": [
|
"chatHistory": [
|
||||||
[],
|
[],
|
||||||
@@ -16,8 +25,7 @@
|
|||||||
true
|
true
|
||||||
],
|
],
|
||||||
"currentLocationId": "",
|
"currentLocationId": "",
|
||||||
"globalFloats": {
|
"globalFloats": {},
|
||||||
},
|
|
||||||
"globalInts": {},
|
"globalInts": {},
|
||||||
"inventory": {
|
"inventory": {
|
||||||
"items": []
|
"items": []
|
||||||
@@ -494,6 +502,22 @@
|
|||||||
-15.038200378417969
|
-15.038200378417969
|
||||||
],
|
],
|
||||||
"hp": 100.0,
|
"hp": 100.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
10,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
8,
|
||||||
|
11,
|
||||||
|
9,
|
||||||
|
6,
|
||||||
|
3,
|
||||||
|
2,
|
||||||
|
7
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [
|
"pathWaypoints": [
|
||||||
[
|
[
|
||||||
-6.296899795532227,
|
-6.296899795532227,
|
||||||
@@ -530,8 +554,6 @@
|
|||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"activeNavigationIndex": 0,
|
"activeNavigationIndex": 0,
|
||||||
"cameraAzimuth": -2.3499999046325684,
|
|
||||||
"cameraInclination": 1.103600025177002,
|
|
||||||
"targetInteractNpcId": "",
|
"targetInteractNpcId": "",
|
||||||
"targetInteractiveObjectId": "",
|
"targetInteractiveObjectId": "",
|
||||||
"targetTeleportZoneId": "",
|
"targetTeleportZoneId": "",
|
||||||
@@ -574,10 +596,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"money": 5500,
|
"money": 5500,
|
||||||
"playerHp": 200.0,
|
|
||||||
"playerMaxHp": 200.0,
|
"playerMaxHp": 200.0,
|
||||||
"players": {
|
"players": {
|
||||||
"player": {
|
"player1": {
|
||||||
"animationFrame": 0.0,
|
"animationFrame": 0.0,
|
||||||
"attackTargetId": "",
|
"attackTargetId": "",
|
||||||
"attack_cooldown": 0.0,
|
"attack_cooldown": 0.0,
|
||||||
@@ -594,6 +615,11 @@
|
|||||||
0.0
|
0.0
|
||||||
],
|
],
|
||||||
"hp": 200.0,
|
"hp": 200.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [
|
"pathWaypoints": [
|
||||||
[
|
[
|
||||||
6.8031005859375,
|
6.8031005859375,
|
||||||
@@ -764,12 +790,14 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"savedAt": "2026-10-30 14:48",
|
"savedAt": "2026-11-10 20:38",
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 5,
|
||||||
"taxiIsCalled": false,
|
"taxiIsCalled": false,
|
||||||
"tutorialJournalScreenOpened": false,
|
"tutorialJournalScreenOpened": false,
|
||||||
"tutorialNeedOpenTaxiScreen": false,
|
"tutorialNeedOpenTaxiScreen": false,
|
||||||
"tutorialPhoneChatScreenOpened": false,
|
"tutorialPhoneChatScreenOpened": false,
|
||||||
"tutorialStep": 0,
|
"tutorialStep": 0,
|
||||||
"tutorialTaxiHintDone": false
|
"tutorialTaxiHintDone": false
|
||||||
|
},
|
||||||
|
"persistenceVersion": 1
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"localState": {
|
"localState": {
|
||||||
"locations": {
|
"locations": {
|
||||||
"uni_exterior": {
|
"park_korea": {
|
||||||
"cameraAzimuth": -2.3499999046325684,
|
"cameraAzimuth": -2.3499999046325684,
|
||||||
"cameraInclination": 1.103600025177002
|
"cameraInclination": 1.103600025177002
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,12 @@
|
|||||||
"networkState": {
|
"networkState": {
|
||||||
"campaignId": "battle_zone",
|
"campaignId": "battle_zone",
|
||||||
"chatHistory": [
|
"chatHistory": [
|
||||||
[],
|
[
|
||||||
[],
|
],
|
||||||
[]
|
[
|
||||||
|
],
|
||||||
|
[
|
||||||
|
]
|
||||||
],
|
],
|
||||||
"chatPreviewMsg": [
|
"chatPreviewMsg": [
|
||||||
"",
|
"",
|
||||||
@@ -27,15 +30,17 @@
|
|||||||
"currentLocationId": "",
|
"currentLocationId": "",
|
||||||
"globalFloats": {
|
"globalFloats": {
|
||||||
},
|
},
|
||||||
"globalInts": {},
|
"globalInts": {
|
||||||
|
},
|
||||||
"inventory": {
|
"inventory": {
|
||||||
"items": []
|
"items": [
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"isDarklands": true,
|
"isDarklands": true,
|
||||||
"isDawn": false,
|
"isDawn": false,
|
||||||
"isNight": true,
|
"isNight": true,
|
||||||
"locations": {
|
"locations": {
|
||||||
"uni_exterior": {
|
"park_korea": {
|
||||||
"dialogue": {
|
"dialogue": {
|
||||||
"active": false
|
"active": false
|
||||||
},
|
},
|
||||||
@@ -44,7 +49,7 @@
|
|||||||
"alpha": 1.0,
|
"alpha": 1.0,
|
||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 0.6000000238418579,
|
"positionX": 0.60000002384185791,
|
||||||
"positionY": 0.45736101269721985,
|
"positionY": 0.45736101269721985,
|
||||||
"positionZ": 3.8499999046325684,
|
"positionZ": 3.8499999046325684,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
@@ -54,7 +59,7 @@
|
|||||||
"alpha": 1.0,
|
"alpha": 1.0,
|
||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 1.399999976158142,
|
"positionX": 1.3999999761581421,
|
||||||
"positionY": 0.45736101269721985,
|
"positionY": 0.45736101269721985,
|
||||||
"positionZ": 3.8499999046325684,
|
"positionZ": 3.8499999046325684,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
@@ -64,7 +69,7 @@
|
|||||||
"alpha": 1.0,
|
"alpha": 1.0,
|
||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 2.200000047683716,
|
"positionX": 2.2000000476837158,
|
||||||
"positionY": 0.45736101269721985,
|
"positionY": 0.45736101269721985,
|
||||||
"positionZ": 3.8499999046325684,
|
"positionZ": 3.8499999046325684,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
@@ -85,7 +90,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 0.0,
|
"positionX": 0.0,
|
||||||
"positionY": 3.200000047683716,
|
"positionY": 3.2000000476837158,
|
||||||
"positionZ": 0.0,
|
"positionZ": 0.0,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -95,7 +100,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": -1.0,
|
"positionX": -1.0,
|
||||||
"positionY": 0.9150000214576721,
|
"positionY": 0.91500002145767212,
|
||||||
"positionZ": -3.9000000953674316,
|
"positionZ": -3.9000000953674316,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -105,7 +110,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 0.0,
|
"positionX": 0.0,
|
||||||
"positionY": 0.9150000214576721,
|
"positionY": 0.91500002145767212,
|
||||||
"positionZ": -3.9000000953674316,
|
"positionZ": -3.9000000953674316,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -115,7 +120,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 1.0,
|
"positionX": 1.0,
|
||||||
"positionY": 0.9150000214576721,
|
"positionY": 0.91500002145767212,
|
||||||
"positionZ": -3.9000000953674316,
|
"positionZ": -3.9000000953674316,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -134,7 +139,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -155,14 +160,15 @@
|
|||||||
11
|
11
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -170,7 +176,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
]
|
]
|
||||||
@@ -187,7 +193,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -208,14 +214,15 @@
|
|||||||
6
|
6
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -223,7 +230,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
]
|
]
|
||||||
@@ -240,7 +247,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -261,14 +268,15 @@
|
|||||||
11
|
11
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -276,7 +284,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
]
|
]
|
||||||
@@ -293,7 +301,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -314,14 +322,15 @@
|
|||||||
6
|
6
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -329,7 +338,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
]
|
]
|
||||||
@@ -346,7 +355,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -367,14 +376,15 @@
|
|||||||
11
|
11
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -382,7 +392,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
]
|
]
|
||||||
@@ -399,7 +409,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -420,14 +430,15 @@
|
|||||||
2
|
2
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -435,13 +446,338 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"ghost_07x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
4,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_08x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
8,
|
||||||
|
11,
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
2,
|
||||||
|
9,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
7,
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_09x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
8,
|
||||||
|
3,
|
||||||
|
6,
|
||||||
|
10,
|
||||||
|
9,
|
||||||
|
7,
|
||||||
|
5,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_10x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
7,
|
||||||
|
10,
|
||||||
|
5,
|
||||||
|
11,
|
||||||
|
9,
|
||||||
|
2,
|
||||||
|
8,
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-12.5
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_11x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
2,
|
||||||
|
9,
|
||||||
|
4,
|
||||||
|
10,
|
||||||
|
6,
|
||||||
|
5,
|
||||||
|
3,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_12x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
7,
|
||||||
|
11,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
9,
|
||||||
|
8,
|
||||||
|
6,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scriptGlobals": {},
|
"scriptGlobals": {
|
||||||
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"activeNavigationIndex": 0,
|
"activeNavigationIndex": 0,
|
||||||
"targetInteractNpcId": "",
|
"targetInteractNpcId": "",
|
||||||
@@ -460,61 +796,23 @@
|
|||||||
"rotation": 0.0,
|
"rotation": 0.0,
|
||||||
"steeringAngle": 0.0,
|
"steeringAngle": 0.0,
|
||||||
"velocity": 0.0,
|
"velocity": 0.0,
|
||||||
"waypoints": [],
|
"waypoints": [
|
||||||
|
],
|
||||||
"wheelAngle": 0.0
|
"wheelAngle": 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"teleportZones": {},
|
"teleportZones": {
|
||||||
"triggerZones": {}
|
},
|
||||||
|
"triggerZones": {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"money": 5500,
|
"money": 5500,
|
||||||
"playerHp": 200.0,
|
"playerHp": 200.0,
|
||||||
"playerMaxHp": 200.0,
|
"playerMaxHp": 200.0,
|
||||||
"players": {
|
"players": {
|
||||||
"player2": {
|
"player1": {
|
||||||
"animationFrame": 0.0,
|
|
||||||
"attackTargetId": "",
|
|
||||||
"attack_cooldown": 0.0,
|
|
||||||
"battle_state": 0,
|
|
||||||
"currentState": 0,
|
|
||||||
"currentWaypointIndex": 0,
|
|
||||||
"enabled": false,
|
|
||||||
"faceTargetId": "",
|
|
||||||
"facingAngle": 0.0,
|
|
||||||
"homeDriftCheckTimer": 5.0,
|
|
||||||
"homePosition": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
],
|
|
||||||
"hp": 200.0,
|
|
||||||
"pathWaypoints": [[
|
|
||||||
-6.4,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
]],
|
|
||||||
"position": [
|
|
||||||
-6.4,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
],
|
|
||||||
"requestedWalkTarget": [
|
|
||||||
-6.4,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
],
|
|
||||||
"showWeapon": true,
|
|
||||||
"targetFacingAngle": 0.0,
|
|
||||||
"visibleRange": 6.0,
|
|
||||||
"walkTarget": [
|
|
||||||
-6.4,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"player": {
|
|
||||||
"animationFrame": 0.0,
|
"animationFrame": 0.0,
|
||||||
"attackTargetId": "",
|
"attackTargetId": "",
|
||||||
"attack_cooldown": 0.0,
|
"attack_cooldown": 0.0,
|
||||||
@@ -533,18 +831,18 @@
|
|||||||
"hp": 200.0,
|
"hp": 200.0,
|
||||||
"pathWaypoints": [
|
"pathWaypoints": [
|
||||||
[
|
[
|
||||||
-5.8,
|
-5.4,
|
||||||
0.0,
|
0.0,
|
||||||
12.8
|
12.8
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-5.8,
|
-5.4,
|
||||||
0.0,
|
0.0,
|
||||||
12.8
|
12.8
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-5.8,
|
-5.4,
|
||||||
0.0,
|
0.0,
|
||||||
12.8
|
12.8
|
||||||
],
|
],
|
||||||
@@ -552,14 +850,144 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.0,
|
"visibleRange": 6.0,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-5.8,
|
-5.4,
|
||||||
0.0,
|
0.0,
|
||||||
12.8
|
12.8
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"player2": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": false,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"hp": 200.0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
[
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.0,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"player3": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": false,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"hp": 200.0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
[
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.0,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"player4": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": false,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"hp": 200.0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
[
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.0,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"questJournal": {
|
"questJournal": {
|
||||||
"quests": []
|
"quests": [
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"savedAt": "2026-11-05 17:43",
|
"savedAt": "2026-11-05 17:43",
|
||||||
"schemaVersion": 5,
|
"schemaVersion": 5,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"localState": {
|
"localState": {
|
||||||
"locations": {
|
"locations": {
|
||||||
"uni_exterior": {
|
"park_korea": {
|
||||||
"cameraAzimuth": -2.3499999046325684,
|
"cameraAzimuth": -2.3499999046325684,
|
||||||
"cameraInclination": 1.103600025177002
|
"cameraInclination": 1.103600025177002
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,12 @@
|
|||||||
"networkState": {
|
"networkState": {
|
||||||
"campaignId": "battle_zone",
|
"campaignId": "battle_zone",
|
||||||
"chatHistory": [
|
"chatHistory": [
|
||||||
[],
|
[
|
||||||
[],
|
],
|
||||||
[]
|
[
|
||||||
|
],
|
||||||
|
[
|
||||||
|
]
|
||||||
],
|
],
|
||||||
"chatPreviewMsg": [
|
"chatPreviewMsg": [
|
||||||
"",
|
"",
|
||||||
@@ -27,15 +30,17 @@
|
|||||||
"currentLocationId": "",
|
"currentLocationId": "",
|
||||||
"globalFloats": {
|
"globalFloats": {
|
||||||
},
|
},
|
||||||
"globalInts": {},
|
"globalInts": {
|
||||||
|
},
|
||||||
"inventory": {
|
"inventory": {
|
||||||
"items": []
|
"items": [
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"isDarklands": true,
|
"isDarklands": true,
|
||||||
"isDawn": false,
|
"isDawn": false,
|
||||||
"isNight": true,
|
"isNight": true,
|
||||||
"locations": {
|
"locations": {
|
||||||
"uni_exterior": {
|
"park_korea": {
|
||||||
"dialogue": {
|
"dialogue": {
|
||||||
"active": false
|
"active": false
|
||||||
},
|
},
|
||||||
@@ -44,7 +49,7 @@
|
|||||||
"alpha": 1.0,
|
"alpha": 1.0,
|
||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 0.6000000238418579,
|
"positionX": 0.60000002384185791,
|
||||||
"positionY": 0.45736101269721985,
|
"positionY": 0.45736101269721985,
|
||||||
"positionZ": 3.8499999046325684,
|
"positionZ": 3.8499999046325684,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
@@ -54,7 +59,7 @@
|
|||||||
"alpha": 1.0,
|
"alpha": 1.0,
|
||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 1.399999976158142,
|
"positionX": 1.3999999761581421,
|
||||||
"positionY": 0.45736101269721985,
|
"positionY": 0.45736101269721985,
|
||||||
"positionZ": 3.8499999046325684,
|
"positionZ": 3.8499999046325684,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
@@ -64,7 +69,7 @@
|
|||||||
"alpha": 1.0,
|
"alpha": 1.0,
|
||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 2.200000047683716,
|
"positionX": 2.2000000476837158,
|
||||||
"positionY": 0.45736101269721985,
|
"positionY": 0.45736101269721985,
|
||||||
"positionZ": 3.8499999046325684,
|
"positionZ": 3.8499999046325684,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
@@ -85,7 +90,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 0.0,
|
"positionX": 0.0,
|
||||||
"positionY": 3.200000047683716,
|
"positionY": 3.2000000476837158,
|
||||||
"positionZ": 0.0,
|
"positionZ": 0.0,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -95,7 +100,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": -1.0,
|
"positionX": -1.0,
|
||||||
"positionY": 0.9150000214576721,
|
"positionY": 0.91500002145767212,
|
||||||
"positionZ": -3.9000000953674316,
|
"positionZ": -3.9000000953674316,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -105,7 +110,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 0.0,
|
"positionX": 0.0,
|
||||||
"positionY": 0.9150000214576721,
|
"positionY": 0.91500002145767212,
|
||||||
"positionZ": -3.9000000953674316,
|
"positionZ": -3.9000000953674316,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -115,7 +120,7 @@
|
|||||||
"isActive": true,
|
"isActive": true,
|
||||||
"isAnimating": false,
|
"isAnimating": false,
|
||||||
"positionX": 1.0,
|
"positionX": 1.0,
|
||||||
"positionY": 0.9150000214576721,
|
"positionY": 0.91500002145767212,
|
||||||
"positionZ": -3.9000000953674316,
|
"positionZ": -3.9000000953674316,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"scale": 1.0
|
"scale": 1.0
|
||||||
@@ -134,7 +139,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -155,14 +160,15 @@
|
|||||||
11
|
11
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -170,7 +176,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
]
|
]
|
||||||
@@ -187,7 +193,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -208,14 +214,15 @@
|
|||||||
6
|
6
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
],
|
],
|
||||||
@@ -223,7 +230,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.0
|
-12.0
|
||||||
]
|
]
|
||||||
@@ -240,7 +247,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -261,14 +268,15 @@
|
|||||||
11
|
11
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -276,7 +284,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
]
|
]
|
||||||
@@ -293,7 +301,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -314,14 +322,15 @@
|
|||||||
6
|
6
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
],
|
],
|
||||||
@@ -329,7 +338,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-12.5
|
-12.5
|
||||||
]
|
]
|
||||||
@@ -346,7 +355,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -367,14 +376,15 @@
|
|||||||
11
|
11
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -382,7 +392,7 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-5.599999904632568,
|
-5.5999999046325684,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
]
|
]
|
||||||
@@ -399,7 +409,7 @@
|
|||||||
"facingAngle": 0.0,
|
"facingAngle": 0.0,
|
||||||
"homeDriftCheckTimer": 5.0,
|
"homeDriftCheckTimer": 5.0,
|
||||||
"homePosition": [
|
"homePosition": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -420,14 +430,15 @@
|
|||||||
2
|
2
|
||||||
],
|
],
|
||||||
"navigationRetryTicks": 0,
|
"navigationRetryTicks": 0,
|
||||||
"pathWaypoints": [],
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
"position": [
|
"position": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
"requestedWalkTarget": [
|
"requestedWalkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
],
|
],
|
||||||
@@ -435,13 +446,338 @@
|
|||||||
"targetFacingAngle": 0.0,
|
"targetFacingAngle": 0.0,
|
||||||
"visibleRange": 6.5,
|
"visibleRange": 6.5,
|
||||||
"walkTarget": [
|
"walkTarget": [
|
||||||
-6.400000095367432,
|
-6.4000000953674316,
|
||||||
0.0,
|
0.0,
|
||||||
-13.0
|
-13.0
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"ghost_07x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
4,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_08x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
8,
|
||||||
|
11,
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
2,
|
||||||
|
9,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
7,
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_09x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
8,
|
||||||
|
3,
|
||||||
|
6,
|
||||||
|
10,
|
||||||
|
9,
|
||||||
|
7,
|
||||||
|
5,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_10x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
7,
|
||||||
|
10,
|
||||||
|
5,
|
||||||
|
11,
|
||||||
|
9,
|
||||||
|
2,
|
||||||
|
8,
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-12.5
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-14.5
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_11x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
2,
|
||||||
|
9,
|
||||||
|
4,
|
||||||
|
10,
|
||||||
|
6,
|
||||||
|
5,
|
||||||
|
3,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.5999999046325684,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ghost_12x": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": true,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"hp": 35.0,
|
||||||
|
"movedLastTick": false,
|
||||||
|
"movementBlockedTicks": 0,
|
||||||
|
"navigationRetryCooldownIndex": 0,
|
||||||
|
"navigationRetryCooldownTicks": [
|
||||||
|
7,
|
||||||
|
11,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
10,
|
||||||
|
9,
|
||||||
|
8,
|
||||||
|
6,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"navigationRetryTicks": 0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.5,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.4000000953674316,
|
||||||
|
0.0,
|
||||||
|
-15.0
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scriptGlobals": {},
|
"scriptGlobals": {
|
||||||
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"activeNavigationIndex": 0,
|
"activeNavigationIndex": 0,
|
||||||
"targetInteractNpcId": "",
|
"targetInteractNpcId": "",
|
||||||
@@ -460,61 +796,23 @@
|
|||||||
"rotation": 0.0,
|
"rotation": 0.0,
|
||||||
"steeringAngle": 0.0,
|
"steeringAngle": 0.0,
|
||||||
"velocity": 0.0,
|
"velocity": 0.0,
|
||||||
"waypoints": [],
|
"waypoints": [
|
||||||
|
],
|
||||||
"wheelAngle": 0.0
|
"wheelAngle": 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"teleportZones": {},
|
"teleportZones": {
|
||||||
"triggerZones": {}
|
},
|
||||||
|
"triggerZones": {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"money": 5500,
|
"money": 5500,
|
||||||
"playerHp": 200.0,
|
"playerHp": 200.0,
|
||||||
"playerMaxHp": 200.0,
|
"playerMaxHp": 200.0,
|
||||||
"players": {
|
"players": {
|
||||||
"player2": {
|
"player1": {
|
||||||
"animationFrame": 0.0,
|
|
||||||
"attackTargetId": "",
|
|
||||||
"attack_cooldown": 0.0,
|
|
||||||
"battle_state": 0,
|
|
||||||
"currentState": 0,
|
|
||||||
"currentWaypointIndex": 0,
|
|
||||||
"enabled": false,
|
|
||||||
"faceTargetId": "",
|
|
||||||
"facingAngle": 0.0,
|
|
||||||
"homeDriftCheckTimer": 5.0,
|
|
||||||
"homePosition": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
],
|
|
||||||
"hp": 200.0,
|
|
||||||
"pathWaypoints": [[
|
|
||||||
-6.8,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
]],
|
|
||||||
"position": [
|
|
||||||
-6.8,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
],
|
|
||||||
"requestedWalkTarget": [
|
|
||||||
-6.8,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
],
|
|
||||||
"showWeapon": true,
|
|
||||||
"targetFacingAngle": 0.0,
|
|
||||||
"visibleRange": 6.0,
|
|
||||||
"walkTarget": [
|
|
||||||
-6.8,
|
|
||||||
0.0,
|
|
||||||
13.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"player": {
|
|
||||||
"animationFrame": 0.0,
|
"animationFrame": 0.0,
|
||||||
"attackTargetId": "",
|
"attackTargetId": "",
|
||||||
"attack_cooldown": 0.0,
|
"attack_cooldown": 0.0,
|
||||||
@@ -556,10 +854,140 @@
|
|||||||
0.0,
|
0.0,
|
||||||
12.8
|
12.8
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"player2": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": false,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"hp": 200.0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
[
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.0,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
13.0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"player3": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": false,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"hp": 200.0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
[
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.0,
|
||||||
|
"walkTarget": [
|
||||||
|
-5.4,
|
||||||
|
0.0,
|
||||||
|
14.8
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"player4": {
|
||||||
|
"animationFrame": 0.0,
|
||||||
|
"attackTargetId": "",
|
||||||
|
"attack_cooldown": 0.0,
|
||||||
|
"battle_state": 0,
|
||||||
|
"currentState": 0,
|
||||||
|
"currentWaypointIndex": 0,
|
||||||
|
"enabled": false,
|
||||||
|
"faceTargetId": "",
|
||||||
|
"facingAngle": 0.0,
|
||||||
|
"homeDriftCheckTimer": 5.0,
|
||||||
|
"homePosition": [
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"hp": 200.0,
|
||||||
|
"pathWaypoints": [
|
||||||
|
[
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
],
|
||||||
|
"requestedWalkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
],
|
||||||
|
"showWeapon": true,
|
||||||
|
"targetFacingAngle": 0.0,
|
||||||
|
"visibleRange": 6.0,
|
||||||
|
"walkTarget": [
|
||||||
|
-6.8,
|
||||||
|
0.0,
|
||||||
|
15.0
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"questJournal": {
|
"questJournal": {
|
||||||
"quests": []
|
"quests": [
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"savedAt": "2026-11-05 17:43",
|
"savedAt": "2026-11-05 17:43",
|
||||||
"schemaVersion": 5,
|
"schemaVersion": 5,
|
||||||
|
|||||||
@@ -172,6 +172,13 @@ if(BUILD_TESTING)
|
|||||||
GameServerWebsocketLockstepTests PRIVATE "${BOOST_BUNDLED_DIR}")
|
GameServerWebsocketLockstepTests PRIVATE "${BOOST_BUNDLED_DIR}")
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
GameServerWebsocketLockstepTests PRIVATE NETWORK)
|
GameServerWebsocketLockstepTests PRIVATE NETWORK)
|
||||||
|
GameServerWebsocketLockstepTests PRIVATE
|
||||||
|
NETWORK WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00)
|
||||||
|
if(MSVC)
|
||||||
|
set_source_files_properties(
|
||||||
|
"${GAME_ROOT}/src/game_server/WebsocketGameClient.cpp"
|
||||||
|
PROPERTIES COMPILE_OPTIONS "/bigobj")
|
||||||
|
endif()
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
GameServerWebsocketLockstepTests PRIVATE game_server_core)
|
GameServerWebsocketLockstepTests PRIVATE game_server_core)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|||||||
@@ -194,6 +194,59 @@ int main()
|
|||||||
return fail("Hostile NPC did not return home after losing its target");
|
return fail("Hostile NPC did not return home after losing its target");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto blocker = std::make_shared<FRG::CharacterState>();
|
||||||
|
blocker->enabled = true;
|
||||||
|
blocker->hp = 50.f;
|
||||||
|
blocker->position = {0.8f, 0.f, 0.f};
|
||||||
|
state.npcs["blocker"] = blocker;
|
||||||
|
hostileNpc.position = Eigen::Vector3f::Zero();
|
||||||
|
hostileNpc.homePosition = {5.f, 0.f, 0.f};
|
||||||
|
hostileNpc.attackTargetId = "player";
|
||||||
|
hostileNpc.requestedWalkTarget = playerOne->position;
|
||||||
|
hostileNpc.walkTarget = playerOne->position;
|
||||||
|
hostileNpc.pathWaypoints = {playerOne->position};
|
||||||
|
hostileNpc.currentWaypointIndex = 0;
|
||||||
|
hostileNpc.movementBlockedTicks = 0;
|
||||||
|
playerOne->enabled = true;
|
||||||
|
playerOne->hp = 75.f;
|
||||||
|
playerOne->position = {4.f, 0.f, 0.f};
|
||||||
|
playerTwo->enabled = true;
|
||||||
|
playerTwo->hp = 75.f;
|
||||||
|
playerTwo->position = {2.f, 0.f, 0.f};
|
||||||
|
|
||||||
|
bool blockedRetryRequested = false;
|
||||||
|
for (int tick = 0; tick < 10 && !blockedRetryRequested; ++tick) {
|
||||||
|
const FRG::LocationSimulationEvents events =
|
||||||
|
state.update(100, combatPlayers, false);
|
||||||
|
for (const auto& event : events.characters) {
|
||||||
|
if (event.characterId == "npc" &&
|
||||||
|
event.events.forceNavigationReplan) {
|
||||||
|
blockedRetryRequested = true;
|
||||||
|
if (!state.replanCharacter(
|
||||||
|
"npc", combatPlayers,
|
||||||
|
event.events.blockingCharacterId)) {
|
||||||
|
return fail("Blocked NPC replan was rejected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!blockedRetryRequested ||
|
||||||
|
hostileNpc.attackTargetId != "player2" ||
|
||||||
|
(hostileNpc.requestedWalkTarget - playerTwo->position).norm() >
|
||||||
|
FRG::CharacterState::kWalkThreshold) {
|
||||||
|
return fail("Blocked NPC did not switch to the nearest player");
|
||||||
|
}
|
||||||
|
|
||||||
|
playerOne->enabled = false;
|
||||||
|
playerTwo->enabled = false;
|
||||||
|
if (!state.replanCharacter("npc", combatPlayers, "blocker") ||
|
||||||
|
!hostileNpc.attackTargetId.empty() ||
|
||||||
|
hostileNpc.battle_state != 0 ||
|
||||||
|
(hostileNpc.requestedWalkTarget - hostileNpc.homePosition).norm() >
|
||||||
|
FRG::CharacterState::kWalkThreshold) {
|
||||||
|
return fail("Blocked NPC did not return home without an eligible target");
|
||||||
|
}
|
||||||
|
|
||||||
FRG::CampaignConfig battleZone;
|
FRG::CampaignConfig battleZone;
|
||||||
battleZone.id = "battle_zone";
|
battleZone.id = "battle_zone";
|
||||||
battleZone.questsPath = "resources/config/quests_battle_zone.json";
|
battleZone.questsPath = "resources/config/quests_battle_zone.json";
|
||||||
|
|||||||
@@ -32,6 +32,31 @@ bool waitFor(Predicate predicate)
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
FRG::WebsocketEndpoint secureEndpoint;
|
||||||
|
require(
|
||||||
|
secureEndpoint.parse(
|
||||||
|
"wss://api.shadowoverbishkek.com/server001/"),
|
||||||
|
"secure WebSocket endpoint was rejected");
|
||||||
|
require(
|
||||||
|
secureEndpoint.host == "api.shadowoverbishkek.com" &&
|
||||||
|
secureEndpoint.port == "443" &&
|
||||||
|
secureEndpoint.path == "/server001/" &&
|
||||||
|
secureEndpoint.useTls,
|
||||||
|
"secure WebSocket endpoint was parsed incorrectly");
|
||||||
|
FRG::WebsocketEndpoint insecureEndpoint;
|
||||||
|
require(
|
||||||
|
insecureEndpoint.parse("ws://127.0.0.1:8080/"),
|
||||||
|
"insecure WebSocket endpoint was rejected");
|
||||||
|
require(
|
||||||
|
insecureEndpoint.host == "127.0.0.1" &&
|
||||||
|
insecureEndpoint.port == "8080" &&
|
||||||
|
!insecureEndpoint.useTls,
|
||||||
|
"insecure WebSocket endpoint was parsed incorrectly");
|
||||||
|
FRG::WebsocketEndpoint invalidEndpoint;
|
||||||
|
require(
|
||||||
|
!invalidEndpoint.parse("https://api.shadowoverbishkek.com/"),
|
||||||
|
"non-WebSocket endpoint was accepted");
|
||||||
|
|
||||||
FRG::CampaignConfig campaign;
|
FRG::CampaignConfig campaign;
|
||||||
campaign.id = "test_lockstep";
|
campaign.id = "test_lockstep";
|
||||||
campaign.networkPlayerSlots = {"player", "player2"};
|
campaign.networkPlayerSlots = {"player", "player2"};
|
||||||
|
|||||||
+5
-1
@@ -564,6 +564,10 @@ namespace FRG
|
|||||||
if (!endpoint.parse(kMultiplayerServerUrl)) {
|
if (!endpoint.parse(kMultiplayerServerUrl)) {
|
||||||
logger() << "[network] Invalid multiplayer server URL: "
|
logger() << "[network] Invalid multiplayer server URL: "
|
||||||
<< kMultiplayerServerUrl << std::endl;
|
<< kMultiplayerServerUrl << std::endl;
|
||||||
|
remoteCampaignActive = false;
|
||||||
|
gameServer.use(internalGameServer);
|
||||||
|
gameServerHost.use(localGameServerHost);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
websocketGameClient = std::make_unique<WebsocketGameClient>(endpoint);
|
websocketGameClient = std::make_unique<WebsocketGameClient>(endpoint);
|
||||||
remoteGameServerHost =
|
remoteGameServerHost =
|
||||||
@@ -688,7 +692,7 @@ namespace FRG
|
|||||||
// Developer workflow: uncomment to (re)generate the campaign's start-state JSON
|
// Developer workflow: uncomment to (re)generate the campaign's start-state JSON
|
||||||
// from this freshly-rebuilt state after changing gameplay/content JSON or Lua.
|
// from this freshly-rebuilt state after changing gameplay/content JSON or Lua.
|
||||||
// Re-comment before shipping.
|
// Re-comment before shipping.
|
||||||
saveInitialState();
|
//saveInitialState();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -890,11 +890,11 @@ namespace FRG
|
|||||||
}
|
}
|
||||||
|
|
||||||
Character* Location::raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance) {
|
Character* Location::raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance) {
|
||||||
// Every NPC is treated as a vertical cylinder: radius 0.25m, height 1.6m,
|
// Every NPC is treated as a vertical cylinder
|
||||||
// base at npc->position (the model's foot). Intersection = circle hit in the
|
// base at npc->position (the model's foot). Intersection = circle hit in the
|
||||||
// XZ plane, then clip the entry/exit t against the [yFoot, yFoot+height] slab.
|
// XZ plane, then clip the entry/exit t against the [yFoot, yFoot+height] slab.
|
||||||
static constexpr float NPC_CLICK_RADIUS = 0.25f;
|
static constexpr float NPC_CLICK_RADIUS = 0.35f;
|
||||||
static constexpr float NPC_CLICK_HEIGHT = 1.6f;
|
static constexpr float NPC_CLICK_HEIGHT = 1.8f;
|
||||||
static constexpr float NPC_PICK_EPSILON = 1e-6f;
|
static constexpr float NPC_PICK_EPSILON = 1e-6f;
|
||||||
|
|
||||||
Character* closestNpc = nullptr;
|
Character* closestNpc = nullptr;
|
||||||
|
|||||||
+77
-33
@@ -173,11 +173,84 @@ bool LocationGameState::replanCharacter(
|
|||||||
{
|
{
|
||||||
CharacterState* character = findCharacter(id, players);
|
CharacterState* character = findCharacter(id, players);
|
||||||
if (!character || !location) return false;
|
if (!character || !location) return false;
|
||||||
|
if (!forcedObstacleId.empty() && !character->isPlayer &&
|
||||||
|
character->canAttack && character->hp > 0.f) {
|
||||||
|
const std::string selectedTarget =
|
||||||
|
selectNpcTarget(*character, players, false);
|
||||||
|
if (selectedTarget != character->attackTargetId) {
|
||||||
|
character->stopInPlace();
|
||||||
|
character->attackTargetId = selectedTarget;
|
||||||
|
character->battle_state = 0;
|
||||||
|
character->attack = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedTarget.empty()) {
|
||||||
|
const CharacterState* target = findCharacter(selectedTarget, players);
|
||||||
|
if (target) {
|
||||||
|
character->setTarget(
|
||||||
|
target->position, {}, *location, id,
|
||||||
|
collectPathObstacles(id, players, forcedObstacleId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
character->attackTargetId.clear();
|
||||||
|
character->battle_state = 0;
|
||||||
|
character->attack = 0;
|
||||||
|
const Eigen::Vector3f homeTarget(
|
||||||
|
character->homePosition.x(), 0.f, character->homePosition.z());
|
||||||
|
if ((homeTarget - character->position).norm() >
|
||||||
|
CharacterState::kWalkThreshold) {
|
||||||
|
character->setTarget(
|
||||||
|
homeTarget, {}, *location, id,
|
||||||
|
collectPathObstacles(id, players, forcedObstacleId));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
character->forceReplan(
|
character->forceReplan(
|
||||||
*location, id, collectPathObstacles(id, players, forcedObstacleId));
|
*location, id, collectPathObstacles(id, players, forcedObstacleId));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string LocationGameState::selectNpcTarget(
|
||||||
|
const CharacterState& npc,
|
||||||
|
const PlayerStateMap& players,
|
||||||
|
bool preserveValidLock) const
|
||||||
|
{
|
||||||
|
if (preserveValidLock) {
|
||||||
|
const auto locked = players.find(npc.attackTargetId);
|
||||||
|
if (locked != players.end() && locked->second &&
|
||||||
|
locked->second->enabled && locked->second->hp > 0.f)
|
||||||
|
return npc.attackTargetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> playerIds;
|
||||||
|
playerIds.reserve(players.size());
|
||||||
|
for (const auto& [id, player] : players)
|
||||||
|
if (player && player->enabled && player->hp > 0.f)
|
||||||
|
playerIds.push_back(id);
|
||||||
|
std::sort(playerIds.begin(), playerIds.end());
|
||||||
|
|
||||||
|
const float visibleRangeSquared = npc.visibleRange * npc.visibleRange;
|
||||||
|
std::string selectedTarget;
|
||||||
|
float nearestDistanceSquared = visibleRangeSquared;
|
||||||
|
for (const std::string& playerId : playerIds) {
|
||||||
|
const Eigen::Vector3f delta =
|
||||||
|
players.at(playerId)->position - npc.position;
|
||||||
|
const float distanceSquared =
|
||||||
|
delta.x() * delta.x() + delta.z() * delta.z();
|
||||||
|
if (distanceSquared <= nearestDistanceSquared &&
|
||||||
|
(selectedTarget.empty() ||
|
||||||
|
distanceSquared < nearestDistanceSquared ||
|
||||||
|
(distanceSquared == nearestDistanceSquared &&
|
||||||
|
playerId < selectedTarget))) {
|
||||||
|
selectedTarget = playerId;
|
||||||
|
nearestDistanceSquared = distanceSquared;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedTarget;
|
||||||
|
}
|
||||||
|
|
||||||
void LocationGameState::startTaxi()
|
void LocationGameState::startTaxi()
|
||||||
{
|
{
|
||||||
location->taxiCar.waypoints = location->taxiCarWaypoints;
|
location->taxiCar.waypoints = location->taxiCarWaypoints;
|
||||||
@@ -321,13 +394,6 @@ LocationSimulationEvents LocationGameState::update(
|
|||||||
if (player) playerIds.push_back(id);
|
if (player) playerIds.push_back(id);
|
||||||
std::sort(playerIds.begin(), playerIds.end());
|
std::sort(playerIds.begin(), playerIds.end());
|
||||||
|
|
||||||
std::vector<std::string> eligiblePlayerIds;
|
|
||||||
for (const std::string& id : playerIds) {
|
|
||||||
const auto& player = players.at(id);
|
|
||||||
if (player->enabled && player->hp > 0.f)
|
|
||||||
eligiblePlayerIds.push_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> npcIds;
|
std::vector<std::string> npcIds;
|
||||||
npcIds.reserve(npcs.size());
|
npcIds.reserve(npcs.size());
|
||||||
for (const auto& [id, npc] : npcs)
|
for (const auto& [id, npc] : npcs)
|
||||||
@@ -343,30 +409,8 @@ LocationSimulationEvents LocationGameState::update(
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const std::string previousTarget = npc.attackTargetId;
|
const std::string previousTarget = npc.attackTargetId;
|
||||||
const auto locked = players.find(previousTarget);
|
const std::string selectedTarget =
|
||||||
const bool lockValid =
|
selectNpcTarget(npc, players, true);
|
||||||
locked != players.end() && locked->second &&
|
|
||||||
locked->second->enabled && locked->second->hp > 0.f;
|
|
||||||
std::string selectedTarget = lockValid ? previousTarget : std::string();
|
|
||||||
|
|
||||||
if (!lockValid) {
|
|
||||||
float nearestDistanceSquared = npc.visibleRange * npc.visibleRange;
|
|
||||||
for (const std::string& playerId : eligiblePlayerIds) {
|
|
||||||
const Eigen::Vector3f delta =
|
|
||||||
players.at(playerId)->position - npc.position;
|
|
||||||
const float distanceSquared =
|
|
||||||
delta.x() * delta.x() + delta.z() * delta.z();
|
|
||||||
if (distanceSquared <= nearestDistanceSquared) {
|
|
||||||
if (selectedTarget.empty() ||
|
|
||||||
distanceSquared < nearestDistanceSquared ||
|
|
||||||
(distanceSquared == nearestDistanceSquared &&
|
|
||||||
playerId < selectedTarget)) {
|
|
||||||
selectedTarget = playerId;
|
|
||||||
nearestDistanceSquared = distanceSquared;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedTarget != previousTarget) {
|
if (selectedTarget != previousTarget) {
|
||||||
npc.stopInPlace();
|
npc.stopInPlace();
|
||||||
@@ -474,7 +518,7 @@ LocationSimulationEvents LocationGameState::update(
|
|||||||
source.events.attackDirection});
|
source.events.attackDirection});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto player = players.find("player");
|
auto player = players.find("player1");
|
||||||
if (!interactiveObjectsLocked &&
|
if (!interactiveObjectsLocked &&
|
||||||
!location->targetInteractiveObjectId.empty() &&
|
!location->targetInteractiveObjectId.empty() &&
|
||||||
player != players.end() && player->second && player->second->enabled) {
|
player != players.end() && player->second && player->second->enabled) {
|
||||||
@@ -502,7 +546,7 @@ LocationSimulationEvents LocationGameState::update(
|
|||||||
(player->second->position - npc->position).norm();
|
(player->second->position - npc->position).norm();
|
||||||
if (distance <= NPC_TALK_DISTANCE) {
|
if (distance <= NPC_TALK_DISTANCE) {
|
||||||
player->second->stopInPlace();
|
player->second->stopInPlace();
|
||||||
npc->faceTargetId = "player";
|
npc->faceTargetId = "player1";
|
||||||
result.npcInteractionId = location->targetInteractNpcId;
|
result.npcInteractionId = location->targetInteractNpcId;
|
||||||
location->targetInteractNpcId.clear();
|
location->targetInteractNpcId.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ struct LocationGameState {
|
|||||||
void load(const nlohmann::json& in);
|
void load(const nlohmann::json& in);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string selectNpcTarget(
|
||||||
|
const CharacterState& npc,
|
||||||
|
const PlayerStateMap& players,
|
||||||
|
bool preserveValidLock) const;
|
||||||
bool updateNpcCar(std::int64_t deltaMs);
|
bool updateNpcCar(std::int64_t deltaMs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ namespace FRG {
|
|||||||
<< npcId << "'\n";
|
<< npcId << "'\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loc->faceCharacter(*npc, "player");
|
loc->faceCharacter(*npc, "player1");
|
||||||
});
|
});
|
||||||
|
|
||||||
api.set_function("player_walk_to",
|
api.set_function("player_walk_to",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ private:
|
|||||||
GameSnapshot buildSnapshot() const;
|
GameSnapshot buildSnapshot() const;
|
||||||
|
|
||||||
GameState state_;
|
GameState state_;
|
||||||
std::string localPlayerId_ = "player";
|
std::string localPlayerId_ = "player1";
|
||||||
std::string resourceZipFile_;
|
std::string resourceZipFile_;
|
||||||
std::vector<std::string> networkPlayerSlots_;
|
std::vector<std::string> networkPlayerSlots_;
|
||||||
std::int64_t battleZoneTestBotElapsedMs_ = 0;
|
std::int64_t battleZoneTestBotElapsedMs_ = 0;
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ public:
|
|||||||
attributes.createOnMainThread = EM_TRUE;
|
attributes.createOnMainThread = EM_TRUE;
|
||||||
socket_ = emscripten_websocket_new(&attributes);
|
socket_ = emscripten_websocket_new(&attributes);
|
||||||
if (socket_ <= 0) {
|
if (socket_ <= 0) {
|
||||||
fail("create WebSocket");
|
fail("create WebSocket", socket_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,11 +205,21 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static EM_BOOL onClose(
|
static EM_BOOL onClose(
|
||||||
int, const EmscriptenWebSocketCloseEvent*, void* userData)
|
int, const EmscriptenWebSocketCloseEvent* event, void* userData)
|
||||||
{
|
{
|
||||||
auto* self = static_cast<Impl*>(userData);
|
auto* self = static_cast<Impl*>(userData);
|
||||||
self->connected_ = false;
|
self->connected_ = false;
|
||||||
if (!self->closing_) self->fail("WebSocket close");
|
if (!self->closing_) {
|
||||||
|
std::cerr << "[network] WebSocket closed";
|
||||||
|
if (event) {
|
||||||
|
std::cerr << " (code " << event->code;
|
||||||
|
if (event->reason[0] != '\0')
|
||||||
|
std::cerr << ", reason: " << event->reason;
|
||||||
|
std::cerr << ')';
|
||||||
|
}
|
||||||
|
std::cerr << '\n';
|
||||||
|
self->connectionFailed_ = true;
|
||||||
|
}
|
||||||
return EM_TRUE;
|
return EM_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,11 +236,13 @@ private:
|
|||||||
return EM_TRUE;
|
return EM_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fail(const char* operation)
|
void fail(const char* operation, int result = 0)
|
||||||
{
|
{
|
||||||
connected_ = false;
|
connected_ = false;
|
||||||
connectionFailed_ = true;
|
connectionFailed_ = true;
|
||||||
std::cerr << "[network] " << operation << " failed" << std::endl;
|
std::cerr << "[network] " << operation << " failed";
|
||||||
|
if (result != 0) std::cerr << " (result " << result << ')';
|
||||||
|
std::cerr << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string host_;
|
std::string host_;
|
||||||
|
|||||||
Reference in new issue
Block a user