Commit Graph

65 Commits

Author SHA1 Message Date
Acentech Dev
f5e1f46444 feat(hs): add open-team-panel (S2C) and team-select (C2S) packets 2026-07-20 23:22:33 +03:00
Acentech Dev
cc0b7abb44 feat(hs): add event NPC 560 and place it in Lorencia
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 23:15:52 +03:00
Acentech Dev
5bc5f461e5 feat(hs): warp teams to base on start + cancel if a team is empty
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 23:09:39 +03:00
Acentech Dev
8295c30b71 feat(hs): wire HeykelSavasiContext in GetMiniGameAsync + team gate resolver 2026-07-20 23:04:21 +03:00
Acentech Dev
968eb0c155 feat(hs): HeykelSavasiContext team tracking + balance rule
Adds the HeykelSavasiTeam enum (None/Red/Blue) and the HeykelSavasiContext
skeleton (subclass of MiniGameContext) with team registration
(AssignTeam/GetTeam/PlayersOf/TeamCount) and a join-balance rule
(|Red-Blue| <= 2 after the prospective join), exposed as a pure static
IsJoinAllowed for fast unit testing without constructing the full context.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 22:59:15 +03:00
Acentech Dev
5d0f475472 feat(hs): add HeykelSavasi MiniGameDefinition initializer 2026-07-20 22:44:38 +03:00
Acentech Dev
b90013c4bb feat(hs): add MiniGameType.HeykelSavasi 2026-07-20 22:41:00 +03:00
Acentech Dev
732196f623 feat(hs): add red/blue base exit gates on Heykel Savasi map 2026-07-20 22:38:20 +03:00
Acentech Dev
5a354fb419 feat(hs): add Heykel Savasi event map skeleton (map 90)
Adds HeykelSavasiMap (BaseMapInitializer, Number=90/World91) as an empty
terrain-only skeleton and registers it in GameMapsInitializer. Statue/guard
monster definitions and spawns are added by later Heykel Savasi tasks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 22:31:46 +03:00
Acentech Dev
3d5d40b753 Add Warrior Wings & Cape (12/242-247)
Some checks failed
.NET Core / build (push) Has been cancelled
Six high-tier imported wings, one per class line: Wizard (242, Soul Master),
Magic (243, Duel Master), Elf (244, High Elf), Summoner (245, Dimension Master),
Warrior Cape (246, Lord Emperor + Fist Master) and Knight (247, Blade Master).
Each: base defense + defense-per-level, 3rd Wing Options, damage increase and
fast flight. Applied via update v99 (AddWarriorWingsUpdateSeason6), reusing the
shared "3rd Wing Options" option set to avoid Guid collisions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 23:27:22 +03:00
Acentech Dev
1cadaa08ab fix(items): reuse shared 3rd Wing Options + level tables for Poison wings (avoid Guid collision) 2026-07-19 18:36:38 +03:00
Acentech Dev
3e8cd8fdae feat(items): Poison Wing/Cape as high-tier wings (defense + options + level bonuses)
Switch from the basic CreateWing overload to the full one: base
defense 65/60, defense-per-level, wing options (HP recover / phys
damage / defense), damage increase, fast flight. Level req 100.
2026-07-19 18:14:46 +03:00
Acentech Dev
affa4bd73b feat(items): add Poison Wing (12/240) and Poison Cape (12/241)
Basic wings via the simple CreateWing overload (base defense, class
restriction, CanFly; no options). Poison Wing=Dark Knight, Poison
Cape=Dark Lord+Rage Fighter. Update-plugin v98 + fresh-seed via
Wings.Initialize().
2026-07-19 16:54:33 +03:00
Acentech Dev
fc9ba0e594 docs: design spec for Poison Wing & Poison Cape (wings 12/240, 12/241) 2026-07-19 16:44:35 +03:00
Acentech Dev
d84b29eac3 feat(maps): add Acheron, Debenter, Uruk, Ferea (maps 83-86)
Same pattern as Arkania: terrain resources Terrain84-87.att, map
initializer classes, registration, and update-plugin (v97) that
creates each map + spawn gate + /move warp AND assigns it to the
game server configuration so it is hosted. Also fix the Arkania
update-plugin to assign the game server config (was missing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 15:47:05 +03:00
Acentech Dev
80ec466ab1 fix(maps): Arkania is map number 82 (client World = number+1 off-by-one)
Client tried to load World84 for map 83; MU client world index is
server map number + 1 (Lorencia 0 -> World1). Arkania client assets
are World83, so the server map number is 82 and the terrain resource
is Terrain83.att (number+1).
2026-07-19 14:08:01 +03:00
Acentech Dev
e3d37467d5 feat(maps): add Arkania DB update-plugin with spawn gate and /move warp 2026-07-19 13:45:37 +03:00
Acentech Dev
7e21fc1fb3 feat(maps): add Arkania map initializer (number 83) and register it 2026-07-19 13:43:26 +03:00
Acentech Dev
4628902f11 feat(maps): add Arkania (map 83) terrain resource Terrain84.att 2026-07-19 13:42:46 +03:00
Acentech Dev
a61890ef6e docs: implementation plan for Arkania map pilot
7 tasks: terrain resource (Terrain84.att, off-by-one), map class +
registration, update-plugin with spawn gate + /move warp, docker
build/verify, deploy + panel verify, client assets, client verify.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 13:31:34 +03:00
Acentech Dev
3b2e26b27c docs: design spec for new maps import (pilot: Arkania/World83)
End-to-end import of one pilot map across server (OpenMU C# map
initializer + Terrain83.att resource + DB update-plugin), PC client
(World83/Object83 assets), and web (no changes; MapEditor renders
seeded terrain, user adds spawns/NPCs). Other 4 maps + mobile are
follow-up from the proven template.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 13:21:40 +03:00
Acentech Dev
1de06d83ab fix(reset): warp the player home instead of moving him silently
Some checks failed
.NET Core / build (push) Has been cancelled
MoveHomeAsync wrote PositionX/PositionY/CurrentMap/Rotation on the character
record directly, which is a partial copy of Player.PlaceAtGateAsync: it placed
the player but skipped removing him from the map and telling the client.

Player.Position is backed by those very fields, so the coordinates jumped on the
server while the client never got a map change. The client then interpolated a
walk to the new spot and the character visibly slid across the map after a reset.

WarpToAsync does the same placement plus the map removal and the map change
notification, and it handles respawning on the same map. It is the path every
other caller uses (duel room, gate NPCs, mini games, castle siege portal).

The existing tests all ran with MoveHome = false, which is why this path was
never covered. The new test pins the notification: it fails on the old code
because MapChangeAsync is never invoked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 00:26:04 +03:00
Acentech Dev
2927be1ba9 chore(docs): regenerate QuestProgressExtended packet doc as C2
Some checks failed
.NET Core / build (push) Has been cancelled
The packet definition declares C2HeaderWithSubCode, but the committed
doc was generated from an older C1 header and never refreshed. This is
the doc generator's output for the current XML, so the tree stays clean
after a build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 22:04:13 +03:00
Acentech Dev
16752f3649 chore(deploy): default RESOLVE_IP to the emulator host alias
Without RESOLVE_IP the ConnectServer advertises the public IP, which the
emulator cannot reach, so server select hangs. Default to 10.0.2.2 and
allow an override for real devices on the LAN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 22:04:13 +03:00
Acentech Dev
ef3bffe39c feat(items): add Imperial Sword (0/50) and Imperial Staff (5/50)
Two new weapons placed at free item slots so they never collide with
standard Season 6 items. The client name DB (Item_eng.bmd) is the source
of tooltip name/stats, so only free slots are usable for custom items.

Both seed paths are covered:
- Fresh DB: Weapons.Initialize() calls the new CreateImperialWeapons050().
- Existing DB: AddImperialWeapons050UpdateSeason6 (UpdateVersion 95),
  applied from the AdminPanel Updates page, with an idempotency guard.

Imperial Sword is a Magic Gladiator weapon (copy of 0/28), Imperial Staff
is a Wizard weapon (copy of 5/31).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 22:03:52 +03:00
Acentech Dev
fbe75d55be feat(CS): run the siege on ONE designated server (CastleSiegeServerId)
Some checks failed
.NET Core / build (push) Has been cancelled
With multiple game servers each has its own map instances, so the siege ran
independently on all of them - a guild could win uncontested on an empty server's
Valley of Loren. Now the siege (tick/spawn/battle/registration) runs only on the
server whose Id == config.CastleSiegeServerId (AdminPanel-editable). Other servers
skip the siege and just mirror the shared castle owner from config so the hunting-map
gate + castle flag rewards still work everywhere. The Guardsman on non-siege servers
tells players which server to switch to.
2026-07-15 19:10:48 +03:00
Acentech Dev
3e465c016e feat(CS): AdminPanel-friendly config (day checkboxes, minute/second durations)
Some checks failed
.NET Core / build (push) Has been cancelled
The generic plugin-config editor couldn't edit IList<DayOfWeek> and showed durations
in milliseconds + the runtime Persisted* state. Add [JsonIgnore] proxy properties that
the AutoFields editor CAN render: OpenDays ([Flags] enum -> checkboxes), Registration/
Preparation/Siege minutes + CrownHold seconds (int inputs). Hide the underlying TimeSpan/
list/Persisted* fields with [Browsable(false)]. Runtime JSON shape is unchanged (proxies
are JsonIgnore) so no persisted-config break.
2026-07-15 17:41:09 +03:00
Acentech Dev
f135e90899 fix(CS): stop crown re-capture loop + show seal panel only to the master
Some checks failed
.NET Core / build (push) Has been cancelled
- The occupier can no longer re-register its own throne (canCapture = eligible != occupier),
  which caused a repeating 60s panel loop; only a DIFFERENT guild can contest.
- The 60s registration panel (0xB2/0x15) is now sent ONLY to the master on the crown,
  not broadcast to switch-holders/other players. Shield(0x16) + capture(0x18) still broadcast.
+1 test (15 total).
2026-07-15 16:22:13 +03:00
Acentech Dev
e5dfa24585 fix(CS): send crown shield packet (0xB2/0x16) only on change, not every tick
Some checks failed
.NET Core / build (push) Has been cancelled
The shield packet pops a modal message box on the client; sending it every tick
re-opened the modal continuously and froze player input at siege start. Track the
shield state in the context and only push the packet when it actually flips.
2026-07-15 15:36:51 +03:00
Acentech Dev
3dd4881406 feat(CS): authentic Crown-hold throne capture (S6 protocol) replacing Sinior-talk
Some checks failed
.NET Core / build (push) Has been cancelled
Break all gates + hold both switches (defenses down) -> the Crown shield drops
(C1 B2 16=0). The guild master then stands on the Crown (176,212) and holds for
CrownHoldDuration (default 60s, client shows a 60s countdown via C1 B2 15) to
capture; capture broadcasts C1 B2 18 + golden text and sets the occupier. Losing a
switch or leaving the crown resets the hold (contestable until the siege timer ends).
Sinior (223) is now informational guidance. +2 tests (14 total).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:04:10 +03:00
Acentech Dev
4651ef232c refactor(CS): schedule + periods are config-owned, AdminPanel-editable
Some checks failed
.NET Core / build (push) Has been cancelled
Move the auto-schedule from context-owned state to the plugin config (single source
of truth): RegistrationOpenDays + RegistrationOpenTimes + Registration/Preparation/
SiegeDuration are all editable in the AdminPanel plugin config and take effect live
(context refreshes its config reference each tick via UpdateConfiguration). /csschedule
now writes the config. Removed the duplicate Persisted schedule fields. 12 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:52:07 +03:00
Acentech Dev
f586321123 feat(CS): castle flag owner logo (C1 B9 02) + catapults for war atmosphere
Some checks failed
.NET Core / build (push) Has been cancelled
#1 Castle flags now show the owner guild's logo: resolve owner name -> guild logo
(cached), broadcast C1 B9 02 (32-byte mark) to players on the castle map every 15s.
#3 War atmosphere: spawn catapult NPCs 221/222 at siege start (client renders them
as siege weapons); the 0xB2/0x17 start flag already flips the map to warzone mode.
All raw S6 packets, no client changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:19:07 +03:00
Acentech Dev
7cf790c2a8 feat(CS): on-map siege countdown timer (S6 client protocol C1 B2 17/1E)
Some checks failed
.NET Core / build (push) Has been cancelled
Client already renders the siege-map countdown but never received the packets.
New ICastleSiegeStatusViewPlugIn + RemoteView impl send the raw S6 packets:
C1 B2 17 (battle start/stop flag, arms the countdown) and C1 B2 1E (remaining
hour/minute). CastleSiegeEventPlugIn broadcasts them to players on the battle map
every 10s during Siege and sends stop at Settlement. No client changes. +1 test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 13:45:01 +03:00
Acentech Dev
ac6700a356 feat(CS): weekly auto-schedule (day-of-week + UTC time), persisted, /csschedule GM cmd
Some checks failed
.NET Core / build (push) Has been cancelled
The siege can now auto-open registration on scheduled days/time instead of only
manual /csphase. Schedule is context-owned state (like owner), persisted across
restarts via the same config-JSON path. New GM command /csschedule sets/views/clears
it (e.g. /csschedule Sunday 20:00, UTC). +2 unit tests (11 total).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 12:47:29 +03:00
Acentech Dev
05a10d495d fix(CS): persist config via non-caching typed context (caching context saved nothing)
Some checks failed
.NET Core / build (push) Has been cancelled
CreateNewContext(config) returns a caching context whose returned config objects
aren't tracked by that context, so SetConfiguration+SaveChanges was a silent no-op
(DB row never updated). Load a fresh change-tracked PlugInConfiguration by id in a
non-caching typed context, rewrite the JSON, save. Adds a confirmation log line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 12:30:18 +03:00
Acentech Dev
9bdd57703f feat(CS): persist owner/phase/registrations across restarts via plugin config JSON
Some checks failed
.NET Core / build (push) Has been cancelled
Castle Siege state was in-memory, so the castle owner (and thus the P4 hunting-map
reward) reset on every server restart/redeploy. Now the context marks itself dirty
on any persistable change (phase transition, registration, owner set); the plugin's
periodic tick writes a snapshot into its own PlugInConfiguration CustomConfiguration
(a JSON blob already stored in PostgreSQL - no schema migration) and restores it on
startup. Battle state (defenses/switches/occupier) stays transient. +2 unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 12:17:34 +03:00
Acentech Dev
f03f6aa7ad fix(CS-P4): Guard portal uses Land of Trials entry ExitGate (no spawn gate exists)
Some checks failed
.NET Core / build (push) Has been cancelled
Land of Trials (31) has no IsSpawnGate, so SafeZoneSpawnGate was null -> portal
said 'not available'. Fall back to the map's single entry ExitGate (60-69,10-19,
the real map entrance) so owner-guild members actually warp in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:55:54 +03:00
Acentech Dev
d5097752af feat(CS-P4): castle Guard (220) as Land of Trials hunting portal
Some checks failed
.NET Core / build (push) Has been cancelled
The Valley of Loren Guard NPC now warps castle-owning guild members into the
hunting ground (map 31); non-owners get the sealed/owner-only reason. Provides
the in-world entry point that was missing (talking to Guard was unimplemented).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:45:01 +03:00
Acentech Dev
dfa884b86c feat(CS-P4): castle-exclusive hunting map (Land of Trials 31) gated to owner guild
Some checks failed
.NET Core / build (push) Has been cancelled
Ownership reward: only members of the current castle-owning guild may warp into
Land of Trials (map 31); sealed while unowned; GMs bypass. Enforced in both
WarpAction and WarpGateAction (// ADAMU-CUSTOM). Tax system deferred per user.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:35:34 +03:00
Acentech Dev
b890e82a88 refactor(CS-P3): siege defenses = 6 castle gates only (removed 4 statues per user - kept clean gate mechanic)
Some checks failed
.NET Core / build (push) Has been cancelled
2026-07-15 11:18:28 +03:00
Acentech Dev
8114930855 feat(CS-P3): 4 real guardian statues (283) at castle positions 82/107/94,129/131/126 - all defenses required for throne 2026-07-15 10:53:57 +03:00
Acentech Dev
af9554bf91 feat(CS-P3): REAL castle gates (NPC 277) at 6 client gate positions -> client closes+blocks them; breakable via HP template; inner guardian statues (283)
Some checks failed
.NET Core / build (push) Has been cancelled
2026-07-15 03:18:00 +03:00
Acentech Dev
72ebc96e28 feat(CS-P3): throne registration via Sinior/Crown talk (223/216) after defenses down + both switches held; reachable defense positions
Some checks failed
.NET Core / build (push) Has been cancelled
2026-07-15 02:49:27 +03:00
Acentech Dev
db8bdd394f feat(CS-P3): PROPER siege - position-based Crown Switch hold (stand on them) + gates & statues destructibles + auto throne capture; remove non-working talk handlers
Some checks failed
.NET Core / build (push) Has been cancelled
2026-07-15 02:28:14 +03:00
Acentech Dev
c50af5e5c2 feat(CS-P3): full siege objective chain - guardian statues (Destructible spawn) + dual Crown Switch hold + throne capture gating 2026-07-15 01:52:19 +03:00
Acentech Dev
5549c2bec7 feat(CS-P3): siege PvP on Valley of Loren during siege (ADAMU-CUSTOM) + golden phase announcements
Some checks failed
.NET Core / build (push) Has been cancelled
2026-07-15 01:23:57 +03:00
Acentech Dev
c7147f7a63 feat(CS-P3): warp registered members to Valley of Loren on siege start + Crown Switch throne capture (NPC 217/218)
Some checks failed
.NET Core / build (push) Has been cancelled
2026-07-15 00:57:28 +03:00
Acentech Dev
9f2078d724 feat(CS-P3): throne capture + settlement winner in state machine + tests
Some checks failed
.NET Core / build (push) Has been cancelled
2026-07-15 00:48:09 +03:00
Acentech Dev
396527a62a docs: CS P3 siege battle plan (minimal playable increment first) 2026-07-15 00:42:05 +03:00
Acentech Dev
41588bd237 feat(CS-P2): registration fee (zen) + already-registered guard on Guardsman 2026-07-15 00:36:20 +03:00