Jump to content
IGNORED

Jumpman levels with custom code


playermissile

Recommended Posts

There's a new release of Omnivore that includes a built-in MAC/65 compatible assembler:

 

https://github.com/robmcmullen/omnivore/releases/tag/0.14.0

 

There's an overview of creating custom levels here: https://playermissile.com/jumpman/#advanced-levels-with-custom-code

 

and I'm including my level Clockwise as an example.

 

post-39022-0-05833900-1479856354_thumb.png

clockwise.atr

clockwise.s

  • Like 4
Link to comment
Share on other sites

  • 1 month later...

Bloody hell, I missed this post...PM that is an awesome bit of coding, its a level that would have shone on the game when released..

 

Of course I'm loving all these new levels so a MASSIVE thank you to Goochman, Kevin, yourself and anyone else who made some, wish the contest had gone better but I guess its been a tough old year all around so people were lost for time.

 

Still, it makes the ones that did get made even more special...

 

Thank you all..

  • Like 1
Link to comment
Share on other sites

Yeah, looking at the routine in the code at $4b00 it looks like there is a 256 byte limit for the harvest table. Each harvest table entry is 6 bytes long, so that means there's a limit of 42 triggers.

 

I'll have to add a check for than into Omnivore.

 

Well I hit it :) - I had a pretty cool idea to pretty much wipe a map.....maybe I can still do it with fewer triggers :)

Link to comment
Share on other sites

 

Well I hit it :) - I had a pretty cool idea to pretty much wipe a map.....maybe I can still do it with fewer triggers :)

 

It's not supported in Omnivore because it's not something that is very useful in general, but it's possible to design your own drawing elements. I haven't experimented with it, but Kevin and I noted the possibility in our reverse engineering notes:

 

http://playermissile.com/jumpman/notes.html#h.wtrim2a10znr

 

I don't know what the limits are, so I'm not sure how wide or tall the elements can be, but for your purposes, maybe you could create a large erasable element that could wipe out a bigger area.

Link to comment
Share on other sites

  • 4 weeks later...

Ok seeing some of the samples Im trying to add some custom code (or should I say steal and reuse :) ) - In the editor I dont see a way to add custom code the way its documented on your website:

 

You will need to edit the assembly source with your favorite text editor and then use the Jumpman -> Custom Code... to add the source file to your level. After that it will remember the file when you load the level again. Be sure the source code is in the same directory as the .atr image. If you move the .atr file to a new place, be sure to copy your assembly file as well.

 

At this point Im taking some custom code and trying to change the sprite definitions for my use.

Link to comment
Share on other sites

Ok that does explain the issue :) - I have the latest Omnivore and have the menu item.

 

One last question before I sorta give up. I copied the scoreeater.s file from this entry: http://atariage.com/forums/topic/255262-jumpman-level-design-contest/page-4#entry3674126

 

I renamed it to x.s

I created a new level in the same folder called x.atr

 

When I tried to add the custom code file I got an error stating:

 

In file x.s line 4-- Error: Illegal label name, must start with '@', '?', or a letter

 

Here are the first couple of lines of the file:

 

;score eater, a jumpman level
;by Kevin Savetz, October 26-27 2016
.org $2900
vbi1:
It seems it doesnt like .org $900????
Link to comment
Share on other sites

You're right — it doesn't work. This is my fault, but really @playermissile's fault :)

 

He changed Omnivore's source code syntax from cc65 to Mac/65. So — while score eater and jetpack compiled fine when I wrote them, Omnivore's required syntax changed out from under me since then. I need to update the code to the new syntax. In the mean time, lasers.s is already in Mac/65 syntax so it should work.

 

—Kevin

 

 

 

Ok that does explain the issue :) - I have the latest Omnivore and have the menu item.

 

One last question before I sorta give up. I copied the scoreeater.s file from this entry: http://atariage.com/forums/topic/255262-jumpman-level-design-contest/page-4#entry3674126

 

I renamed it to x.s

I created a new level in the same folder called x.atr

 

When I tried to add the custom code file I got an error stating:

 

In file x.s line 4-- Error: Illegal label name, must start with '@', '?', or a letter

 

Here are the first couple of lines of the file:

 

;score eater, a jumpman level
;by Kevin Savetz, October 26-27 2016
.org $2900
vbi1:
It seems it doesnt like .org $900????

 

Link to comment
Share on other sites

I don't know. I don't use a PC, and anyway I like to design graphics on graph paper.

 

On a Mac, you can the the calculator app: in binary mode, enter the image data for that line (e.g. 10010101 then convert to hex (95). I'm sure something is similar on a PC.

 

-Kevin

 

One last question - is there some easy to use editor on the PC which would give me the sprite strings for the data (is it in hex?)

 

$00,$00,$24,$18,$18,$24,$00,$00

  • Like 1
Link to comment
Share on other sites

You're right — it doesn't work. This is my fault, but really @playermissile's fault :)

 

He changed Omnivore's source code syntax from cc65 to Mac/65. So — while score eater and jetpack compiled fine when I wrote them, Omnivore's required syntax changed out from under me since then. I need to update the code to the new syntax. In the mean time, lasers.s is already in Mac/65 syntax so it should work.

 

The previous system (unpublished, Kevin was testing it) used the assembler & linker from cc65, but it was Makefile based and not integrated into Omnivore. Linking on cc65 is a particular pain, because you have to set up all these strange segments in a separate file and there's precious little documentation. And I don't know how it would have ever worked under Windows.

 

So, wanting to make life much, much easier for everybody except Kevin, I found this great standalone assembler, ATasm, that uses MAC/65 source. I hacked around with it and created a python wrapper, then embedded this into Omnivore. It is much simpler and easier to use, plus all the vectors and triggers are automatically plugged into the level. Kevin is welcome to go back to the cc65 approach if he wants to. :)

  • Like 1
Link to comment
Share on other sites

One last question - is there some easy to use editor on the PC which would give me the sprite strings for the data (is it in hex?)

 

$00,$00,$24,$18,$18,$24,$00,$00

 

There's a flash-based player you can use from your browser at http://www.playsoft.co.uk/aplayed.html

 

You can save the data in a binary format to reload in the browser, or LIST it to a file and you'll get the text output you want. It can do animation, too.

  • Like 1
Link to comment
Share on other sites

 

There's a flash-based player you can use from your browser at http://www.playsoft.co.uk/aplayed.html

 

You can save the data in a binary format to reload in the browser, or LIST it to a file and you'll get the text output you want. It can do animation, too.

 

That worked perfectly - expect a few updates to some of my older levels :)

Link to comment
Share on other sites

  • 2 months later...

It's been too long, but I will start to post the source code to Randy Glover's custom-code Jumpman levels, with my comments. By studying the code and my comments, you can learn to make custom-coded levels, too!

 

There's no custom code on level 1.

Here's level 2, Robots II.

02: robots I.s

 

; Commented code for ROBOTS II Jumpman level

; Comments by Kevin Savetz, 2017
*= $2880
L2880 JSR $49d0 ; Standard main game loop
L2883 JSR $4b00
LDA L283E
CMP #$00
BEQ L289E
LDA $30be
CMP #$08
BCC L2883
LDA $30f0
CMP #$ff
BNE L2880
JMP L283F
L289e JMP (L2844)
*= $2900
LDA $30bd ; VBI entry point.
CMP #$02 ; if Jumpman is super dead,
BNE L2912
L2907 JMP $311b ; exit
L290a LDA #$00 ; after the 2x loop
STA L284F+1 ; Set no peanut has been taken
JMP $311b ; exit
L2912 LDA L2A5C ; $2a5c is Are Players initialized?
CMP #$00
BNE L291C
JMP L2A0C ; Go initialize Players.
L291c JSR $41e0 ; Players are already initialized. 41e0 gets a number that's
; 1 just 1/4 of the time
BNE L2907 ; exit 1/4 of the time. Slows things down.
INC L2A65
LDA L2A65 ; alternates between 0 and 1 for animation frames
AND #$01
STA L2A65 ; alternate it
LDX #$ff
L292e INX ; this loop is done twice, as 0 and 1
CPX #$02
BEQ L290A ; exit the loop
LDA L2A5A,X ; is robot already on the move to a destination?
CMP #$00
BNE L2990 ; If so, JMP away
LDA L284F+1 ; Robot is not on the move.
CMP #$00 ; Has a peanut just been taken?
BNE L2955 ; If so, JMP away
LDA L2A66,X ; Nope. No robots are not moving, so just animate in place.
; 2a66 Counts 1-4
AND #$03 ; set the image for each robot
STA L2A66,X ; to one of the first 4 graphics
INC L2A66,X ; rotating in order
LDA L2A66,X ; their graphics move in unison
STA $3076,X ; Set image data for Player 2&3
JMP L292E ; next loop
L2955 JSR L29DA ; Oh boy a peanut has been taken
LDA #$01 ; reminder: we're in a loop where X will be 0 or 1
STA L2A5A,X ; Set this robot is on the move
LDA L2A61,X ; get pointer to next 3-tuple of movement data, LB
STA $cb ; cb-d1 are scratch 0-page addresses
LDA L2A63,X ; starts by loading cb-cc with 2e00 when X=0 and 2f00 when X=1
STA $cc
LDY #$00
LDA ($cb),Y ; load 2e00, e.g. This is the robot's X change.
STA L2A5D,X ; remember robot's X change
INY
LDA ($cb),Y ; load 2e01, e.g.
STA L2A5F,X ; remember robot's Y change
INY
LDA ($cb),Y ; load 2e02, e.g.
STA L2A68,X ; remember robot move counter
LDA L2A61,X ; pointer to next 3-tuple of movement data
CLC
ADC #$03 ; set up pointer to read next set
STA L2A61,X
LDA L2A68,X ; get robot move counter
CMP #$00
BNE L292E ; if >0, iterate X to next robot
STA L2A5A,X ; robot's not to its destination yet. Store counter in the On The Move? byte
JMP L292E ; iterate X to next robot
L2990 DEC L2A68,X ; Robot is not to its destination. Move a step. Decrement robot move countdown.
BEQ L2955 ; if its 0, jump to oh boy a peanut has been taken
LDA $306c,X ; get Horizontal position of robot
CLC
ADC L2A5D,X ; add robot X change
STA $306c,X ; change robot's X
CLC
LDA $3071,X ; get Vertical position of robot
ADC L2A5F,X ; add robot Y change
STA $3071,X ; change robot's Y
LDA L2A5D,X ; get robot X change again
CMP #$02 ; Show graphic for robot facing the right way, and animate. is it going 02 (right)?
BEQ L29B9
CMP #$fe ; is it fe (left)?
BEQ L29BE
LDA #$05 ; robot's X is not changing (so it's on a ladder)
JMP L29C3
L29b9 LDA #$01 ; it's 02 right, so use image 1 (or 2)
JMP L29C3
L29be LDA #$03 ; its fe left, so use image 3 (or 4)
JMP L29C3 ; this JMP is silly.
L29c3 CLC ; A is loaded with a pointer to a different image based on X movement
ADC L2A65 ; add 0 or 1 to animate movement
STA $3076,X ; Set image data for robot
JMP L292E ; end of loop; NEXT X
LDA #$00 ; THIS CODE IS UNREACHABLE
STA L2A5A,X ; UNREACHABLE:Store that robot has reached its destination, no longer moving
LDA #$01 ; UNREACHABLE:
STA L2A66,X ; UNREACHABLE:reset 1-4 counter back to 1 for standing still animation
JMP L292E ; UNREACHABLE:iterate loop; NEXT X
L29da LDA #$f1 ; sound subroutine
STA $3040
LDA #$29 ; load address of sound
STA $3041
STX L29F0 ; temp. storage of X register. Basically, a PHX
LDA #$07
JSR $32b0 ; submit the sound list to the player for robot sound
LDX L29F0 ; reset X register after JSR. PLX
RTS ; end sound subrouine
L29f0 BRK ; Temporary stortage of X in the sound routine.
.byte $01, $a2, $14, $01; Robot sound data
.byte $f0, $01, $3c, $01
.byte $c8, $01, $64, $01
.byte $a0, $01, $8c, $01
.byte $78, $01, $7d, $01
.byte $73, $01, $82, $01
.byte $6e, $01, $00
L2a0c LDA #$00 ; PM Initialization
STA $3080 ; old Y position of Player 2
STA $3081 ; old Y position of Player 3
LDA #$6a
STA $305d ; image data LB for Player 2
STA $305e ; image data LB for Player 3
LDA #$2a
STA $3062 ; image data HB for Player 3
STA $3063 ; image data HB for Player 3
LDA #$0c
STA $3067 ; image data bytes per image for Player 2
STA $3068 ; image data bytes per image for Player 3
LDA #$01
STA $3076 ; Set image data for Player 2
STA $3077 ; Set image data for Player 3
LDA L2A5D
STA $306c ; Horizontal position of player 2
LDA L2A5E
STA $306d ; Horizontal position of player 3
LDA L2A5F
STA $3071 ; Y position of Player 2
LDA L2A60
STA $3072 ; Y position of Player 3
LDA #$01
STA $3058 ; P2 active
STA $3059 ; P3 active
INC L2A5C ; Mark players as initialized
JMP $311b ; exit
L2a5a .byte $00 ; Player 2 on the move? 0=reached destination
.byte $00 ; Player 3 on the move? 0=reached destination
L2a5c .byte $00 ; Are Players initialized? 1=yes
L2a5d .byte $98 ; Player 2 robot X change
L2a5e .byte $44 ; Player 3 robot X change
L2a5f .byte $be ; Player 2 robot Y change
L2a60 .byte $32 ; Player 3 robot Y change
L2a61 .byte $00 ; Player 2 pointer to next 3-tuple of movement data, LB
.byte $00 ; Player 3 pointer to next 3-tuple of movement data, LB
L2a63 .byte $2e ; Player 2 pointer to 3-tuples of movement data, HB (this never changes)
.byte $2f ; Player 3 pointer to 3-tuples of movement data, HB (this never changes)
L2a65 .byte $00 ; alternates between 0 and 1 (for animation)
L2a66 .byte $01 ; Counts 1-4 for Player 2 robot animation
.byte $01 ; Counts 1-4 for Player 3 robot animation
L2a68 .byte $00 ; Player 2 robot move countdown
.byte $00 ; Player 3 robot move countdown
.byte $18, $3c, $70, $70; UNUSED DATA
.byte $3c, $18, $18, $24
.byte $42, $81, $81, $81
.byte $18, $3c, $70, $70
.byte $3c, $18, $18, $24
.byte $42, $81, $42, $24
.byte $18, $3c, $0e, $0e
.byte $3c, $18, $18, $18
.byte $24, $42, $42, $42
.byte $18, $3c, $0e, $0e
.byte $3c, $18, $18, $18
.byte $24, $42, $24, $18
.byte $18, $3c, $66, $66
.byte $3c, $18, $18, $18
.byte $18, $24, $42, $81
.byte $18, $3c, $66, $66
.byte $3c, $18, $18, $18
.byte $18, $18, $24, $42
What follows is a lot of mystery code that should not be there, which is duplicated in Roll Me Over.
Then some graphic data from The Roost. Skipping all that mess.
*= $2dff
BRK ; movement data for Player 2 bot (orange)
.byte $02 ; 3-tuples: X change - +2 pixels is right
.byte $00 ; Y change is 0
.byte $05 ; ...for 5 cycles
.byte $00 ; step 2 of move 1: moving up so X change is 0
.byte $fe ; Y change is -2.
.byte $21 ; for 21 cycles
.byte $02, $00 ; step 3: move right again
.byte $07 ; for 7 cycles
.byte $00, $00, $00, $02; 000000 means end of data for that move
.byte $00, $0d, $00, $fe
.byte $28, $fe, $00, $08
.byte $00, $00, $00, $fe
.byte $01, $10, $fe, $00
.byte $0f, $00, $fe, $11
.byte $fe, $00, $09, $00
.byte $00, $00, $02, $00
.byte $09, $00, $02, $11
.byte $fe, $00, $0b, $00
.byte $02, $11, $fe, $00
.byte $09, $00, $00, $00
.byte $fe, $00, $07, $00
.byte $02, $11, $fe, $00
.byte $0d, $00, $02, $11
.byte $02, $00, $09, $00
.byte $00, $00, $02, $00
.byte $05, $02, $01, $22
.byte $02, $00, $06, $00
.byte $00, $00, $02, $00
.byte $05, $00, $fe, $21
.byte $02, $00, $07, $00
.byte $00, $00, $02, $00
.byte $0d, $00, $fe, $28
.byte $fe, $00, $08, $00
.byte $00, $00, $fe, $01
.byte $10, $fe, $00, $0f
.byte $00, $fe, $11, $fe
.byte $00, $09, $00, $00
.byte $00, $02, $00, $09
.byte $00, $02, $11, $fe
.byte $00, $0b, $00, $02
.byte $11, $fe, $00, $09
.byte $00, $00, $00, $fe
.byte $00, $07, $00, $02
.byte $11, $fe, $00, $0d
.byte $00, $02, $11, $02
.byte $00, $09, $00, $00
.byte $00, $02, $00, $05
.byte $02, $01, $22, $02
.byte $00, $06, $00, $00
.byte $00
*= $2f00
.byte $02, $01, $0f, $02; movement data for Player 3 bot (green)
.byte $00, $05, $00, $02
.byte $11, $02, $00, $0d
.byte $00, $00, $00, $fe
.byte $00, $1b, $00, $02
.byte $11, $02, $00, $0b
.byte $00, $00, $00, $fe
.byte $00, $17, $00, $02
.byte $21, $02, $00, $07
.byte $00, $00, $00, $fe
.byte $00, $07, $00, $fe
.byte $11, $02, $00, $09
.byte $00, $00, $00, $fe
.byte $00, $09, $00, $fe
.byte $11, $02, $00, $0d
.byte $00, $fe, $11, $02
.byte $00, $23, $00, $00
.byte $00, $00, $fe, $11
.byte $fe, $00, $19, $fe
.byte $ff, $0f, $00, $00
.byte $00, $02, $01, $0f
.byte $02, $00, $05, $00
.byte $02, $11, $02, $00
.byte $0d, $00, $00, $00
.byte $fe, $00, $1b, $00
.byte $02, $11, $02, $00
.byte $0b, $00, $00, $00
.byte $fe, $00, $17, $00
.byte $02, $21, $02, $00
.byte $07, $00, $00, $00
.byte $fe, $00, $07, $00
.byte $fe, $11, $02, $00
.byte $09, $00, $00, $00
.byte $fe, $00, $09, $00
.byte $fe, $11, $02, $00
.byte $0d, $00, $fe, $11
.byte $02, $00, $23, $00
.byte $00, $00, $00, $fe
.byte $11, $fe, $00, $19
.byte $fe, $ff, $0f, $00
.byte $00, $00
  • Like 4
Link to comment
Share on other sites

Commented code for BOMBS AWAY.

03: bombs away.s

 

*= $2860
L2860 JSR $49d0 ; Main loop (standard)
L2863 JSR $4b00
LDA L283E
CMP #$00
BEQ L287E
LDA $30be
CMP #$08
BCC L2863
LDA $30f0
CMP #$ff
BNE L2860
JMP L283F
L287e JMP (L2844)
*= $2900
LDA $30bd ; VBI entry point #1
CMP #$02 ; is Jumpman super dead?
BNE L2916
LDA $3034 ; Yes, he's dead. Is a sound playing on voice 2? (Explosion noise)
CMP #$00
BNE L2913 ; There's a sound, exit. (Wait for the explosion sound to end)
LDA #$00 ; Explosion sound is over, so quiet and falling sound, which happens on audio channel 3
STA $d205 ; Quiet AUDC3
L2913 JMP $311b
L2916 JSR $41e0 ; Jumpman is alive
BNE L2913 ; Exit 1/4 of the time. Keeps the bombs from falling too fast
L291b LDA $d20a ; get a random number
AND #$07 ; only want 3 bits - make the number from 0-7
BNE L2960 ; if it's >0 JMP to make bombs fall and explode
LDA $d20a ; get another random number
AND #$07 ; make it 0-7 too
CMP #$05 ; this is a second chance for bombdrop
BCS L2960 ; if it's >= 5, JMP to make bombs fall and explode
TAX
LDA L29C3,X ; check the table of available Players to see if a Player is available as a new bomb
CMP #$00
BNE L2960 ; if that table entry>0, Player not available as a new bomb, so, JMP away
LDA #$01 ; Start a new bomb
STA $3055,X ; Turn Player on
LDA #$c9
STA $305a,X ; image data LB
LDA #$29
STA $305f,X ; image data HB. We're using the first group of bombs in the image series.
LDA #$08
STA $3064,X ; image data bytes per image
L2947 LDA $d20a ; random number
CMP #$30
BCC L2947 ; if < $30 go get another random # (too far left)
CMP #$c8
BCS L2947 ; >= #c8 is also unacceptable (too far right), get another #
STA $3069,X ; that's the player X
LDA #$01
STA $306e,X ; Player Y = top of screen
STA $3073,X ; Use graphic 1
STA L29C3,X ; Set player is in use as a bomb
L2960 INC L29C8 ; The following happens whether a new bomb was made or not.
LDA L29C8
AND #$03
L2968 STA L29C8 ; 29c8 iterates 0-3 for animation frames
LDX #$ff
L296d INX ; FOR X = 0 TO 4
CPX #$05
BEQ L29AA ; if X=5 end the loop
LDA L29C3,X ; 29c3 is "is this player usable as a bomb?" 0=available, 1=in use, 5-0a=exploding, ff=don't use
CMP #$ff
BEQ L296D ; this player is not available as a bomb, iterate to next player
CMP #$05
BCS L296D ; if its >=5 (exploding), iterate to next player
CMP #$00
BEQ L296D ; if its 0, iterate to next player
LDA $306e,X ; So it must be 1. Make it fall. Get Y position
CLC
ADC #$03 ; move it down
CMP #$c5 ; if it at the bottom, 'splode it
BCS L29A2
STA $306e,X ; if it's not too low, save new Y position
STA $d204 ; falling sound on AUDF3
LDA #$a2
STA $d205 ; AUDC3
LDA L29C8 ; the 0-3 counter
CLC
ADC #$01
STA $3073,X ; Set Player to next animation frame
JMP L296D ; NEXT X
L29a2 LDA #$05 ; Bomb reached the floor
STA L29C3,X ; Mark it as ready to explode.
JMP L296D ; NEXT X
L29aa LDA L29C6 ; done iterating thru players
ORA L29C6 ; if both bombs are "availilable" (not falling or exploding) then quiet AUD3
ORA L29C7 ; Notice how 29c6 is used twice. I bet one of those was originally 29c3 to support the combined-missile Player bomb
CMP #$00
BEQ L29BA
JMP $311b
L29ba STA $d204 ; quiet AUDF3
STA $d205 ; quiet AUDC3
JMP $311b
L29c3 .byte $ff ; Table of Players. Don't use Combined Missile Player as a bomb. (But you can! try it by changing it to 0)
; I ended up doing that in my Smart Bombs Away level
.byte $ff ; don't use Player 0 as a bomb - that's jumpman!
.byte $ff ; don't use player 1 as a bomb - that's the shadow!
L29c6 BRK ; Do use Player 2 for a bomb
L29c7 BRK ; Do use Player 3 as a bomb
L29c8 BRK ; iterates 0-3 for animation frames
.byte $66, $3c, $18, $18; Images start here
.byte $3c, $2c, $3c, $18
.byte $34, $3c, $18, $18
.byte $3c, $34, $3c, $18
.byte $18, $18, $18, $18
.byte $3c, $3c, $3c, $18
.byte $2c, $3c, $18, $18
.byte $3c, $3c, $3c, $18
.byte $00, $00, $00, $00
.byte $00, $24, $18, $18
.byte $00, $00, $00, $24
.byte $3c, $18, $7e, $18
.byte $10, $4a, $52, $5a
.byte $2c, $bd, $7e, $18
.byte $00, $00, $08, $52
.byte $3c, $99, $7e, $18
.byte $00, $00, $00, $08
.byte $10, $4a, $3c, $18
.byte $4c, $1b, $31, $00
.byte $ff, $ff, $00, $00
.byte $00
.byte $66, $3c, $18, $18; Here's a second copy of the bomb graphics, not used.
.byte $3c, $2c, $3c, $18
.byte $34, $3c, $18, $18
.byte $3c, $34, $3c, $18
.byte $18, $18, $18, $18
.byte $3c, $3c, $3c, $18
.byte $2c, $3c, $18, $18
.byte $3c, $3c, $3c, $18
.byte $00, $00, $00, $00
.byte $00, $24, $18, $18
.byte $00, $00, $00, $24
.byte $3c, $18, $7e, $18
.byte $10, $4a, $52, $5a
.byte $2c, $bd, $7e, $18
.byte $00, $00, $08, $52
.byte $3c, $99, $7e, $18
.byte $00, $00, $00, $08
.byte $10, $4a, $3c, $18
*= $2ac0
ORA ($8e,X) ; Sound data for explosion
.byte $14
.byte $03
ORA ($8b,X)
ASL $0103,X
DEY
PLP
.byte $03
ORA ($85,X)
.byte $32
.byte $03
ORA ($81,X)
.byte $3c
.byte $03
*= $2b00
INC L2B9E ; VBI entry point #2 - handles explosions
LDA L2B9E
AND #$01
STA L2B9E ; 2b9e switches between 0 and 1
BEQ L2B10
L2b0d JMP $311b ; if it's 1 - half the time - exit
L2b10 LDX #$ff
L2b12 INX ; FOR X=0 to 4
CPX #$05
BEQ L2B0D ; after the looping, exit
LDA L29C3,X
CMP #$0a ; Has this bomb finished explosion sequence? (05-0a)
BEQ L2B6C ; Yes: JMP away for cleanup
BCS L2B12 ; if status>$0a (that is, $ff, iterate to next player)
CMP #$05 ; if it is not about to explode or already exploding, iterate to next bomb
BCC L2B12 ; NEXT X
INC L29C3,X ; This bomb is exploding. Increment explosion counter (5-0a) there are 4 animation frames, 6-9. 5 is ready to explode, 0a is done and ready for cleanup Note: we've incremented it for NEXT time, but A is still the lower number.
STA $3073,X ; choose image for bomb. conveniently, explosion images are numbers 6-9 in the graphics list.
CMP #$05 ; if this is the first image in the explosion sequence
BEQ L2B41 ; JMP away to cycle back to 1st frame
L2b2e LDA $3073,X ; get current animation image in use for bomb
TAY ; which goes in Y
LDA L2B94,Y ; It looks up the animation frame number in this table to get the color for this part of the explosion. The first 5 cells of the table are unused; only the data in the 5th-0Ath cells are used.
PHA ; That color number goes on the stack
LDA L2B8A,X ; offset table for Player colors
TAY ; which goes in Y
PLA ; fetch the color the stack
STA $02c0,Y ; change Player color for pretty, colorful explosion
JMP L2B12 ; NEXT X
L2b41 LDA $3069,X ; cycle back to 1st image of 4 in a series
SEC
SBC #$04
STA $3069,X ; revert to 1st image in animation set
LDA L2B8F,X ; get offset for adjusting Player width from table
TAY
LDA #$55 ; $55 is an interesting choice here for doube width. References I found say to use 0 for std, 1 for dbl, 2 for quad. There's no $55. But the LSB makes it double width.
STA $d008,Y ; adjust Player width
STX L2B6B ; PHX: Store X register (our offset from the table) for a sec, sound routine at 32b0's gonna clobber it
LDA #$c0
STA $3040 ; LB of sound data
LDA #$2a
STA $3041 ; HB of sound data
LDA #$04 ; A is the duration or speed? for the music driver
JSR $32b0 ; music driver: start playing a tune pointed to by $3040
LDX L2B6B ; PLX: I want my X back
JMP L2B2E ; Loop back
L2b6b BRK ; Temp storage for X register. 6502 doesn't have PHX. Sad!
L2b6c LDA L2B8F,X ; Bomb explosion sequence is done, clean up
TAY ; 2b8f-2b93 is table of offets from d008 for resetting Player widths
LDA #$00
STA $d008,Y ; reset Player width to single
LDA L2B8A,X ; 2b8a-e is table of offets for reseting Player colors, from 02c0
TAY
LDA L282A,Y ; get startup color for that Player
STA $02c0,Y ; reset player colors after splosion
LDA #$00
STA L29C3,X ; reset Player: available for new bomb
STA $3069,X ; set player X offscreen
JMP L2B12 ; NEXT X
L2b8a .byte $07, $00, $01, $02; offset table - reset Player colors from $$02c0
.byte $03
L2b8f .byte $04, $00, $01, $02; offset table - resetting player widths from $d008
.byte $03
L2b94 .byte $00, $00, $00, $00; Table of colors for explosion. The first 5 bytes are unused, the real colors are in the 5th thru 0a spaces
.byte $00, $54, $1a, $0f
.byte $28, $54
L2b9e BRK ; switches between 0 and 1
; later in the level there's some garbage data

 

  • Like 2
Link to comment
Share on other sites

Jumping Blocks.

04: jumping blocks.s

 

; Commented code for JUMPING BLOCKS Jumpman level

; Comments by Kevin Savetz, 2017
*= $2860
LDA #$04
STA $30b6 ; Missiles are 2 pixels high
LDA #$55 ; Wide missiles
STA $d00c
JMP L2880
*= $2880
L2880 JSR $49d0
L2883 JSR $4b00
LDA L283E
CMP #$00
L288b BEQ L289E
L288d LDA $30be
CMP #$08
BCC L2883
LDA $30f0
CMP #$ff
BNE L2880
JMP L28A6
L289e LDA #$02
STA $30b6
JMP (L2844)
L28a6 LDA #$02
STA $30b6 ; put Missile height back to normal
JMP L283E+1
*= $28f9
BRK ; This level is interesting, programatically very simple.
BRK ; It uses the Jumpman engine's regular bullet logic
BRK ; But changes the size and color of the bullets.
BRK ; Instead of the usual "bullet hit means death" code at 49a0,
BRK ; the level's custom hit detection routine tricks the engine
BRK ; into thinking the trigger was pressed and the joystick was
BRK ; moved to jump in one of three directions.
LDA $3098 ; VBI entry point
ORA $3099
L2906 ORA $309a
ORA $309b
AND #$01 ; Did any of the Missiles hit Jumpman? (In some other levels Glover uses $30a0 to do the exact same thing. I wonder if this was written before he wrote that.)
CMP #$00
BNE L2915
JMP L2943 ; if not, jump away
L2915 LDA #$10 ; A missile hit Jumpman
STA $302c ; Fake pressing the trigger
LDA $d20a
AND #$03 ; Random # 0-3
CMP #$00 ; Fake joystick push in a direction based on the random #
BEQ L292B
CMP #$01
BEQ L2933
CMP #$02
BEQ L293B
L292b LDA #$e0 ; Joystick up
STA $3028
JMP L2953
L2933 LDA #$70 ; Joystick right
STA $3028 ; STA here makes the game engine think the stick is pushed
JMP L2953
L293b LDA #$b0 ; Joystick left
STA $3028
JMP L2953
L2943 LDA $3028 ; No missile hit Jumpman
AND #$0f ; ?force the joystick to 0-127. Hm, why not just STA 0?
STA $3028
LDA $302c
AND #$0f ; ?Same thing with the trigger result. What information is saved in those 4 bits?
STA $302c
L2953 LDA $30b8 ; This continues whether or not a missile hit JM
STA $02c7 ; Change the misiles to a random(ish) color.
JMP $311b ; And we're done
ORA ($9d,X) ; The rest of the level code is junk/unused code.
ORA L2C30+1 ; Some seems to be assembly source from Builder level. See Reverse Engineering Notes.
  • Like 1
Link to comment
Share on other sites

Vampire.

 

05: vampire.s

 

*= $2900

LDA $30be ; VBI vector. If Jumpman status
CMP #$08 ; is super dead
BCS L290E ; exit this routine. Allows the death song to play with out bats flying around
LDA $30bd ; Check the other Jumpman alive flag.
CMP #$02 ; if JM is Dead With Birdies
BNE L2911
L290e JMP $311b ; ...also exit this routine
L2911 LDA L2A73 ; check Are Players initialized? byte
CMP #$00
BNE L291B
JMP L29C8 ; Not initialized, JMP away to initialize them
L291b INC L2A5E ; 2a5e increments 0-7
LDA L2A5E ; only continue if it==7
CMP #$07 ; otherwise exit
BNE L290E ; this gives the bats their relatively slow pace
LDA #$00
STA L2A5E ; reset counter to 0
LDX #$ff
L292c INX ; FOR X=0 TO 4
CPX #$05 ; Iterating through the Players, where 0=Combined Missile Player, 3 and 4=the other available Players. These are the bats.
BEQ L290E ; after the loop, exit
CPX #$01
BEQ L292C ; if X=1, NEXT X
CPX #$02
BEQ L292C ; if X=2, NEXT X
LDA L2A5F,X ; Check Bat Asleep/Awake Table
CMP #$02
BEQ L2943
JMP L292C ; If it's not 2 (awake), NEXT X
L2943 INC $3073,X ; Move bat to next animation frame
LDA $3073,X
CMP #$08 ; But if its 8...
BNE L2952
LDA #$02 ; move it back to 2. The flying animation is frames 2-7
STA $3073,X
L2952 LDA $306a ; Get Jumpman X
CMP $3069,X ; Compare with Bat X
BEQ L298B ; if they're equal, JMP away
LDA $306f ; But they're not equal, so get Jumpman Y
CMP $306e,X ; compare with Bat Y
BEQ L29A8 ; If the Ys are equal, JMP away
CLC ; Neither Xs or Ys are equal. Sad bat.
L2963 LDA $3069,X ; Get Bat X again
ADC L2A64,X ; Add X to this bat's entry in Bat X Change Table
STA $3069,X ; New Bat X
CLC
LDA $306e,X ; Get Bat Y
CLC
ADC L2A68+1,X ; Add Y to this bat's entry in Bat Y change table
CMP #$c2
BCS L297E ; If the Y would be >=$c2, JMP to fix that
STA $306e,X ; New Bat Y
JMP L292C ; NEXT X
L297e LDA #$00 ; Bat Y is >=C2, at bottom of screen, move it back to top
STA $306e,X
LDA #$02
STA L2A68+1,X ; Adjust Bat Y Change Table: This bat will continue moving downward
JMP L292C ; NEXT X
L298b LDA #$00 ; JMP dest when Bat X = JM X
STA L2A64,X ; Store 0 in this Bat's X Change Table entry
LDA $306f ; Get JM Y
CMP $306e,X ; Compare to Bat's Y
BCS L29A0 ; JMP away if JM Y >= Bat Y (JM is below bat)
LDA #$fe ; Bat is below JM, so
STA L2A68+1,X ; modify Bat Change Table entry to move it up
JMP L2A0E
L29a0 LDA #$02 ; Bat is above JM, so...
STA L2A68+1,X ; Modify Bat Y Change table to move it down
JMP L2A0E
L29a8 LDA #$00 ; JMP dest when Bat Y = JM Y
STA L2A68+1,X ; Modify Bat's Y change table entry to 0
LDA $306a ; Get Jumpman's X
CMP $3069,X ; compare to bat's X
BCS L29BD ; If JM X >= Bat's (bat is to the left of JM) JMP away
LDA #$fe ; Bat wants to move left
STA L2A64,X ; store that in X change table
JMP L2A0E
L29bd LDA #$02 ; Bat is to JM's left
STA L2A64,X ; Modify Bat X Table to start Bat moving right
JMP L2A0E
L29c5 JMP $311b
L29c8 LDX #$ff ; Player initialization
STX L2A73 ; Set Are Players Initialized? byte
L29cd INX ; FOR X=0 to 4
CPX #$05
BEQ L29C5 ; after this loop, exit
CPX #$01
BEQ L29CD ; IF X=1 NEXT X cuz this player is for JM
CPX #$02
BEQ L29CD ; IF X=2 NEXT X cuz this player is for the shadow
LDA #$26
STA $305a,X ; Player Image Data LB
LDA #$2a
STA $305f,X ; Player Image Data Table HB
LDA #$08
STA $3064,X ; there are 8 data bytes per image
STA $3082,X ; just stuff anything other than the startup image in the "old" image data table
LDA L2A64,X ; Get Bat Starting X from Bat X Change Table
STA $3069,X ; Save Bat X
LDA L2A68+1,X ; Get Bat starting Y from table
STA $306e,X ; Save Bat Y
LDA #$01
STA $3073,X ; Start all bats with Image 1 (sleeping)
STA $3055,X ; Activate that Player
LDA #$00
STA L2A64,X ; From now on the Bat X table is change (X movement direction) so store 0. Bats always start traveling down
LDA #$02
STA L2A68+1,X ; Same thing for the Y change table. Bats will head down when they wake
JMP L29CD ; NEXT X
L2a0d BRK ; temp storage for X
L2a0e STX L2A0D ; If bat changed X or Y direction, it wants to talk about it. PHX
LDA #$74
STA $3040 ; Sound data LB
LDA #$2a
STA $3041 ; Sound data HB
LDA #$07 ; This is speed or duration or something for the sound routine
JSR $32b0 ; start playing bat sound
LDX L2A0D ; PLX
JMP L2963 ; JMP to actually move the bat based on new X and Y change choices
L2a26 .byte $24, $18, $18, $3c; Image Data
.byte $7e, $18, $18, $00
.byte $81, $42, $42, $3c
.byte $18, $00, $00, $00
.byte $00, $00, $81, $7e
.byte $18, $00, $00, $00
.byte $00, $00, $00, $7e
.byte $99, $00, $00, $00
.byte $00, $00, $00, $3c
.byte $5a, $42, $81, $00
.byte $00, $00, $00, $5a
.byte $bd, $00, $00, $00
.byte $00, $00, $81, $db
.byte $3c, $00, $00, $00
L2a5e .byte $00 ; Counts 0-7
L2a5f .byte $01, $00, $00, $01; Bat asleep(01)/wake(02) Table
L2a63 .byte $01
L2a64 .byte $74, $00, $00, $7c; Bat X Change Table
.byte $84
L2a69 .byte $2a, $00, $00, $28; Bat Y Change Table
.byte $2a
.byte $01, $00, $00, $01; This looks like a "use this Player as a bat?" table but is unused
.byte $01
L2a73 .byte $00 ; Are Players Initialized? byte 0=no
.byte $01, $a6, $05, $01; Sound data
.byte $0f, $01, $0a, $01
.byte $00, $a0, $cc, $ae
.byte $a0, $c7, $cc, $cf
.byte $d6, $c5, $d2, $20
.byte $a0, $cc, $ae, $a0
.byte $c7, $cc, $cf, $d6
.byte $c5, $d2, $20
*= $2aff
BRK ; This VBI vector runs with every peanut collection
L2b00 LDA L283E ; # of peanuts left to take? Level starts with 14.
CMP #$0c ; If >=12, exit
BCS L2B13
CMP #$09
BCS L2B14 ; if 9, wake 1st bat
CMP #$06
BCS L2B21 ; if 6, wake second bat
CMP #$03
BCS L2B2E ; if 3, wake 3rd bat
L2b13 RTS ; otherwise exit
L2b14 LDA L2A5F ; Is bat 1 (CMP) sleeping?
CMP #$01 ; he really should be at this juncture
BNE L2B13 ; but if not, exit
LDA #$02
STA L2A5F ; mark him as awake
RTS ; exit
L2b21 LDA L2A62 ; Is bat 2 (Player 2) asleep
CMP #$01 ; again, he really should be when we get here
BNE L2B13 ; if not, exit
LDA #$02
STA L2A62 ; mark him as awake
RTS ; exit
L2b2e LDA L2A62+1 ; and Bat 3 (Player 3)
CMP #$01
BNE L2B13
LDA #$02
STA L2A62+1 ; same deal
RTS
; The rest of the stuff on this level is unused/junk, including
; image data from The Roost
  • Like 1
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...