Map / province
Purpose
Strategic map rendering and province data: loading tile art from map01.pl8,
province records from l2_maps.dat, building neighbor topology, placing
starting units, and maintaining the 64×64 province cell table used during
gameplay and sim-tick setup.
Key entry points
Load pipeline
| Symbol |
Address |
Role |
lotr2_map_load_new_game |
0x00477580 |
New-game orchestrator: layers → dat → PL8 → neighbors → setup |
lotr2_map_load_from_dat |
0x00477610 |
Read l2_maps.dat slice (0x80c1 bytes) into province cell table |
lotr2_map_clear_layer_province_lists |
0x00433901 |
Zero 6×16 layer province-id lists before dat parse |
lotr2_map_clear_province_slot_pairs |
0x004b1e75 |
Zero 6 province slot pairs before dat parse |
lotr2_map_append_province_to_layer |
0x00433984 |
Append province id to layer list when cell flag 0x40 |
lotr2_map_set_province_slot_pair |
0x004b1e40 |
Set province slot pair when cell flag 0x80 |
lotr2_map_load_pl8_tiles |
0x0047a007 |
Count available map01.pl8 tile sheet variants |
lotr2_map_load_pl8_province_tiles |
0x00479f3d |
Load province PL8 tile slices (0x4000 bytes each) |
lotr2_map_clear_province_layers |
0x0047c48a |
Zero one of 8 parallel 64×64 province data layers |
lotr2_map_clear_cell_highlights |
0x0047de23 |
Clear highlight bit on all cells; mark viewport dirty |
lotr2_map_paint_visible_grid |
0x0047dac7 |
Paint visible 0x81×0x41 index grid from tile indices |
lotr2_map_paint_sea_tiles |
0x0047dc06 |
Set sea sentinel (0xfff0006) tiles in visible grid |
lotr2_map_build_province_neighbors |
0x00477bc4 |
Build DAT_0055c40c adjacency lists from grid scan |
lotr2_map_setup_all_provinces |
0x00478c6d |
Per-province castle, special tiles, keep, farm setup |
lotr2_map_place_starting_units |
0x004778d6 |
Difficulty-tier starting unit placement |
lotr2_map_build_army_slot_table |
0x0047d91d |
Map starting units into per-province army slot table |
Grid / view
| Symbol |
Address |
Role |
lotr2_map_init_province_grid |
0x004346a1 |
Clear and fill 0x81×0x41 province index grid; set facing |
lotr2_map_seed_grid_from_dat |
0x0047781d |
Seed grid cell indices from l2_maps.dat offset 0x6000 |
lotr2_map_set_view_mode |
0x0045c9ec |
Set map zoom/view scale (modes 0, 1, 2) |
lotr2_map_clear_province_rect |
0x0047a078 |
Clear province cells in a rectangular region |
lotr2_map_clear_province_cell |
0x0047a167 |
Clear one province grid cell |
lotr2_map_stamp_tile_block |
0x0047aaf4 |
Stamp N×N tile block on province grid |
lotr2_map_set_cell_display |
0x0047d6c6 |
Update cell tile index and sprite char |
Province topology
| Symbol |
Address |
Role |
lotr2_map_find_castle_cell |
0x00477eef |
Locate castle tile; store in DAT_0055c420 |
lotr2_map_find_keep_cell |
0x0047803f |
Locate keep tile; store in DAT_0055c428 |
lotr2_map_collect_special_tiles |
0x00478b5f |
Collect 0x10-flag special tiles into province table |
lotr2_map_locate_province_structures |
0x00478d7f |
Mark town/castle/capital cells on grid |
lotr2_map_place_province_farm |
0x00478f48 |
Place farm tile nearest to capital |
lotr2_map_province_has_neighbor |
0x00477d4a |
Test membership in province neighbor list |
lotr2_map_provinces_are_neighbors |
0x00477dce |
Bidirectional adjacency check |
lotr2_map_province_has_hostile_neighbor |
0x00477e4c |
Hostile-neighbor check for diplomacy |
Runtime / armies
| Symbol |
Address |
Role |
lotr2_map_draw_capital_tiles |
0x0047818a |
Stamp capital marker tiles |
lotr2_map_restore_province_tiles |
0x00478267 |
Restore 2×2 province tile sprites |
lotr2_map_clear_province_armies |
0x0047833a |
Clear army units at province capital |
lotr2_map_recount_all_armies |
0x00479a6f |
Recount armies for all provinces |
lotr2_map_count_province_armies |
0x00479aab |
Tally army types into province counters |
lotr2_map_apply_gold_upkeep |
0x004794ad |
Apply gold upkeep from army counts |
lotr2_map_apply_food_upkeep |
0x00479578 |
Apply food upkeep from army counts |
lotr2_map_clear_cell_with_upkeep |
0x00479d79 |
Clear cell; adjust province gold/food counters |
Campaign army movement (pass 30–31)
| Symbol |
Address |
Role |
lotr2_map_tick_province_army_move |
0x004752b0 |
Per-tick army step along path; resource transfer hooks |
lotr2_map_advance_army_path_step |
0x004758a0 |
Advance one path step; relocate tile link |
lotr2_map_probe_army_step_direction |
0x00475de6 |
Probe neighbor cell for direction 0–7 |
lotr2_map_classify_army_target_cell |
0x0047618f |
Classify target tile (empty, battle, structure) |
lotr2_map_pathfind_province_army |
0x004766e9 |
Build path for active province army record |
lotr2_map_find_nearest_hostile_army |
0x0047690b |
Nearest hostile army by Manhattan distance |
lotr2_map_find_nearest_friendly_army |
0x00476a85 |
Nearest friendly army (diplomacy filter) |
lotr2_map_spawn_province_army_at_cell |
0x0047fb40 |
Allocate province army record on empty cell |
lotr2_map_highlight_province_cells |
0x0047dea7 |
Set highlight bit on all cells owned by province |
lotr2_map_rect_has_passable_cell |
0x0047d002 |
Rect scan: any cell passable (flags & 0xfd == 0) |
Army-type dispatch table (PTR_LAB_004f1b28): lotr2_map_army_handler_tick_move,
lotr2_map_army_handler_merge_arrive, lotr2_map_army_handler_trade_arrive, stubs.
Campaign army AI (pass 34)
AI turn step 10 calls lotr2_map_ai_pathfind_player_armies; order dispatch uses
lotr2_map_ai_dispatch_army_by_order_type on army opcode DAT_005643ea (2=move,
3=follow, 4=siege, 5=assault, 6=merge). See game/MODULE.md
turn-sim section and game_renames_pass34.py.
| Symbol |
Address |
Role |
lotr2_map_ai_pathfind_player_armies |
0x004bb461 |
Pathfind all active armies for one player |
lotr2_map_ai_dispatch_army_by_order_type |
0x004bb5a8 |
Dispatch move/follow/siege/assault/merge orders |
lotr2_map_ai_order_move_to_target |
0x004bb842 |
Move/attack order handler |
lotr2_map_ai_set_army_destination |
0x004bc1eb |
Set army waypoint from castle/capital scan |
lotr2_map_ai_pick_nearest_attack_province |
0x004b63c2 |
Pick attack province by distance |
lotr2_map_ai_validate_army_merge_target |
0x004b61ff |
Validate merge destination army |
Build queue / fog (pass 30)
| Symbol |
Address |
Role |
lotr2_map_advance_build_queue_slot |
0x0047c1b0 |
Advance build-queue overlay slot |
lotr2_map_paint_build_queue_rect |
0x0047c375 |
Paint build-queue rect on overlay grid |
lotr2_map_init_edge_visibility |
0x0047ad96 |
Init fog-edge visibility counters |
lotr2_map_update_visibility_north |
0x0047b1b9 |
North-edge fog update |
Runtime armies + conquest (pass 40)
| Symbol |
Address |
Role |
lotr2_map_spawn_starting_armies_from_list |
0x00432940 |
Place starting armies from DAT_00573bc0 layer table |
lotr2_map_cell_has_nearest_flag_ring |
0x00432a77 |
Cell probe: nearest flagged tile within 3 rings |
lotr2_map_cell_has_passable_rect_ring |
0x00432ae8 |
Cell probe: passable rect within 3 rings |
lotr2_map_tick_province_army_pathfind |
0x00432b59 |
Per-tick pathfind for type-3 province armies |
lotr2_map_spawn_reinforcement_army |
0x00433ae0 |
Spawn type-4 reinforcement at capital cell |
lotr2_map_tick_conquest_army_pathfind |
0x00433c49 |
Pathfind tick for type-4 conquest armies |
lotr2_map_on_province_army_conquered |
0x00433ee6 |
Transfer loot; economy/diplomacy; release army slot |
lotr2_map_build_layer_province_chains |
0x004339e4 |
Collapse layer province lists into spawn table |
lotr2_map_apply_population_growth |
0x00433474 |
Apply gold-spend population tier growth |
Map draw + viewport (pass 40)
| Symbol |
Address |
Role |
lotr2_map_draw_cell_tile |
0x00435263 |
Draw one 0x81×0x41 grid cell; dispatches lotr2_gfx_fill_iso_cell_rot* (9 variants on view rotation + edge clip) |
lotr2_map_stamp_tile_pattern_small |
0x0043500d |
9-cell tile stamp composite |
lotr2_map_stamp_tile_pattern_large |
0x004350ec |
11-cell tile stamp composite |
lotr2_map_blit_map_sprite_scaled |
0x004355d1 |
Blit map sprite from DAT_0059bfd0 sheet (scaled) |
lotr2_map_find_cell_by_tile_index |
0x004345e0 |
Reverse lookup tile index → grid coordinates (walks lotr2_map_tile_index_grid) |
lotr2_map_hit_test_cell_from_cursor |
0x00434982 |
Mouse hit-test on isometric map grid |
lotr2_map_clamp_viewport_origin |
0x004348fb |
Clamp scroll origin to map bounds |
lotr2_map_rotate_grid_view_cw |
0x00434cf0 |
Rotate province grid + adjust viewport |
lotr2_map_rotate_grid_view_ccw |
0x00434df9 |
Counter-clockwise grid rotation |
lotr2_map_sync_cursor_to_cell_origin |
0x00434f3d |
Sync pixel origin from last hit-test cell |
Load pipeline
flowchart TD
loadFull[lotr2_map_load_new_game]
clearLayers[lotr2_map_clear_province_layers]
loadDat[lotr2_map_load_from_dat]
clearHi[lotr2_map_clear_cell_highlights]
paintVis[lotr2_map_paint_visible_grid]
paintSea[lotr2_map_paint_sea_tiles]
loadPl8[lotr2_map_load_pl8_province_tiles]
neighbors[lotr2_map_build_province_neighbors]
setupProv[lotr2_map_setup_all_provinces]
startUnits[lotr2_map_place_starting_units]
armySlots[lotr2_map_build_army_slot_table]
loadFull --> clearLayers
loadFull --> loadDat
loadFull --> clearHi
loadFull --> paintVis
loadFull --> paintSea
loadFull --> loadPl8
loadFull --> neighbors
loadFull --> setupProv
loadFull --> startUnits
loadFull --> armySlots
Dependencies
Data files
| File |
Role |
map01.pl8 |
Map tile sprite sheets (multiple variants) |
l2_maps.dat |
Province layout records (0x80c1 bytes per province index) |
Record layout: ../../spec/data/l2_maps_dat.md,
struct ../../structs/lotr2_maps_dat_record.md.
Key globals (pass 51)
| Symbol |
Address |
Role |
lotr2_map_tile_index_grid |
0x5934e0 |
0x81×0x41 dword grid of province-cell indices for paint and hit-test |
lotr2_map_province_cell |
0x552180 |
64×64 province cell byte records (8-byte stride) |
Open questions