Jump to content

adamantyr

+AtariAge Subscriber
  • Posts

    1,891
  • Joined

  • Last visited

Posts posted by adamantyr

  1. 10 hours ago, Elia Spallanzani fdt said:

    "corridor digging function links any two rooms, and knows how to follow an existing tunnel to avoid digging extra tunnels; I keep track of which rooms (and clusters of rooms) are connected using the disjoint set data structure"

    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.

    • Like 6
  2. So I wrote up a prototype map generation in Extended BASIC to test out making corridors. My initial one definitely connects all the rooms but honestly makes WAY too many corridors:

     

    image.thumb.png.4e7567ac62b6c3fc6ab137282d53b26c.png

     

    Here's the code for the interested. Next step is to make it a bit less thirsty.

     

    100 RANDOMIZE 1982 :: OPTION BASE 1 :: DIM RTB(26),RLR(26),RY(26),RX(26),RD(26),RYR(4),RYA(4),RXR(4),RXA(4)
    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 290
    201 FOR R2=1 TO 26 :: IF R=R2 THEN 210 :: IF RY(R2)=0 THEN 210 :: IF RX(R)<>RX(R2) THEN 210
    202 X=RX(R):: IF RY(R) < RY(R2) THEN Y=1+RY(R):: YS=Y ELSE Y=1+RY(R2) :: YS=Y
    203 CALL GCHAR(Y,X,G):: IF G=107 THEN Y=Y+1 :: GOTO 203 ELSE CALL VCHAR(YS,X,97,Y-YS)
    210 NEXT R2
    290 NEXT R
    
    300 CALL SCREEN(14):: FOR R=1 TO 26 :: IF RY(R)=0 THEN 390
    301 FOR R2=1 TO 26 :: IF R=R2 THEN 310 :: IF RY(R2)=0 THEN 310 :: IF RY(R)<>RY(R2) THEN 310
    302 Y=RY(R):: IF RX(R) < RX(R2) THEN X=1+RX(R) :: XS=X ELSE X=1+RX(R2) :: XS=X
    303 CALL GCHAR(Y,X,G):: IF G=107 THEN X=X+1 :: GOTO 303 ELSE CALL HCHAR(Y,XS,96,X-XS)
    304 IF G=97 THEN CALL VCHAR(Y,X,101)
    310 NEXT R2
    390 NEXT R
    
    400 CALL SCREEN(11):: GOSUB 500 :: CALL SCREEN(4)
    410 GOTO 410
    
    500 FOR R=1 TO 26 :: IF RD(R)>1 OR RY(R)=0 THEN 990
    510 CC=0 :: UC=0 :: DC=0 :: LC=0 :: RC=0
    515 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 IF GR=97 THEN CALL VCHAR(RY(R),RX(R)+1,101):: CC=CC+1 :: GOTO 530
    521 IF GR=102 THEN CALL VCHAR(RY(R),RX(R)+1,98):: CC=CC+1 :: GOTO 530
    522 IF GR=107 THEN RC=1
    
    530 IF GL=97 THEN CALL VCHAR(RY(R),RX(R)-1,102):: CC=CC+1 :: GOTO 540
    531 IF GL=102 THEN CALL VCHAR(RY(R),RX(R)-1,98):: CC=CC+1 :: GOTO 540
    532 IF GL=107 THEN LC=1
    
    540 IF GU=96 THEN CALL VCHAR(RY(R)-1,RX(R),100):: CC=CC+1 :: GOTO 550
    541 IF GU=99 THEN CALL VCHAR(RY(R)-1,RX(R),98):: CC=CC+1 :: GOTO 550
    542 IF GU=107 THEN UC=1
    
    550 IF GD=96 THEN CALL VCHAR(RY(R)+1,RX(R),99):: CC=CC+1 :: GOTO 560
    551 IF GD=100 THEN CALL VCHAR(RY(R)+1,RX(R),98):: CC=CC+1 :: GOTO 560
    552 IF GD=107 THEN DC=1
    
    560 RD(R)=CC :: IF CC>=2 THEN 990
    
    600 IF RC=0 OR CC>=2 THEN 700 ELSE Y=RY(R):: X=RX(R):: XS=X+1
    610 X=X+1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 610
    620 IF G=32 THEN 700
    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
    
    700 IF LC=0 OR CC>=2 THEN 800 ELSE Y=RY(R):: X=RX(R):: XS=X-1
    710 X=X-1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 710
    720 IF G=32 THEN 800
    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
    
    800 IF UC=0 OR CC>=2 THEN 900 ELSE Y=RY(R):: X=RX(R):: YS=Y-1
    810 Y=Y-1 :: IF Y=0 THEN 900 ELSE CALL GCHAR(Y,X,G):: IF G=107 THEN 810
    830 IF G>102 THEN CE=G :: GOTO 860
    840 IF (G=99 OR G=100) THEN CE=98 :: GOTO 860
    850 IF G=96 THEN CE=100 
    860 CALL VCHAR(Y,X,97,1+YS-Y):: CALL VCHAR(Y,X,CE):: CC=CC+1
    
    900 IF DC=0 OR CC>=2 THEN 990 ELSE Y=RY(R):: X=RX(R):: YS=Y+1
    910 Y=Y+1 :: CALL GCHAR(Y,X,G):: IF G=107 THEN 910
    920 IF G=32 THEN 990
    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
    
    990 NEXT R :: 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
    
    10000 DATA 000000FFFF0000001818181818181818181818FFFF181818181818FFFF000000
    10001 DATA 000000FFFF181818181818F8F81818181818181F1F181818FF81BDA5A5BD81FF
    10002 DATA 7EE7FFC3FF81FF7E7EFF81FFC3FFE77E3C66DBBDBDDB663C0000000000000000
    10003 DATA 8383838383838383C0C0C0C0C0C0C0C000000000000000000000000000000000
    11000 DATA 8,2,16,4
    11001 DATA 8,10,10,20
    11002 DATA 5,5,13,7
    11003 DATA 5,10,7,20

     

    • Like 3
  3. Oh yes, I found the first part of his article awhile back (I even posted on it), but I forgot he does talk about the algorithm a bit. Confirmed what I thought about verticals always being drawn!

     

    I just noticed yesterday that corridors only come as straights, T's, or a cross. There's no corner pieces because there wasn't quite enough graphic room to store them. It's definitely a feature-centric algorithm.

     

    I'll do some prototyping and see if I can get something going. I mainly would want the maps to match what the original engine would generate, but if it at least makes playable maps that could be good enough.

    • Like 2
  4. 52 minutes ago, Tursi said:

    You'll probably get more efficient code from not seeing the original source anyway. The programming styles we see today are pretty different from what we did in '81, not to mention TOD would have strictly followed the TI rules that we blatantly ignore today. ;)

     

    It would be really cool to see a new driver for the games... but it won't be me. :)

     

    You have done far MORE than your fair share for the TI community, Mike. I bow to you.

    • Like 1
  5. Hey all,

     

    Recently I got an urge to play a 10-level Tunnels of Doom game again, so I fired one up on Classic99. (For the record, successful game! My rogue ended up with triple digit hit points.)

     

    As I played, I noticed flaws that always irked me. A mistaken keystroke causes you to lose your turn, or even canceling a ranged weapon. The weird artifacts, like monsters attempting and failing to use special attacks. The SLOW generation of the 3D view.

     

    Then I found the truly excellent TOD guide by Michael Vepraukas, which is a gold mine on how the game file is structured. And it got me thinking, what if I could write a new engine in 100% TMS9900 assembly that could replicate the original game engine but with refinements and corrections, AND could also drive ANY of the TOD games?

     

    The big challenge, really, is that there's no source available for the game. GPL is an eclectic thing, and when I tried using the GPL disassembler on a cartridge binary, it's 2nd line was a CALL to an area in the 32k expansion. Clearly not working. :P MOST of the game engine could be replicated without source, there's just two major hurdles:

     

    1. The basic attack/defense mechanics. These can probably be gleaned through observation, but it may take a lot of work to tune it to match the original engine's style. (I notice, for example, that the miss rate is inordinately high.)
    2. Map corridors. Due to lack of space, the corridors for floors are algorithmically generated each time to descend or ascend. Replicating this exactly is crucial. So far based on observation, the one thing I noticed is that rooms that are aligned vertically are always connected.

     

    Any interest in this? Any insights or suggestions?

    • Like 13
  6. On my PC, I like using GraphiCV, a tool developed in Java by @unhuman. It lets you do not only sprites but layer up to four of them on top of each other. You can also do bitmap graphics.

     

     

    For RoA, I rolled my own sprite editor on the TI itself that loaded and saved data from and to the binary file directly, so I could make quick edits as needed.

     

    • Like 4
  7. On 9/9/2023 at 7:32 AM, senior_falcon said:

    I included APERTURE, by Adamantyr with the XB game developer's package, and use it as an example of how to compile a program.

    I did not ask for permission to do this, and now realize that I should have done so. If this is a problem then I will remove it and substitute something else.

    I recall someone asking me in the past if they could compile it and I asked them not to, because I felt the game was written for and balanced to the speed of TI-Basic.

     

    But I'm all right with it, so long as someone doesn't complain the game's too hard because certain puzzles relied on the slowness to give you time to react. :)

    • Thanks 1
  8. On 6/19/2023 at 5:20 AM, TheMole said:

    I think I have the core ghost catching mechanic implemented. It's not 100% identical to my two main sources of inspiration (SMS and C64), but it comes pretty close, imho...

     

    Note that I'm showing a ghost in each location to facilitate testing for now, things like haunted buildings, the PK energy progression and getting paid for catching ghosts aren't implemented yet. Wanted to get the more challenging technical bits done first. It turns out that getting the whole state machine implemented was a bit more challenging than I thought... from laying down the trap (which turns into characters to keep the 4-sprites-per-line limit under control) over positioning the men and ultimately animating the victory or loss condition... all these "phases" are treated as different states in the game engine.

     

    Lastly, just wanted to point out that I used Bill Murray's "he slimed me" quote from the movie in lieu of the one used on the C64 to keep the quality as high as possible.

     

    Hope you guys like it!

     

    Nice work! I would definitely test the speech out on hardware; the emulators all use a slightly later generation core.

     

    Also, please make sure music can be disabled. While I enjoy the tune, it's nice to have the option to not listen to it non-stop. Plus you could then add in some sound effects for the proton guns, the trap, etc.

    • Like 3
  9. 16 hours ago, TheMole said:

    So, quick question to those of you that know and have played the game... I'm on the fence about the approach for the driving segments. I could go home-computer style, where you have a huge car filling almost the entire screen, and the game play is limited to potentially vacuuming ghosts, as shown here:

    ghosts-on-road-616x436.thumb.png.397cfe41990a52f32c549e4f4b373f82.png\

     

    I've heard people call this part of the game boring (although honestly, I kinda like the more chill gameplay myself), so the console versions spruced it up a bit, where you also have to avoid cars and obstacles (and in the NES version even pick up fuel barrels), and the graphical presentation has been changed quite a bit:

    Ghostbusters-nes.png.315460a5f64302efbf51ebe8e25f2677.png ghostbusters-ms.png.87ea44e41bc70add33e077fe814f6174.png

     

    Which would you prefer?

    I only ever played the C64 version myself. I think it really depends on if you want to implement all the various car upgrades and different models of car. If you do, I'd stick with the passive version. If not, then the small mini-game of dodging cars and grabbing fuel works.

  10. 1 hour ago, TheMole said:

     

    Nah, nothing as fancy as that... and for gameplay reasons, it probably wouldn't be a good idea, might make the game too easy...

    Here's how the C64 and Amstrad CPC do it:

    ghostbusters-c64-12.webp.0833630d83da47f8b087d410cfdeb1fd.webp

    ghostbusters_6.png.a62531ecd3f3d84ffd00de84e8bdcaad.png

     

    I think model after the C64 but lose the center column, go single color, but have it rotate color rapidly between red, blue and yellow. I used color rotation in RoA frequently to zazz up single color sprites at low cost. :)

    • Like 1
  11. 23 hours ago, TheMole said:

    So, here are some mock-ups showing some of the game's screens. These are all made in Gimp and haven't been put into the game yet, but should all work within the restrictions of the tms9918a.

    house.png.18bd044cfda4020d4f913bc95e90c655.png    map.png.73fd02753ba59b9123df17176b5796f8.png

     

    A lot of the inspiration for the graphics comes from the Master System version, but I'm also looking at the MSX and C64 versions closely for each part of the game. Any feedback is welcome!

    Excellent graphic work! I'm very excited to see the finished product.

     

    I would say using a consistent color for the tops of buildings will help users navigate the main map easier; most of the ports only use a limited number of colors anyway.

     

    Looking at the MSX screenshots, I'm surprised at how pedestrian it looks. Definitely shoot for the stars; the Sega Master System has a much better appearance.

    • Like 1
  12. Glad to see you are free, Gary!

     

    I almost put a reference to Oasis Pensive Abjucators in RoA, but I thought there was no real way to do it that would work. (A dreamy merchant at an oasis?)

    • Like 2
  13. I found that software sprite rotation... isn't great. I wrote a small test program and found that it caused a lot of blinking that was pretty harsh.

     

    FORTUNATELY you should be okay, because it's only horizontal that's the problem. If you only use four sprite (two proton streams and two for the target ghost) you should be okay. You DO have 32 sprites to work with, although I would warn you can't use half-bitmap/enhanced graphics mode in that case, only full bitmap, because the table masks mess up the sprites and you're limited to 8 unique sprites. (If you use 9 or higher, they just repeat the first eight.)

    • Like 2
  14. 15 hours ago, llabnip said:

    With three cups of coffee and some help from @Tursi (mostly to eliminate things to try) I've got a discovery.  ROA is making use of the 9901 timer. When I did my re-write, I didn't understand that very well - and based on some experiments and some reading, it looked like it was mostly used for Cassette IO handling which I wasn't supporting. So I simplified my handling of anything 9901 timer-based...  and by simplified I mean I almost totally ignore it.  I suspect ROA is one of those rare games that makes use of it. I don't know if it enables the timer interrupt or if it's just setting and checking the countdown register... but this is my current best guess as to what's going wrong with DS99.

    It does use the timer, but it's for random numbers. The clock runs so fast it's usable in any state. (I originally used the VDP timer, but it produced predictable patterns for battlemap generation.) I'm not sure if that would cause the game to not work, though, unless even trying to set the CRU bits to access it caused your emulator to crash.

     

    Also, for the 180K version, you have to use the cartridge binary, and put all the rest of the files from the game disk on a single disk, and split the world disks into four disks. And be sure to configure their location in the configuration menu.

    • Like 5
  15. On 1/27/2023 at 2:08 PM, InfiniteTape said:

    Realms of Antiquity. It's a modern TI release by @adamantyr. It's not free, but it may push your implementation in new ways. http://quixotic.adamantyr.com/roa.htm

    Yeah, developer of Realms of Antiquity here. :) In order for it to run, you will need to emulate the SAMS card, which provides 1024mb of CPU memory to the base TI.

     

    Hardware details can be found here: http://www.unige.ch/medecine/nouspikel/ti99/superams.htm

    • Like 2
  16. BLWP, by having an isolated register set, is useful because it's sort of like a method in a high-end language like Java, C, C#, etc.

     

    For BL/RT, I usually set up an internal stack and burn R10 as a pointer for it, so I can push and pop return addresses off if needed. That way BL routines can call other BL routines but still work their way back to the original caller.

     

    What I did find when coding Realms of Antiquity was that I'd frequently run into issues where I was using registers to hold specific values at the top of a return stack, and either I'd end up running out of registers to use or worse, accidentally use one and cause a bug. That's where I would convert some subroutines into BLWP versions, because then they operated independently.

     

    Also, I've used register sets in the regular CPU memory areas other than the scratch pad and not had performance problems. It's all about the context of what you're using them for.

    • Like 7
    • Thanks 1
×
×
  • Create New...