Multi-Part Games
A game can ship as several separate DDBs - "parts" - that switch between each other at runtime with EXTERN n 4 (MALUVA's XPART n). The two usual reasons are a game too large for one DDB's 64K ceiling, and a natural chapter or episode structure.
This is entirely optional. A single-part game, which is what the kit builds by default, never touches any of the machinery below.
- Part 1 is your main
.DSFin the kit folder, built exactly as it always was and staged asGAME.DDBat the SD root. Nothing about a single-part build changes. - Parts 2 to 9 - the supported range - each get a
PART<n>\folder in the kit directory, holding exactly one.DSF(auto-detected the same way as the main game) plus that part's own already-converted art and audio, if any. BUILD.BATcompiles eachPART<n>\DSF the same way as the main game and stages the result asRELEASE\GAME<n>.DDBandRELEASE\PART<n>\0.XMBif that part uses XMESSAGE or XMES. It then copies every other file fromPART<n>\intoRELEASE\PART<n>\untouched.- On the SD card that becomes
GAME.DDB,GAME2.DDB,GAME3.DDBand so on at the root, alongsidePART2\,PART3\folders holding each part's own shadowed assets.
Part folders take converted files, not sources. Put ready-to-use .NX2, .NXI, .AKY, .AYS, .WAV, .VID, GAME.SFB, FONT.CHR to FONT9.CHR and POINTER.SPR to POINTER9.SPR files in a PART<n>\ folder - not .png or .aks sources. Only the main kit folder's IMAGES\ and AUDIO\ are converted.
A part switch opens its target by the exact name GAMEn.DDB, so a stray file beside it - a GAMEn.DSF source left next to the compiled DDB, say
- is ignored and harmless.
EXTERN n 4(XPART nunder MALUVA) switches the running game to partn, 1 to 9. It loadsGAMEn.DDB(GAME.DDBfor part 1) from the SD root.- If that file is not there, the switch is a silent no-op. The game keeps running in the current part, unaffected. A game that ships an
EXTERN n 4trigger must also ship that part's DDB, or the trigger quietly does nothing. - A successful switch is a fresh entry into the new part, not a resume. It starts at the new part's own
PRO 0, never at wherever theEXTERNwas called from.
For a part of 2 or above, these asset kinds are looked for in PART<n>\<name> first, and fall back to the game root if they are not there:
- location art (the whole extension probe runs under
PART<n>\, then again at the root if that whole pass misses) - see Graphics NNN.WAVsamples, and numberedNNN.AYS/NNN.AKYsongs, andGAME.SFB- see AudioNNN.VIDvideos - see Video0.XMBexternal message textFONT.CHR, and numberedFONT1.CHRtoFONT9.CHR- see FontsPOINTER.SPR, and numberedPOINTER1.SPRtoPOINTER9.SPR- see Mouse
Root-only, never shadowed: the title screen (DAAD.*, shown once at cold boot), and the boot-autoplay default song (GAME.AYS / GAME.AKY). The music sub-commands' n=255 sentinel - the "play GAME.AYS/GAME.AKY" case, see Audio - is also always root-only and behaves identically from every part. SFX 255 6 or SFX 255 7 plays the game's theme from anywhere. That is by design, not an override that failed.
Part 1 never looks in PART<n>\ at all, so a part-1-only game is byte-identical to a plain single-part build.
- All 256 flags carry verbatim. Score, turns, and every other system or user flag survive a switch unchanged (caveat 6).
- Object locations carry by index, for as many objects as both parts define in common (caveats 1, 2, 4).
- Object attributes and descriptions do not carry. Weight, container and wearable bits, extended attributes, and text always come from the currently active part's own DDB (caveat 3).
- Vocabulary is per-part and entirely independent. A word's spelling, its ID, and whether it exists at all can differ freely between parts. Only OBJECT NUMBERS need a shared convention across parts (caveat 1); vocabulary needs none.
SAVE always records the current part number in the file, and LOAD reads it back and switches automatically if it differs from the running part. A cross-part LOAD is a part entry, exactly like EXTERN n 4, not a resume (caveat 7). Save files share one filename namespace in the game root regardless of part (caveat 9) - SAVE and LOAD never look inside PART<n>\.
Only distribute save files your own build wrote, and do not hand-edit them. Save files are length-detected, and a malformed or hand-edited file can be misclassified. The outcome is always bounded to a wrong-part restore or a clean rejection, never file corruption, but it is a pointless class of bug to invite.
RAMSAVE and RAMLOAD (caveat 8) use one buffer that also survives a switch, so a RAMLOAD taken two parts later still restores to wherever the RAMSAVE was last taken - the "died, try again" checkpoint feature. A cross-part RAMLOAD is always a full restore: it ignores RAMLOAD's "restore up to flagno" partial-restore argument, which only applies within the same part. Refresh RAMSAVE in the new part's PRO 0 after a switch if you want the checkpoint to track it.
- OBJECT NUMBERING IS YOUR CONTRACT. The carry copies object locations BY INDEX. Object 7 in part 1 must mean the same thing as object 7 in part 2, or a carried lamp becomes whatever part 2 defined at that index. Keep a shared object-numbering map across parts, and define cross-part objects at the same indexes in every part.
- THE WHOLE TABLE CARRIES, NOT JUST THE INVENTORY. Objects left in part-1 rooms arrive in part 2 holding part-1 location NUMBERS, which now name different rooms, or nothing. If only carried and worn objects matter across a boundary, have the new part's
PRO 0re-PLACE or ABSENT everything else - the classic housekeeping idiom. - Attributes are per-part. Weight, container and wearable bits, and descriptions come from the ACTIVE part's DDB, so a carried object weighs what part 2 says it weighs.
- Object counts may differ. Objects the new part defines beyond the old part's count start at the new part's compiled initial locations.
- Inventory limits are per-part (CTL). Arriving with more carried objects than the new part's limit is stable until the next GET. Authors who lower the limit should handle the overflow in
PRO 0. - ALL 256 FLAGS CARRY - there is no clean slate. A part that assumes its scratch flags start at zero must zero them in
PRO 0, or the previous part must clear them before switching. System flags carry too: score and turns carry naturally, and the location flag holds a part-1 room number untilPRO 0places the player. Always set the start location first. - SAVE and LOAD. A save records flags, objects and part; loading it from ANY part lands in the SAVED part, and every caveat above applies to the restored state exactly as it does to a live switch. A cross-part LOAD enters the saved part at
PRO 0rather than resuming mid-turn; a same-part LOAD behaves as classic DAAD. - RAMSAVE is ONE SLOT and survives switches. A RAMLOAD two parts later restores to wherever the RAMSAVE was taken. That is the death-retry feature - but a stale slot restores a stale part, so authors using RAMSAVE for checkpoints should refresh it after each switch, with a RAMSAVE in
PRO 0. - Save files share one namespace in the game root regardless of part; identical names overwrite across parts.
Every part of a multi-part game must be compiled in the same DAAD dialect, because a part switch reloads a header while the flags carry across. If you change the compiler version away from the kit default, change it for the main game and for the PART<n>\ folders together - both sites or neither. See DAAD V3.