A possible (janky) solution to the melee in air problems

Rancor

New member
I know I said in that previous thread about castlevania jumping that I'd be a good boy and wait for 4.1 but I can't keep away from this program since I activated it.
I've been frankenstein-ing some code together from the threads here about melee in the platform module and I think I found a way to make the weapon stay with the character while in the air.
Basically, I created a new action of the attacking animation, but the second action takes gravity into account while the first does not.
I've been able to get it so at least while idle or while jumping straight up, my character will correctly use the attacking animation as intended.
I've been having some pretty serious issues in other areas though and I'm pretty sure it has to do with this specific code (I've commented out my changes made to jumping/player movement/stopping movement and the problems persist)
Namely, my character stops/staggers their horizontal movement in mid-air when attacking, and the weapon doesn't keep moving with the character horizontally (I end up running into the weapon on the ground or passing through it in air)

Anyway, here's the code for anyone who wants a headache:

shootWeapon.asm:
Code:
 LDA gameHandler                                                                                    ; Load argument "gamehandler" into Accumulator
 AND #%00100000                                                                                     ; Leave accumulator with bits in common with #$00100000 (No idea what this value is, maybe it's explained in 'gamehandler')
 BEQ notNPCstate_attack                                                                             ;; If the bits are in common, jump to label "notNPCstate_attack"
 JMP doneAttacking                                                                                  ;; If the bits are not in common, jump to label "done Attacking"
 notNPCstate_attack                                                                                 ; Label: "notNPCstate_attack"
 LDA weaponsUnlocked                                                                                ; Load argument "weaponsUnlocked" into Accumulator
 AND #%00000001                                                                                     ; leave accumulator with bits in common with #$00000001 (Again, no clue.)
 BNE canAttack                                                                                      ;; If the value is false go to label "canAttack"
 JMP doneAttacking                                                                                  ;; If the value is not false jump to label "doneAttacking"
 canAttack:                                                                                         ; Label: "canAttack"
 LDX player1_object                                                                                 ; Load player1_object into x
 GetCurrentActionType player1_object                                                                ; Macro "GetCurrentActionType" on player1_object
    CMP #$01    ;; if the Player is walking/running                                                 ; compare value #$01 to accumulator ("if the Player is walking/running")
    CMP #$02    ;; if the Player is jumping                                                         ; compare value #$02 to accumulator ("if the Player is jumping")
    BEQ isNowAttacking  ;; keep it walking/running/jumping                                          ;; If the stored result is true jump to label "isNowAttacking"
    CMP #$04    ;; else if is already attacking...                                                  ; else compare value #$04 to accumulator ("if player is already attacking")
    BNE notAlreadyAttacking                                                                         ;; If the stored result is true jump to label "notAlreadyAttacking"
    JMP doneAttacking                                                                               ;; If neither stored result is true jump to label "doneAttacking"
 notAlreadyAttacking                                                                                ; Label: "notAlreadyAttacking"
 ;;; don't attack if already attacking     }
 ;;; do we have to check for hurt here?     }>(I have no idea what any of this means in conjunction. Is this a suggestion for the structure of a new function?)
 ;;;;; Here, we WOULD create melee         }
 
 LDA Object_movement,x          ;                                                                   ; Store value of Object_movement at offset x into Accumulator
 CMP #$00                       ;If player is moving, skip changing the animation                   ; Compare value #$00 to accumulator (checking if idle?)
 BNE +                          ;                                                                   ;; If the stored result is false jump to label "+"
 LDX player1_object             ;                                                                   ;; If true, Load player1_object into X
 ChangeObjectState #$04, #$02   ;                                                                   ; then macro ChangeObjectState to 04 (attacking) with animation speed 02
 +                                                                                                  ; Label: "+"
 BEQ isNowAttacking                                                                                 ;; If the stored result is true jump to label "isNowAttacking"

 LDA Object_movement,x          ;This script seems to keep my weapon in place while I jump          ; Store value Object_movement at offset x into Accumulator
 AND #%00001111                                                                                     ; Leave accumulator with bits in common with #$00001111 (some mix of directions?)
 STA Object_movement,x                                                                              ; Store object type Object_movement from object x into Accumulator
 LDA #$00                                                                                           ; Load literal value #$00 into Accumulator
 STA Object_h_speed_hi,x                                                                            ; Store accumulator value into object type Object_h_speed_hi at offset x
 STA Object_h_speed_lo,x                                                                            ; Store accumulator value into object type Object_h_speed_lo at offset x
 STA Object_v_speed_hi,x                                                                            ; Store accumulator value into object type Object_v_speed_hi at offset x
 STA Object_v_speed_lo,x                                                                            ; Store accumulator value into object type Object_v_speed_lo at offset x
                                                                                                    ; Still can't figure out how this works, need to look at the specific object types
isNowAttacking:                                                                                     ; Label: "isNowAttacking"
    ;; the script continues from here                                               
                                                                                                    ; What follows is my franken-script using airborne checks from playerJump.asm
    LDX player1_object                          ; If player1_object is in the air...                ; Load player1_object into X
    LDA Object_status,x                                                                             ; Store value Object_status at offset x into Accumulator
    AND #%00000100                                                                                  ; Leave accumulator with bits in common with #$00000100
    BEQ isAirborne                                                                                  ;; If the bits are in common, jump to label "isAirborne"
    LDA Object_x_hi,x                                                                               ; Store value of Object_x_hi at offset x into Accumulator
    STA temp                                                                                        ; Store value "temp" into Accumulator
    LDA Object_y_hi,x                                                                               ; Store value of Object_y_hi at offset x into Accumulator
    STA temp1                                                                                       ; Store value "temp1" into Accumulator
 
    LDA Object_x_hi,x                                                                               ; Store value of Object_x_hi at offset x into Accumulator
    STA temp                                                                                        ; Store value "temp into Accumulator
    LDA Object_y_hi,x                                                                               ; Store value of Object_y_hi at offset x into Accumulator
    STA temp1                                                                                       ; Store value "temp1" into accumulator
                                                                                                    ;;; Not sure why this is in here twice. Is it necessary?
    LDA Object_movement,x                                                                           ; Store value of Object_movement at offset x into Accumulator
    AND #%00000111                                                                                  ; Leave accumulator with bits in common with #$00000111 (I get the feeling that isn't "down left")
    STA temp2                                                                                       ; Store value "temp2" into Accumulator 
 
    LDA temp2                                                                                       ; Load value "temp2" into accumulator
    TAY                                                                                             ; Transfer value of Accumulator to Y
    LDA temp                                                                                        ; Load value "temp" into accumulator
    SEC                                                                                             ; Set Carry flag to 1
    SBC #$10 ;; width of weapon                                                                     ; Subtract value #$10 from accumulator (determines x offset of weapon relative to player)
    CLC                                                                                             ; Clear the Carry bit
    ADC weaponOffsetTableX,y                                                                        ; Add value of weaponOffsetTableX at offset y into Accumulator
    STA temp                                                                                        ; Store value of "temp" into accumulator
    LDA temp1                                                                                       ; Load value "temp1" into accumulator
    SEC                                                                                             ; Set Carry flag to 1
    SBC #$08 ;; height of weapon                                                                    ; Subtract value #$08 from accumulator (determines y offset of weapon relative to player)
    CLC                                                                                             ; Clear the Carry bit
    ADC weaponOffsetTableY,y                                                                        ; Add value of weaponOffsetTableY at offset y into Accumulator
    STA temp1                                                                                       ; Store value of "temp1" into Accumulator
    
    CreateObject temp, temp1, #$01, #$02         ; ...create weapon with state 02...                ; Macro CreateObject with coordinates temp, temp1 using object state 02 with animation speed 01 (???)
    JMP meleeCreated                                                                                ; Jump to label "meleeCreated"
    
isAirborne                                                                                          ; Label: "isAirborne"
LDA Object_x_hi,x                                                                                   ; Store value Object_x_hi at offset x into Accumulator
    STA temp                                                                                        ; Store value "temp" into Accumulator
    LDA Object_y_hi,x                                                                               ; Store value Object_y_hi at offset x into Accumulator
    STA temp1                                                                                       ; Store value "temp1" into Accumulator
                                                                                                    ; [My assumption so far is that this makes it so value of Object_x_hi,x is given a temp name, correct?]
 LDA Object_x_hi,x                                                                                  ; Store value Object_x_hi at offset x into Accumulator
 STA temp                                                                                           ; Store value "temp" into Accumulator
 LDA Object_y_hi,x                                                                                  ; Store value Object_y_hi at offset x into Accumulator
 STA temp1                                                                                          ; Store value "temp1" into Accumulator
 
 LDA Object_movement,x                                                                              ; Store value Object_movement at offset x into Accumulator
 AND #%00000111                                                                                     ; Leave Accumulator with bits in common with value #$00000111
 STA temp2                                                                                          ; Store value "temp2" into Accumulator (Leftovers from the AND are put into "temp2"? Unnecessary?)
 
 LDA temp2                                                                                          ; Load value temp2 into Accumulator
 TAY                                                                                                ; Transfer value of Accumulator (i.e temp2) into Y
 LDA temp                                                                                           ; Load value temp into Accumulator
 SEC                                                                                                ; Set Carry flag to 1
 SBC #$10 ;; width of weapon                                                                        ; Subtract value #$10 from accumulator (determines x offset of weapon relative to player
 CLC                                                                                                ; Clear the Carry bit
 ADC weaponOffsetTableX,y                                                                           ; Add value of weaponOffsetTableX at offset y into Accumulator
 STA temp                                                                                           ; Store value of "temp" into accumulator
 LDA temp1                                                                                          ; Load value "temp1" into accumulator
 SEC                                                                                                ; Set Carry flag to 1
 SBC #$08 ;; height of weapon                                                                       ; Subtract value #$08 from accumulator (determines y offset of weapon relative to player)                                                                 
 CLC                                                                                                ; Clear the Carry bit
    ADC weaponOffsetTableY,y
    STA temp1
    
    CreateObject temp, temp1, #$01, #$04        ; ...else create weapon with state 04.              ; Macro CreateObject with coordinates temp, temp1 using object state 04 with animation speed 01 (???)
 
meleeCreated:
    ;;;; x is now the newly created object's x.
    LDA Object_movement,x                                                                           ; Store value of Object_movement at offset x into Accumulator
    ORA temp2                                                                                       ; Leave accumulator with all true bits in temp2 and Accumulator
    STA Object_movement,x                                                                           ; Store value of Object_movement into Accumulator
    ;PlaySound #sfx_slash                                                                           ; Macro to play sound "#sfx_slash"
    doneAttacking:                                                                                  ; Label: "doneAttacking"
RTS                                                                                                 ; Return to subroutine


;;000 down
;010 right
;100 up
;110 left

So, to summarize, I've found a way for the weapon to keep track of vertical movement, essentially by having it fall with the player, which likely creates a number of problems in other situations (as opposed to having it glued to the spot in some way or perhaps that parenting technique I've been hearing about)
I think this could be fixed and working if I understood enough of this code to make a function where the weapon also moves horizontally with the player (maybe if I give it speed+acceleration equal to the player, and link it with movement scripts somehow?)
The one thing I really don't understand though is the staggered horizontal movement in mid-air while attacking. I've tried commenting out various small bits of this trying to narrow down which function does that but I can't make sense of it quite yet.

EDIT: I should also mention I still have the issue of being able to spam the B button and create more instances of the weapon. Still no idea how I would go about fixing that.
EDIT(2): fixed some of my comments so they made a bit more sense
EDIT(3): The whole thing is narrated to the best of my ability now through the comments. Still plenty for me to learn but baby steps are still steps.
 

dale_coop

Moderator
Staff member
A inspiring topic (by CutterCross), for the wonderful "Tower of Turmoil", here:
http://nesmakers.com/viewtopic.php?p=7659#p7659

And also some interesting scripts for melee weapons:
http://nesmakers.com/viewtopic.php?f=3&t=1018
 

Rancor

New member
I am familiar with CutterCross' work and I am very impressed to say the very least. He and Jorotroid appear to be institutions.
I eagerly await Jorotroid's reveal of the parenting technique for his melee scripts, as well.
 
Top Bottom