Jump to content
  • entries
    657
  • comments
    2,693
  • views
    899,061

do you hear what I hear?


SpiceWare

1,364 views

  • Sound effects by Bob DeCrescenzo!
  • Added a hyperspace cool-down timer to eliminate infinite-hyperspace. Before you could hold down and continually warp out/warp in w/out risk of collision and only let go of the joystick once you warped into a safe spot. Cool-down time is currently 5 seconds.
  • A couple of the small killer satellites could explode in the wrong color in monochrome games. This has been fixed.
  • Fixed a couple minor issues in the menu - the kids down option wasn't always forced to shields, and the down option would flash colors instead of staying a muted grey.
  • Revised the heartbeat speeds.
  • Revised the sound effect routines to compact the sample data.

My original test sound effects always changed the frequency and/or volume and/or control (sound type) on every frame, so the original sound effect routines used an implied duration of 1 frame per sample. Bob's sound effects often held values over multiple frames, so I modified the sound driver to support duration to shrink the amount of space the samples would take. The killer satellite entrance sound effect is a good example of the change, it originally looked like this:

SoundFreq: ; 0-31 0 = highest freq.
.byte 0,$0e,$0e,$0e,$29,$29,$29,$0e,$0e,$0e,$29,$29,$29
.byte $0e,$0e,$0e,$29,$29,$29,$0e,$0e,$0e,$29,$29,$29
.byte $0e,$0e,$0e,$29,$29,$29,$0e,$0e,$0e,$29,$29,$29
.byte $0e,$0e,$0e,$29,$29,$29,$0e,$0e,$0e,$29,$29,$29
.byte $0e,$0e,$0e,$29,$29,$29,$0e,$0e,$0e,$29,$29,$29
.byte $0e,$0e,$0e,$29,$29,$29,$0e,$0e,$0e,$29,$29,$29 ; Killer Satellite Entry

SoundVol: ; upper nybble AUDC, lower nybble volume. $00 = end of sound effect.
.byte 0,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8
.byte $c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8
.byte $c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8
.byte $c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8
.byte $c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8
.byte $c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8,$c8 ; Killer Satellite Entry

 

SoundFreq data only uses the lower 5 bits to hold the frequency, so I added the ability to use the upper 8 bits to hold a duration. After that, 50 bytes was able to hold what originally resided in 146 bytes.

D1 = 0
D2 = 1*32
D3 = 2*32
D4 = 3*32
D5 = 4*32
D6 = 5*32
D7 = 6*32
D8 = 7*32
SoundFreq: ; 0-31 0 = highest freq.
; upper 3 bits control duration, 0 = 1 frame, 1 = 2 frames... 7=8 frames
.byte 0, D3+$0e, D3+$29, D3+$0e, D3+$29
.byte D3+$0e, D3+$29, D3+$0e, D3+$29
.byte D3+$0e, D3+$29, D3+$0e, D3+$29
.byte D3+$0e, D3+$29, D3+$0e, D3+$29
.byte D3+$0e, D3+$29, D3+$0e, D3+$29
.byte D3+$0e, D3+$29, D3+$0e, D3+$29 ; Killer Satellite Entry

SoundVol: ; upper nybble AUDC, lower nybble volume. $00 = end of sound effect.
.byte 0, $c8, $c8, $c8, $c8
.byte $c8, $c8, $c8, $c8
.byte $c8, $c8, $c8, $c8
.byte $c8, $c8, $c8, $c8
.byte $c8, $c8, $c8, $c8
.byte $c8, $c8, $c8, $c8 ; Killer Satellite Entry

 

ROMs

spacerocks20120914_NTSC.bin

spacerocks20120914_PAL.bin

 

Source

spacerocks20120914.zip

18 Comments


Recommended Comments

I encountered a weird scenario, I think it went like this:

 

1) both enemies appeared on screen

2) I died, either from a shot from the UFO or a rock

3) The UFO shot the other enemy, and it split

4) The enemy continually circled the middle of the screen waiting for me to re-spawn, but I couldn't re-spawn because of the enemy.

 

 

I did notice that you don't seem to be using a lot of Zero page ram. Perhaps if bytes are tight you can offload some code in there, and jump into ram to execute? Probably preferable to put some tables of similar bytes in there, if you can.

 

 

Then maybe you can squeeze in Genesis support. :P

Link to comment

Can any part of the 'hit rock' sound be changed for the three types, sm, med, lg?

Looking at source shows sound data for each size. Hmmm...

Maybe it is too late at night and I'm not hearing or recalling right...

Other suggestions are maybe change the duration echo, longer for lg; shorter for sm, or 3 different volumes...

Does the game logic even know if a sm, med or lg has been hit? If no, please disregard this suggestion.

There is no sound in space, so for maximum realism, turn the sound all the way down during a game!

All looks good. Played Multi color vector, white vector, white solid, then orange. Orange is very Halloween with all the black and orange.

I recommend at least one orange game play for September/October.

P.S. You do an awful lot of work for not being able to do any work this week!!!

Link to comment

The new sound effects are awesome - they complement the game nicely.

 

How about:

 

int HexToBCD(int value)
{
return ((value / 10) << 4) | (value % 10);
}

 

EDIT: I just noticed this function isn't actually used :)

Link to comment

@Omegamatrix - that is an odd one. If you get die, the LEAVE_SCREEN flag for the satellite is only set if the satellite is onscreen. This happens in function PlayerDied(). As such, I think what happened was you crashed into a small asteroid when there where just 4 asteroids onscreen, which triggered the satellite to show up (it appears when there's 3 asteroids). I'll see what I can do, that should be easy to recreate and test.

 

ZP RAM - yeah, the game is mostly driven by the ARM which cannot access ZP RAM. I could put some code in there, but that would require the code to be stored in ROM, plus a new COPY CODE function would have to be written, so I don't see how that would save any space.

 

Genesis controller support would be way cool - sadly, at this point, I don't see it happening.

 

 

@iesposta - yes, there's 3 separate asteroid explosions. Which one is selected in function BreakAsteroid as part of the splitting logic, so the size is known. There's no more room for any more sound effects unless an existing one is shrunk. The SoundFreq and SoundVol tables are both 256 bytes long and the indexes into the table bytes so that's all they can span. At one point I looked at changing the indexes to short ints but then the ARM code exceeded its free space.

 

 

@cd-w - yep - as always, Bob did excellent work! I did a division once that wasn't a power of 2 divide and the code ballooned in size. I researched it and found that power of 2 divides are converted to shifts, but a software library is added for all other integer divides.

 

 

@mojofltr - :lol: thanks.

Link to comment

I just took a look, and if I calculated right you can free up 51 bytes more in bank 5 by using a NOP delay table. Right now you are just using a lot of SLEEP macros which are inefficient. So do a hunt for wherever you use SLEEP12 and replace with calls to this table:

 

WasteTime30 SUBROUTINE
 .byte $80
WasteTime29
 .byte $80
WasteTime28
 .byte $80
WasteTime27
 .byte $80
WasteTime26
 .byte $80
WasteTime25
 .byte $80
WasteTime24
 .byte $80
WasteTime23
 .byte $80
WasteTime22
 .byte $80
WasteTime21
 .byte $80
WasteTime20
 .byte $80
WasteTime19
 .byte $80
WasteTime18
 .byte $80
WasteTime17
 .byte $80
WasteTime16
 .byte $80
WasteTime15
 .byte $04
WasteTime14
 nop
WasteTime12
 rts

 

Okay, most calls are straight forward, but there is no WasteTime13 available, so just do what you are doing now, i.e.:

 

P0EarlyHM63:				    ; 5 20
    jsr P0RepoExtra		 ;27 47
    jsr WasteTime12		 ;12 59  or use SLEEP12
    sta.w RESP0			 ; 4 53  ... we delay 1 more cycle here
    jmp KernelLoop		  ; 3 56

 

 

When you need delays of 57 and 47 just do two JSR's like you have been doing i.e.:

 

 jsr WasteTime30  ;  delay 57
 jsr WasteTime27  ;

 jsr WasteTime20  ;  delay 47
 jsr WasteTime27  ;

 

 

Anyhow, if I calculated correctly it should free up 51 bytes over what the sleep marcos are giving you, and bring the total bytes free in that bank to 61.

 

 

Jeff

Link to comment

Great find, thanks!

 

Nathan's sent over the XOR data for the vector version of the Killer Satellites Magna-Mines, and at 176 bytes it's going to use up most of 196 bytes that's currently free. I'm guessing that the XOR data for the solid Magna-Mines will take a similar amount, so I've got another hundred bytes or so that I need to free up.

 

If I drop the lower case letters in the easter egg and switch to a 3x5 font that should save another 128s. The capital letters, with the exception of Q, are already using a 3x5 font, so the letters will mostly look the same.

Link to comment

I think another 14 bytes can be saved:

 

- Use DEC $2E (2 bytes) instead of SLEEP 5 (3 bytes)

- No need for clearing PF0, PF1, and PF2 in ShowTwoColorGraphic, as they playfield gets colored black when the routine is done, and the playfield gets cleared or updated elsewhere. So remove STX PF0, STX PF1, and STX PF2 at $50b6 - $50bb.

 

 

I'll see if I can find some more.

Link to comment

Good point - I keep forgetting that the ARM in the Harmony doesn't have a divide unit.

 

How about:

 

1) Dropping the "bonus life" option from the menu and just hard-wiring it to 10K, or making it a feature of the level type (kids=2K, easy=5K, normal=10K, hard=20K).

 

2) Storing the easter-egg text as non-ASCII? If you have less than 64 letters you could pack 4 characters into every 3 bytes, i.e: AAAAAABB BBBBCCCC CCDDDDDD

 

Chris

Link to comment

@Omegamtrix - sweet!

 

@cd-w - dropping "bonus life" is an interesting idea, I'll think on it. Packing the easter egg text is something I've been thinking about, and dropping lower case will certainly make it easier. One of the things I need to take into consideration is I've been using 1-15 to denote # of spaces so I can center a line of text using just 1 byte instead of 1-15.

Link to comment

One small feature request - can you add a "blip" sound when an option is changed on the menu screen. Sometimes it can be difficult to be sure the option has actually changed, particularly the color options. I think AUDC=5, AUDF=24, AUDV=8 for a few frames makes a reasonably nice sound.

 

Chris

Link to comment

Are you ever setting the stack pointer (besides the clear loop)? I didn't see any TSX or TXS.

 

 

So you might be able to use PLA PHA in ~ 4 places to save some bytes.

 

- This is not good when stack pointer is at $FF, as you'll strobe VSYNC with whatever was at $FF

- This is also not good if you are two or more subroutines deep.

 

A solution is to have the stack pointer at $FE, with $FF acting as a buffer to prevent writes to VSYNC. You are not using a lot of ram, so it might be feasible as long as the stack pointer is at $FE. Now here is a modified CLEAN START that will do this for you:

 

START:
 sei  ; optional
 cld
 ldx  #0
 txa
.loopClear
 txs
 inx
 pha
 bne  .loopClear
;A=0, X=0, Y=Unknown, SP=$FE
;now free to use PLA PHA to delay 7 cycles

 

I usually don't use SEI, but at 1 byte it doesn't cost much to just leave it. Now you might be able to save 4 more bytes right off the bat because A and X are known to be zero. In your code it looks like X is loaded twice after clean start with 0:

 

    CLEAN_START
    ldx #0
ZERO4 = * - 1	   
    stx FASTFETCH   ; 0 turns on fast fetch mode
		   
    ; call ARM subroutine Initialize()
    ldx #<ARMsub
    stx DF0LOW
    ldx #>ARMsub
    stx DF0HI
    ldx #0				  ; 0 = selects Initialize();
    stx DF0WRITE
    dex					 ; $FF = w/out digitized audio
    stx CALLFUNCTION	    ; triggers ARM routine

 

 

If at this point everything works you can now modify in Reposition0:

 

;old
 lax  DS_MISSILE  ; 4 58
 asl  ; 2 60
 tay  ; 2 62
 lda  #<DS_HMP0  ; 2 64
 lda  #<DS_GRP1  ; 2 66
 ;SLEEP 7   ; 7 73
 nop   0
 nop
 nop
 sta  HMOVE  ; 3 76/0

;new save 2 bytes
 lax  DS_MISSILE  ; 4 58
 asl  ; 2 60
 tay  ; 2 62
 PLA  ; 4 66  stack pointer $FE --> $FF
 PHA  ; 3 69  stack pointer $FF --> $FE
 lda  #<DS_HMP0  ; 2 71
 lda  #<DS_GRP1  ; 2 73
 sta  HMOVE  ; 3 76/0

 

More savings can be had by similarly modifying ShowSpiceWareLogo (sleep 11), a sleep 14 between SSWLskip1 and EndShowSpiceWareLogo, and a sleep 9 below DEloop.

Link to comment

A little after CLEAN START the code does:

 

dex ; X=$FF

stx CALLFUNCTION

jmp VerticalBlank ; change to BNE or BMI

 

In VerticalBlank the code does:

 

ldx #2

stx WSYNC

stx VSYNC

ldy #$2B

sty TIM64T

 

Maybe reuse Y value, as it doesn't affect bits 7 and 6 of Vblank:

 

ldy #$2B ; okay for NTSC, but maybe not for PAL timings...

sty WSYNC

sty VSYNC

sty TIM64T

 

With this change I believe X will now always be $FF at this point (from Overscan, or Arm initialization). So a little ways down in VeritcalBlank replace the LDX #0 with INX.

Link to comment

Thinking about it now, if you are not in a subroutine and the stack pointer was at $FF, you could just PHA PLA to delay 7 bytes as long as you don't mind trashing $FF, and don't care what you are loading in the accumulator. I don't know why I had it so difficult. You probably should make a new clean start routine however, where you don't include the TAY to save a byte. I don't think you are using Y=0 right after.

Link to comment

It appears 6 more bytes can be freed in VerticalBlank by not writing 0 to GRP0, GRP1, and COLUBK. This was tested by hacking the rom in Stella, so might need a close look.

 

After the ScoreLoop you could maybe do something like this to save another 4 bytes:

 

 ldx #0  ; clear all------------------------> LDY #0
 stx ENAM0 ---------------------------------> STY, all
 stx ENAM1
 stx GRP0
 stx GRP1
 stx REFP1
   ; prep for call to OverScan()
 ldx #<ARMsub
 stx DF0LOW
 ldx #>ARMsub
 stx DF0HI
 ldx #1  ; 2  - 1 = OverScan(); ------------> INY, Y=1
 stx DF0WRITE  -----------------------------> STY DF0WRITE
 ; pass the PIA and TIA registers to the ARM code
 ldx SWCHA
 stx DF0WRITE
 ldx SWCHB
 stx DF0WRITE
 ldx INPT4
 stx DF0WRITE
 ldx INPT5
 stx DF0WRITE
 ldx #zr_____XXX
 stx PF0
 ldx #zzXXXXXXXX  ; - the colored scanline -------> maybe TSX, if X=$FF
 stx PF1
 ldx #zrXXXXXX__
 stx PF2
 lda #<DS_SCORE8
 sta COLUP0
 lda #<DS_SCORE8
 sta COLUP1
 ldy #2  ; - set SCORE mode  -------> INY, Y=2
 sty CTRLPF
 ldx  #18+8
 stx  TIM64T
 jsr  SLEEP12
 jsr  SLEEP12
 ldx  #zr_______X
 stx  PF0
 ldx  #zrXXXXXXXX -------------------------> maybe TSX, if X=$FF
 stx  PF2

Link to comment

Still working my way down from the top of the rom. I think some bytes may be freed by changing some JMP's to always branch:

 

  4992  5223		 0a	    asl  ; 2 27
  4993  5224		 10 06    TESTA	  bpl CheckRepo1 ; 2 29 - 3 30 if taken
  4994  5226		 4c 5d f2	    jmp Reposition0 ; 3 32
  4995  5229
  4996  5229	   NotRepo1  ; 3 35
  4997  5229		 4c 8c f2	    jmp KernelDone ; 3 38
  4998  522c
  4999  522c	   CheckRepo1  ; 3 30
  5000  522c	  -	   if ((TESTA >>  != (CheckRepo1 >> )
  5001  522c	  -	   echo "Page break to get to CheckRepo1, cycles are now off"
  5002  522c		   endif
  5003  522c		 0a	    asl  ; 2 32
  5004  522d		 10 fa	    bpl NotRepo1 ; 2 34 - 3 35 if taken

 

Here jmp Reposition0 could be changed to BMI Reposition0 (always branch, no page boundary crossed), and I think jmp KernelDone can be changed to BPL KernelDone.

 

 

Anyhow I think I will leave it at that until a new rom is built. Too many changes now to keep track of!

 

Jeff

Link to comment

@cd-w - small blip should be doable. I'll have to free up 2 bytes in the sound effects table to do that. Possible 1 frame from the ship and UFO shots will do it, or a couple frames from the bonus life sound effect.

 

@Omegamatrix - Thanks! I'll take a look at those tomorrow or next week.

Link to comment

Yeah, there is always more rom that can be freed. At a certain point it really gets to be fighting for each byte, but I don't think we're there yet.

 

 

Consider KernelLoop. If you could move your Jmp tables for earlier positioning (P0 and P1), then you would be able to branch instead of jumping to specific points saving a byte for each jump. It could be shorter still by moving the sta RESP0 and sta RESP1 inside the loop (freeing up more bytes), and finally by inlaying the delay table, combining the subroutine, etc you save a lot of bytes.

 

i.e:

 

 


P0EarlyHM48:
  dec  $2E  ;5
P0EarlyHM43:
  dec  $2E  ;5
P0EarlyHM38:
  dec  $2E  ;5
P0EarlyHM33:
  dec  $2E  ;5
  nop  ;2   PHA PLA  to save a byte?
P0EarlyHM28:
  lda  zeroRamLocationAtZero  ;3
P0EarlyHM23:
  beq  NEW_KL_R1 ;3	  always branch
P0EarlyHM73:
    dec  $2E  ;5
P0EarlyHM68:
    dec  $2E  ;5
P0EarlyHM63:
    dec  $2E  ;5
P0EarlyHM58:
    dec  $2E  ;5
P0EarlyHM53:
    dec  $2E  ;5
    dec  $2E  ;5
    dec  $2E  ;5
    lda  #<DS_HMP1  ;2
    sta  HMP1  ;3
    lax  DS_MISSILE  ;4
    asl  ;2
    tay  ;2
    lda  #<DS_GRP0  ;2
    sta   RESP0  ;3

    sta WSYNC
KernelLoopNoWSYNC:
    sta HMOVE			 
    sta GRP0			   
    lda #<DS_GRP1	   
    sta GRP1			   
    stx ENAM0			 
    sty ENAM1			
    lda #<DS_EVENT_BL   
    sta ENABL		   
TESTB:  bmi KernelEvent	  
    nop					 ; 2 26 - can't have the LDA #< right after a branch
    lda #<DS_COLOR_SIZE	 ; 2 28 - read to keep in sync, only used during reposition
    lda #<DS_HMP0		   ; 2 30 - for next line
    sta HMP0			    ; 3 33 - for next line
    .byte $0C ; NOP absolute, skip 2 bytes
NEW_KL_R1:
    STA RESP0
KL_R1:  lda #<DS_HMP1		   ; 2 35 - for next line
    sta HMP1			    ; 3 38 - for next line
    .byte $0C ; NOP absolute, skip 2 bytes
NEW_KL_R2:
    STA RESP1
KL_R2:  lax DS_MISSILE		  ; 4 42 - for next line
    asl					 ; 2 44 - for next line
    tay					 ; 2 46 - for next line
    lda #<DS_GRP0		   ; 2 48 - for next line
    jmp KernelLoop		  ; 3 51

 

That is just an example. You do the same for P1 jumps. Then you just fix up all the other branches etc. It should free a lot of bytes. I'm not sure how many.

Link to comment
Guest
Add a comment...

×   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...