Jump to content
IGNORED

The Legend of Tilda


PeteE

Recommended Posts

Yes very nice!

 

The movement of the monsters is perfect, although I did notice they aren't shooting projectiles. I imagine the sprite use and 4 per line limit is starting to get annoying.

 

One aspect of utilizing the 32k would be you could do some good optimizations, such as a rotating sprite table in CPU memory.

Link to comment
Share on other sites

Yes very nice!

 

The movement of the monsters is perfect, although I did notice they aren't shooting projectiles. I imagine the sprite use and 4 per line limit is starting to get annoying.

 

One aspect of utilizing the 32k would be you could do some good optimizations, such as a rotating sprite table in CPU memory.

 

The projectiles are on my todo list, but they didn't make the cut for this release. Some projectiles will also bounce off the player if they face the shield toward it, and I'll work on that too when I add projectiles.

 

The 4 sprites per line limit doesn't seem too terrible. What I'm doing now is the 2 hero sprites and 4 status bar sprites are always highest priority, since I never want them to flicker. The rest are written in forward order, or in reverse order, alternating every frame, so that sprites on the same line will appear to flicker. In reverse order, I write the VDP address once, then copy 6*4 bytes from sprites 0-5, then copy 4 bytes from 31st sprite to the VDP then the 30th sprite, 29th, etc. This is the SPRUPD (sprite update) function in tilda_b0.asm. There is a chance that sprites in the middle of the list will not be displayed if too many sprites are on the same line, but this happens very rarely (and most people probably have the 4-sprites-per-line limitation turned off in an emulator or the F18A.) I am keeping a copy of the sprite list table in the fast CPU RAM even though it takes 128 bytes out of the total 256. Manipulating the sprite list is the bulk of the work for each frame, so it seemed like a good idea to use the fast RAM instead of the slower expansion RAM.

 

 

Hmm, when I brought it up in Classic99, it loads the first screen but if I move any direction but down it scrolls up the menu screen and then locks up. Anyone else experiencing that?

 

UPDATE: Nevermind, figured it out. The joystick #2 was also configured to PC keyboard, which meant it was sending double inputs and causing some hijinks.

 

Ah, I never considered that configuration. All of the joystick 2 inputs are mapped to the 3 action buttons: sword, item, and menu screen. This is so it will work with various 6-button controller configurations. This also reminded me of the alpha-lock problem, and other games I've seen ask the user to press the joystick up just to make sure alpha-lock is off, that would also help to ensure joystick 1 is being used. Thanks!

 

 

No need to be sorry, as far as I am concerned; I keep coding in this way because I'm using the classic assembler in E/A and TASM on the Geneve.

I'm not sorry. :) It feels retro to use all caps, and was intended to set up the joke about caps being used for shouting and the computer being old and hard of hearing: "Eh, speak up, sonny"

Link to comment
Share on other sites

 

The projectiles are on my todo list, but they didn't make the cut for this release. Some projectiles will also bounce off the player if they face the shield toward it, and I'll work on that too when I add projectiles.

 

The 4 sprites per line limit doesn't seem too terrible. What I'm doing now is the 2 hero sprites and 4 status bar sprites are always highest priority, since I never want them to flicker. The rest are written in forward order, or in reverse order, alternating every frame, so that sprites on the same line will appear to flicker. In reverse order, I write the VDP address once, then copy 6*4 bytes from sprites 0-5, then copy 4 bytes from 31st sprite to the VDP then the 30th sprite, 29th, etc. This is the SPRUPD (sprite update) function in tilda_b0.asm. There is a chance that sprites in the middle of the list will not be displayed if too many sprites are on the same line, but this happens very rarely (and most people probably have the 4-sprites-per-line limitation turned off in an emulator or the F18A.) I am keeping a copy of the sprite list table in the fast CPU RAM even though it takes 128 bytes out of the total 256. Manipulating the sprite list is the bulk of the work for each frame, so it seemed like a good idea to use the fast RAM instead of the slower expansion RAM.

 

 

 

Ah, I never considered that configuration. All of the joystick 2 inputs are mapped to the 3 action buttons: sword, item, and menu screen. This is so it will work with various 6-button controller configurations. This also reminded me of the alpha-lock problem, and other games I've seen ask the user to press the joystick up just to make sure alpha-lock is off, that would also help to ensure joystick 1 is being used. Thanks!

 

I'm not sorry. :) It feels retro to use all caps, and was intended to set up the joke about caps being used for shouting and the computer being old and hard of hearing: "Eh, speak up, sonny"

 

Ah yes, it makes sense to keep a copy of the table in the scratch-pad!

 

The main thing with the 32k expansion is you could explore a "memory for time" approach. Generally speaking, any algorithm can be written to be faster by just being more memory wasteful. I'd need to look at your code first to see what could be done, but I've explored it with my work on the Gauntlet clone.

 

I understand you have a goal here though, to not require the 32k expansion, so I'll be quiet about it. :) Just don't let it stop you from finishing the game!

Link to comment
Share on other sites

Seriously impressive work here :)

 

I also never noticed before today that the Triforce on the title page was actually Texas. ;)

Thanks! I've been calling it the "TIFORCE", so what other shape would it have? ;-)

 

Oh, there is a sword ??? Can I use that on keyboard ?

The Enter key is sword. (On classic99 you can also use Tab since I think that is the emulated joystick fire button)

  • Like 2
Link to comment
Share on other sites

  • 3 weeks later...

WOW. I am loving the look and feel of this. Will a finished cart of this require a F18A?

No, this version will not require F18A. I may decide to do a special F18A version to add 4 color graphics later, but no guarantee.

 

Edit: Might as well post a status update since I'm here. Lately I've been working on the menu screen and item selection, and have animations done for the candle, bombs, boomerang, and magic rod. Started populating the overworld cave screens. I'm researching LZ77 compression for pattern tables since I'm getting close to running out of cartridge space in 32K, and haven't even started dungeons yet. I could go 64K but then I think it won't work on the FlashROM. I can't believe I thought this project would be easy in the beginning, but it's been great fun learning all the little things that go into making a game. Maybe it's a good thing I picked a classic game that makes it feel worthwhile to port so I don't get frustrated and give up thinking "why am I porting a 20 year-old game to a 26 year-old computer with worse graphics" :razz:

Edited by PeteE
  • Like 4
Link to comment
Share on other sites

I found a compression algorithm in the ColecoVision programming forum: DAN2 which has nice properties of good compression ratio and low complexity. I converted the C decoder to TMS9900 asm, and it worked on the very first try - that never happens! This version only decodes from RAM/ROM to VDP memory, which is exactly what I need for pattern tables. The code assembles to about 220 bytes, not including VDPWB and VDPRB.

 

 

 

; Dan2 decompression
; R5 = Source data address
; R7 = VDP output address
; Register usage
; R3 = length (elias_gamma)
; R8 = status bits
; R9 = offset
; R10 = saved return address
; R12 = max offset bits
DAN2DC
       MOV R11,R10  ; Save return address
       CLR R8
       LI R12,9   ; R12 = 10 (max offset bits initial value)
!      INC R12
       BL @D2RBIT   ; R12 = (count of 1 bits) + 10
       DATA -!
D2LIT ; literal
       MOVB *R5+,R1
       MOV R7,R0
       BL @VDPWB
       INC R7
D2LZLP ; LZ loop
       BL @D2RBIT
       DATA D2LIT
       ; length = read_elias_gamma()
       CLR R4      ; len (number of bits in elias_gamma)
       LI R3,1     ; elias_gamma
!      INC R4      ; while carry_flag == 0
       CI R4,17
       JEQ D2_L17
       BL @D2RBIT
       DATA !      ; if carry, increment counter
       JMP -!
D2_L17
       ; elias_gamma = 0; so length = 0, done!
       B *R10       ; Return to saved address

D2_IEG ; increment elias_gamma
       INC R3   ; elias_gamma += 1
!      DEC R4
       JEQ !
       SLA R3,1
       BL @D2RBIT
       DATA D2_IEG   ; if carry, increment elias_gamma
       JMP -!
!      ; R3 = elias_gamma = length (known to be nonzero)
       ; offset = read_offset(length)

       CLR R9   ; offset = 0

       ; read_offset(option=R3) returns offset in R1
       CI R3,2
       JLE !  ; if (option > 2)

       BL @D2RBIT
       DATA D2OFF3
!
       CI R3,1
       JLE !  ; if (option > 1)

       BL @D2RBIT
       DATA D2OFF2
!
       BL @D2RBIT
       DATA D2OFF1

       INC R9
       BL @D2RBIT
       DATA D2_OFF
       CLR R9
D2_OFF
       ; offset = R9
       NEG R9
       DEC R9
       A R7,R9   ; R9 index = = out_addr - offset - 1
!
       MOV R9,R0    ; Read byte from R9 (index)
       BL @VDPRB
       INC R9

       MOV R7,R0    ; Write byte to R7 (out_addr)
       BL @VDPWB
       INC R7

       DEC R3
       JNE -!
       JMP D2LZLP

MAXOF1 EQU 2             ; 1<<1
MAXOF2 EQU MAXOF1+16     ; 1<<4
MAXOF3 EQU MAXOF2+256    ; 1<<8

D2OFF3
       ; read_bits(max_bits - 
       MOV R12,R4
       AI R4,-8      ; R4=MAX_OFFSET_BITS-8
       BL @D2RBTS
       SLA R9,8
       AI R9,MAXOF3-MAXOF2
       ;fall thru
D2OFF2
       MOVB *R5+,@R9LB
       AI R9,MAXOF2
       JMP D2_OFF
D2OFF1
       LI R4,4
       BL @D2RBTS
       AI R9,MAXOF1
       JMP D2_OFF

; read_bits(count=R4) return in R9
D2RBTS
       MOV R11,R0  ; Save return address
!      SLA R9,1
       BL @D2RBIT
       DATA D2RBT2
       JMP D2RBT3
D2RBT2 INC R9
D2RBT3 DEC R4
       JNE -!
       B *R0   ; Return to saved address

; read_bit, jump to *R11+ if set, return otherwise
; Modifies R2
D2RBIT
       MOV *R11+,R2
D2RBI2
       SLA R8,1
       JEQ D2RFIL
       JNC !
       B *R2
!      RT

; read_bit refill bits
D2RFIL
       LI R8,>0080
       MOVB *R5+,R8
       JMP D2RBI2

 

  • Like 9
Link to comment
Share on other sites

I found a compression algorithm in the ColecoVision programming forum: DAN2 which has nice properties of good compression ratio and low complexity. I converted the C decoder to TMS9900 asm, and it worked on the very first try - that never happens! This version only decodes from RAM/ROM to VDP memory, which is exactly what I need for pattern tables. The code assembles to about 220 bytes, not including VDPWB and VDPRB.

 

 

 

; Dan2 decompression
; R5 = Source data address
; R7 = VDP output address
; Register usage
; R3 = length (elias_gamma)
; R8 = status bits
; R9 = offset
; R10 = saved return address
; R12 = max offset bits
DAN2DC
       MOV R11,R10  ; Save return address
       CLR R8
       LI R12,9   ; R12 = 10 (max offset bits initial value)
!      INC R12
       BL @D2RBIT   ; R12 = (count of 1 bits) + 10
       DATA -!
D2LIT ; literal
       MOVB *R5+,R1
       MOV R7,R0
       BL @VDPWB
       INC R7
D2LZLP ; LZ loop
       BL @D2RBIT
       DATA D2LIT
       ; length = read_elias_gamma()
       CLR R4      ; len (number of bits in elias_gamma)
       LI R3,1     ; elias_gamma
!      INC R4      ; while carry_flag == 0
       CI R4,17
       JEQ D2_L17
       BL @D2RBIT
       DATA !      ; if carry, increment counter
       JMP -!
D2_L17
       ; elias_gamma = 0; so length = 0, done!
       B *R10       ; Return to saved address

D2_IEG ; increment elias_gamma
       INC R3   ; elias_gamma += 1
!      DEC R4
       JEQ !
       SLA R3,1
       BL @D2RBIT
       DATA D2_IEG   ; if carry, increment elias_gamma
       JMP -!
!      ; R3 = elias_gamma = length (known to be nonzero)
       ; offset = read_offset(length)

       CLR R9   ; offset = 0

       ; read_offset(option=R3) returns offset in R1
       CI R3,2
       JLE !  ; if (option > 2)

       BL @D2RBIT
       DATA D2OFF3
!
       CI R3,1
       JLE !  ; if (option > 1)

       BL @D2RBIT
       DATA D2OFF2
!
       BL @D2RBIT
       DATA D2OFF1

       INC R9
       BL @D2RBIT
       DATA D2_OFF
       CLR R9
D2_OFF
       ; offset = R9
       NEG R9
       DEC R9
       A R7,R9   ; R9 index = = out_addr - offset - 1
!
       MOV R9,R0    ; Read byte from R9 (index)
       BL @VDPRB
       INC R9

       MOV R7,R0    ; Write byte to R7 (out_addr)
       BL @VDPWB
       INC R7

       DEC R3
       JNE -!
       JMP D2LZLP

MAXOF1 EQU 2             ; 1<<1
MAXOF2 EQU MAXOF1+16     ; 1<<4
MAXOF3 EQU MAXOF2+256    ; 1<<8

D2OFF3
       ; read_bits(max_bits - 
       MOV R12,R4
       AI R4,-8      ; R4=MAX_OFFSET_BITS-8
       BL @D2RBTS
       SLA R9,8
       AI R9,MAXOF3-MAXOF2
       ;fall thru
D2OFF2
       MOVB *R5+,@R9LB
       AI R9,MAXOF2
       JMP D2_OFF
D2OFF1
       LI R4,4
       BL @D2RBTS
       AI R9,MAXOF1
       JMP D2_OFF

; read_bits(count=R4) return in R9
D2RBTS
       MOV R11,R0  ; Save return address
!      SLA R9,1
       BL @D2RBIT
       DATA D2RBT2
       JMP D2RBT3
D2RBT2 INC R9
D2RBT3 DEC R4
       JNE -!
       B *R0   ; Return to saved address

; read_bit, jump to *R11+ if set, return otherwise
; Modifies R2
D2RBIT
       MOV *R11+,R2
D2RBI2
       SLA R8,1
       JEQ D2RFIL
       JNC !
       B *R2
!      RT

; read_bit refill bits
D2RFIL
       LI R8,>0080
       MOVB *R5+,R8
       JMP D2RBI2

 

 

Nice! I'll have to try this with my text and see how it works...

Link to comment
Share on other sites

I found a compression algorithm in the ColecoVision programming forum: DAN2 which has nice properties of good compression ratio and low complexity. I converted the C decoder to TMS9900 asm, and it worked on the very first try - that never happens! This version only decodes from RAM/ROM to VDP memory, which is exactly what I need for pattern tables. The code assembles to about 220 bytes, not including VDPWB and VDPRB.

 

Thank you, that will be handy for my projects. I have not used anything more advanced than RLE before.

 

I also once wrote some assembly code that worked the first time. It has never happened since. ;)

Link to comment
Share on other sites

Unfortunately for my needs, it won't quite work... I tested a single line of text with the command-line encoder and it only shrunk it like 9%.

 

In my case, I have a lot of separate data records of different fixed sizes, each of which is compressed individually. Most compression techniques rely upon finding matches and similarities over a much larger sample size.

 

For example, if you embedded ALL text dialogue for a given map or location into a large block, you would probably be able to compress it much better. However, this would be a major architecture change to my engine at this point, plus I'm not a fan of it because it means variable sized files, and a great amount of difficulty adding and removing dialogue later.

 

I may play around with some variants with my text encoding after I get the bulk of my data complete, see if I can find something that works a little better. Dropping the use of the 8th bit for "precede with space" and instead using the upper 128 for another set of dictionary replacements is worth trying... I just need to find a way to identify the most common character combinations in my text, an N^2 job to say the least...

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

Finally got the NPCs, cave text and items appearing now. As you can see in the screenshots, the NPCs use two sprites and background characters for full detail, and the fire is one sprite and background characters. Each item is also a sprite (which means if you walk on the same row they will flicker due to the 4 sprites per line limitation on the 9918.) The text appears one character at a time, like the original.

 

post-43480-0-57839100-1508359962.png

post-43480-0-17750800-1508359977.png

post-43480-0-81457300-1508359991.png

  • Like 10
Link to comment
Share on other sites

Finally got the NPCs, cave text and items appearing now. As you can see in the screenshots, the NPCs use two sprites and background characters for full detail, and the fire is one sprite and background characters. Each item is also a sprite (which means if you walk on the same row they will flicker due to the 4 sprites per line limitation on the 9918.) The text appears one character at a time, like the original.

 

:o A W E S O M E ! :lust: Love the old-school zelda's, not so much the new ones. Zelda 1, and Star tropics 1 & 2 are probably my top favorite NES titles ever.

Speaking of star tropics, does anyone know of a re-implementation / clone of star tropics for pc? (If you know what the program "zelda classic" is, think that only for playing custom star tropics levels)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...