10 REM CITADEL RANDOMISER 0.5 20 REM by 'Diminished', March 2026 30 REM this BASIC file will load from &1900 to about &5F80 ish, 40 REM so we'll begin placing code and data from &6000 up. 50 REM CITAX will load from &1900 to &5F00 60 : 70 MODE 7:CLEAR 80 REM select assembly mode (0 or 1): 90 LST%=0 100 LST%=LST%+2 110 AS%=FALSE:SD%=-1:DP%=FALSE 120 REM page &A (the "stash page") hides away as CITAX is loaded; then it is moved to &7800 130 REM all code and data for patching must reside in the stash page 140 REM starts with room ID by item ID master table 150 STASH%=&A00:HISTASH%=&7800:DTA%=STASH%+2:HIDTA%=HISTASH%+2:ISROFF%=&30:PAYLOADOFF%=&90:SEEDASCOFF%=&F0:OLDISROFF%=&FE 160 : 170 DIM ROOMS% 37:DIM SLV% 1:DIM PTS% 1:DIM AT% 1:DIM MAXAT% 1:DIM MINPTS% 1:DIM MINAT% 1:DIM IW% 1:DIM PRNGVARS% 12 180 INV%=HISTASH%-&800: REM 40 items; give it half a page 190 INSTALLER%=HISTASH%-&880: REM place ISR installer after it 200 IBR%=HISTASH%-&700: REM goes up to e.g. IBR%+&EA so really needs a page 210 REM code addresses start here: 220 SHUF%=HISTASH%-&600: REM shuffle routine; one page 230 PRNG%=HISTASH%-&500: REM RNG routine; two pages 240 SOLVE%=HISTASH%-&300: REM solver routine; three pages 250 PRINT "Assembling ..."' 260 PROCasmMarsaglia 270 PROCinitRooms 280 PROCasmShufStuff 290 PROCasmSolve 300 CLS:PRINT "Citadel Randomiser v0.5":PRINT "(c) 'Diminished', March 2026"' 310 PROCinst 320 DA%=TRUE:REM DA%=FNyn("Disable attract mode spoilers"):REM v0.5: removed 330 SLOW%=FNyn("Original (slower) game speed") 340 DP%=FNyn("Show score for chosen seed") 350 REM v0.5: fixed ambiguous question: stardot.org.uk/forums/viewtopic.php?p=239756#p239756 360 ?IW%=NOT FNyn("Omit seeds needing trampo-warp") 370 AS%=FNyn("Automatic randomisation seed"):IF AS% THEN 440 380 REPEAT:INPUT "Enter seed: " SEED%:IF SEED%<=0 PRINT "Seed must be a positive integer." 390 UNTIL SEED%>0 400 ?MINAT%=0:?MINPTS%=0:!PRNGX%=SEED%:CALL SHUF% 410 CALL SOLVE%:PROCprintScore:IF 1=?SLV% GOTO 560 420 PRINT:PRINT CHR$(129);"Warning: This seed looks unsolvable!"' 430 IF NOT FNyn("Are you sure") THEN PRINT "Aborting.":END ELSE 560 440 P99%=FNyn("Only seeds giving 99 points") 450 PL99%=FALSE:IF NOT P99% THEN PL99%=FNyn("Only seeds giving < 99 points") 460 GI%=RND(-TIME) 470 PRINT '"Looking for a suitable seed ..."'';:REPEAT 480 SEED%=RND(999999999) 490 ?MINAT%=0:?MINPTS%=0 500 !PRNGX%=SEED%:CALL SHUF% 510 CALL SOLVE% 520 IF P99% AND ?PTS%<99 ?SLV%=0 530 IF PL99% AND ?PTS%=99 ?SLV%=0 540 PROCprintScore 550 UNTIL ?SLV%=1:REM 2, 3, 0 are all errors 560 PRINT:TP%=FNtape("Tape or disc version") 570 PRINT:IF NOT FNyn("Ready. Load game") PRINT "Aborting.":END 580 CLS:PROCbuildseedtext(SEED%):PROCsave(FNfindSarco, DA%, NOT SLOW%) 590 IF NOT TP% THEN GOTO 620 600 *TAPE 610 PAGE=&E00 620 CHAIN "CITADEL" 630 END 640 REM v0.5: build title screen ASCII for seed 650 DEF PROCbuildseedtext(SD%) 660 LOCAL DIGIT%,I%,J%,K% 670 K%=STASH%+SEEDASCOFF% 680 FOR I%=0 TO 13:?(K%+I%)=&20:NEXT 690 FOR I%=3 TO 11:J%=(K%+I%):IF SD%=0 THEN ?J%=&20 ELSE DIGIT%=SD% MOD 10:SD%=SD% DIV 10:?J%=&30+DIGIT% 700 NEXT:ENDPROC 710 : 720 DEF FNyn(M$) 730 PRINT M$;" (Y/N)? "; 740 LOCAL A$ 750 *FX15,1 760 REPEAT:A$=GET$:UNTIL A$="y" OR A$="n" OR A$="Y" OR A$="N" 770 PRINT A$ 780 =(A$="Y" OR A$="y") 790 : 800 DEF FNtape(M$) 810 PRINT M$;" (T/D)? "; 820 LOCAL A$ 830 *FX15,1 840 REPEAT:A$=GET$:UNTIL A$="t" OR A$="d" OR A$="T" OR A$="D" 850 PRINT A$ 860 =(A$="T" OR A$="t") 870 : 880 DEF PROCprintScore 890 LOCAL XI%:XI%=0:IF ?SLV%>1 THEN XI%=?SLV%:?SLV%=0 900 IF 1=?SLV% THEN 930 910 IF AS% PRINT SEED%,; ELSE IF DP% PRINT 'CHR$133;SEED%,; ELSE PRINT 'CHR$133;SEED%';:ENDPROC 920 GOTO 950 930 IF AS% PRINT '"Found seed:"''CHR$133;SEED%; ELSE PRINT 'CHR$133;SEED%; 940 IF NOT DP% THEN PRINT:ENDPROC 950 IF XI%=2 PRINT ;CHR$135"(Ice crystal in sarcophagus)":ENDPROC 960 IF XI%=3 PRINT ;CHR$135"(Chicken in sarcophagus)":ENDPROC 970 IF ?MINAT%<>0 PRINT ;CHR$135"(rounds ";?MINAT%;"/";?MAXAT%;", points ";?MINPTS%;"/";?PTS%;")":ENDPROC 980 PRINT ;CHR$135"(rounds ";?MAXAT%;", points ";?PTS%;")" 990 ENDPROC 1000 : 1010 REM read the rooms-by-item-slot list into ROOMS% 1020 DEF PROCinitRooms 1030 LOCAL LI%,LJ%:RESTORE:FOR LI%=0 TO 36:READ LJ%:?(ROOMS%+LI%)=LJ%:NEXT 1040 ENDPROC 1050 : 1060 DEF PROCasmShufStuff 1070 PRINT "Shuffler" 1080 REM this copies the initial room table into DTA% before the shuffle is done 1090 FOR C=0 TO LST% STEP LST% 1100 P%=SHUF% 1110 [ 1120 OPT C 1130 LDX #36 1140 .L1 1150 LDA ROOMS%,X 1160 STA DTA%,X 1170 DEX 1180 BPL L1 1190 LDA #&3F:PHA \ mask 1200 LDX #36 1210 .LA0 1220 JSR PRNG% 1230 PLA:PHA \ mask 1240 AND PRNGX%+2 \ get one byte from the PRNG 1250 STA PRNGV% 1260 TXA 1270 CMP PRNGV% 1280 BCS LA1 \ repeat until we get a random number that's <= loop index 1290 BNE LA0 \ ??? 1300 .LA1 1310 LDA DTA%,X \ get DTA% + LI% 1320 PHA \ push A (DTA% + LI%) 1330 TXA:PHA \ push X (loop counter) 1340 LDX PRNGV% 1350 LDA DTA%,X \ get DTA% + LJ% 1360 TAY:PLA:TAX \ pop X 1370 TYA:STA DTA%,X \ *(DTA% + LI%) = *(DTA% + LJ%) 1380 PLA:TAY:TXA:PHA:TYA:LDX PRNGV%:STA DTA%,X \ *(DTA% + LJ%) = old *(DTA% + LI%) 1390 PLA:TAX \ loop counter 1400 CMP #32:BNE LA2:PLA:LDA #&1F:PHA 1410 .LA2:TXA:CMP #16:BNE LA3:PLA:LDA #&F:PHA 1420 .LA3:TXA:CMP #8:BNE LA4:PLA:LDA #&7:PHA 1430 .LA4:TXA:CMP #4:BNE LA5:PLA:LDA #&3:PHA 1440 .LA5:DEX 1450 BNE LA0 1460 PLA 1470 LDX #38 \ make space for the two missing elements (0x17, 0x30) and insert them 1480 .L5 1490 LDA DTA%-2,X \ this is why we place DTA at A02 and not A00 ... 1500 STA DTA%,X 1510 DEX 1520 CPX #29 \ so last iteration is 30 1530 BNE L5 1540 LDX #27:LDA DTA%,X:STA DTA%+1,X:LDA #&17:STA DTA%,X:LDA #&E1:STA DTA%+2,X \ insert missing elements 1550 LDX #0 \ zero out IBR table 1560 LDA #0 1570 .LZ 1580 STA IBR%,X 1590 INX 1600 BNE LZ 1610 LDX #38 \ this one builds the reverse lookup table, IBR%, after the shuffle is done 1620 .L2 1630 TXA:PHA 1640 LDA DTA%,X 1650 TAX 1660 PLA 1670 STA IBR%,X 1680 TAX 1690 DEX 1700 BPL L2 1710 RTS 1720 ] 1730 NEXT 1740 PRINT"Shuffler ";(P%-SHUF%);" bytes"' 1750 ENDPROC 1760 : 1770 DEF FNfindSarco 1780 LOCAL LI%, LJ% 1790 LJ%=&FF 1800 FOR LI%=0 TO 38:IF ?(DTA%+LI%)=&3D LJ%=LI% 1810 NEXT 1820 IF LJ%=&2 THEN ?SLV%=0 1830 IF LJ%=&FF PRINT "Error: Fixup failed.":END 1840 =LJ% 1850 : 1860 DEF PROCsave(SI%,DA%,FAST%) 1870 IF DA% THEN AMOP%=&E8 ELSE AMOP%=&C8 1880 IF FAST% THEN FAST%=3 ELSE FAST%=4 1890 REM A00 (7800) room data table (STASH%, HISTASH%) 1900 REM A30 (7830) IRQ handler (+ISROFF%) 1910 REM A90 (7890) payload (+PAYLOADOFF%) 1920 REM ACE-ACF (78CE-78CF) saved old IRQ vector target (+OLDISROFF%) 1930 : 1940 PRINT "Building stash page ..."' 1950 REM here is the ISR; it waits for memory to be modified, signalling that CITAX has finished loading 1960 PRINT "ISR" 1970 FOR C=0 TO LST% STEP LST% 1980 P%=STASH%+ISROFF% 1990 [ 2000 OPT C 2010 PHA 2020 TXA:PHA 2030 TYA:PHA 2040 LDA &5700 \ CITAX version 2050 CMP #&B0 2060 BEQ L1 2070 PLA:TAY \ memory not modified yet, return, pass control to OS 2080 PLA:TAX 2090 PLA 2100 JMP (STASH%+OLDISROFF%) \ resume old saved vector target 2110 .L1 \ initial check passed; check to see if relocation has happened yet 2120 LDA &205 2130 CMP #&78 2140 BEQ LB 2150 LDX #0 \ no? copy page &A00 (STASH%) to &7800 (HISTASH%) 2160 .L2 2170 LDA STASH%,X 2180 STA HISTASH%,X 2190 INX 2200 CPX #0 \ stash page length (&100) 2210 BNE L2 2220 LDA #(ISROFF%) \ risky... switch ISR vector from STASH to HISTASH 2230 STA &204 2240 LDA #(HISTASH% DIV 256) 2250 STA &205 2260 .LB:LDA &8A5 \&4C8 \ second check -- code being moved into position 2270 CMP #&D6 \#&3C 2280 BNE LX \ no? return 2290 LDA &4284 \ third check 2300 CMP #&C8 2310 BNE LX \ no? return 2320 LDA HISTASH%+OLDISROFF% \ restore original OS handler 2330 STA &204 2340 LDA HISTASH%+OLDISROFF%+1 2350 STA &205 2360 JSR HISTASH%+PAYLOADOFF% \ release the hounds 2370 .LX:PLA:TAY \ pass control to OS 2380 PLA:TAX 2390 PLA 2400 .L35 2410 JMP (HISTASH%+OLDISROFF%) \ caution; indirect jump! 2420 ] 2430 NEXT 2440 PRINT "ISR ";(P%-(STASH%+ISROFF%));" bytes"' 2450 REM assemble the installer for ISR at A30, then execute installer 2460 PRINT "Installer" 2470 P%=INSTALLER% 2480 [ 2490 OPT LST% 2500 SEI 2510 LDA &204 2520 STA STASH%+OLDISROFF% 2530 LDA &205 2540 STA STASH%+OLDISROFF%+1 2550 LDA #(ISROFF%) 2560 STA &204 2570 LDA #(STASH% DIV 256) 2580 STA &205 2590 CLI 2600 RTS 2610 ] 2620 PRINT "Installer ";(P%-INSTALLER%);" bytes"' 2630 REM assemble payload at &A90 (STASH%+PAYLOADOFF%) 2640 REM "tile table address", "room table address" 2650 REM point to the item we're going to change into the crystal 2660 REM SI% may point off the end of the table, e.g. when unshuffled 2670 REM in this case just hack it so the writes go to ROM instead 2680 REM &590 was once &4C8, but it wouldn't patch reliably 2690 REM now it's modified before game moves table down to 4C8 2700 TTA%=SI%+&590:RTA%=SI%+&880:IF SI%=&26 THEN TTA%=&9000:RTA%=&9000 2710 PRINT "Payload" 2720 FOR C=0 TO LST% STEP LST% 2730 P%=STASH%+PAYLOADOFF% 2740 [ 2750 OPT C 2760 \ copy room table to its destination 2770 LDX #&25 2780 .L3 2790 LDA HIDTA%,X 2800 STA &880,X 2810 DEX 2820 BPL L3 2830 \ table copy done; TTA% is the item slot assigned to the &3D room (the pyramid sarco room) 2840 \ there's no item pad in here, so it needs a patch -- look up the tile ID for this 2850 \ item slot 2860 LDA TTA% 2870 \ and patch the sarcophagus routine with its tile ID 2880 STA &2D89 2890 \ now, we're going to use this item slot for something else -- the crystal 2900 \ the crystal's tile ID is 2 2910 LDA #&02 2920 \ overwrite the 3D item's tile ID, so this item is now the crystal 2930 STA TTA% 2940 \ we also need to patch the new crystal item's room ID to the room that we want the crystal 2950 \ to appear in, and this is in the final, "extra" entry in the room table (&26) 2960 LDA HIDTA%+&26 2970 STA RTA% 2980 \ now, fix up the attract mode (or not) -- changes branch at &4283 (once relocated) 2990 .L0:LDA #AMOP% 3000 STA &4284 3010 \ v0.5; patch title screen text 3020 LDX #13 3030 .P42 3040 LDA HISTASH%+SEEDASCOFF%,X 3050 STA &7DC,X 3060 LDA #32 \ just delete drop-shadowed copy 3070 STA &7C6,X 3080 DEX 3090 BNE P42 3100 \ v0.5; patch game speed 3110 LDA #FAST% 3120 STA &4114 3130 RTS 3140 ] 3150 NEXT 3160 PRINT "Payload ";(P%-(STASH%+PAYLOADOFF%));" bytes"' 3170 REM enable our ISR 3180 TIME=0:REPEAT UNTIL TIME>60 3190 CALL INSTALLER% 3200 *FX 14,4 3210 ENDPROC 3220 : 3230 DATA &72,&D5,&97,&6E,&01,&5E,&1C,&6F,&0B,&A6,&C4,&84,&68,&81,&36,&6C 3240 DATA &87,&95,&05,&86,&85,&5C,&64,&82,&CB,&E4,&EA,&70,&58,&83 3250 DATA &A3,&29,&5A,&90,&94,&D6 3260 DATA &3D: REM this one is the added one, sarco room -- it's fixed up specially after the solver 3270 : 3280 DEF PROCasmSolve 3290 PRINT "Solver" 3300 REM attempt limit 3310 ATLIMIT%=6 3320 FOR C=0 TO LST% STEP LST% 3330 P%=SOLVE% 3340 [ 3350 OPT C 3360 LDX #38 3370 LDA #0 3380 .P6 \ init inventory loop 3390 STA INV%,X 3400 DEX 3410 BPL P6 3420 LDA #1 \ collect initial twelve items 3430 LDA IBR%+&5E:TAX:INC INV%,X 3440 LDA IBR%+&84:TAX:INC INV%,X 3450 LDA IBR%+&81:TAX:INC INV%,X 3460 LDA IBR%+&6C:TAX:INC INV%,X 3470 LDA IBR%+&87:TAX:INC INV%,X 3480 LDA IBR%+&85:TAX:INC INV%,X 3490 LDA IBR%+&5C:TAX:INC INV%,X 3500 LDA IBR%+&82:TAX:INC INV%,X 3510 LDA IBR%+&70:TAX:INC INV%,X 3520 LDA IBR%+&58:TAX:INC INV%,X 3530 LDA IBR%+&83:TAX:INC INV%,X 3540 LDA IBR%+&5A:TAX:INC INV%,X 3550 LDA #0:STA SLV%:STA AT% \ attempts=0, solved=false 3560 .P7 \ begin attempts loop 3570 LDY #4:TYA:STA PTS% \ start with 4 points 3580 INC AT%:LDA AT%:STA MAXAT% \ attempts++, max_attempts = attempts 3590 LDA INV%+35:BEQ L8:INY:INY \ handle points for crowns 3600 .L8:LDA INV%+36:BEQ L9:INY:INY 3610 .L9:LDA INV%+37:BEQ L10:INY:INY 3620 .L10:LDA INV%+17:BEQ L11 \ no prison key 3630 INY:INY \ unlock prison => 2 points 3640 LDA IBR%+&86:TAX:INC INV%,X \ get prison item 3650 LDA INV%+24:ORA INV%+30:BEQ L11:INY:INY:LDA IBR%+&72:TAX:INC INV%,X \ if have either trampo then collect top item, red flask 3660 .L11:LDA INV%+14:BEQ L15:INY:INY:INY \ unlock well => 3 points (2 for door, 1 for flask) 3670 LDA IBR%+&D5:TAX:INC INV%,X:LDA INV%+2:BEQ L12:LDA IBR%+&D6:TAX:INC INV%,X \ get item at bottom of well, if ice crystal => crown pad item 3680 .L12:LDA INV%+26:BEQ L13:LDA INV%+21:BEQ L13:INY:INY:LDA IBR%+&C4:TAX:INC INV%,X \ both gunpowder & cannonball => lab item, red flask 3690 .L13:LDA INV%+26:BEQ L14:INY:INY:INY \ cannonball worth 3 points 3700 .L14:LDA INV%+21:BEQ L15:INY:INY:INY \ gunpowder worth 3 points 3710 .L15 \ end of well 3720 LDA INV%+11:BNE L16:JMP L22 \ wasteland unlock *** BRANCH POSSIBLY OUT OF RANGE? 3730 .L16:INY:INY:INY \ 2 points for door, 1 for flask; 4 items also available: 3740 LDA IBR%+&EA:TAX:INC INV%,X \ Mountains pad 3750 LDA IBR%+&68:TAX:INC INV%,X \ outside Witch's House 3760 LDA IBR%+&64:TAX:INC INV%,X \ desert 3770 LDA IBR%+&1:TAX:INC INV%,X \ pyramid pad 1 3780 LDA INV%+0:ORA INV%+1:BEQ L17:LDA IBR%+&29:TAX:INC INV%,X:INY \ either mask => pyramid pad 2, flask 3790 .L17:LDA INV%+0:BEQ L18:LDA INV%+1:BEQ L18:LDA INV%+25:BEQ L18 \ both masks & statuette ... 3800 INY:INY:INY:LDA IBR%+&3D:TAX:INC INV%,X \ ... gets you the item in the sarcophagus, and 3 points 3810 3820 .L18:LDA INV%+23:ORA INV%+24:ORA INV%+30:BEQ L22 \ no trampos, no barrel => skip witch 3830 LDA IBR%+&90:TAX:INC INV%,X \ witch crown pad item 3840 LDA INV%+4:BEQ L19:INY:INY:INY \ blue bone in cauldron gives 3 points 3850 .L19:LDA INV%+5:BEQ L20:INY:INY:INY \ magenta bone in cauldron gives 3 points 3860 .L20:LDA INV%+6:BEQ L21:INY:INY:INY \ skull in cauldron gives 3 points 3870 .L21:LDA INV%+4:BEQ L22:LDA INV%+5:BEQ L22:LDA INV%+6:BEQ L22 \ all three cauldron items gets you ... 3880 LDA IBR%+&A6:TAX:INC INV%,X:INY:INY:INY:INY:INY \ ... lower item; 3 points for witch, 2 points for red flask 3890 .L22 \ end of witch, end of wasteland 3900 LDA INV%+16:BEQ L23:INY:INY:INY \ unlock cellar, 2 pts for door, 1 for flask 3910 LDA IBR%+&95:TAX:INC INV%,X:LDA IBR%+&97:TAX:INC INV%,X \ 2 items 3920 LDA INV%+24:ORA INV%+30:ORA INV%+23:BEQ L23:LDA IBR%+&94:TAX:INC INV%,X \ if have either trampo (v0.5; or barrel), get crown item 3930 .L23:LDA INV%+13:BEQ L24:INY:INY:INY:INY \ unlock east tower; 2 pts for door, 2 for red flask 3940 LDA INV%+2:BEQ L24:LDA IBR%+&36:TAX:INC INV%,X \ ice crystal gets item 3950 .L24:LDA INV%+12:BEQ L25:INY:INY:INY:INY \ unlock west tower; 2 pts for door, 2 for red flask 3960 LDA IBR%+&1C:TAX:INC INV%,X \ item available 3970 .L25:LDA INV%+15:BEQ L26:INY:INY:INY \ unlock freezer; 2 pts for door, 1 for flask 3980 LDA IBR%+&6E:TAX:INC INV%,X:LDA IBR%+&6F:TAX:INC INV%,X \ two items available 3990 .L26:LDA INV%+20:BEQ L27:INY:INY:LDA IBR%+&B:TAX:INC INV%,X:BNE L28 \ bucket; red flask + central tower item 4000 .L27:LDA IW%:BEQ L28:LDA INV%+3:BEQ L28:LDA INV%+24:ORA INV%+30:BEQ L28 \ OR, island warp; chicken & one trampo ... 4010 INY:INY:LDA IBR%+&B:TAX:INC INV%,X \ also gets you a red flask and the central tower item 4020 .L28:LDA INV%+3:BEQ L29:TYA:CLC:ADC #7:TAY \ cook chicken; 3 pts, feed guardians; 3 pts, starport flask; 1 pt 4030 LDA IBR%+&A3:TAX:INC INV%,X \ item; star port 4040 LDA IBR%+&CB:TAX:INC INV%,X \ item; temple 4050 LDA IBR%+&E4:TAX:INC INV%,X \ item; ocean 4060 .L29:LDA INV%+7:BEQ L30:INY:INY:INY:INY:INY \ crystals give 5 pts each 4070 .L30:LDA INV%+8:BEQ L31:INY:INY:INY:INY:INY 4080 .L31:LDA INV%+9:BEQ L32:INY:INY:INY:INY:INY 4090 .L32:LDA INV%+10:BEQ L33:INY:INY:INY:INY:INY 4100 .L33:LDA INV%+38:BEQ L34:INY:INY:INY:INY:INY 4110 .L34:LDA INV%+7:BEQ L37:LDA INV%+8:BEQ L37:LDA INV%+9:BEQ L37:LDA INV%+10:BEQ L37:LDA INV%+38:BEQ L37:LDA INV%+3:BEQ L37 \ 5 crystals + chicken 4120 LDA IBR%+&5:TAX:INC INV%,X \ use teleporter => get alien star port item 4130 LDA INV%+18:BEQ L37:INY:INY:INY:INY:INY \ unlock marduk door; 2 points + 3 points for star port destruction 4140 LDA SLV%:BNE L36 \ solved, but have we solved it before? 4150 .L39:TYA:STA MINPTS%:INC SLV%:LDA AT%:STA MINAT%:BNE L37 \ no! newly solved, so record min pts, min attempts needed 4160 .L36:TYA:CMP #99:BNE L37:STA PTS%:BEQ L38 \ solved already ... if have 99 points, store points and quit 4170 .L37 \ either solved previously @ <99 pts, not solved, or just solved => carry on 4180 TYA:STA PTS% \ store points 4190 LDA AT% 4200 CMP #ATLIMIT% 4210 BEQ L38 \ enough attempts already, quit 4220 JMP P7 \ next attempt 4230 .L38 \ done 4240 LDA DTA%+2 \ prevent ice crystal (IID 2) in sarcophagus bug 4250 CMP #&3D \ sarco chamber 4260 BNE L40 4270 LDA #2 4280 STA SLV% \ ice crystal in sarco => mark seed bad 4290 \ v0.5; ban sarco chicken too; stardot.org.uk/forums/viewtopic.php?p=478777#p478777 4300 .L40 4310 LDA DTA%+3 \ chicken (IID 3) 4320 CMP #&3D \ sarco chamber 4330 BNE L41 4340 LDA #3 4350 STA SLV% \ chicken in sarco => seed bad 4360 \ end v0.5 4370 .L41:RTS 4380 ] 4390 NEXT 4400 PRINT"Solver ";(P%-SOLVE%);" bytes"':TIME=0:REPEAT UNTIL TIME>50 4410 ENDPROC 4420 : 4430 DEF PROCinst 4440 PRINT CHR$131;"This software will load Citadel with" 4450 PRINT CHR$131;"its item locations randomised."' 4460 PRINT CHR$131;"Each supported permutation is" 4470 PRINT CHR$131;"represented by a single integer or" 4480 PRINT CHR$131;"'seed' in the range 1 to 999,999,999." 4490 PRINT CHR$131;"The randomiser can either generate a" 4500 PRINT CHR$131;"solvable seed automatically, or the" 4510 PRINT CHR$131;"user may supply one."' 4520 PRINT CHR$131;"The figurine on the alien planet" 4530 PRINT CHR$131;"needed to complete the game remains" 4540 PRINT CHR$131;"unrandomised in its original location."' 4550 PRINT CHR$131;"Any item may appear in the three" 4560 PRINT CHR$131;"secret rooms that normally contain" 4570 PRINT CHR$131;"the crowns."' 4580 ENDPROC 4590 : 4600 DEF PROCasmMarsaglia:REM needs a couple of pages 4610 PRINT "RNG" 4620 PRNGX%=PRNGVARS%:PRNGO%=PRNGVARS%+4:PRNGV%=PRNGVARS%+8 4630 FOR C=0 TO LST% STEP LST% 4640 P%=PRNG% 4650 [ 4660 OPT C 4670 PHA 4680 TXA:PHA 4690 TYA:PHA 4700 \ shift left 13 4710 LDA #0:STA PRNGO% 4720 LDA PRNGX%:ASL A:ASL A:ASL A:ASL A:ASL A:STA PRNGO%+1 4730 LDA PRNGX%:ROR A:ROR A:ROR A:AND #&1F:STA PRNGO%+2 4740 LDA PRNGX%+1:ASL A:ASL A:ASL A:ASL A:ASL A:ORA PRNGO%+2:STA PRNGO%+2 4750 LDA PRNGX%+1:ROR A:ROR A:ROR A:AND #&1F:STA PRNGO%+3 4760 LDA PRNGX%+2:ASL A:ASL A:ASL A:ASL A:ASL A:ORA PRNGO%+3:STA PRNGO%+3 4770 \ XOR 4780 LDA PRNGO%:EOR PRNGX%:STA PRNGX% 4790 LDA PRNGO%+1:EOR PRNGX%+1:STA PRNGX%+1 4800 LDA PRNGO%+2:EOR PRNGX%+2:STA PRNGX%+2 4810 LDA PRNGO%+3:EOR PRNGX%+3:STA PRNGX%+3 4820 \ shift right 17 4830 LDA PRNGX%+2:ROR A:AND #&7F:STA PRNGO% 4840 LDA PRNGX%+3:ROR A:ROR A:AND #&80:ORA PRNGO%:STA PRNGO% 4850 LDA PRNGX%+3:ROR A:AND #&7F:STA PRNGO%+1 4860 LDA #0:STA PRNGO%+2:STA PRNGO%+3 4870 \ XOR 4880 LDA PRNGO%:EOR PRNGX%:STA PRNGX% 4890 LDA PRNGO%+1:EOR PRNGX%+1:STA PRNGX%+1 4900 LDA PRNGO%+2:EOR PRNGX%+2:STA PRNGX%+2 4910 LDA PRNGO%+3:EOR PRNGX%+3:STA PRNGX%+3 4920 \ shift left 5 4930 LDA PRNGX%:ASL A:ASL A:ASL A:ASL A:ASL A:STA PRNGO% 4940 LDA PRNGX%:ROR A:ROR A:ROR A:AND #&1F:STA PRNGO%+1 4950 LDA PRNGX%+1:ASL A:ASL A:ASL A:ASL A:ASL A:ORA PRNGO%+1:STA PRNGO%+1 4960 LDA PRNGX%+1:ROR A:ROR A:ROR A:AND #&1F:STA PRNGO%+2 4970 LDA PRNGX%+2:ASL A:ASL A:ASL A:ASL A:ASL A:ORA PRNGO%+2:STA PRNGO%+2 4980 LDA PRNGX%+2:ROR A:ROR A:ROR A:AND #&1F:STA PRNGO%+3 4990 LDA PRNGX%+3:ASL A:ASL A:ASL A:ASL A:ASL A:ORA PRNGO%+3:STA PRNGO%+3 5000 \ XOR 5010 LDA PRNGO%:EOR PRNGX%:STA PRNGX% 5020 LDA PRNGO%+1:EOR PRNGX%+1:STA PRNGX%+1 5030 LDA PRNGO%+2:EOR PRNGX%+2:STA PRNGX%+2 5040 LDA PRNGO%+3:EOR PRNGX%+3:STA PRNGX%+3 5050 PLA:TAY 5060 PLA:TAX 5070 PLA 5080 RTS 5090 ] 5100 NEXT 5110 PRINT"RNG ";(P%-PRNG%);" bytes"' 5120 ENDPROC 5130