EarthQuake Posted September 16, 2004 Share Posted September 16, 2004 Well, that's certainly strange, because ever since I started swapping those values, I've had no problems at all. Prior to that, it took me minutes just to connect one room... I figured someone just commented it wrong, so I switched the values and stuff started working. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 16, 2004 Author Share Posted September 16, 2004 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 Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 16, 2004 Share Posted September 16, 2004 So is this thread about programming or is there an actual bin to try? Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 16, 2004 Author Share Posted September 16, 2004 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! Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 16, 2004 Author Share Posted September 16, 2004 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... Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted September 16, 2004 Share Posted September 16, 2004 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... Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 16, 2004 Author Share Posted September 16, 2004 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' Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 16, 2004 Author Share Posted September 16, 2004 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 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 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 16, 2004 Author Share Posted September 16, 2004 Current assembly...trimmed out a few more things, and I kept the DoVSYNC change in (seeing how nobody seems to be having problems with it)... adventure_8k.zip Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 16, 2004 Author Share Posted September 16, 2004 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. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 17, 2004 Author Share Posted September 17, 2004 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 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 17, 2004 Author Share Posted September 17, 2004 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 Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted September 17, 2004 Share Posted September 17, 2004 No comment. Quote Link to comment Share on other sites More sharing options...
atwwong Posted September 17, 2004 Share Posted September 17, 2004 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! (As long as I don't find any jitters...) Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 17, 2004 Author Share Posted September 17, 2004 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. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 17, 2004 Author Share Posted September 17, 2004 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 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 17, 2004 Author Share Posted September 17, 2004 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 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 17, 2004 Author Share Posted September 17, 2004 BTW just for kicks, I shared all the bitmap data as it was in the original optimized code (which had 313 bytes free)...and now it's up to 504 adventure_4k_504free_.zip Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted September 17, 2004 Share Posted September 17, 2004 Impressive. Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted September 17, 2004 Share Posted September 17, 2004 If I known you were going to do this, I could have stayed under 4K with Odyssey... I only needed a few extra bytes. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 17, 2004 Author Share Posted September 17, 2004 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. Quote Link to comment Share on other sites More sharing options...
atwwong Posted September 18, 2004 Share Posted September 18, 2004 Amazing work as always, Nukey! Hopefully others besides EarthQuake and myself will use this! It's a good way to get your teeth into hacking and possibly homebrews. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 18, 2004 Author Share Posted September 18, 2004 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 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!!). Quote Link to comment Share on other sites More sharing options...
atwwong Posted September 18, 2004 Share Posted September 18, 2004 This is very tempting to try out on the fresh source code. I fear it will cause screen flips in my HA2 hack because of all the extra routines and a couple extra objects I already squeezed in. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 18, 2004 Author Share Posted September 18, 2004 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 Give a yell if you get stuck. Nearly everything requires code changes at this point, so I hope that nobody gets lost. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.