Jump to content
IGNORED

Turning Adventure into an 8k game...


Nukey Shay

Recommended Posts

Offset 8 is really offset #7 in the 8k version (because I eliminated the B&W bytes in each line)...but it's confirmed that the last value is where to go off to the left - as detailed by the program...

 

DealWithLeft_3:

      LDA    #$9E               ;Set new X coordinate for the ball

DealWithLeft_4:

      STA    VBLANK,X           ;Store the next X coordinate

      LDY    #$07               ;And get the direction wanted

      BNE    GetNewRoom         ;Go and get new room

That LDY is loading an offset of 7 (it would be 8 in yours)...setting up to read the last byte when moving left.

 

 

BTW all of the above code changes for adding things is regarding the 8k build posted here...since I reorganized the ram to make additions easier to do and changed all of the constants used by objects into variables, trying to make the above changes in the 4k assembly won't work :!:

Link to comment
Share on other sites

Nope...this thread is about an 8k assembly. Once Channel 2 disappeared, there was nobody around to do an 8k version of the game...so I took a look at his code (I still don't know how his flicker routine works...Avalon's is much better). After posting the first binary of Advent, I'd gotten a few requests about how it was done...so I figured that I'd put a bit more work into Joel's assembly to make it more easily hacked ;)

I tried to refrain from customizing it too much...but I did leave a few extra rooms in as an example of how to add them. And now the ram reorganization to make adding game objects less confusing.

 

I wasn't sure about adding this to the programming section, since everyone who hacks games had a greater chance of seeing it here IMO...not to mention that the 8k assembly itself is a hack.

 

If it helps people move beyond doing just plain graphic hacks, it was already worth posting! :D

Link to comment
Share on other sites

Next tutorial...

Making similar objects have a unique look

 

There's not much editing that needs to be done to accomplish this. It's just throwing in a different bitmap and then telling the program to use that one instead. Let's work with the red key that was added.

 

First, scroll up to the 1st bank and locate the key image...which looks like this:

 

;Object #0B : State FF : Graphic

GfxKey:

      .byte $07                 ;     XXX

      .byte $FD                 ;XXXXXX X

      .byte $A7                 ;X X  XXX

      .byte $00                 ;bitmap end

 

The first thing that you need to do is define a new label. You might want to just copy/paste the existing bitmap and change it's label to read "GfxRedKey"...copy the existing one, scroll up to the unused area, and paste it there, then change the label...

 

;Object #0B : State FF : Graphic

GfxRedKey:

      .byte $07                 ;     XXX

      .byte $FD                 ;XXXXXX X

      .byte $A7                 ;X X  XXX

      .byte $00                 ;bitmap end

 

You might already know that it's easy to change the height of objects, just by adding more non-zero bytes to the bitmap. Let's make one that is oriented vertically...

 

;Object #0B : State FF : Graphic

GfxRedKey:

      .byte $3C                 ;  XXXX

      .byte $24                 ;  X  X

      .byte $3C                 ;  XXXX

      .byte $18                 ;   XX

      .byte $1C                 ;   XXX

      .byte $18                 ;   XX

      .byte $00                 ;bitmap end

 

There's a new image that's different from the regular keys. Now you'll need to tell the program to use this image for the red key. Scroll all the way down to the "list of states" table for the keys. It looks like this...

 

;Object #0B : List of States

KeyStates:

      .byte $FF,<GfxKey,>GfxKey

 

As before, copy/paste an identical table...

 

;Object #0B : List of States

KeyStates:

      .byte $FF,<GfxKey,>GfxKey


;Object #0B : List of States

KeyStates:

      .byte $FF,<GfxKey,>GfxKey

 

 

...and then change the names. I just used "RedKeyStates"...

 

 

;Object #0B : List of States

KeyStates:

      .byte $FF,<GfxKey,>GfxKey


;Object #0B : List of States

RedKeyStates:

      .byte $FF,<GfxRedKey,>GfxRedKey

 

 

Only one more thing to do...go down to the object matrix, and edit just the line used by the red key. It currently looks like this...

 

 

RKeyData:

      .word RKeyR,KeyCurr,KeyStates

      .byte $36,$00;Red Key            #$0D  Red, Small

 

 

Simply change the .word "KeyStates" to read the name of the new table instead...

 

 

RKeyData:

      .word RKeyR,KeyCurr,RedKeyStates

      .byte $36,$00;Red Key            #$0D  Red, Small

 

 

That's it :) The red key will now look different from the rest of them. The variable "KeyCurr" is used for animation...I'll touch on this in the next post...

Link to comment
Share on other sites

w00t! Finally something I knew how to do.

Nukey, if I ever got around to it, would you allow for me to display your posts on a website regarding how to hack Adventure? Perhaps in a tutorial format?

 

Perhaps I could just bundle it up in html format, and upload it somewhere. That way you could download the tutorial instead of having it online, where it might not always exist down the road...

Link to comment
Share on other sites

All of the "Curr" labels apply to objects that only have 1 frame (i.e. non-animated). In order to animate something, you'd normally need a byte of ram memory to hold the frame number that the program is supposed to display (i.e. display this bitmap...or this other one)...but there's an easy solution around this.

The bat uses 2 frames of animation...one with wings up, and one with wings down. It's list of states looks like this...

 

;Object #0E : List of States

BatStates:

      .byte $03,<GfxBat1,>GfxBat1         ;State 03 at &FD1A

      .byte $FF,<GfxBat2,>GfxBat2         ;State FF as &FD22

 

 

Two bitmaps...GfxBat1 and GfxBat2. How does the program know which of those images to use? There's a byte of ram that the bat uses that is constantly flipping between values $00 and $03...when it's $00, the first line is used, and when it's $03 the second is used instead. We can "borrow" this byte of ram to animate another object...like the sword for example. But I'll just use the key that was made. First, scroll up to the bitmap of the new red key...and copy/paste a duplicate of that bitmap...

 

;Object #0B : State FF : Graphic

GfxRedKey:

      .byte $3C                 ;  XXXX

      .byte $24                 ;  X  X

      .byte $3C                 ;  XXXX

      .byte $18                 ;   XX

      .byte $1C                 ;   XXX

      .byte $18                 ;   XX

      .byte $00                 ;bitmap end




;Object #0B : State FF : Graphic

GfxRedKey:

      .byte $3C                 ;  XXXX

      .byte $24                 ;  X  X

      .byte $3C                 ;  XXXX

      .byte $18                 ;   XX

      .byte $1C                 ;   XXX

      .byte $18                 ;   XX

      .byte $00                 ;bitmap end

 

 

...and then change the image and label name for the second one. I'll just use a "2" in the label, and flip the bitmap across...

 

 

;Object #0B : State FF : Graphic

GfxRedKey:

      .byte $3C                 ;  XXXX

      .byte $24                 ;  X  X

      .byte $3C                 ;  XXXX

      .byte $18                 ;   XX

      .byte $1C                 ;   XXX

      .byte $18                 ;   XX

      .byte $00                 ;bitmap end




;Object #0B : State FF : Graphic

GfxRedKey2:

      .byte $3C                 ;  XXXX

      .byte $24                 ;  X  X

      .byte $3C                 ;  XXXX

      .byte $18                 ;   XX

      .byte $38                 ;  XXX

      .byte $18                 ;   XX

      .byte $00                 ;bitmap end

 

 

There's the 2 frames. We can only use 2 frames, because the bat only uses 2...and we are sharing it's ram. If you wanted to have more than 2 frames...you'd need to assign another byte of ram to the object (that's why the bat and dragons each have one...plus an additional one to indicate what direction they are moving in).

 

 

But anyway...2 frames is good enough. Next, scroll down to the list of states for the red key (the one that was added in the previous post)...

 

 

;Object #0B : List of States

RedKeyStates:

      .byte $FF,<GfxRedKey,>GfxRedKey

 

 

Just edit it to look similar to the bat's table...using $03 for the first frame, and $FF for the second. Also change the label in the second line to be the name of the new second bitmap...

 

 

;Object #0B : List of States

RedKeyStates:

      .byte $03,<GfxRedKey,>GfxRedKey

      .byte $FF,<GfxRedKey2,>GfxRedKey2

 

 

Only 1 more thing to do...we need to edit the object matrix again to use the bat's ram instead of the "Curr" variable (Curr never changes, so the bitmaps never animate). Here's the original line...

 

 

RKeyData:

      .word RKeyR,KeyCurr,RedKeyStates

      .byte $36,$00;Red Key            #$0D  Red, Small

 

 

Change that center .word to point to the bat's ram instead (at BatR+4)...

 

 

RKeyData:

      .word RKeyR,BatR+4,RedKeyStates

      .byte $36,$00;Red Key            #$0D  Red, Small

 

 

That's all :) The red key will now be flippin' in tune to the bat's flappin' :D

Link to comment
Share on other sites

Nukey, if I ever got around to it, would you allow for me to display your posts on a website regarding how to hack Adventure? Perhaps in a tutorial format?

Sure, if you wanted to. I'm not particularly attached to my ramblings :lol:

 

 

 

Perhaps I could just bundle it up in html format, and upload it somewhere. That way you could download the tutorial instead of having it online, where it might not always exist down the road...

Shame on you...have faith in the almighty Al's ;)

Link to comment
Share on other sites

Bytes can be picked up by rethinking some of the routines as well. Try to follow what the A, X, and Y registers are currently holding...and if those values can be used regarding something else. For example, here in the dragon routine...

 

       LDA    NUSIZ0,X    ;Get the Object's State.    ;4

      BNE    MoveDragon_6;Branch if not.             ;2
;Dragon Normal (State 1)

      BIT    SWCHB       ;Read console switches.     ;4

      BPL    MoveDragon_2;If Amateur Branch.         ;2

      LDA    #$00        ;Set Hard - Ignore Nothing  ;2

      .byte  $2C         ; opcode for BIT.w (Skip 2) ;4

MoveDragon_2:

 

A is loaded with the object's state. If it's non-zero, the program branches...but when zero, the program uses BIT to check the console switches (which does not affect the value sitting in A...which is still equal to zero). So by the time LDA #$00 is reached, A still holds zero. No need to load it at all :)

 

Edited...

       LDA    NUSIZ0,X    ;Get the Object's State.    ;4

      BNE    MoveDragon_6;Branch if not.             ;2
;Dragon Normal (State 1)

      BIT    SWCHB       ;Read console switches.     ;4

      BPL    MoveDragon_2;If Amateur Branch.         ;2
;A=0...nothing ignored (hard)

      .byte  $2C         ; opcode for BIT.w (Skip 2) ;4

MoveDragon_2:

2 bytes saved

 

 

 

 

And here's something from the bat's routines...

;Move Bat

MoveBat:

      INC    BatR+4      ;Put Bat in the Next State  ;5

      LDA    BatR+4      ;Get the Bat State          ;3

      CMP    #$08        ;Has it Reached the Maximum?;2

      BNE    MoveBat_2   ;                           ;2

      LDA    #$00        ;If So, Reset the Bat State ;2

      STA    BatR+4      ;                           ;3

MoveBat_2:

      LDA    BatR+6      ;Get the Bat Fed-Up Value   ;3

 

The bat's state is allowed to count up to 8...at which point it is cleared and started over at 0, and then it is stored.

8 is also the value of bit 3...so a shorter method would be to use an AND instruction to look at the bits with smaller values (bits 2,1,and 0)...trimming off bits 3 and higher. This means that the zero value we need to store will already be in A :) You can scrap the MoveBat_2 label as well (since a branch no longer exists)...

 

Edited...

;Move Bat

MoveBat:

      INC    BatR+4      ;Put Bat in the Next State  ;5

      LDA    BatR+4      ;Get the Bat State          ;3

      AND    #$07        ;Has it Reached the Maximum?;2

      STA    BatR+4      ;(reset to zero when 8)     ;3

      LDA    BatR+6      ;Get the Bat Fed-Up Value   ;3

4 bytes saved

 

 

 

In addition to saving program space, you are also trimming out machine cycles...which make future additions less likely to run INTIM out of time.

Link to comment
Share on other sites

Replacement gate checking routine uses X to hold the gate's state value...using 13 fewer bytes:

 

;Deal with Portcullis and Collisions.

Portals:

      LDY    #Gates             ;For Each Portcullis.                         ;2

Portals_2:

      LDX    PortOffsets,Y      ;Get the Portcullises offset number.          ;4

      JSR    FindObjHit         ;See if an Object Collided with it.           ;6

      STA    CurrentObject+4    ;      Store that Object.                     ;3

      LDX    YGateR,Y           ;                                             ;4

      CMP    KeyOffsets,Y       ;Is it the Associated Key?                    ;4

      BNE    Portals_3          ;If not then Branch.                          ;2

      INX                       ;Change it's state to open it.                ;2

Portals_3:

      STX    YGateR,Y           ;Save its State.                              ;4

      CPX    #$1C               ;Is it Closed?                                ;2

      BEQ    Portals_9          ;Yes - then Branch.                           ;2

      LDA    PortOffsets,Y      ;Get Portcullis number.                       ;4

      JSR    PBCollision        ;Get the Player-Ball Collision.               ;6

      BEQ    Portals_4          ;If Not Then Branch.                          ;2

      LDX    #$01               ;Set the Portcullis to Closed.                ;2

      STX    YGateR,Y           ;                                             ;4

      LDX    #PlayerRoom        ;Set to the Castle.                           ;2

      BNE    Portals_6          ;Put the Ball in the Castle.                  ;2

Portals_4:

      LDA    CurrentObject+4    ;Get the Object that hit the Portcullis.      ;3

      CMP    #NullNumber        ;Is it nothing?  (Num Is (8 * NumOfObj) - 8)  ;2

      BEQ    Portals_7          ;If so, Branch.                               ;2

      LDX    CurrentObject+4    ;Get Object.                                  ;3

      STY    ObjAddress         ;Save Y                                       ;3

      JSR    GetObjectAddress   ;And find it's Dynamic Address.               ;6

      LDY    ObjAddress         ;Retrieve Y                                   ;3

      LDX    CurrentObject      ;Get Object's Address.                        ;3

Portals_6:

      LDA    EntryRoomOffsets,Y;Look up Castle endry room for this port.      ;4

      STA    VSYNC,X            ;Make it the object's Room.                   ;4

      LDA    #$10               ;Give the Object a new Y coordinate.          ;2

      STA    WSYNC,X            ;                                             ;4

Portals_7:

      LDX    YGateR,Y           ;Get its State.                               ;4

      CPX    #$01               ;Is it Open?                                  ;2

      BEQ    Portals_9          ;Yes - Then Branch.                           ;2

      INX                       ;                                             ;2

      CPX    #$38               ;Has it reached the maximum state.            ;2

      BNE    Portals_8          ;If not, Branch.                              ;2

      LDX    #$01               ;Set to Closed State.                         ;2

Portals_8:

      STX    YGateR,Y           ;                                             ;4

Portals_9:

      DEY                       ;Goto the next portcullis.                    ;2

      BPL    Portals_2          ;Do next Protcullis.                          ;2

      RTS                       ;                                             ;6



Link to comment
Share on other sites

lol

 

Here's a routine to add a flapping sound to the bat when it's in your room...the first section changes MakeSound, the rest is added. All other sounds still play on the same channel.

 

;Make A Noise.

MakeSound:

      LDA    NoteCnt      ;Check Not Count.                 ;3

      BNE    MakeSound_2  ;Branch if Noise to be made.      ;2

      LDX    PlayerRoom   ;Get the Current Room.            ;3

      CPX    BatR         ;Is it the bat's room?            ;3

      BEQ    MakeSound_1  ;Branch if Noise to be made.      ;2

      STA    AUDV0        ;Turn off the Volume.             ;3

      RTS                 ;                                 ;6



MakeSound_1:

      LDA    BatR+4       ;Use bat's state for flap sound   ;3

      EOR    #$07         ;                                 ;2

      STA    AUDF0        ;Store in Frequency for Channel 0 ;3

      LDA    #$01         ;                                 ;2

      STA    AUDV0        ;Set Volume on Channel 00.        ;3

      LDA    #$08         ;                                 ;2

      STA    AUDC0        ;Set a Noise on Channel 00.       ;3

      RTS                 ;                                 ;6

Link to comment
Share on other sites

lol

 

Here's a routine to add a flapping sound to the bat when it's in your room...the first section changes MakeSound, the rest is added.  All other sounds still play on the same channel.

Love this effect. I'm going to use it to avoid confusion between the two ghosts in my hack, if that's okay. ;) I've been updating my code with your optimizations, which allowed room for this! 8) (As long as I don't find any jitters...)
Link to comment
Share on other sites

All registers are OK to use in the sound routine BTW...so 25 bytes could be trimmed out by loading the values into all 3 and then branching to save them (rather than saving them in every seperate sound branch)...

 

;Make A Noise.

MakeSound:

      LDA    NoteCnt            ;Check Not Count.                             ;3

      BEQ    NoiseSaveVolume    ;Branch if no Noise to be made.               ;2

      DEC    NoteCnt            ;Goto the Next Note.                          ;5
; instead of comparing with A, we use X:

      LDX    Sound              ;Get the Noise Type.                          ;3

      BEQ    NoiseGameOver      ;Game Over                                    ;2

      DEX                       ;Roar                                         ;2

      BEQ    NoiseRoar          ;                                             ;2

      DEX                       ;Man Eaten.                                   ;2

      BEQ    EatenNoise         ;                                             ;2

      DEX                       ;Dying Dragon.                                ;2

      BEQ    DragDieNoise       ;                                             ;2

      DEX                       ;Dropping Object.                             ;2

      BEQ    NoiseDropObject    ;                                             ;2

      DEX                       ;Picking up Object.                           ;2

      BEQ    NoiseGetObject     ;                                             ;2

      RTS                       ;                                             ;6
;Noise 0 : Game Over

NoiseGameOver:

      LDA    NoteCnt            ;                                             ;3

      TAX                       ;Audio-Control 00                             ;2

      LSR                       ;                                             ;2

      TAY                       ;Audio-Volume 00                              ;2

      TXA                       ;Audio-Frequency 00                           ;2

      STA    COLUPF             ;Color-Luminance Playfield.                   ;3

      JMP    NoiseSave          ;                                             ;3
;Noise 1 : Roar

NoiseRoar:

      LDA    NoteCnt            ;Get noise count.                             ;3

      TAY                       ;      the Volume.                            ;2

      LSR                       ;                                             ;2

      LDX    #$03               ;If it was even then                          ;2

      BCS    SetVolume          ;Branch.                                      ;2

      LDX    #$08               ;Get a different audio control value.         ;2

SetVolume:

      TYA                       ;      the Volume.                            ;2

      CLC                       ;                                             ;2

      ADC    #$70               ;Set the Frequency.                           ;2

NoiseFrequency:

      LSR                       ;Divide by Four.                              ;2

      LSR                       ;                                             ;2

      BNE    NoiseSave          ;Always branch                                ;2
;Noise 2 : Man Eaten

EatenNoise:

      LDA    NoteCnt            ;                                             ;3

      LSR                       ;                                             ;2

      ADC    #$08               ;                                             ;2

      TAY                       ;      the Volume.                            ;2

      LDA    NoteCnt            ;                                             ;3

      EOR    #$0F               ;                                             ;2

      JMP    NoiseSaveX         ;Always branch                                ;3
;Noise 3 : Dyning Dragon

DragDieNoise:

      LDA    NoteCnt            ;Put the Note Count In                        ;3

      TAY                       ;      the Volume.                            ;2

      EOR    #$1F               ;                                             ;2

      LDX    #$04               ;Set the Audio Control                        ;2

      BNE    NoiseSave          ;Always branch                                ;2
;Noise 4 : Dropping Object.

NoiseDropObject:

      LDA    NoteCnt            ;Get Not Count                                ;3

      EOR    #$03               ;Reverse it as noise does up.                 ;2

      .byte $2C
;Noise 5 : Picking up an Object.

NoiseGetObject:

      LDA    NoteCnt            ;Get Note Count.                              ;3

      LDY    #$05               ;                                             ;2

NoiseSaveX:

      LDX    #$06               ;                                             ;2

NoiseSave:

      STA    AUDF0              ;Store in Frequency for Channel 00.           ;3

      STX    AUDC0              ;Set a Noise on Channel 00.                   ;3

NoiseSaveVolume:

      STY    AUDV0              ;Set Volume on Channel 00.                    ;3

      RTS                       ;                                             ;6

 

 

The above is Adventure's standard sounds...naturally, it would need editing for any custom sounds. Just load the frequency, volume, and distortion into the A, Y, and X registers...and branch to NoiseSave.

Link to comment
Share on other sites

Correction...

 

 

;Noise 0 : Game Over

NoiseGameOver:

      LDA    NoteCnt            ;                                             ;3

      STA    COLUPF             ;Color-Luminance Playfield.                   ;3

      TAX                       ;Audio-Control 00                             ;2

      LSR                       ;                                             ;2

      TAY                       ;Audio-Volume 00                              ;2

      LSR                       ;                                             ;2

      LSR                       ;                                             ;2

      BPL    NoiseSave          ;Always branch                                ;2

Link to comment
Share on other sites

I might be done cleaning this thing up...so I made a 4k build as well (it still includes the signature, unshares all the screen GFX, and has 5 custom screens, but I did share the castle GFX again). The 4k version still has half a page of memory free, but more can be reclaimed by removing the signature bitmap and sharing screens (or even upper/lower lines of screens).

4k_8kassemblies.zip

Link to comment
Share on other sites

Even I didn't know that I was going to do this. I just realized how easy it is to edit the 8k file back down to 4k ;) It's just moving a lot of bitmaps around and getting rid of the duplicate PosSpriteX subroutine and the 2 bankswitch LDA's. I was just curious about how much I'd managed to get cut out.

 

So there's 3 flavors now...8k, and 2 Supercharger-compatable 4k's.

Link to comment
Share on other sites

Me? I doubt it. I'm just too comfortable exploiting other people's work by hacking ;)

 

 

Next tutorial...Adding computer-controlled opponents:

Part 1: Dragons

 

In Adventure, there is only 1 routine that deals with all of the dragons - called MoveDragon. It's currently branched to from one of three routines...MoveRedDragon, MoveYellowDragon, and MoveGreenDragon. The top of those routines looks like this...

 

;Move the Red Dragon

MoveRedDragon:

      LDA    #<RedDragMatrix    ;                                             ;2

      LDY    #$03               ;                                             ;2

      LDX    #RDragonNumber     ;Select Dragon #1 : Red                       ;2

      BNE    MoveDragon         ;                                             ;2


;Move the Yellow Dragon.

MoveYellowDragon:

      LDA    #<YelDragMatrix    ;                                             ;2

      LDY    #$02               ;                                             ;2

      LDX    #YDragonNumber     ;                                             ;2

      BNE    MoveDragon         ;Select Dragon #2 : Yellow.                   ;3


;Move the Green Dragon

MoveGreenDragon:

      LDA    #<GreenDragonMatrix;                                             ;2

      LDY    #$02               ;                                             ;2

      LDX    #GDragonNumber     ;Select Dragon #3 : Green                     ;2


;Move A Dragon

MoveDragon:

      STA    ObjLst             ;Set Low Address of Object Store.             ;3

      STY    Delta2             ;Set the Green Dragon's Delta.                ;3

 

As you can probably see, the only differences between moving the three dragons are the values saved to A, X, and Y. Y holds their movement speed, X holds their object number, and A needs the low byte of their specific matrix (that's why all the dragon matrixes must appear on the same page). So all that is required to change this routine to work with an additional dragon is to set up a new Move(color)Dragon header :)

 

Let's set up a black one. First, alter the ram locations at the top...squeezing in 5 more bytes for the new dragon...

 

;object variables...

SurroundR     =  $B1;(3 bytes)

DotR          =  $B4;(3 bytes)


;all dragons must be consecutive

RDragonR      =  $B7;(5 bytes)

YDragonR      =  $BC;(5 bytes)

GDragonR      =  $C1;(5 bytes)


;new line...

BDragonR      =  $C6;(5 bytes)
;...etc.

 

 

 

As before, adjust all of the ram locations on your way down the list following BDragonR (the new one at $C6). Then add in it's number...

 

BDragonNumber  =  BDragonData - Objects

 

 

 

Now that the number of objects has been changed...you'd need to edit the object matrix...adding in a line for the new dragon...

Objects:
;NOTE: SurroundData must be listed first, NullData last.

SurroundData:     ;<-these "Data" tags used up top to define "Number" constants
;Offset 0 : Low byte object information (moveable stuff)
;Offset 1 : High byte object information (moveable stuff)
;Offset 2 : Low byte to object's current state
;Offset 3 : High byte to object's current state
;Offset 4 : Low byte list of states
;Offset 5 : High byte list of states
;Offset 6 : Color (if odd, object is to Flash)
;Offset 7 : Size of object ($00 = small, $07 = large)

Store1:

      .byte <SurroundR                ;#0 Invisible Surround Offsets

Store2:

      .byte >SurroundR                ;1

Store3:

      .byte <SurroundCurr             ;2 Current state location

Store4:

      .byte >SurroundCurr             ;3

Store5:

      .byte <SurroundStates           ;4 list of states location

Store6:

      .byte >SurroundStates           ;5

Store7:

      .byte $28                       ;6 color (Orange)

Store8:

      .byte $07                       ;7 size (Large)



YGateData:

      .word PortInfo1,YGateR,PortStates

      .byte $00,$00;Yellow castle Gate #$01  Yellow, Small



WGateData:

      .word PortInfo2,WGateR,PortStates

      .byte $00,$00;White castle Gate  #$02  White, Small



BGateData:

      .word PortInfo3,BGateR,PortStates

      .byte $00,$00;Black castle Gate  #$03  Black, Small



AuthorData:

      .word AuthorInfo,AuthorCurr,AuthorStates

      .byte $CB,$00;Author Signature   #$04  Flash, Small



NumberData:

      .word NumberInfo,Level,NumberStates

      .byte $C8,$00;Number token       #$05  Green, Small



RDragonData:

      .word RDragonR,RDragonR+4,DragonStates

      .byte $36,$00;Red Dragon         #$06  Red, Small



YDragonData:

      .word YDragonR,YDragonR+4,DragonStates

      .byte $1A,$00;Yellow Dragon      #$07  Yellow, Small



GDragonData:

      .word GDragonR,GDragonR+4,DragonStates

      .byte $C8,$00;Green Dragon       #$08  Green, Small


;new lines---------------------

BDragonData:

      .word BDragonR,BDragonR+4,DragonStates

      .byte $00,$00;Black Dragon       #$06  Black, Small


;etc....

 

 

 

...and also edit the game1objects and game2objects lines...putting the black dragon in the exact same order that the ram is configured...

;Game1Objects and Game2Objects must hold the same number of bytes
;Object locations (room and coordinate) for game 01.

Game1Objects:

      .byte $15,$51,$12           ;Black dot (Room, X, Y) B4

      .byte $0E,$50,$20,$00,$00   ;Red Dragon (Room, X, Y, Movement, State) B7

      .byte $01,$50,$20,$00,$00   ;Yellow Dragon (Room, X, Y, Movement, State) BC

      .byte $1D,$50,$20,$00,$00   ;Green Dragon (Room, X, Y, Movement, State) C1


;added

      .byte $10,$50,$20,$00,$00   ;Black Dragon (Room, X, Y, Movement, State) C6
;...etc...

 

- and -

 

;Object locations (room and coordinate) for Games 02 and 03.

Game2Objects:

      .byte $15,$51,$12           ;Black Dot (Room,X,Y)

      .byte $1F,$50,$20,$A0,$00   ;Red Dragon (Room,X,Y,Movement,State)

      .byte $19,$50,$20,$A0,$00   ;Yellow Dragon (Room,X,Y,Movement,State)

      .byte $04,$50,$20,$A0,$00   ;Green Dragon (Room,X,Y,Movement,State)


;added...

      .byte $10,$50,$20,$A0,$00   ;Black Dragon (Room,X,Y,Movement,State)


;...etc...

 

 

 

Now scroll back up to that MoveDragon routine...and copy/paste the red dragon's header...changing the text in one of them to read "Black" instead of "Red"....

 

;Move the Red Dragon

MoveBlackDragon:

      LDA    #<BlackDragMatrix  ;                                             ;2

      LDY    #$03               ;                                             ;2

      LDX    #BDragonNumber     ;Select Dragon #4 : Black                     ;2

      BNE    MoveDragon         ;                                             ;2


;Move the Red Dragon

MoveRedDragon:

      LDA    #<RedDragMatrix    ;                                             ;2

      LDY    #$03               ;                                             ;2

      LDX    #RDragonNumber     ;Select Dragon #1 : Red                       ;2

      BNE    MoveDragon         ;                                             ;2

 

Note: you can have these headers in any order that you want...but the Green dragon's header MUST appear last (because it doesn't use a branch). I just paste the new headers moving upward.

 

 

So how does the program even get here? That's where the "main game loop" comes in. What this is is the group of JSR's that branches off to everything else when a game is running. It's up near the top...just search for one of those Move(color)Dragon tags and you'll find it...

 

This is it...

MainGameLoop_2:

      LDY    #$00               ;Allow joystick read - all movement.          ;2

      JSR    BallMovement       ;Check ball collisions and move ball.         ;6

      JSR    MoveCarriedObject  ;Move the Carried Object                      ;6

      JSR    DoVSYNC            ;Wait for VSYNC                               ;6

      JSR    SetupRoomPrint     ;Setup the room and objects for display.      ;6

      JSR    PrintDisplay       ;Display the room and objects.                ;6

      JSR    PickupPutdown      ;Deal with object pickup and putdown.         ;6

      LDY    #$01               ;Disallow joystick read - move vertically only.;2

      JSR    BallMovement       ;Check ball collisions and move ball.         ;6

      JSR    Surround           ;Deal With Invisible Surround Moving.         ;6

      JSR    DoVSYNC            ;Wait for VSYNC                               ;6

      JSR    MoveBat            ;Move and deal with bat.                      ;6

      LDY    #Gates             ;For Each Portcullis.                         ;2

      JSR    Portals_2          ;Move and deal with portcullises.             ;6

      JSR    PrintDisplay       ;Display the room and objects.                ;6

      JSR    MoveGreenDragon    ;Move and deal with the green dragon.         ;6

      JSR    MoveYellowDragon   ;Move and deal with the yellow dragon.        ;6

      JSR    DoVSYNC            ;Wait for VSYNC.                              ;6

      LDY    #$02               ;Disallow stick read/bridge check-move hor.only;2

      JSR    BallMovement       ;Check ball collisions and move ball.         ;6

      JSR    MoveRedDragon      ;Move and deal with red dragon.               ;6

      JSR    Mag_1              ;Deal with the magnet.                        ;6

      JSR    PrintDisplay       ;Display the room and objects.                ;6

      BNE    MainGameLoop       ;always branch                                ;2

 

 

 

This section is set up to only move 3 dragons. If you try adding another JSR in there, the console will run out of cycle time while executing it and cause a screen roll. The gate that we added didn't...but 1 gate is a significantly smaller number of extra lines to execute than a machine-controlled dragon. So what you need to do is change this routine so it has the extra time to move the additional dragon. The way that this is done is to give it an extra pair of DoVSYNC/PrintDisplay JSR's...just above the BNE...

 

       JSR    DoVSYNC            ;Wait for VSYNC.                              ;6

      LDY    #$02               ;Disallow stick read/bridge check-move hor.only;2

      JSR    BallMovement       ;Check ball collisions and move ball.         ;6

      JSR    MoveRedDragon      ;Move and deal with red dragon.               ;6

      JSR    Mag_1              ;Deal with the magnet.                        ;6

      JSR    PrintDisplay       ;Display the room and objects.                ;6


;added line

      JSR    DoVSYNC            ;Wait for VSYNC.                              ;6


;added line

      JSR    PrintDisplay       ;Display the room and objects.                ;6



      BNE    MainGameLoop       ;always branch                                ;2

 

 

 

This WILL slow the game down a small amount...but not by an annoying amount. What was just done is that the main loop now has extra time to execute added routines. You'll have enough time to move 2 dragons above the added DoVSYNC, and 2 more above the added PrintDisplay. Let's put a new JSR to move the black dragon just above the DoVSYNC...

 

 

       JSR    MoveRedDragon      ;Move and deal with red dragon.               ;6

      JSR    Mag_1              ;Deal with the magnet.                        ;6

      JSR    PrintDisplay       ;Display the room and objects.                ;6


;added line

      JSR    MoveBlackDragon    ;Move and deal with black dragon.             ;6
;added line

      JSR    DoVSYNC            ;Wait for VSYNC.                              ;6


;added line

      JSR    PrintDisplay       ;Display the room and objects.                ;6



      BNE    MainGameLoop       ;always branch                                ;2

 

 

 

That takes care of the program itself :) Now, you just need to add in a matrix for the black dragon. Paste it right to the other ones...and you can add any objects that you want it to fear or guard. The ball (you) should be between them as the first guarded object...so it will always chase you no matter what else is on the screen...

 

 

;all must be on 1 page
;if an object is listed befor the dragon, it is "feared"
;if an object is listed after the dragon, it is "guarded"
;extra bytes can be used to add more objects to guard or fear...be sure to end with $00
;Red Dragon Object Matrix

RedDragMatrix:

      .byte SwordR,RDragonR       ;Sword, Red Dragon

      .byte RDragonR,PlayerRoom   ;Red Dragon, Ball

      .byte RDragonR,ChaliseR     ;Red Dragon, Chalise

      .byte RDragonR,WKeyR        ;Red Dragon, White Key

      .byte $00                   ;matrix end
;Yellow Dragon's Object Matrix

YelDragMatrix:

      .byte SwordR,YDragonR       ;Sword, Yellow Dragon

      .byte YKeyR,YDragonR        ;Yellow Key, Yellow Dragon

      .byte YDragonR,PlayerRoom   ;Yellow Dragon, Ball

      .byte YDragonR,ChaliseR     ;Yellow Dragon, Chalise

      .byte $00                   ;matrix end
;Green Dragon's Object Matrix

GreenDragonMatrix:

      .byte SwordR,GDragonR       ;Sword, Green Dragon

      .byte GDragonR,PlayerRoom   ;Green Dragon, Ball

      .byte GDragonR,ChaliseR     ;Green Dragon Chalise

      .byte GDragonR,BridgeR      ;Green Dragon, Bridge

      .byte GDragonR,MagnetR      ;Green Dragon, Magnet

      .byte GDragonR,BKeyR        ;Green Dragon, Black Key

      .byte $00                   ;matrix end


;added...

BlackDragMatrix:

      .byte SwordR,BDragonR       ;Sword, Black Dragon

      .byte BDragonR,PlayerRoom   ;Black Dragon, Ball

      .byte $00                   ;matrix end

 

 

This sample one doesn't guard anything but you...so it's always looking for ya :twisted:

 

 

Optionally, you can add the dragon to the bat's matrix (so the bat can pick it up)...and the room bounds data (so it can be randomly placed in game 3...

 

 

;Bat Object Matrix.

BatMatrix:

      .byte BatR,ChaliseR         ;Bat,Chalise

      .byte BatR,SwordR           ;Bat,Sword

      .byte BatR,BridgeR          ;Bat,Bridge

      .byte BatR,YKeyR            ;Bat,Yellow Key

      .byte BatR,WKeyR            ;Bat,White Key

      .byte BatR,BKeyR            ;Bat,Black Key

      .byte BatR,RDragonR         ;Bat,Red Dragon

      .byte BatR,YDragonR         ;Bat,Yellow Dragon

      .byte BatR,GDragonR         ;Bat,Green Dragon

      .byte BatR,BDragonR         ;Bat,Black Dragon <-added

      .byte BatR,MagnetR          ;Bat,Magnet

      .byte $00                   ;matrix end

 

...and...

 

;Room Bounds Data.
;Ex. the chalise at location &B9 can only
;     exist in rooms 13-1A for level 3.

Loc_1:

      .byte ChaliseR              ;

Loc_2:

      .byte $13                   ;Chalise

Loc_3:

      .byte $1A                   ;

      .byte RDragonR,$01,$1D      ;Red Dragon

      .byte YDragonR,$01,$1D      ;Yellow Dragon

      .byte GDragonR,$01,$1D      ;Green Dragon


;added line

      .byte BDragonR,$01,$1D      ;Black Dragon


;...etc...

 

 

 

That's all :) The game will now have 4 Dragons in it...and you can add up to 3 more following the same method (that would be a total of 7 dragons!!).

Link to comment
Share on other sites

Possibly. Though I haven't yet explored the chance of removing WSYNC's in bank 1. If that could be done, the amount of time spent in PrintDisplay could be transferred to MainGameLoop. Since the code is already more efficient than it was, it might already be safe to transfer one notch :) I'll keep ya posted.

 

 

I decided to take a break from describing enemies...because adding a bat is REALLY complex...not only do you have to copy entire sections of the program and rename them...but you also have to contend with the problems of the other bat "seeing" it's held object, and visa-versa. So I'll go into a different area instead.

 

 

Sharing objects:...keys

 

You might notice that adding in 7 dragons would make the game much more challenging and interesting - allowing all those extra rooms to have monsters afoot...it will also eliminate the chance of adding in additional castles (because a key requires 3 bytes of ram in addition to the gate's 1). Or so it seems... :)

Take another look at the first 2 portal data tables...

 

;Portcullis #1, #2, #3

PortOffsets:

    .byte YGateNumber,WGateNumber,BGateNumber,RGateNumber


;Keys #1, #2, #3  (Yellow, White, Black, Red)

KeyOffsets:

    .byte YKeyNumber,WKeyNumber,BKeyNumber,RKeyNumber

 

 

The Portals subroutine looks at these data tables to find out if a key has hit the gate that it controls. If so, the gate opens (or shuts). The key listed in KeyOffsets is matched up with the gate in PortOffsets. So what do you suppose would happen if we did this...

 

;Portcullis #1, #2, #3

PortOffsets:

    .byte YGateNumber,WGateNumber,BGateNumber,RGateNumber


;Keys #1, #2, #3  (Yellow, White, Black, Red)

KeyOffsets:

    .byte YKeyNumber,YKeyNumber,YKeyNumber,YKeyNumber

 

 

The Ports are all still listed seperately, but now they ALL have the yellow key assigned to them. Right, the yellow key in this case would act as a skeleton key...and open any gate. While this might seem like it would make the game much easier, it only partially does. It's true that tracking down 1 key would be easier than having to track down 4 of them...you'd still end up having to drag that key all over the kingdom whenever a door needed opening. And with the 12 bytes of ram you'd save (that would otherwise go to those other 3 keys...you could add in a plethora of doors...right?

 

Um...nope. Take another look at the "Number" variables...like this one for the dot...

 

       LDA    CurrentObject+3    ;If object2 (to print) is                     ;3

      CMP    #DotNumber         ;      not the black dot then collide.        ;2

 

The "Number" variables MUST be a value of $FF or lower...because at zero, it would roll and the game would no longer be tracking the correct object. The Number variables are assigned to every object in the game...including the invisible surround, the "null" object, the number token, signature graphic, all the gates, all the objects you can pick up, and all the enemies. Since this value goes up by 8 for every one, that would make the maximum amount of in-game objects to be set at 32 (32x8=256). But still...that would leave enough space for 8 additional gates IN ADDITION TO 7 dragons and all the objects from the original game.

 

 

But there's one little problem with this (as well as using more than 5 keys in general)...and that is cycle time. What you would need to do in this case is to break that now-huge job of dealing with all of those gates in 1 go...to be shorter and only do -some- of those gates. Take another look at the first and last branches of the Portals routine...

 

Portals:

      LDY    #Gates             ;For Each Portcullis.                         ;2

and

Portals_9:

      DEY                       ;Goto the next portcullis.                    ;2

      BPL    Portals_2          ;Do next portcullis.                          ;2

      RTS                       ;                                             ;6

 

You can see that the routine starts with the number of gates (actually, the number of gates -1...as defined by the #Gates variable)...and at the end this counter is bumped down and loops back up if there are still more to be checked.

You can "cheat time" a bit by using the game's internal clock...called LoCnt in this assembly. What this variable does is that it is bumped up by 1 on every frame. So all we need to do is check if this clock value is odd or even...and have the game check odd or even-numbered gates on that frame instead of doing all of them in one swallow. Here's a solution that does that...(the first and last sections shown only)...

 

Portals:

      LDA    LoCnt              ;Use frame counter for gates.                 ;3

      AND    #$01               ;Keep only bit 0 (value zero or 1)            ;2

      CLC                       ;                                             ;2

      ADC    #Gates-1           ;Add to the number of gates -2                ;3

      TAY                       ;Give that value to the Y counter...          ;2

 

Portals_9:

      DEY                       ;Goto the next portcullis.                    ;2

      DEY                       ;Number (by two).                             ;2

      BPL    Portals_2          ;Do next portcullis.                          ;2

      RTS                       ;                                             ;6

 

What is happening at the top is that the routine starts off with an odd or even value...and then the last section counts down by 2 (keeping the counter odd or even). This has the effect of slowing down the gate movement and making a flashing gate even more difficult to open...but it works :)

 

 

And the other solution? That would be to eliminate one of the dragons...and use it's cycle time to deal with all of the gates in one go. You'd still need to keep a close watch on it tho if the main game loop is still trying to move a dragon in the same DoVSYNC/PrintDisplay gap.

 

 

 

Is this getting too complex? There are a few more things that can be done (that I can think of off the top of my head)...but they only get moreso :P Give a yell if you get stuck. Nearly everything requires code changes at this point, so I hope that nobody gets lost.

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