Combat and siege#
Purpose#
Real-time tactical battles: infantry and siege unit figures, projectile resolution, and (during castle sieges) an 80×80 destructible map with gates, walls, boiling oil, and a capture flag.
Covers open-field battles and siege assaults. Unit display names live in external l2.eng; the client uses numeric type IDs 0–10.
Key entry points#
Battle tick#
| Symbol | Address | Role |
|---|---|---|
| Per-type tick dispatch | PTR_LAB_004f46a0 |
11 handlers indexed by lotr2_combat_figure_unit_type |
lotr2_combat_init_battle_state |
0x004907ec | Initialize battle state, clear figure/projectile/group slots, seed combat setup |
lotr2_combat_tick_all_figures |
0x004934a2 | Walk active figures 1..0x50; dispatch unit tick handlers |
lotr2_combat_clear_all_figures |
0x00480a81 | Clear all 0x1b0-byte battle figure slots |
lotr2_combat_clear_figure_slot |
0x004804d0 | Clear one 0x1b0-byte battle figure slot |
lotr2_combat_remove_figure |
0x00480575 | Remove a figure from its tile and clear its slot |
lotr2_combat_update_all_move_steps |
0x004936ff | Update movement steps for all active figures |
lotr2_combat_update_walk_anim_step |
0x00496f63 | Per-figure walk animation step (wrapper) |
lotr2_combat_advance_walk_sprite |
0x00498008 | Advance walk sprite frame/direction for infantry types 0–6 |
lotr2_combat_update_counter_anim_step |
0x00496f73 | Counter-attack animation step wrapper |
lotr2_combat_advance_counter_sprite |
0x00498662 | Advance counter-attack sprite frame |
lotr2_combat_update_idle_anim_step |
0x00496f83 | Idle/stance animation step wrapper |
lotr2_combat_advance_idle_sprite |
0x00498a3e | Advance idle sprite; siege types use sprite_b path |
lotr2_combat_update_fire_anim_step |
0x00496f93 | Ranged fire animation step wrapper |
lotr2_combat_advance_fire_sprite |
0x00498da4 | Archer/crossbow fire sprite from facing quadrant |
lotr2_combat_direction_from_points |
0x00480dc5 | Convert source/destination coordinates to an 8-way direction |
lotr2_combat_pop_queued_move_dir |
0x004a1f0f | Pop a queued path coordinate and return the next direction |
lotr2_combat_step_figure_tile |
0x004a1ffa | Step a figure one tile in direction 0..7 and update occupancy |
lotr2_combat_update_attack_damage |
0x00492cb1 | Load melee attack_damage from 0x004f4c18 by type + formation tier |
lotr2_combat_apply_melee_hit |
0x004a48c6 | Apply damage_acc; counter-attack; casualties |
lotr2_combat_update_move_step |
0x00496fa3 | Infantry movement animation steps (types 0–6) |
lotr2_combat_siege_update_sprite_a |
0x004994ed | Siege sprite step (types 7–10) |
lotr2_combat_siege_update_sprite_b |
0x004996b8 | Siege sprite step variant |
lotr2_combat_load_formation_thresholds |
0x00490b60 | Load formation tier thresholds from 0x4f4b28 |
lotr2_combat_place_figures_on_tiles |
0x0049055b | Write active figure slot into tile occupancy |
lotr2_combat_handle_map_click |
0x00490648 | Mouse coords → tile index; resolve selected figure |
lotr2_combat_clamp_scroll_pos |
0x004905e1 | Clamp battle scroll position to map bounds |
lotr2_combat_tally_army_survivors |
0x00490ba7 | Sum surviving infantry back into province army records |
lotr2_combat_compute_unit_score |
0x00490e96 | Weighted strength score by unit type multiplier |
lotr2_combat_rout_player_figures |
0x00491077 | Set all figures of a player to routing state |
lotr2_combat_reset_figure_move_targets |
0x00492127 | Clear move-target field for all active figures |
lotr2_combat_assign_figure_sprite_ptrs |
0x00492184 | Assign sprite pointers by unit type and side |
lotr2_combat_draw_figure_tooltip |
0x00489505 | Draw unit hover tooltip; mark tile dirty |
lotr2_combat_poll_figure_hover |
0x004897a1 | Poll hover state; compute tooltip screen position |
lotr2_combat_tick_figure_walk |
0x004940d6 | Walk-phase state handler; walk anim + counter decrement |
lotr2_combat_tick_figure_move |
0x0049436e | Move-phase state handler; move-step + walk anim |
lotr2_combat_tick_figure_melee_engage |
0x004943f8 | Melee engage state; calls lotr2_combat_apply_melee_hit |
lotr2_combat_tick_figure_walk_and_fire |
0x0049450a | Walk + conditional ranged fire dispatch |
lotr2_combat_tick_figure_ranged_fire |
0x00494557 | Spawn projectile via lotr2_combat_alloc_projectile_slot |
| Per-state tick dispatch | PTR_LAB_004f46d0 |
18 handlers indexed by figure state byte lotr2_combat_figure_state |
lotr2_combat_tick_all_groups |
0x0049a0b5 | Group AI tick; dispatches PTR_LAB_004f4718 / 004f4758 order handlers |
lotr2_combat_try_advance_figure_path |
0x0049f7b9 | Pathfind step + tile step + melee engage probe |
lotr2_combat_scan_adjacent_melee_target |
0x004a4dfd | 8-neighbor enemy scan; sets engage direction |
lotr2_combat_spawn_army_open_field |
0x00491113 | Spawn figures from province army records (open battle) |
lotr2_combat_spawn_army_siege |
0x00491468 | Spawn siege defender figures from army table |
lotr2_combat_tick_figure_start_melee |
0x00494dfb | Walk toward target; mutual melee engage on close range |
lotr2_combat_tick_figure_chase_target |
0x00494f6f | Chase assigned target tile; pathfind + move step |
lotr2_combat_tick_figure_siege_move |
0x004953b0 | Siege engine move + sprite update |
lotr2_combat_tick_figure_catapult_fire |
0x004954a6 | Catapult/oil ranged fire state |
lotr2_combat_tick_battle_screen |
0x004aeaf5 | Per-frame battle screen handler |
Battle viewport render glue (pass 43)#
Called each frame from lotr2_game_main_frame_tick when lotr2_game_active_view == 2 and screen mode is battle (0x28–0x2f). Uses battle grid globals DAT_00502df8 / DAT_00502da0 (tile size 0x10 or 0x20).
| Symbol | Address | Role |
|---|---|---|
lotr2_game_main_frame_tick |
0x004d49a0 | Per-frame winmain tick: combat sim, viewport, UI, present |
lotr2_combat_init_battle_grid_layout |
0x004d7020 | Bind battle map pointer, stride, viewport dimensions |
lotr2_combat_init_battle_sprite_tables |
0x004d7107 | Bind terrain/overlay PL8 sprite tables |
lotr2_combat_mp_frame_gate |
0x004d6479 | MP debounce + host sync before advancing battle sim |
lotr2_combat_tick_battle_viewport |
0x004d7142 | Orchestrate dirty-tile + figure + projectile blit passes |
lotr2_combat_blit_dirty_tiles_16px |
0x004d78f0 | 16px-tile dirty terrain pass (lotr2_gfx_blit_tile16_strip) |
lotr2_combat_blit_dirty_tiles_32px |
0x004d7bcf | 32px-tile dirty terrain + wall overlay pass |
lotr2_combat_blit_siege_damage_tiles |
0x004d8071 | Siege damage-layer tile refresh |
lotr2_combat_build_figure_paint_list |
0x004d892b | Build Y-sorted list of figures in viewport |
lotr2_combat_blit_figure_sprite |
0x004d8c24 | Blit one figure with walk/siege sprite offsets |
lotr2_combat_blit_projectile_chain |
0x004d9ec7 | Walk projectile linked list and blit sprites |
Battle session entry / exit#
| Symbol | Address | Role |
|---|---|---|
lotr2_combat_enter_open_battle |
0x0048b180 | Initialize open-field battle; set screen mode 0x2c |
lotr2_combat_enter_siege_battle |
0x0048b469 | Load castle layout; init pathfinding and figures |
lotr2_combat_start_battle_music |
0x0048b35b | Start battle1_wav / battle2_wav stream by siege and MP mode |
lotr2_combat_check_battle_outcome |
0x0048b58d | Detect zero-headcount side; transition to defeat screen |
lotr2_combat_set_battle_outcome_code |
0x0048b8fb | Writes win/loss/draw code from attacker/defender sides |
lotr2_combat_record_siege_battle_score |
0x0048b9ac | Persists survivor counts into 0x300-byte battle record |
lotr2_combat_return_to_campaign_map |
0x0048bda8 | Post-battle: reload campaign map; screen mode 0x13 |
lotr2_combat_load_open_field_map |
0x0048d4c9 | Load batfield.pl8; build 80×80 open-field tile grid |
lotr2_combat_load_siege_field_map |
0x0048e127 | Load stnfield.pl8; decode siege terrain markers |
lotr2_combat_draw_unit_info_panel |
0x00488769 | Draw unit portrait, name, and stats panel |
lotr2_combat_exit_to_campaign |
0x00488dea | Stop audio; restore campaign screen after battle |
Pathfinding / map init#
| Symbol | Address | Role |
|---|---|---|
lotr2_combat_init_pathfinding_grid |
0x00483570 | Fill 80×80 cost grid (0 passable, 999 blocked) |
lotr2_combat_pack_tile_heights |
0x00483662 | Copy tile height bytes into compact 80×80 array |
lotr2_combat_init_wall_adjacency_map |
0x004836d8 | Mark wall-adjacent tiles with movement cost 4 |
lotr2_combat_mark_figure_tiles_blocked |
0x004837f2 | Block pathfinding cells occupied by friendly figures |
lotr2_combat_build_path_cost_grid |
0x004818c5 | Build 64×64 tile movement cost table from battle map flags |
lotr2_combat_reset_pathfind_search |
0x0048101f | Clear pathfind buffer; set origin tile for A* search |
lotr2_combat_pathfind_query_neighbor |
0x00481b2e | Trace 8-way path through cost grid; store waypoint list |
Combat groups#
| Symbol | Address | Role |
|---|---|---|
lotr2_combat_alloc_group_slot |
0x0048030b | Find and initialize a free 0x34-byte group slot |
lotr2_combat_clear_group_slot |
0x0048053f | Clear one 0x34-byte combat group slot |
lotr2_combat_clear_all_group_slots |
0x00480b1e | Clear group slots 1..0x50 |
lotr2_combat_assign_group_orders |
0x0048be59 | Build side-specific combat groups and assign order types |
lotr2_combat_set_group_siege_order_type |
0x00492634 | Scan group for siege units; assign order types 5–8 |
lotr2_combat_zero_figure_bytes |
0x00480461 | Zero 0x1a4 bytes of province army record |
lotr2_combat_zero_group_bytes_300 |
0x004803b9 | Zero 0x300-byte spawn record buffer |
lotr2_combat_zero_group_bytes_2c |
0x0048042b | Zero 0x2c-byte troop order buffer |
lotr2_combat_unlink_province_army_tile |
0x004805ff | Remove province army from tile occupancy linked list |
lotr2_combat_link_province_army_tile |
0x00480770 | Link province army into tile occupancy linked list (pair of unlink) |
Group globals (pass 53): lotr2_combat_group_table @ 0x00583140 (0x34 stride,
slots 1..0x50); lotr2_combat_group_alloc_index scan cursor;
lotr2_combat_cur_group_index for group-order handlers;
lotr2_combat_focus_group_index for move-to-tile focus. Struct:
lotr2_battle_group.md.
Hover tooltip (pass 53): lotr2_combat_hover_poll_time_ms,
lotr2_combat_tooltip_blit_x / _y in lotr2_combat_poll_figure_hover.
Projectile lifecycle#
| Symbol | Address | Role |
|---|---|---|
lotr2_combat_clear_all_projectiles |
0x00480acf | Clear 100 projectile slots at stride 0x4c |
lotr2_combat_clear_projectile_slot |
0x00480509 | Clear one 0x4c-byte projectile slot |
lotr2_combat_tick_projectile |
0x004a3166 | Advance active projectile, apply terrain/unit effects, expire slots |
lotr2_combat_unlink_projectile_tiles |
0x004808cd | Clear per-tile projectile occupancy links |
lotr2_combat_link_projectile_tile |
0x0048094f | Link projectile slot into its current battle-tile list |
lotr2_combat_alloc_projectile_slot |
0x004800f8 | Find free 0x4c-byte slot; init position, direction, tile link |
lotr2_combat_probe_los_neighbors |
0x0048009f | Scan 0x14 neighbor offsets for line-of-sight obstruction |
lotr2_combat_mark_projectile_tiles |
0x004932c6 | Mark tile dirty bits under active projectiles (siege mode) |
Per-unit tick handlers#
| Type | Symbol | Address |
|---|---|---|
| 0 Peasant | lotr2_combat_tick_peasant |
0x00493754 |
| 1 Archer | lotr2_combat_tick_archer |
0x0049382d |
| 2 Swordsman | lotr2_combat_tick_swordsman |
0x00493906 |
| 3 Maceman | lotr2_combat_tick_maceman |
0x004939df |
| 4 Pikesman | lotr2_combat_tick_pikesman |
0x00493ab8 |
| 5 Crossbowman | lotr2_combat_tick_crossbowman |
0x00493b91 |
| 6 Knight | lotr2_combat_tick_knight |
0x00493c6a |
| 7 Catapult | lotr2_combat_tick_catapult |
0x00493d43 |
| 8 Battering ram | lotr2_combat_tick_battering_ram |
0x00493e25 |
| 9 Siege tower | lotr2_combat_tick_siege_tower |
0x00493f07 |
| 10 Moat / ladder | lotr2_combat_tick_moat_diggers |
0x00493fe9 |
Siege / castle defense#
| Symbol | Address | Role |
|---|---|---|
lotr2_siege_pour_boiling_oil |
0x004966c5 | Start oil pour; projectile kind 5 |
lotr2_siege_mark_gate_hit |
0x00496931 | Mark gate tile after ram contact |
lotr2_siege_open_gate |
0x0048f83c | Destroy gate → open passage (tile type 1) |
lotr2_siege_fire_catapult |
0x0048d23a | Type-10 / catapult aim shot (proj kind 7) |
lotr2_siege_tick_gate_hack |
0x004950fb | Infantry hacking gate (type 2 tile) |
lotr2_combat_siege_modify_tile |
0x0049422e | Moat/ladder terrain modification |
lotr2_siege_load_castle_layout |
0x004c8dfb | Read castles.dat record into the 80×80 battle map |
lotr2_siege_draw_castle_border |
0x0041c1ae | Draw siege-map bottom/left border lines when siege mode is active |
lotr2_siege_init_castle_tile_layout |
0x0048fbee | Top-level castle tile init; six sub-passes |
lotr2_siege_flood_fill_exterior |
0x0048fc21 | Flood-fill exterior ground tiles (type 6) |
lotr2_siege_flood_fill_wall_face |
0x0048fd45 | Flood-fill wall-face tiles (type 5) |
lotr2_siege_set_tile_gate_closed |
0x0048f784 | Set gate tile type 2; mark impassable |
lotr2_siege_clear_tile_gate_face |
0x0048f752 | Clear gate-face tile flags |
lotr2_siege_set_tile_drawbridge_open |
0x0048f99e | Open drawbridge tile (type 9); rebuild adjacency |
lotr2_siege_set_tile_owner_color |
0x0048fb9a | Write owner color nibble into tile byte |
Key globals#
| Symbol | Address | Role |
|---|---|---|
lotr2_combat_cur_figure |
0x0059c32c | Current figure index during tick loop |
lotr2_combat_figure_unit_type |
0x00549552 | Unit type byte (+0x0A in figure) |
lotr2_combat_figure_head_count |
0x005496e0 | Stack / crew size |
lotr2_combat_figure_damage_acc |
0x005496da | 100-point casualty pool |
lotr2_combat_figure_attack_damage |
0x005496dc | Current melee hit damage |
lotr2_combat_figure_state |
0x00549571 | Figure state-machine byte (+0x31); indexes PTR_LAB_004f46d0 |
lotr2_combat_figure_side |
0x00549549 | Side byte (+0x09) |
lotr2_combat_figure_tile_index |
0x0054955c | Current battle tile index (+0x1C) |
lotr2_combat_figure_target_slot |
0x005496be | Melee/ranged target figure slot (+0x186) |
lotr2_battle_tile_figure_link |
0x005841c5 | Tile occupant figure index link |
lotr2_battle_tile_dirty_flag |
0x005841c2 | Tile needs redraw when set |
lotr2_battle_tile_type |
0x005841c7 | Map tile object type |
lotr2_battle_tile_damage_ctr |
0x005841c0 | Gate/wall hit counter |
lotr2_projectile_slots |
0x005476c0 | Base of 100 projectile slots at stride 0x4c |
lotr2_projectile_kind |
0x005476c9 | Projectile type (+0x09 in proj slot) |
lotr2_siege_gate_break_threshold |
0x00543688 | Gate breaks after 15 hits |
lotr2_combat_group_order_type |
0x00583148 | Group order (1–4 infantry, 5–8 siege) |
Battle HUD strip (pass 45)#
Dispatched from lotr2_game_main_frame_tick when lotr2_game_active_view == 2 (battle
active) and screen modes 0x28–0x2f. Frame init also used for modes 0x28
and 0x2c via lotr2_game_screen_mode_tick.
| Symbol | Address | Role |
|---|---|---|
lotr2_combat_init_battle_hud_frame |
0x00428de3 | Status bar, viewport scroll, palette, first present |
lotr2_combat_redraw_hud_resource_counters |
0x00428f1c | Food/gold counters on bottom HUD strip |
lotr2_combat_tick_hud_army_roster |
0x00429113 | Refresh roster when army headcount changes |
lotr2_combat_blit_hud_roster_icons |
0x00429292 | Unit-type icon sprites for active side |
lotr2_combat_draw_hud_roster_headcounts |
0x004293af | Head-count labels beside roster icons |
lotr2_combat_draw_paused_overlay |
0x00429527 | Paused-game banner overlay |
lotr2_combat_tick_dumb_view_banner |
0x0042a098 | Debug “dumb view” banner tick |
lotr2_combat_draw_debug_hud_stats |
0x0042a146 | Debug sync stat panel |
lotr2_combat_draw_debug_figure_inspector |
0x0042a235 | Selected-figure debug dump |
Dependencies#
- Graphics: battle sprites (
trp_*.pl8, siegeengine.pl8), castlecastle*.pl8,gateway.pl8,flags*.pl8 - Audio:
Peas_U1.wav,pouroil.wav,movoil.wav, unit strike sounds - I/O:
castles.datvialotr2_io_open/__read - Network: combat state is part of MP sync, but checksum ownership is not yet mapped in this module.
Data files#
| File | Role |
|---|---|
castles.dat |
Castle siege layouts (0x3200 bytes per castle) |
l2.eng |
Unit and UI display names |
gateway.pl8, gateway.256 |
Drawbridge / gate art |
flags.pl8, flags1a.pl8, … |
Victory flag |
engine.pl8 |
Siege engine sprites |
arm_*.pl8 |
Armoury unit portraits (UI index 1–6 ≠ battle type 0–10) |
Static tables#
Dump all values: python3 tools/ghidra/dump_combat_tables.py
| VA | Contents |
|---|---|
0x004f4c18 |
Melee attack damage (11 types × 4 tiers) |
0x004f4b28 |
Formation tier thresholds |
0x004f4980 |
Base squad size |
0x004f4be8 |
Unit target range |
0x004f49f8 |
Spawn templates |
0x004f4ad8 |
Siege sub-templates |
0x004f4c70 |
Catapult boulder damage (19–24) |
0x004f4cc8 |
Oil pour damage (25–32) |
0x004f4f50 |
Knight movement |
PTR_LAB_004f46a0 |
Unit tick handler pointers |
PTR_LAB_004f46d0 |
Figure state tick handler pointers |
PTR_LAB_004f4718 |
Field-battle group order handlers (indices 0–4) |
PTR_LAB_004f4758 |
Siege attacker group order handlers (indices 0–9) |
PTR_LAB_004f4730 |
Siege defender group order handlers (indices 0–8) |
Full stat reference: ../structs/lotr2_unit_stats.md.
Group order handler tables (retail)#
Normative AI rules: ../../spec/combat/npc-battle-ai.md.
Open field — PTR_LAB_004f4718 @ 0x004f4718:
| Index | Handler |
|---|---|
| 0 | lotr2_combat_group_tick_stub_knight |
| 1 | lotr2_combat_group_tick_order_melee |
| 2 | lotr2_combat_group_tick_order_ranged |
| 3–4 | lotr2_combat_group_tick_order_defend |
Siege attacker — PTR_LAB_004f4758 @ 0x004f4758:
| Index | Handler |
|---|---|
| 0, 5–7 | lotr2_combat_group_tick_stub_knight |
| 1 | lotr2_combat_group_tick_order_knight_capture |
| 2 | lotr2_combat_group_tick_order_defend_lane |
| 3 | lotr2_combat_group_tick_order_defend_wall |
| 4 | lotr2_combat_group_tick_order_hold_line |
| 8 | lotr2_combat_group_tick_order_seek_flag |
| 9 | lotr2_combat_group_tick_stub_tower |
Siege defender — PTR_LAB_004f4730 @ 0x004f4730:
| Index | Handler |
|---|---|
| 0, 8 | lotr2_combat_group_tick_stub_knight |
| 1 | lotr2_combat_group_tick_order_catapult |
| 2 | lotr2_combat_group_tick_order_battering_ram |
| 3 | lotr2_combat_group_tick_order_siege_tower |
| 4 | lotr2_combat_group_tick_order_capture_flag |
| 5 | lotr2_combat_group_tick_order_tower_wall_scan |
| 6 | lotr2_combat_group_tick_order_ram_wall_scan |
| 7 | lotr2_combat_group_tick_order_gatehouse |
Structs#
| Struct | Doc |
|---|---|
lotr2_battle_figure |
../structs/lotr2_battle_figure.md |
lotr2_battle_group |
../structs/lotr2_battle_group.md |
lotr2_battle_tile |
../structs/lotr2_battle_tile.md |
lotr2_projectile |
../structs/lotr2_projectile.md |
Auto-calculation (quick resolve)#
Campaign-layer battle resolution when the player chooses auto-calculate, the auto-resolve game option is off, or no human participates. Does not run the tactical figure tick.
| Symbol | Address | Role |
|---|---|---|
lotr2_game_battle_apply_casualty_split |
0x004c365d | Strength compare → survivor % → update army records |
lotr2_game_army_calc_combat_strength |
0x004c3c05 | Weighted unit sum × static table + 20 |
lotr2_game_battle_resolve_siege_outcome |
0x004c3cde | Capture, army release, diplomacy after split |
lotr2_game_battle_prep_init_combat |
0x004bf4d0 | Human-side check; battle prep globals |
lotr2_game_ui_enter_battle_prep_screen |
0x0043b622 | Auto-calc from prep screen (mode 0x12) |
lotr2_game_battle_halve_loser_army_strength |
0x004c6159 | Loser halving on tactical timeout path |
Normative rules: ../../spec/combat/auto-calculation.md.
Static tables: ../structs/lotr2_unit_stats.md.
Tactical melee/ranged casualties (lotr2_combat_apply_melee_hit, 100-point
accumulator) are a separate model; played battles still call
lotr2_game_battle_apply_casualty_split on return to the campaign map.
Combat flow (summary)#
- Tick loop (
lotr2_combat_tick_all_figures) walks figures 1..0x50; dispatchesPTR_LAB_004f46a0[unit_type]. - Handler calls
lotr2_combat_update_attack_damage(infantry melee) and movement helpers. - On contact,
lotr2_combat_apply_melee_hitadds attacker'sattack_damageto defenderdamage_acc. - Casualty rule: when
damage_acc > 99, decrementhead_countand subtract 100. - Projectiles (arrows, bolts, boulders, oil) use separate slots and the 100-point pool with optional multi-kill thresholds (100/200/300/400).
- Siege map: catapult → wall tiles (type 4); ram → gate face (type 5); oil cauldron (type 7) → spill (type 10); flag at type 14.
Skirmish battles (GoG)#
When DAT_0057a0f0 == 1, combat runs on a fixed preset map with no campaign
return path. Setup loads armies from TROOPS*.ENG and map rows @ 0x004D8E18.
Post-battle: lotr2_game_ui_on_battle_end_return skips siege resolve (0x13).
Many combat/UI branches gate campaign-only behavior with if (DAT_0057a0f0 == 0).
Full flow: ../../skirmish/battle-flow.md.
| Symbol | GoG addr | Role |
|---|---|---|
lotr2_combat_init_battle_ui |
0x00499e5d | Load map row by DAT_0053f258 |
FUN_0042bf46 |
0x0042bf46 | Copy skirmish preset unit counts |
lotr2_combat_enter_mp_lobby_from_battle |
0x00497879 | Gateway return after skirmish |
Open questions#
- Exact English names for unit types 7–10 and tile types from
l2.eng - Full
castles.daton-disk record layout beyond the loaded 0x3200 tile slice - Siege sub-template param0/param1/param2 vs wall/gate HP
- Drawbridge button vs tile type 2 state machine
- Boiling oil cauldron placement rules per castle size
Related#
- Symbol map (combat pass):
../symbol-map.md - Multiplayer sync:
../net/MODULE.md