Monster AI for Custom Spawns, Phases, and Combo Hits

Artix

New member
frostlichhit.gif


Greetings and salutations NESMakers!

Want to spice up your monsters in NESMaker 4.1.5? Custom spawn animations, monster phases, more monster action steps, and double-dragon like combo hits? Then you might enjoy the code below. (Massive kudos and credit to Dale Coop for making this work)

Overview
By default, every time your monster gets hit it will go back to Action Step 0. While there is a lot you can do with this, it has a lot of limitations. (For example, if your monster starts with a custom spawn animation, and it gets hit... it will go back to action step 0 and play the spawn animation all over again.) So, by being able to customize what happens when the monster gets hurt we can unlock a lot of possibilities.

experience.png


How does it work?
We need a place on the monster to set a custom number which will determine what happens when it is hit. Below, we simply hijack the Monsters Experience value.

Experience Value = What happens when monster is hit
0 = Go to Action Step 0
1 = Go to Action Step 1
2 = Go to Action Step 2
3 = Go to Action Step 3
4 = Go to Action Step 4
5 = Go to Action Step 5
6 = Go to Action Step 6
7 = Go to Action Step 7
8 = Increase Action Step by 1
9 = Double Dragons! 3 Hits starting at 5.... this is awesome.
10 or higher = Do nothing at all (but we can always add more!)

What kind of fights can be made this with?
O_O I thought you would never ask. Here are some examples....

skeletonfight.gif


Custom Spawn Animation
Create a custom spawn animation and put it on action step 0. Then, set the monster's experience to 1. Done! It will play the monsters spawn animation when it loads, and never play the spawn animation again.

Create a monster that gets smaller or breaks more every time you hit it

Let's make a slime that gets smaller every time we hit it. Setting the monster's experience to 8 causes the monster to simply go to the next action step. So make 8 different animations of the slime at different sizes and assign each one to an action step. Done! Oh, be sure to set the final action step should end on the monster being immune to weapons and destroying itself.

Slimehit.gif


Create a monster that gets faster every time you hit it
Same as above.. Just needs a custom monster AI script to increase speed.

Create the Grim Reaper from Kid Icarus
"a monster that does terrible things, but only after it is hit"
Easy. Create a monster that just walks around using the first few action steps. Then, enter 3 into the Experience field to make it go to action step 3 when it is hit. This monster will never go below action step 3 again... so the moment it is hit, it is considered hostile and can chase, shoot after, or play a raging rampaging animation. (Amazing use of such a simple feature)

Double Dragon style combo hits
In games like Double Dragon and Golden Axe, a monster is stunned when you hit it. If you stop attacking, the monster will go back to normal. However, if you hit it again, the monster will be in a second stunned state. And typically, on the third, they fly back and stay on the ground for a bit before getting back up to fight you. Setting the experience to 9 allows you to do just that. Whenever you hit the monster, it will go to action step 5. For that action step, set a timer for 5 that will take you back to the first frame. So, if nothing happens the monster will return to the first frame and go back to hunting the hero. However, if the player hits the monster again while it is already on 5, it will move to action step 6. Same as before. Set a timer of 5 to take us back to the first frame. But if the monster is hit again, it will now move to the final hit action step 7. You can play your fall to the ground animation here and make the monster wait in an invulnerable prone position until another timer (maybe set to 10?) finishes, then the monster will go back to the first action step and start hunting the player. (Note: The code below assumes you also have custom spawn animation in this monster. Either change it to go to 0 or use a custom end timer action script to go to frame 2)

INSTRUCTIONS
Be sure to back everything up first! This requires modifying a lot of scripts in your NESMaker project and also in the NESMaker system folder. (Note: If you do not use a repository, backing up your entire NESFolder into a zip is pretty easy small... I keep multiple regular zipped backups of my entire NESMaker folder named like this 2019-09-02-SomeNoteAboutIt.zip )


Step 1: Capture the Experience into Object_Worth (HandleUpdateObjects.asm)

Modify the HandleUpdateObjects.asm script (in the System folder).
Find the line
Code:
LDY Object_type,x ;; restore y
;;///////////////////// Load other pertinent details for object here

And below those lines, add
Code:
LDA ObjectStrengthDefense,y
STA Object_strengthDefense,x

Step 2: Add tempArtix in the Zero Page RAM section of the settings

tempArtix.png


Step 3: Add Object_Worth to Object variables in the settings

ObjectWorth.png


Step 4: Change your Handle Update Objects (HandleUpdateObjects.asm)

Find the line
Code:
ChangeObjectState #$00,#$02

Change To (Well, comment it out)
Code:
;; ChangeObjectState #$00,#$02
;; You might need to check and make sure it is a monster first if anything else breaks.

Step 5: Change your Handle Monster Hurt script (HandleHurtMonster.asm)

Find this line... it is around line 20
Code:
ChangeObjectState #$00,#$02

Replace that one line with the following code

Code:
    ;; Monster Hurt Reaction
        ;; Hijacks the Monster's Experience field. Value is readable as Object_worth,x
        ;; -------------------------------------
        ;; Object_worth 0 (#$00) = Go to Action Step 0
        ;; Object_worth 1 (#$01) = Go to Action Step 1
        ;; Object_worth 2 (#$02) = Go to Action Step 2
        ;; Object_worth 3 (#$03) = Go to Action Step 3
        ;; Object_worth 4 (#$04) = Go to Action Step 4
        ;; Object_worth 5 (#$05) = Go to Action Step 5
        ;; Object_worth 6 (#$06) = Go to Action Step 6
        ;; Object_worth 7 (#$07) = Go to Action Step 7
        ;; Object_worth 8 (#$08) = Increase Action Step by 1
        ;; Object_worth 9 (#$09) = Double Dragons! 3 Hits starting at 5.... this is awesome.
        ;; Object_worth 10 (#$10) = Do nothing at all
            
        LDA Object_worth,x  ;; Load the value from the Monster's Experience field
        STA tempArtix       ;; Store it in this temp variable
        
        CMP #$08    ;; Compare against 8
        BCS +       ;; If it is equal to or higher than 8, skip this.
            ;; It is 7,6,5,4,3,2,1, or 0 so we can just plug that value in for which action step for the monster to go to.
            ChangeObjectState tempArtix,#$02    ;; Set the Monster's action state to the value in tempArtix
            JMP doneMonsterHurtBehavior
        +
        
        BNE +   
            ;; If it is 8 // Increase Action Step by 1 Behavior
            ;; Read the current action step of the monster object in X:
            LDA Object_action_step,x
            AND #%00000111
            CLC
            ADC #$01        ;; Add +1
            STA tempArtix   ;; Store the result in tempArtix
            CMP #$08        ;; Is it 8? Because if it is... it is too high.
            BNE ++
                LDA #$00    ;; It's too high, so wrap it back around to 0
                STA tempArtix   ;; Store the result in tempArtix
            ++
            ChangeObjectState tempArtix, #$02   ;; Set the Monster's action state to the value in tempArtix
            JMP doneMonsterHurtBehavior  
        +   
        
        CMP #$09    ;; You want 9? Double Dragon time? Oh boy! Here we go.
        BNE +
            ;; Double Dragon Time!
            ;; When you get hit, you go to 5,6,7... only 7 should have the knockback
            LDA Object_action_step,x
            CMP #$05    ;; Is it greater than or equal to 5?
            BCS ++      ;; if so, just incriment it by one
                ;; Not under 5... so let's set the monster's action step to 5 here
                LDA #$05 ;; Set it to 5 and we are done here.
                STA tempArtix
                ;; Make it so number one!
                ChangeObjectState tempArtix, #$02   ;; Set the Monster's action state to the value in tempArtix
                JMP doneMonsterHurtBehavior  
            ++
            
            LDA Object_action_step,x
            AND #%00000111
            CLC
            ADC #$01        ;; Add +1
            STA tempArtix   ;; Store the result in tempArtix
            CMP #$08        ;; Is it 8? Because if it is... it is too high.
            BNE +++
                LDA #$01    ;; It's too high, so wrap it back around to 0... no, 1 because this is probably a spawning monster and 0 is used for the spawn animation
                STA tempArtix   ;; Store the result in tempArtix
            +++
            ChangeObjectState tempArtix, #$02   ;; Set the Monster's action state to the value in tempArtix
            JMP doneMonsterHurtBehavior  
        +

Create fun and interesting monsters!
I also recommend adding a few custom end actions which can let you go to more action steps. A nice one to have would be "random action step" which choose between 2 or 4. I am going to rename mine-- but I just got all of this finally working on Saturday.

bonusendactions.png


CREDITS
This is thanks to an incredible amount of work by Dale Coop, the mentoring of Kasumi, Functional Form, Chronicler of Legends, and all the helpful people in the NESMaker Discord channel.

I have been using these scripts to make fun and challenging boss fights in my Dungeons & DoomKnights game project. Sharing with you so you can experiment with these concepts in your NES game projects.

Feedback and improvements
As they say, "There's more than one way to skin a moglin." Please do share other (and better ways) we could accomplish fights like these. Kasumi wrote a super optimized version of this ASM code. Posted my far less optimized original version for readability. Please let me know anything I should fix or improve here.

I am aware this will probably be completely obsolete when 5.0 comes out. Would be awesome for something like this to be built into it. But if you are building in 4.1.5 this can add a crazy amount of fun.

Battle on!
Artix
 

jcramer

New member
Does this stuff work with Dale's 2 player core? I want to add it to an already existing game.
 

Artix

New member
Hiya Jcramer. Yes, I am using Dale Coop's 2 player core. If you have any trouble getting it to work, let me know.
 

DanielT1985

Member
This is so cool, but I wish I can get this to work in 4.1.0. Don't know if anyone did something like this for that version.
 

dale_coop

Moderator
Staff member
The 4.1.0 is very close from the 4.1.5 (the scripts are the same... it should work)
Or maybe it's a typo and you mean "4.0.1"?
 

n8bit

Member
Hmm... messed around with this a bit today just for fun. Doesn't appear to play nice with platformers. My player sprite just falls through the screen to the next and moves to a frozen death animation, odd. Might mess with it some more to see if there are changes that need to be made to work with platformers...
 

dale_coop

Moderator
Staff member
There is a small (but annoying) mistake in the tutorial...

Step 1: Capture the Experience into Object_Worth (HandleUpdateObjects.asm):
You don't need to add the lines:
Code:
	LDA ObjectStrengthDefense,y
	STA Object_strengthDefense,x

Instead, you need those lines:
Code:
	LDA ObjectWorth,y
	STA Object_worth,x
 
Top Bottom