Armies of the Night¶
Verified against: SLUS_212.15 (NTSC-U, SHA1 e9cb2cc49aa046b9e494313dce2f5038ed17b2f4) and the compiled Lua chunks
of the retail disc (read as disassembly, the method of Scripts; names, numbers and calls only).
Static reading, 2026-10-11. Each claim carries its evidence level.
Purpose¶
Armies of the Night is the original's bonus game: five stages of a side-on brawler in the game's own engine. This page says how the player reaches it, what loads, and which engine pieces exist only for it. It ends with what Coney needs to show it instead of a black screen (user checklist item 19). The pieces have their own pages, linked below. This page gathers them and does not repeat them.
What it is¶
- Five levels.
level60tolevel64, records 24-28 of the level table, titledStage 1toStage 5, with 3, 3, 3, 3 and 4 sections (Levels). Each one's last checkpoint script loads the next (level60_mothers→level61, ...), andlevel64's last returns to the hub (Story order; inferred, from the scripts). - The way in. The clubhouse's trophies in the hub (
level95) start the flashbacks. The sixth entry ofFBMissionis{level = 60, req = {82, 92, 83, 20, 11}}: Armies of the Night is offered once the five flashbacks are complete, andflashback.PlayMission(actionMA_LOADFBLEVEL) loadslevel60(inferred, from the disassembly oflevel95.lua). Nothing else leads there:- the main menu offers STORY, EXTRAS (only the trailer) and QUICK RUMBLE (The screens);
- the mission menu leaves levels 60-65 out (
MissionSelect_IsMissionListed,0x001bc100, confirmed (code)); - a cheat loads the next stage from within one (
CheatArmiesLoadLevel, Debug).
- No mode of its own. A stage plays in the ordinary gameplay mode (mode 1). The engine switches on the
current level's number:
GameState_IsArmiesLevel(0x0041d110) is true when the level record's number (+0x04) is 60-69 (confirmed (code)). What it switches:
| Piece | In an Armies level | Page |
|---|---|---|
| Character models | every human drawn with its type's _a model |
Characters: from a type to a model |
| Camera | the rail's mode 3: trails the hindmost fighter at a fixed downward pitch, forward only | Camera: mode 3 |
| HUD | two ANHud panels (health, power, credits, the boss picture), the GO sign; HideHud does nothing while game state +0x14c is 1 |
HUD: the Armies panel |
| Failure | no mission-failed shot; the Armies game over (mode 0xd, ANGameOver_Toggle 0x001557f8) |
Pause: the game-over screen |
| Pause | its own pause menu | Pause: the Armies pause menu |
| Sound | the sound matrix armies (global.lua, levels 60-64), the bank armies, the load screen's bank armload |
Sound: banks, Scripts: global.lua |
| Two players | player 2 joins through SetArmiesMultiplayerCallback, kept at game state +0x56f4 |
Front end: game-state functions |
- The record
armies. The level table also holds a record namedarmies(index 101, worldlevel60, number 419, no sections, no.levon the disc).LoadLevelreads<name>.lev, herearmies.lev, so the record cannot load as it stands. Its number is not 60-69 either, so it is not an Armies level. Inferred: a leftover test record, like the others with no.lev(Level loading).
level60's start¶
What the first stage does before the player can move, inferred from the disassembly of level60.lua and
level60_destroyers.lua. It shows which bindings the first frames need.
Main: the checkpoint table (1level60_destroyers/P1.SetupDest, 2level60_jsb/P2.SetupJSB, 3level60_mothers/P3.SetupMothers); fog colour black;ScreenQueueEffect(1, 0), an instant fade to black (Screen effects); the radar off and the HUD restored; the bankarmies;preLoadFileof the chapter withRunLevel.RunLevel: the Warriors; walk-only combat (CfgPlayerCombatWalkOnly(1)); the join callback; Lua save floats 1-5 (5 is the bonus); commands 32 and 33 removed, the player's commands 1 and 5 off, jump blocked, rage prevented, speech off, revivable, health 500, revives; mugging and power-up pick-up off;HUDANSetCredit(7); the inventory callbackF1.Health; the stage's cameras. Then a locked cameralock01is made active on the rail's line (y = 39.5): field of view 22°, heading 180°, pitch −7°. Last come the stage's gangs for the checkpoint and the bonus timerF1.Bonus01(after 5 s, then every second).P1.SetupDestsets the start callbackP1.SetupDest02, which teleportsAjax2to its flag and, 100 ms later, plays the intro scenel60_introthrough the stage's own scene runner. The scene brings the picture back (inferred). Its end (PreCashTheWorld, thenP1.Start02) starts the musicmusic/armies_pt1and opens a door. 4.5 s laterP1.Start03makes the rail camera active (Rail1):CamSetupRail("rail", player, 22, {0, −0.25, 1.25}, 0.5, 90), six points along y = 39.5 from x = 100 to x = −850, thenCamModifyRail(5, −7, 0)(mode 3, pitch −7°) andCamModifyRail(7, 0.5).
So until the intro scene runs, the screen is black by the script's own choice.
The original's first frames¶
At level60 checkpoint 1 (confirmed (runtime), PCSX2 2.9.94, 2026-10-11; reached by the game's checkpoint jump from a
story save (slot 6), not from the hub trophy, so what the hub shows before the load is not covered; window captures
about every 4 s, timed by the game's 60 Hz tick count 0x005104f4, which starts again at the level; pad idle
throughout, left stick centred (0, 0)):
| Tick (s) | What shows |
|---|---|
| before 1 | the load screen: the Armies of the Night art with "STAGE ONE" and a red progress bar (two captures, about 7 s) |
| 365-1251 (6-21 s) | the intro scene, no HUD: a fixed side view of a garage under a red graffiti "W", pedestrians walking past, then the shutter rising on a car with Swan standing inside |
| 1667 (28 s) | play: Swan on the pavement in front of the garage, the same side-on view; the HUD on (below) |
| 1667-7527 | nothing moves while the pad is idle; the timer counts down one a second (98 at 1667, 00 at 7527: 98 in 97.7 s) |
| 7543 (126 s) | "CONTINUE?" in red over the scene, "Press the START button to continue" below it |
The HUD in play: top left Swan's portrait, his name and a seven-digit score (0000000) over a green health bar; top
centre the two-digit timer (starting at 99); top right "PRESS THE START BUTTON TO JOIN", blinking; at the right
edge "GO" with an arrow pointing right, blinking; bottom right "CREDITS: 07" (HUDANSetCredit(7)). So the idle
stage runs a 99-second timer that ends in the continue screen without any fight (HUD: the Armies
panel for the panel's code). Which script call starts the timer and the P1.Start03
timing were not traced here.
In Coney¶
Read in the engine and seen in a run of the 2026-10-10 release build (--play-level level60, 600 steps, pad idle).
That run is an observation of Coney, not of the original:
level60loads and its scripts run through the intro scenel60_intro, the music andP1.Start03's rail. The last frame shows the street in a fixed view. Of the stage's 15 new bindings, 11 are not implemented (Story coverage):HuColor,HuEnableController,GangSetMoney,CamLockRail,HUDANEnableJoinMsg,HUDANGetCredit,HUDANSetCredit,HUDANSetGOSignMode,HUDLaunchANGameOver,HUDSetANBossTexture,CfgBaseChanceToBlock. The run goes on past them.- The rail's settings 5, 6 and 7 do nothing (
repo:src/camera/rail_camera.h), so the rail camera does not trail the fighters as mode 3 does. characters::isArmiesLeveltakes levels 60-64 (repo:src/characters/character_class.cpp); the original's test takes 60-69.- The debug menu's Levels page lists every record of the level table,
101 armiesamong them (repo:src/debug/pages_scripts.cpp). Coney looks for that record's world under its name:--play-level armiesstops with "no streamed world is called armiess, armiesd or armies". Chosen from a running game, the level flow has nothing to show. This is the likeliest black screen: the entry reads like "Armies of the Night", but the original cannot load it either. - The Missions page lists only the 18 story missions (
repo:src/debug/story_missions.cpp), and nothing outside the hub's trophies loadslevel60.
Coney fixes (item 19)¶
The minimum to show Armies of the Night instead of a black screen, in order:
- Debug Levels page: do not offer a record that cannot load. Skip, or mark and refuse with a log line, a record
with no
.levof its name:armies, and the other test records with no level file. That is what the original'sLoadLevelwould do with them. This is tooling, so the change is free. - Debug Missions page: add the five Armies stages (
level60-level64, with 3, 3, 3, 3 and 4 checkpoints, fromresearch/missions.yaml'sarmiesgroup). Each starts at a checkpoint as the story missions do, so the stages are one choice away. Do the same for the five flashbacks if they are missing. - The way in: check that the hub's trophies run
flashback.PlayMissionand that the sixth (level60) is offered once levels 82, 92, 83, 20 and 11 are complete. That is the player's path, and a playthrough test should take it. - Make the stage recognisable: build mode 3 of the rail (Camera: mode 3), so the
camera trails the hindmost fighter at the −7° pitch. Take
isArmiesLevelas 60-69. - Then the bindings in the list above, the HUD's credits and GO sign first (HUD: the Armies panel), then the game over (mode 0xd, Pause), so that losing ends in the stage's own screen and not in the story's mission-failed one.
- Tests: a disc test that
level60at checkpoint 1 reachesP1.Start03with the rail camera active and mode 3 set; a debug-menu test that no listed level fails to load; and, once the hub path exists, a playthrough from the trophy. With the pad idle, compare with the original's first frames: the load screen, the intro scene, play with the full HUD at about 28 s, the timer at one a second and "CONTINUE?" at about 126 s.
Open questions¶
- What levels 65-69 would be: the test takes 60-69, but only 60-64 exist on the disc.
- Whether anything reaches the
armiesrecord. No script loads it: in a search of the disassembled chunks, the word appears only in its ownCfgLevelNamerecord (config_preload3.lua), the bankarmiesand the matrixarmies.