[4.5.6] Tutorial Request: Metrovania or LR Melee

nuffsaid15

New member
Has anyone been able to implement a basic Castlevania-style melee weapon in the metrovania or LR scroll mods, and who would be willing to offer a tutorial or some code for it?

I have been playing around for a bit, trying to lift code from other mods and mess with object settings, without much luck. The closest I've gotten is an object that just kind of hovers in space for a bit then disappears.

To define what I mean: a melee weapon object that originates immediately in front of the player, and then disappears, while momentarily pausing player movement so you're not moving away from the object and leaving it floating in space. Think Castlevania, Rush N' Attack, or Kid Niki.

(Eventually I would like to figure out how these games get the melee weapon to travel with the player while jumping or falling, but I am imagining that may be a lot more complex.)

Thanks to anyone who can help!
 

Ayrik

New member
I plan on making a proper tutorial, but here's my haphazardly thrown together tutorial on how to do melee attack with a weapon graphic/object that's "parented" to the player object, meaning it will move with the player 100%:

1) Add a variable to zero page or user variables called `player1_weapon`

2) Paste this into your spritePreDraw asm (make a copy and set in script settings if you haven't already, you probably don't want to add this to the module)
Code:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;; DRAW PLAYER WEAPON
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ;;; From meleeAttack.asm
    ; WEAPON_POSITION_RIGHT_X
    ; WEAPON_POSITION_RIGHT_Y

    ; WEAPON_POSITION_LEFT_X
    ; WEAPON_POSITION_LEFT_Y

    LDX player1_object
    LDY player1_weapon

    ; Make sure player1_weapon is active
    LDA Object_status,y
    AND #%10000000
    BNE +isActive
        JMP +doneAttacking
    +isActive

    ; Make sure player1_weapon actually is the weapon and wasn't
    ; overridden at some point before attacking again
    LDA Object_flags,y
    AND #%00000100
    BNE +isPlayerWeapon
        JMP +doneAttacking
    +isPlayerWeapon

    ; Check direction
    ; Right = 2
    ; Left  = 6
    LDA Object_direction,y
    AND #%00000111
    CMP #$02 ; Check right
    BNE +notRight
        ; Facing right

        ; x pos
        LDA Object_x_hi,x
        CLC
        ADC #WEAPON_POSITION_RIGHT_X
        STA Object_x_hi,y

        ; y pos
        LDA Object_y_hi,x
        CLC
        ADC #WEAPON_POSITION_RIGHT_Y
        STA Object_y_hi,y

        JMP +doneAttacking

    +notRight
        ; Facing left

        ; x pos
        LDA Object_x_hi,x
        CLC
        ADC #WEAPON_POSITION_LEFT_X
        STA Object_x_hi,y

        ; y pos
        LDA Object_y_hi,x
        CLC
        ADC #WEAPON_POSITION_LEFT_Y
        STA Object_y_hi,y

    +doneAttacking

3) Make a new script and add the following script to your input settings for the attack itself:
Code:
    GetActionStep player1_object
    CMP #$03 ;; compare attacking  ;; assumes that "attack" is in action 3
    BEQ +cantAttack
    CMP #$04 ;; compare climbing
    BEQ +cantAttack
    CMP #$07 ;; compare hurt
    BEQ +cantAttack
    CMP #$06 ;; compare dead
    BEQ +cantAttack
    JMP +canAttack
    +cantAttack
        RTS
    +canAttack

    CMP #$02 ;; compare jump  ;; assumes that "jump" is in action 2
    BEQ +isJumping
        ;; Not Jumping. Stop player
        StopMoving player1_object, #$FF
        LDA #$00
        STA Object_x_lo,x
        STA Object_h_speed_hi,x
        STA Object_h_speed_lo,x
        STA xHold_hi ; Zero out acceleration
        STA xHold_lo
    +isJumping

    ChangeActionStep player1_object, #$03 ;; assumes that "attack" is in action 3
        ;arg0 = what object?
        ;arg1 = what behavior?

    WEAPON_POSITION_RIGHT_X = #$10
    WEAPON_POSITION_RIGHT_Y = #$09

    WEAPON_POSITION_LEFT_X = #$F0
    WEAPON_POSITION_LEFT_Y = #$09

    WEAPON_OBJECT = #$01
    WEAPON_RIGHT_STATE = #$00
    WEAPON_LEFT_STATE = #$00

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Now, we have to create the object.
    ;; We will need to determine the direction
    ;; of the player.
    LDA Object_direction,x
    AND #%00000111
    STA tempC
    ;;; this object's direction is now loaded into the 
    ;;; accumulator for comparison after the macro.
    ;; 0 = down
    ;; 1 = downright
    ;; 2 = right
    ;; 3 = upright
    ;; 4 = up
    ;; 5 = upleft
    ;; 6 = left
    ;; 7 = downleft
    
    CMP #$02 ; check right
    BNE +notRight
        ;;; CREATE RIGHT WEAPON
        LDA Object_x_hi,x
        CLC
        ADC #WEAPON_POSITION_RIGHT_X
        STA tempA
        LDA Object_screen,x
        ADC #$00
        STA tempD
        
        LDA Object_y_hi,x
        CLC
        ADC #WEAPON_POSITION_RIGHT_Y
        STA tempB

        JMP +createObject
    +notRight
        ;;; CREATE LEFT WEAPON
        LDX player1_object
        LDA Object_x_hi,x
        CLC
        ADC #WEAPON_POSITION_LEFT_X
        STA tempA
        LDA Object_screen,x
        SBC #$00
        STA tempD
        LDA Object_y_hi,x
        CLC
        ADC #WEAPON_POSITION_LEFT_Y
        STA tempB
        
    +createObject
    CreateObjectOnScreen tempA, tempB, #WEAPON_OBJECT, #$00, tempD
    ;;; x, y, object, starting action.
    ;;; and now with that object, copy the player's
    ;;; direction and start it moving that way.
    STX player1_weapon
    LDA tempC
    STA Object_direction,x
    TAY
    LDA DirectionTableOrdered,y
    STA temp1
    +doneWithCreatingWeapon
RTS

4) Change the constants from the previous script to your desired values.

Steps missing:
- Create weapon object with left/right animations
- Make sure weapon animation is in sync with player animation
- Change the hard-coded action step checks in code to match your game

Note that this is only for platformer games but can be modified for adventures if needed by adding constants and more direction checks

I probably missed some things but let me know and I'll correct them to make a proper tutorial.
 

nuffsaid15

New member
Hey, thanks for the response!

I tried these on the metrovania mod, and got a few errors - there's a "notAttacking" label in the first script that I think is supposed to be a "doneAttacking," and the last two lines of the second script create an error so I commented them out (I think those update the HUD, right?).

I used the metrovania tutorial assets to test this out and used object 1 as the melee weapon - I just used the object created for the tutorial, but set the speed and acceleration to 0 since it's no longer a projectile. I also set it to destroy itself after a timer of 3.

The result was the weapon object is created in front of the player - much further in front to the right, for some reason, as compared to the left. The object does not move with the player, it just stays where it was created until the timer runs out. If you are already moving when the melee object is created, the run animation stops working, and the player just glides along in its idle state, and you cannot use the melee weapon again until you stop moving.

These may all be problems I have created in trying to apply this to the tutorial assets... I am very new to all this!
 

Ayrik

New member
I made changes to the code in my previous post based on the issues you posted.

A few things to try:
1) Make sure your copy of doSpritePreDraw.asm is the one in script settings*
2) Make sure your weapon is flagged as player weapon in the object settings

* I like to play a sound at certain parts of the code while debugging just to be sure it's actually running that code.

As for the animations, that's something you're going to have to figure out with how you have your states set up. Here is my moveRight.asm. In order to get it working, you'll have to assign it to the HOLD R input (not press) and remove the changeStateToMoving.asm as my code does both. In my case, I only allow the player to move right if they're idle (which changes their state to move), already walking, or jumping. If you want to allow them to move while attacking you'll have to add a
Code:
	txa
	sta temp ;; assumes the object we want to move is in x.
	
	GetActionStep temp

	; Movement
	; Allow movement ONLY if the player is in the following states:
	cmp #00; idle
	bne +notIdle
		; idle means start walk animation
		ChangeActionStep temp, #01 ; walk
		jmp +move
	+notIdle
	cmp #01 ; walk
	beq +move
	cmp #02 ; jump
	beq +move
	cmp #03 ; attack
	beq +move
	; No cases match, don't move
	jmp +dontMove
	+move
		StartMoving temp, #RIGHT
		ChangeFacingDirection player1_object, #FACE_RIGHT
	+dontMove
rts
 

9Panzer

Well-known member
Sorry to Nerco this post - I'm trying to use it to add a melee strike into my game just as the OP was trying to do. Its working very well expect the position that the weapon is being created on. I looks like the weapon object gets created on the ground rather then it the air, see my video for the exmaple.
I feel like this should be an easy fix with a couple of changes to the script.

 

Logana

Well-known member
Just give the melee object the ability to not fall in action state, also nice progress
 

9Panzer

Well-known member
Thanks Logana, It doesn't appear to fall. I have the ignore gravity set. I think its just picking the feet of the player to spawn rather then the top of the head.

 

Jonny

Well-known member
Just give the melee object the ability to not fall in action state, also nice progress

Ahh! I couldn't tell by the video that it was observing gravity. I was just about to say, have you tried changing the constants...

WEAPON_POSITION_RIGHT_X = #$10
WEAPON_POSITION_RIGHT_Y = #$09
WEAPON_POSITION_LEFT_X = #$F0
WEAPON_POSITION_LEFT_Y = #$09

and double check bonding box set.
 

Logana

Well-known member
You could also just make the dementions of the melee be 1 width an 2 height and place the animation in the top tile, this also makes it so you can have a wider attack range
 

9Panzer

Well-known member
Nailed it Jonny. I wish I understood what I was reading better when it came to the scripting - but the WEAPON_POSITION_RIGHT_Y set to 0 put the weapon where it should be with my character. Thank you for the help!
 

Jonny

Well-known member
Nailed it Jonny. I wish I understood what I was reading better when it came to the scripting - but the WEAPON_POSITION_RIGHT_Y set to 0 put the weapon where it should be with my character. Thank you for the help!

You're welcome.
Basically, the WEAPON_POSITION_RIGHT_Y etc are fixed values (not variables) like the ones you can setup in the UI under 'User Constants'. It's just a way to make those changes easier. You can actually just put on the values you want and not bother with the constants at all but in this case I think it makes it easier to tweek the positions.
What's happening is, you are loading the players position, adding the WEAPON_POSITION constant then storing it as a temp to be used with the CreateObjectOnScreen macro below it.

I find it easier to learn by commenting almost every line of code to my best understanding of what it does. Usually incorrectly haha šŸ˜
 

davev

New member
Ayrik, thanks for posting that code. It got me really close to something I'm trying to achieve. I would like the "melee" weapon to stay connected to my character across screen transitions. Unfortunately when I move to a new screen the weapon disappears. Do you have any hints on what I could do to prevent this? I tried looking at "doHandleObjects_withinCamera" and "doUpdateCamera" but I can't find the code that would destroy the object anywhere...
 

9Panzer

Well-known member
@davev Crosscutter on the discord channel was helping me with this one. You need to setup a variable check so that the sword gets reset. I'm not that code savey yet but this seemed to work for me.

LDA someVar
AND #%00000001 ;; assuming we're using bit 0 to check if sword is on screen
BEQ +
RTS ;; if bit 0 is flipped to 1, don't attack
+

;;;; Attack code here

LDA someVar
ORA #%00000001
STA someVar


And the you need to go to your destroyobject endaction and add


CPX #$01 ;;whatever object index your sword object is
BNE +
LDA someVar
AND
#%11111110 STA
someVar
+
 

CutterCross

Active member
And the you need to go to your destroyobject endaction and add


CPX #$01 ;;whatever object index your sword object is
BNE +
LDA someVar
AND
#%11111110 STA
someVar
+
Correction: You want to compare the Object_type and not just the X register. The value in X is the draw ID of the object being handled in the doHandleObjects loop, not the type itself.

Code:
LDA Object_type,x
CMP #$01    ;; object type for your sword
BNE +
LDA someVar
AND #%11111110
STA someVar
+
 

Deadbear

New member
i got this set up, and it works great! however i later went to make a title screen, and now whenever i press B, it warps me to screen 0,0. it doesn't do that when i have the melee script disabled.. so i'm thinking the startwithnewcontinuepoints script is conflicting with it somehow. any ideas?
 

Hollow

New member
Is there a way to get this to work without making the sprite hud disappear?

Edit: Just pasting it in along with the code already there fixed the problem
 
Last edited:

baardbi

Well-known member
Thank you. Very nice! It works great. However, I was having a tiny bit of lag on the sprite weapon. It was lagging about one or two pixels behind the player when he was jumping. So I put the code in doDrawSprites_PlatformBase instead, and now the lag is completely gone.
 
Top Bottom