[4.1] Adding Monster Locks for your game (Basic core)

dale_coop

Moderator
Staff member
Don't need it man, I am doing all this for the community <3 I love you all guys. And so grateful for Joe, Josh and Austin for NESMaker, that makes me realize my childhood dreams and share very priceless moments with my son (who loves working with NESMaker too)
 

dale_coop

Moderator
Staff member
I updated my OP, there was an issue, I fixed my script "TriggerScreen_DC.asm" (in the "GameEngineData\Routines\Basic\ModuleScripts\MainScripts\ScrollingPlatformer" folder), replacing the line:
Code:
	JSR screenIsOffForMonsterCheck
With:
Code:
;;Trigger the current screen
	TriggerScreen screenType
	
	;;update all tiles
	LDA showingNametable
	STA temp
	ChangeAllTilesDirect #COL_MONSTER_LOCK, #$00, #TILE_MONSTER_LOCK_OFF, temp

It will be way better now! (now more blackoff screen flash when killed all monsters).
 

vanderblade

Active member
Any update on the Adventure Module issue I'm having where I only have to kill one monster to trigger the lock?

I rechecked all your instructions and followed them perfectly.
 

dale_coop

Moderator
Staff member
vanderblade said:
UPDATE #2: I playtested more, and if I have more than one monster on the screen, the lock disappears after I kill just one monster. What might be the issue?

I tested again... when killed with the weapon (not with projectiles), one monster kill triggers the screen. Don't know why. I am searching for a fix for that.
 

vanderblade

Active member
For me, it doesn't matter if I use the weapon or the projectile. Killing any monster triggers the screen. But maybe if you solve the weapon on your end, it will solve both for me?
 
better than me vanderblade, I get this issue when I shoot and clear the monsters the screen goes wonky with colors. but it works...

so got to clear this up and should be good :)

49946978_10216397895877883_2097655404526829568_n.jpg
 

dale_coop

Moderator
Staff member
For the Adventure module ONLY, modify your "HandleSpriteWeapon_UsingMonsterHealth.asm" script, replacing with this code:
Code:
	GetCurrentActionType player1_object
	CMP #$02 ;; attack state
	BEQ checkSpriteWeapon
	JMP skipSpriteWeaponCheck
checkSpriteWeapon:

	;;;;;;;;;;;;;;;;;;;;;;;;;
	;;here it did equal the melee attack pose.
	LDX player1_object
	LDA Object_movement,x
	AND #%00000111
	TAY ;; direction for offset table index
	LDA Object_x_hi,x
    ;;; offset x for creation
    CLC
    ADC weaponOffsetTableX,y
	STA selfRight
	SEC 
    SBC #$08 ;; width of weapon 
	STA selfLeft
	
	LDA Object_y_hi,x
    ;;; offset x for creation
    CLC
    ADC weaponOffsetTableY,y
	STA selfBottom
	SEC 
    SBC #$08 ;; width of weapon 
	STA selfTop
	;; run through objects.
	
	LDX #$00	
DoMonsterWeaponSpriteLoop:
	LDA Object_flags,x
	AND #%00001000
	BNE +
	JMP ++
+
	JSR GetOtherCollisionBox
	LDA selfRight
	CMP otherLeft
	BCS + ;; no player object collision
	JMP ++
+
	LDA otherRight
	CMP selfLeft
	BCS +
	JMP ++
+
	
	LDA otherBottom
	CMP selfTop
	BCS +
	JMP ++
+
	LDA selfBottom
	CMP otherTop
	BCS +
	JMP ++
+
;; ok, there is a collision with an monster object, from HERE :
;;; what should we do with the monster?
		LDA Object_vulnerability,x
		AND #%00000100 ;; is it weapon immune?
		BEQ notWeaponImmuneSpriteWeapon
		;PlaySound #SFX_MISS
		JMP skipHurtingMonsterAndSoundSpriteWeapon
    notWeaponImmuneSpriteWeapon:
		LDA Object_status,x
		AND #HURT_STATUS_MASK
		BEQ dontskipHurtingMonsterSpriteWeapon
		JMP skipHurtingMonsterSpriteWeapon
    dontskipHurtingMonsterSpriteWeapon:
		LDA Object_status,x
		ORA #%00000001
		STA Object_status,x
		LDA #HURT_TIMER
		STA Object_timer_0,x
		;;; assume idle is in step 0
		ChangeObjectState #$00,#$02
		;;;; unfortunately this recoil is backwards
		LDA Object_status,x
		AND #%00000100
		BNE skipRecoilBecauseOnEdgeSpriteWeapon
		LDA Object_vulnerability,x
		AND #%00001000 
		BNE skipRecoilBecauseOnEdgeSpriteWeapon ;; skip recoil because bit is flipped to ignore recoil

		LDA selfCenterX
		STA recoil_otherX
		LDA selfCenterY
		STA recoil_otherY
		LDA otherCenterX
		STA recoil_selfX
		LDA otherCenterY
		STA recoil_selfY
		JSR DetermineRecoilDirection
    skipRecoilBecauseOnEdgeSpriteWeapon:
		LDA Object_health,x
		SEC
		SBC #$01
		CMP #$01
		BCC isMonsterDeathSpriteWeapon:
		JMP notMonsterDeathSpriteWeapon
		isMonsterDeathSpriteWeapon:

		LDA Object_x_hi,x
		STA temp
		LDA Object_y_hi,x
		STA temp1
		DeactivateCurrentObject
		CreateObject temp, temp1, #OBJ_MONSTER_DEATH, #$00, currentNametable
		PlaySound #SND_SPLAT
		TXA
		STA tempx
		AddValue #$08, myScore, #$01, #$00

		UpdateHud HUD_myScore
		LDX tempx

		JSR HandleDrops
		JSR HandleToggleScrolling
			
		;; check for monter locks begin:
		CountObjects #%00001000, #$00
		LDA monsterCounter
		CLC
		BEQ +
		JMP ++
	+
		.include SCR_KILLED_LAST_MONSTER
		JMP skipHurtingMonsterSpriteWeapon
    notMonsterDeathSpriteWeapon:
		STA Object_health,x
    skipHurtingMonsterSpriteWeapon:
		;PlaySound #SFX_MONSTER_HURT
    skipHurtingMonsterAndSoundSpriteWeapon:
	
++
	INX 
	CPX #TOTAL_MAX_OBJECTS
	BEQ skipSpriteWeaponCheck ;; done with checking against objects 
	JMP DoMonsterWeaponSpriteLoop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
skipSpriteWeaponCheck ;; there is no collision here horizontally.


And for those who have blocks coming back on the triggered screen, could you share your Routines\Basic\ModuleScripts\MainScripts\AdventureGame\Handle_CheckForMonsters.asm script?

...OR.... maybe you set the "HIDE_HUD" user constant to something different than "0"?
I just discover an issue with that constant and the check for triggered tiles / monster locks. If you set to Hide HUD, the code doesn't remove the triggered tiles/doors/monter locks.
 

dale_coop

Moderator
Staff member
OK, guys, I just realized something... for my particular uses, I made the script Trigger the screen, when all my monsters are killed, because I want ti me able to come back to that screen and still have all my monster killed/and my monster block removed.

BUT in the previous versions of NESMaker, monster blocks did not triggering screens. When the monsters were killed, the blocks were removed... but if you came back to the screen, the monsters and monster blocs were here again.

So my mistake m( _ _ )m

To have the NESMaker normal behavior back, just comment out the TriggerScreen screenType line. I updated my tutorial in the OP, to have that behavior by default.
 

vanderblade

Active member
Hey Dale. Your updated code works with the player weapon. But my projectile still triggers the monster lock if I use it to kill the first monster. And I also noticed killing enemies with the weapon now causes two death explosion animations.
 

dale_coop

Moderator
Staff member
vanderblade said:
Hey Dale. Your updated code works with the player weapon. But my projectile still triggers the monster lock if I use it to kill the first monster.

Strange, I will check that. You are using the Adventure Module?


vanderblade said:
And I also noticed killing enemies with the weapon now causes two death explosion animations.

Thanks for the feedback, I will fix that and update the patch and my first post.
If you want to fix it in your script, modify the HandleSpriteWeapon_UsingMonsterHealth. asm script, comment out the line 112 (add a ";" at the beginning), like this:
Code:
	;; CreateObject temp, temp1, #OBJ_MONSTER_DEATH, #$00, currentNametable
 

dale_coop

Moderator
Staff member
vanderblade said:
Hey Dale. Your updated code works with the player weapon. But my projectile still triggers the monster lock if I use it to kill the first monster.

Could you share your Handle Monster Hurt script ? (it might be missing some lines)
 

vanderblade

Active member
Yes, I am using the Adventure Module.

Your fix for the monster death animation worked. Thanks!

Here's my Handle Hurt Monster Script.

Code:
;;; what should we do with the monster?
        ;;; monster is loaded in x
        LDA Object_vulnerability,x
        AND #%00000100 ;; is it weapon immune?
        BEQ notWeaponImmune
        ;PlaySound #SFX_MISS
        JMP skipHurtingMonsterAndSound
    notWeaponImmune:
        
        LDA Object_status,x
        AND #HURT_STATUS_MASK
        BEQ dontskipHurtingMonster
        JMP skipHurtingMonster
    dontskipHurtingMonster:
        LDA Object_status,x
        ORA #%00000001
        STA Object_status,x
        LDA #HURT_TIMER
        STA Object_timer_0,x
        ;;; assume idle is in step 0
        ChangeObjectState #$00,#$02
        ;;;; unfortunately this recoil is backwards
        LDA Object_status,x
        AND #%00000100
        BNE skipRecoilBecauseOnEdge
        LDA Object_vulnerability,x
        AND #%00001000 
        BNE skipRecoilBecauseOnEdge ;; skip recoil because bit is flipped to ignore recoil
        
        LDA selfCenterX
        STA recoil_otherX
        LDA selfCenterY
        STA recoil_otherY
        LDA otherCenterX
        STA recoil_selfX
        LDA otherCenterY
        STA recoil_selfY
        JSR DetermineRecoilDirection
    skipRecoilBecauseOnEdge:
        LDA Object_health,x
        SEC
        SBC #$01
        CMP #$01
        BCC +
        JMP notMonsterDeath
    +

        DeactivateCurrentObject
        PlaySound #SND_SPLAT
        ;;;;;;;;;;;;;;;;;; ok, so now we also add points to score
        ;LDY Object_type,x
        ;LDA ObjectWorth,y
        ;STA temp
;       AddValue #$03, GLOBAL_Player1_Score, temp
                ;arg0 = how many places this value has.
                ;arg1 = home variable
                ;arg2 = amount to add ... places?
        ;; and this should trip the update hud flag?
        
        ;;;; 
    

    TXA
    STA tempx

    AddValue #$08, myScore, #$01, #$00

    ;STA hudElementTilesToLoad
    ;   LDA #$00
    ;   STA hudElementTilesMax
        ; LDA DrawHudBytes
        ; ora #HUD_myScore
        ; STA DrawHudBytes
    UpdateHud HUD_myScore
    LDX tempx

        JSR HandleDrops
        JSR HandleToggleScrolling
        
        CountObjects #$00001000, #$00
        LDA monsterCounter
        CLC
        BEQ +
        JMP ++
    +
        .include SCR_KILLED_LAST_MONSTER
    ++
        
        JMP skipHurtingMonster
    notMonsterDeath
        STA Object_health,x
    skipHurtingMonster: 
        ;PlaySound #SFX_MONSTER_HURT
    
    skipHurtingMonsterAndSound:
        LDX tempx
        ;; what should we do with the projectile?
        DeactivateCurrentObject
 

dale_coop

Moderator
Staff member
Ok, I see...
Try replacing everything with this code (fixed):
Code:
;;; what should we do with the monster?
        ;;; monster is loaded in x
        LDA Object_vulnerability,x
        AND #%00000100 ;; is it weapon immune?
        BEQ notWeaponImmune
        ;PlaySound #SFX_MISS
        JMP skipHurtingMonsterAndSound
    notWeaponImmune:
        
        LDA Object_status,x
        AND #HURT_STATUS_MASK
        BEQ dontskipHurtingMonster
        JMP skipHurtingMonster
    dontskipHurtingMonster:
        LDA Object_status,x
        ORA #%00000001
        STA Object_status,x
        LDA #HURT_TIMER
        STA Object_timer_0,x
        ;;; assume idle is in step 0
        ChangeObjectState #$00,#$02
        ;;;; unfortunately this recoil is backwards
        LDA Object_status,x
        AND #%00000100
        BNE skipRecoilBecauseOnEdge
        LDA Object_vulnerability,x
        AND #%00001000 
        BNE skipRecoilBecauseOnEdge ;; skip recoil because bit is flipped to ignore recoil
        
        LDA selfCenterX
        STA recoil_otherX
        LDA selfCenterY
        STA recoil_otherY
        LDA otherCenterX
        STA recoil_selfX
        LDA otherCenterY
        STA recoil_selfY
        JSR DetermineRecoilDirection
    skipRecoilBecauseOnEdge:
        LDA Object_health,x
        SEC
        SBC #$01
        CMP #$01
        BCC +
		JMP notMonsterDeath
	+

        DeactivateCurrentObject
        PlaySound #SND_SPLAT
        ;;;;;;;;;;;;;;;;;; ok, so now we also add points to score
        ;LDY Object_type,x
        ;LDA ObjectWorth,y
        ;STA temp
;       AddValue #$03, GLOBAL_Player1_Score, temp
                ;arg0 = how many places this value has.
                ;arg1 = home variable
                ;arg2 = amount to add ... places?
        ;; and this should trip the update hud flag?
        
        ;;;; 
    

	TXA
	STA tempy	;;dale_coop

	AddValue #$08, myScore, #$01, #$00

	;STA hudElementTilesToLoad
	;	LDA #$00
	;	STA hudElementTilesMax
		; LDA DrawHudBytes
		; ora #HUD_myScore
		; STA DrawHudBytes
	UpdateHud HUD_myScore
	LDX tempy	;;dale_coop

        JSR HandleDrops
        JSR HandleToggleScrolling
		
		CountObjects #%00001000, #$00
		LDX tempx	;;dale_coop
		LDA monsterCounter
		CLC	;;dale_coop
		BEQ +
		JMP ++
	+
		.include SCR_KILLED_LAST_MONSTER
	++
        JMP skipHurtingMonster
    notMonsterDeath
        STA Object_health,x
    skipHurtingMonster: 
        ;PlaySound #SFX_MONSTER_HURT
    
    skipHurtingMonsterAndSound:
        LDX tempx
        ;; what should we do with the projectile?
        DeactivateCurrentObject
 

vanderblade

Active member
Update: I changed the wrong version of the Monster Hurt Script. I fixed my error, and your code works!

You are a gosh darn hero!

Now we just have to figure out why my lock blocks don't stay disappeared when returning to rooms and why random rooms automatically add a key to my inventory when I enter them.
 

dale_coop

Moderator
Staff member
For the blocks that come back, could you share your Handle_CheckForMonsters.asm script? (or Handle_CheckForMonsters_DC.asm if you’re using that one)
 

vanderblade

Active member
Here it is. Just to be clear, the monster locks don't come back. It's the blocks with the keyhole that I use keys on.

Code:
;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;
	;; monster bit is: #%00001000 
;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;To change collision type and graphic

	CountObjects #%00001000, #$00 ;; count monsters.
	LDA monsterCounter
	CLC
	BEQ doNoMoreMonsterCode
	JMP stillMonstersOnScreen_onScreenload
doNoMoreMonsterCode
	
	;;; all of the tiles you would like to change when this screen is loaded.
	;;; do this routine for:
	;;; FIRST, GET RID OF LOCKS:
	LDA update_screen
	BNE screenIsOffForMonsterCheck
	JMP doScreenOnMonsterCheck
screenIsOffForMonsterCheck:
	
	LDA showingNametable
	STA temp
	ChangeAllTilesDirect #COL_MONSTER_LOCK, #$00, #TILE_OPENDOOR, temp
	JMP stillMonstersOnScreen_onScreenload
doScreenOnMonsterCheck:
	

	;;;;;===================
stillMonstersOnScreen_onScreenload:
;;;;  end what to do if no more objects
 

dale_coop

Moderator
Staff member
Could that be the same same tiles than the “TILE_OPENDOOR” user constant value (in your “Project settings > User constants”)?

I would need some screenshots of the problem (before all monster killed, just after all killed and when you come back to the screen? (or a video)
 

vanderblade

Active member
I'm not sure what you're asking.

My TILE_OPENDOOR is set to value 0
My COL_LOCK is set to value 4.

Looking at the tutorial, I wonder if the solution rests in the Handle_CheckForTriggers script?

Here's what I have currently:

Code:
;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;



		LDA screenType
		;; divide by 32
		LSR
		LSR
		LSR 
		;LSR
		;LSR
		;;; now we have the right *byte* out of the 32 needed for 256 screen bytes
		TAY
		LDA screenTriggers,y ;; now the rigth bit is loaded into the accum
		STA temp
		LDA screenType
		AND #%00000111 ;; look at last bits to know what bit to check, 0-7
		TAX
		LDA ValToBitTable_inverse,x
		AND temp
		BNE +
		JMP thisScreenIsNotTriggered_onScreenLoad
	+
		;; this screen IS triggered
DoDestroyAllTriggerTiles:	
	;;; HERE:
	;;; all of the tiles you would like to change when this screen is loaded.
	;;; do this routine for:
	;;; FIRST, GET RID OF LOCKS:
	LDA showingNametable
	STA temp
	ChangeAllTilesDirect #COL_LOCK, #$00, #TILE_OPENDOOR, temp
	;;; NOW, GET RID OF KEY TILES:
	LDA showingNametable
	STA temp
	ChangeAllTilesDirect #COL_KEY, #$00, #$00, temp ;; arg2 = floor, null, etc
	;ChangeAllTiles #COL_KEY, #$00, #$00, temp
	

thisScreenIsNotTriggered_onScreenLoad:

In particular, I think this line is not currently working:

Code:
;;; FIRST, GET RID OF LOCKS:
	LDA showingNametable
	STA temp
	ChangeAllTilesDirect #COL_LOCK, #$00, #TILE_OPENDOOR, temp
 

dale_coop

Moderator
Staff member
I made some modifications (a lot in fact) today in the scripts.
First, I will explain how the scripts work:
- the "Handle_CheckForTriggers" is executed each time the screen is loaded. if the screen is "triggered" it's removing all the tiles listed in the script : all the tiles "COL_LOCK" (meant to be used for the doors tiles) and "COL_KEY" (the keys tiles).
- the "Handle_CheckForMonsters" is executed each time the screen is loaded. if the screen has 0 monster, it's removing all the tiles listed in the script : all the "COL_MONSTER_LOCK".

One of the big fixes I made today, is to remove the TRIGGER SCREEN from the Killed Last Monster script! When you kill all monsters it shouldn't trigger the screen (else all your doors/keys/ will disappear when you will come back to the screen).
In the previous versions of NESMaker, when all the monsters were killed, the screen was not triggered.

PS then if you WANT to trigger it in that particular situation, you can keep the "TriggerScreen screenType" in the script. Else you should comment out the line and keep the normal intended behavior.
(there many other possibilities to trigger the screen, you still could put for example a trigger screen tile after the monster locks, if you want trigger the screen in certain situations)


Then I decided to fix another part of the scripts... the "ChangeAllTilesDirect #COL_MONSTER_LOCK, #$00, #TILE_OPENDOOR, temp" in your Handle_CheckForTriggers.asm is not correct for many reasons.
The first would be tile open-door is meant for doors tiles. I don't why Joe used it here.


Here my fix (I already updated my tutorial posts, and my zipScripts) :
1/ the Handle_CheckForMonsters.asm script:
Code:
;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;
	;; monster bit is: #%00001000 
;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;To change collision type and graphic
	CountObjects #%00001000, #$00 ;; count monsters.
	LDA monsterCounter
	CLC
	BEQ doNoMoreMonsterCode
	JMP stillMonstersOnScreen_onScreenload
doNoMoreMonsterCode
	
	;;; all of the tiles you would like to change when this screen is loaded.
	;;; do this routine for:
	;;; FIRST, GET RID OF LOCKS:
	LDA update_screen
	BNE screenIsOffForMonsterCheck
	JMP doScreenOnMonsterCheck
screenIsOffForMonsterCheck:
	
	LDA showingNametable
	STA temp
	ChangeAllTilesDirect #COL_MONSTER_LOCK, #$00, #TILE_MONSTER_LOCK_OFF, temp
	JMP stillMonstersOnScreen_onScreenload
doScreenOnMonsterCheck:
	

	;;;;;===================
stillMonstersOnScreen_onScreenload:
;;;;  end what to do if no more objects


2/ the Killed Last Monster script:
Code:
	;; Remove all the monster locks:
	LDA showingNametable
	STA temp
	ChangeAllTiles #COL_MONSTER_LOCK, #$00, #TILE_MONSTER_LOCK_OFF, temp


3/ Add a new user constant in the "Project Settings > User Settings" name it "TILE_MONSTER_LOCK_OFF" with a value of "0" (or the tile index you want to use when the monster lock is removed).
Like that, the tutorial for Platformer and Adventure is exactly the same!
 
Top Bottom