Jump to content

adamantyr

+AtariAge Subscriber
  • Posts

    1,904
  • Joined

  • Last visited

About adamantyr

  • Birthday 07/16/1975

Profile Information

  • Gender
    Male

Recent Profile Visitors

32,444 profile views

adamantyr's Achievements

Stargunner

Stargunner (7/9)

1.6k

Reputation

  1. What Gary said. The TIPI is marvelous as it gives you the equivalent of a disk system without a PEB, AND you can use your home WiFi to upload your programs from Classic99 directly to it. I wrote and tested Realms of Antiquity that way.
  2. So next step was to figure out where all the data was in VDP, so I can pull it into high memory. As I want to preserve the VDP as a viewing portal and not a slow DB. Plus, I'll have to move sound into VDP for use, as the original cart could use GROM. (Although I suppose I COULD re-write the interrupt sound routine to use CPU RAM instead.) The TOD Guide was mapped more for disk file access, so I had to verify locations myself: General Database Breakdown What VDP Location Length Sprite Patterns >0400 >0200 (512) Game Title & Description >0600 >0200 (512) ASCII: Classes Patterns >0800 >0100 (256) ASCII: Regular >0900 >0400 (1024) ASCII: 3D Graphics >0D00 >0400 (1024) Saved Game Party Data >1000 >02CA (714) Monster Data >12CA >04D0 (1232) Monster Special Attacks >179A >0140 (320) Monster Graphics >18DA >0400 (1024) New Game Data >1CDA >0032 (50) Room Data >1D0C >085C (2140) Global Settings >2568 >0096 (150) Vault & Store Settings >25FE >0032 (50) Vault Combination Settings >2630 >0032 (50) Fountain Settings >2662 >0014 (20) Party Order >2676 >0004 (4) Max Monsters/Level in Rooms >267A >000A (10) Initial Hit Points/Class >2690 >0004 (4) Floor Data >2694 >0064 (100) Melee Weapons >26F8 >0090 (144) Ranged Weapons >2788 >0110 (272) Armor >2898 >0090 (144) Shields >2928 >0090 (144) Magical Item Categories >29B8 >0080 (128) Magical Items >2A38 >02D0 (720) Fountain Effects >2D08 >0032 (50) Quest Item Data >2D3A >0098 (152) Ranged/Magical Attack Seq Data >2DD2 >0010 (16) Chest Trap and Effects >2DE2 >0080 (128) Dungeon Colors >2E62 >0032 (50) Combat/Room Colors >2E94 >0020 (32) Combat/Room Graphics >2EC6 >0380 (896) 2x2 Patterns >3246 >0028 (40) Monster XP, Party Position >326E >0005 (5) Soft Key Map >3273 >000B (11) Misc Data (5 unused bytes) >327E >0009 (9) Feature Names >3288 >01F0 (496) Spell Dialogue Data >3478 >0060 (96) Chest/Vault Names >34D8 >0018 (24) Current Floor Map >34F0 >021A (538) PAB Data >370A >0026 (38) Character Locations >3730 >0008 (8)
  3. Got it! That's strange that it requires the memory expansion to work... I guess you had no choice on a bare-bones console except to use GPL to execute GPL commands?
  4. Ah ha... Well now it does something but it either dumps to main title screen after the beep or goes crazy screen. Probably a return address issue? VWS is >8320, incidentally. * Utility GPLLNK DATA VWS,GLINK1 * Labels SUBSTK EQU >8373 * Subroutine stack pointer GETSTK EQU >166C * LDGADR EQU >60 * Load and execute GROM address entry point XTAB27 EQU >200E * Low-men XML table location 27 GXMLAD DATA >176C * Main routine GLINK1 LIMI 0 * Disable interrupts CLR @STATUS * Clear Status LI R9,XMLRTN LI R11,>50 MOV *R11,@GPLWS+8 * Put PUTSTK address into R4 of GPLWS MOV *R14+,@GPLWS+12 * Put GPL routine in R6 of GPLWS LWPI GPLWS BL *R4 MOV @GXMLAD,@>8302(R4) INCT @SUBSTK B @LDGADR XMLRTN MOV @GETSTK,R4 BL *R4 LWPI VWS RTWP
  5. Hmm... anyone have a GPLLNK they KNOW works with ROM banks? I've gotten a few implementations over the years, but the one I am using doesn't appear to work; trying to issue an accept tone does nothing. * Labels SUBSTK EQU >8373 * Subroutine stack pointer GETSTK EQU >166C * LDGADR EQU >60 * Load and execute GROM address entry point XTAB27 EQU >200E * Low-men XML table location 27 * Entry and Workspace GPLLNK DATA GLNKWS DATA GLINK1 RTNADR DATA XMLRTN GXMLAD DATA >176C * GROM address for 'XML >27' PUTSTK DATA >50 * Initialized to >50 where PUTSTK address is GLNKWS $->18 BSS 8 * Main routine GLINK1 LIMI 0 * Disable interrupts CLR @STATUS * Clear Status MOV @PUTSTK,@GPLWS+8 * Put PUTSTK address into R4 of GPLWS MOV *R14+,@GPLWS+12 * Put GPL routine in R6 of GPLWS LWPI GPLWS BL *R4 MOV @GXMLAD,@>8302(R4) INCT @SUBSTK B @LDGADR XMLRTN MOV @GETSTK,R4 BL *R4 LWPI GLNKWS RTWP Please note that like it's RAM implementation, it's embedding it's workspace into itself; the BSS line is worthless since it can't write to it. Fortunately it doesn't get used. I wish I could just skip it altogether but unfortunately GPL is the only (sane) way to allow for cassette use. Plus it wouldn't be terrible to have the error and accept tones readily available.
  6. I've started work on this! Target is a banked cartridge, 32K memory expansion required.
  7. Just curious, how do you know if the 32K expansion is present in code? Is there a flag somewhere, or is it as simple as trying to write then read a value to the memory area?
  8. TOD Revisited already exists for that?
  9. Yeah I'd do 8K banked ROM, and the 32K expansion for buffering, variables, a root module, and whatnot. The room coordinates are stored but only the current map of the dungeon is stored in entirety. It procedurally generates the corridors as you are ascending or descending and it plays the 2nd voice of the main theme. My suspicion is he spent WAY too much time on this and eventually just stuck with a "good enough" implementation, as during dungeon stocking if it finds the room doesn't connect to anything, it leaves it empty.
  10. I had that thought as well, Tursi. Some things GPL can do fast, other things were probably a nightmare. A lot of the pushing and pulling from VDP memory because the scratch-pad didn't have enough room for data sets must have been agony to program. Okay, so I have a new version, and this one seems like it does pretty well: I started using stacks to store rooms in given columns and rows, track connections between vertical and horizontal, then attempt to add horizontal to any verticals missing horizontals. And a final pass to find any rooms without connections and attempt to connect them. All in a non-random deterministic fashion. The pseudo-algorithm is as follows: Place stairs up and stairs down Tighter window, 11 x 22 center area Place fountains Full window of 16 x 26 Place rooms Full window of 16 x 26 Draw vertical corridors Check for aligned features on a given column. Dig straight vertical corridors between features. Store the rooms in a stack for the given column. Draw horizontal corridors between aligned features. Check for aligned features on a given row. Dig straight horizontal corridors between features. If a vertical corridor is hit, make a T and stop. Store the column where the corridor was hit in a connection stack. Store the rooms in a stack for the given row. Do NOT store the 2nd room if it was not reached. Iterate through the column stack Check if the column has any rooms, or if a connection already exists to this column. Take the last room in the connection stack. Attempt a plot, left or right depending on the room's quadrant bias, to make a new connection. If successful, store the new connection in the stack and move on to the next column. If not successful, decrement the index of the connection stack and try again. If completely failed, move on to the next column. Iterate through all features and check for connections. If none on a given feature, try horizontal then vertical to try and make one. Direction based on quadrant location of room. Obviously I still need to test it for edge cases and make sure it's consistent with a wide variety of map types. I'll probably implement it in assembly for much faster turn-around. And here is the code, if interested. 100 RANDOMIZE 1982 :: OPTION BASE 1 :: DIM RTB(26),RLR(26),RY(26),RX(26),RYR(4),RYA(4),RXR(4),RXA(4),CV$(26),CH$(17) 110 CALL CLEAR :: CALL SCREEN(4):: CALL COLOR(9,6,15,10,6,15):: FOR I=96 TO 108 STEP 4 :: READ C$ :: CALL CHAR(I,C$):: NEXT I 120 FOR I=1 TO 4 :: READ RYR(I),RYA(I),RXR(I),RXA(I):: NEXT I :: FOR I=1 TO 19 :: CALL HCHAR(I,3,107,28):: NEXT I 130 R=1 :: GOSUB 1000 :: CALL VCHAR(Y,X,104):: RTB(R)=TB :: RLR(R)=LR :: RY(R)=Y :: RX(R)=X 140 FOR R=3 TO 4 :: GOSUB 1000 :: CALL VCHAR(Y,X,105):: RTB(R)=TB :: RLR(R)=LR :: RY(R)=Y :: RX(R)=X :: NEXT R 150 FOR R=5 TO 6 :: GOSUB 1000 :: CALL VCHAR(Y,X,106):: RTB(R)=TB :: RLR(R)=LR :: RY(R)=Y :: RX(R)=X :: NEXT R 160 FOR R=7 TO 26 :: GOSUB 1000 :: CALL VCHAR(Y,X,103):: RTB(R)=TB :: RLR(R)=LR :: RY(R)=Y :: RX(R)=X :: NEXT R 200 CALL SCREEN(10):: FOR R=1 TO 26 :: IF RY(R)=0 THEN 260 210 FOR R2=1 TO 26 :: IF R=R2 THEN 250 :: IF RY(R2)=0 THEN 250 :: IF RX(R)<>RX(R2) THEN 250 220 X=RX(R):: IF RY(R) < RY(R2) THEN Y=1+RY(R):: YS=Y ELSE Y=1+RY(R2) :: YS=Y 230 CALL GCHAR(Y,X,G):: IF G=107 THEN Y=Y+1 :: GOTO 230 240 IF G=97 THEN 250 ELSE CALL VCHAR(YS,X,97,Y-YS) 241 IF POS(CV$(X-3),CHR$(R),1)=0 THEN CV$(X-3)=CV$(X-3)&CHR$(R) 242 IF POS(CV$(X-3),CHR$(R2),1)=0 THEN CV$(X-3)=CV$(X-3)&CHR$(R2) 250 NEXT R2 260 NEXT R 300 CALL SCREEN(14):: CY$="" :: CX$="" :: FOR R=1 TO 26 :: IF RY(R)=0 THEN 360 310 FOR R2=1 TO 26 :: IF R=R2 THEN 350 :: IF RY(R2)=0 THEN 350 :: IF RY(R)<>RY(R2) THEN 350 320 Y=RY(R):: IF RX(R) < RX(R2) THEN X=1+RX(R) :: XS=X ELSE X=1+RX(R2) :: XS=X 330 CALL GCHAR(Y,X,G):: IF G=107 THEN X=X+1 :: GOTO 330 340 CALL HCHAR(Y,XS,96,X-XS):: IF G=97 THEN CALL VCHAR(Y,X,101) 341 IF POS(CH$(Y),CHR$(R),1)=0 THEN CH$(Y-1)=CH$(Y-1)&CHR$(R) 342 IF Y=RY(R2) AND X=RX(R2) AND POS(CH$(Y),CHR$(R),1)=0 THEN CH$(Y-1)=CH$(Y-1)&CHR$(R2) 343 IF G<103 THEN CY$=CY$&CHR$(Y-1):: CX$=CX$&CHR$(X-3) 350 NEXT R2 360 NEXT R 400 CALL SCREEN(11):: FOR XC=1 TO 26 :: IF CV$(XC)="" OR POS(CX$,CHR$(XC),1)>0 THEN 450 410 CC=0 :: N=LEN(CV$(XC)) 415 R=ASC(SEG$(CV$(XC),N,1)):: CALL GCHAR(RY(R),RX(R)-1,GL):: CALL GCHAR(RY(R),RX(R)+1,GR) 420 ON RLR(R) GOTO 430,440 430 Y=RY(R):: X=RX(R):: XS=X+1 431 X=X+1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 431 432 IF G=32 THEN 450 433 IF G>102 THEN CE=G :: GOTO 437 434 IF (G=101 OR G=102) THEN CE=98 :: GOTO 437 435 IF G=97 THEN CE=101 436 GOTO 450 437 CALL HCHAR(Y,XS,96,X-XS):: CALL HCHAR(Y,X,CE):: CY$=CY$&CHR$(Y):: CX$=CX$&CHR$(X):: CC=1 :: GOTO 460 440 Y=RY(R):: X=RX(R):: XS=X-1 441 X=X-1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 441 442 IF G=32 THEN 450 443 IF G>102 THEN CE=G :: GOTO 447 444 IF (G=101 OR G=102) THEN CE=98 :: GOTO 447 445 IF G=97 THEN CE=102 446 GOTO 450 447 CALL HCHAR(Y,X+1,96,XS-X):: CALL HCHAR(Y,X,CE):: CY$=CY$&CHR$(Y):: CX$=CX$&CHR$(X):: CC=1 450 IF CC=0 THEN N=N-1 :: IF N>0 THEN 415 460 NEXT XC 500 CALL SCREEN(8):: FOR R=1 TO 26 :: GOSUB 1100 :: IF CC>0 THEN 580 510 CALL GCHAR(RY(R)-1,RX(R),GU):: CALL GCHAR(RY(R)+1,RX(R),GD):: CALL GCHAR(RY(R),RX(R)-1,GL):: CALL GCHAR(RY(R),RX(R)+1,GR) 520 N=(RTB(R)-1)*2 + RLR(R) 530 Y=RY(R):: X=RX(R) :: ON N GOTO 540,550,560,570 540 GOSUB 600 :: IF CC=0 THEN Y=RY(R):: X=RX(R):: GOSUB 900 :: GOTO 580 ELSE 580 550 GOSUB 700 :: IF CC=0 THEN Y=RY(R):: X=RX(R):: GOSUB 900 :: GOTO 580 ELSE 580 560 GOSUB 600 :: IF CC=0 THEN Y=RY(R):: X=RX(R):: GOSUB 800 :: GOTO 580 ELSE 580 570 GOSUB 700 :: IF CC=0 THEN Y=RY(R):: X=RX(R):: GOSUB 800 580 NEXT R 585 CALL SCREEN(4) 590 GOTO 590 600 XS=X+1 610 X=X+1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 610 620 IF G=32 THEN 670 630 IF G>102 THEN CE=G :: GOTO 660 640 IF (G=101 OR G=102) THEN CE=98 :: GOTO 660 650 IF G=97 THEN CE=101 660 CALL HCHAR(Y,XS,96,X-XS):: CALL HCHAR(Y,X,CE):: CC=CC+1 670 RETURN 700 XS=X-1 710 X=X-1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 710 720 IF G=32 THEN 770 730 IF G>102 THEN CE=G :: GOTO 760 740 IF (G=101 OR G=102) THEN CE=98 :: GOTO 760 750 IF G=97 THEN CE=102 760 CALL HCHAR(Y,X+1,96,XS-X):: CALL HCHAR(Y,X,CE):: CC=CC+1 770 RETURN 800 YS=Y-1 810 Y=Y-1 :: IF Y=0 THEN 860 ELSE CALL GCHAR(Y,X,G):: IF G=107 THEN 810 820 IF G>102 THEN CE=G :: GOTO 850 830 IF (G=99 OR G=100) THEN CE=98 :: GOTO 850 840 IF G=96 THEN CE=100 850 CALL VCHAR(Y,X,97,1+YS-Y):: CALL VCHAR(Y,X,CE):: CC=CC+1 860 RETURN 900 YS=Y+1 910 Y=Y+1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 910 920 IF G=32 THEN 970 930 IF G>102 THEN CE=G :: GOTO 960 940 IF (G=99 OR G=100) THEN CE=98 :: GOTO 960 950 IF G=96 THEN CE=99 960 CALL VCHAR(YS,X,97,Y-YS):: CALL VCHAR(Y,X,CE):: CC=CC+1 970 RETURN 1000 TB=INT(RND*2)+1 :: LR=INT(RND*2)+1 1001 IF R>4 THEN Y=INT(RND*RYR(TB))+RYA(TB):: X=INT(RND*RXR(LR))+RXA(LR) ELSE Y=INT(RND*RYR(TB+2))+RYA(TB+2):: X=INT(RND*RXR(LR+2))+RXA(LR+2) 1002 CALL GCHAR(Y,X,G):: IF G<>107 THEN 1001 1003 CALL GCHAR(Y-1,X,G):: IF G<>107 THEN 1001 :: CALL GCHAR(Y+1,X,G):: IF G<>107 THEN 1001 1004 CALL GCHAR(Y,X-1,G):: IF G<>107 THEN 1001 :: CALL GCHAR(Y,X+1,G):: IF G<>107 THEN 1001 1005 RETURN 1100 CC=0 :: IF RY(R)=0 THEN CC=4 :: GOTO 1160 1110 CALL GCHAR(RY(R)-1,RX(R),GU):: CALL GCHAR(RY(R)+1,RX(R),GD):: CALL GCHAR(RY(R),RX(R)-1,GL):: CALL GCHAR(RY(R),RX(R)+1,GR) 1120 IF GU<>96 AND GU<>99 AND GU<>107 THEN CC=CC+1 1130 IF GD<>96 AND GD<>100 AND GD<>107 THEN CC=CC+1 1140 IF GL<>97 AND GL<>101 AND GL<>107 THEN CC=CC+1 1150 IF GR<>97 AND GR<>102 AND GR<>107 THEN CC=CC+1 1160 RETURN 10000 DATA 000000FFFF0000001818181818181818181818FFFF181818181818FFFF000000 10001 DATA 000000FFFF181818181818F8F81818181818181F1F181818FF81BDA5A5BD81FF 10002 DATA 7EE7FFC3FF81FF7E7EFF81FFC3FFE77E3C66DBBDBDDB663C0000000000000000 10003 DATA 8383838383838383C0C0C0C0C0C0C0C000000000000000000000000000000000 11000 DATA 7,5,15,5 11001 DATA 7,10,9,20 11002 DATA 5,5,13,7 11003 DATA 5,10,7,20
  11. Yeah, GPL is more compact than TMS9900 assembly. #3 would be my favorite option, as I did that with ROA and it works great. But making the engine require a SAMS card may sour the offer for some. I may initially do a SAMS version first but mindful that I should design with ROM paging in mind. #1 is the more likely choice, with 32K expansion required because the whole point is to make a fast smooth engine, not one crammed into 256 bytes of RAM. #2 is right out. I have ZERO interest in using GPL.
  12. Yeah, that was due to a miscalculation of room connections. The trouble is, if I set it to a minimum set of connections per room, it still doesn't solve the disconnected large sections problem. So I'm going to try a different approach and start storing the set data and see what I can do with that.
  13. After some iterating, I got a map like this: Looks great, right? Look closer... two large sections never connect with each other! On the one hand, the map is still usable in the game because you can always "check" for secret doors in one of the rooms to get into the other area. But the original TOD engine tracked sets of rooms to prevent it happening at this large of a scale. (Although not well; I remember finding maps with "barbell" rooms that connected to nothing else.)
  14. I get the feeling he may have over-engineered this one. I was able to deterministically connect every room to a corridor without having to store much other than "this room has this many connections". I would guess he MUST consider the room's quadrant (top, bottom, left right) as well since the room coordinates are stored to retain that data. Otherwise why wouldn't he have just used the two bytes to store a row and column? I'd probably use those data points to make sure it is biased to "head to center" so a room in the top left quadrant would try and go down and right, for example. Also, his algorithm doesn't work if rooms are too far. A map I created randomly put two rooms along the topmost row and they failed to connect to the rest of the dungeon when the TOD cart rendered it. All in all, this exercise is giving me confidence I can write a corridor algorithm that works well. It may mean a new engine renders a different maze, but that's fine.
  15. There aren't any L corridors in Tunnels of Doom. Just T's, four-way, up/down and left/right.
×
×
  • Create New...