Limit the projectiles 2 bullets at a time [NESMaker 4.0.0]

dale_coop

Moderator
Staff member
Managed to limit the Player projectiles: 2 bullets at a time, to avoid slowdowns or flickering (when to much game objects) when the player shoots like a maniac!

2BulletsProjectilesf250fccff2159398.gif


The technique is to declare a variable "limitProjectile" to be the limit (the number of bullets being at the same time on screen). Each time, a projectile is created, the variable is decreased. If the variable is equal to "0", it means already 2 bullets created, the creating object code of the script is skipped.
When the bullet is destroyed (on edge/solid with "Destroy Me" or on a Monsters collision), the variable is increased.

Scripts:
In the "SystemVariable.asm" script, I declared a "limitProjectile" variable:
Code:
	limitProjectile .dsb 1  ;; to limit the projectiles

In the "InitLoads.asm" script, I initialize the variable (number of bullets at a time):
Code:
	LDA #$02
	STA limitProjectile

Then I modified the "CreateSimpleProjectileWithMotion.asm" script to check that variable:
Code:
CreateSimpleProjectileWithMotion:
    LDY player1_object
    CPY #$FF ;; if the player object is set to ff, he's dead.
    BNE playerCanCreateProjectile
    RTS
playerCanCreateProjectile:
	LDA limitProjectile
	BNE continueCreateProjectile
	RTS
continueCreateProjectile:
    ;; get offset
    ;; in a later version, we will use user defined offsets.
    ;; for now, we'll place projectile creation at center of object
    LDA Object_movement,y
    AND #%00000111
    TAX
    LDA weaponOffsetTableX,x
    ;;; now we have the offset
     CLC
     ADC Object_x_hi,y
    STA temp1
    LDA weaponOffsetTableY,x
    CLC
    ADC Object_y_hi,y
    STA temp2
    CreateObject temp1, temp2, #$01, #$00  ;;testVar
    LDA Object_movement,y
    AND #%00000111
    STA temp
    TAY
    LDA DirectionMovementTable,y
    ORA temp
    
    STA Object_movement,x
    
    ;; add object size offset.
    LDA Object_x_hi,x
    SEC
    SBC #$08 ;; half of the width of the intended projectile
    STA Object_x_hi,x
    LDA Object_y_hi,x
    SEC
    SBC #$08 ;; half of the height of the intended projectile
    STA Object_y_hi,x

    ;;PlaySound #$00, #$00
	
    DEC limitProjectile

    RTS

I modified the "HandleObjectCollisions.asm" script (around line 362):
Code:
	skipHurtingMonster:
		LDX tempx
		;; what should we do with the projectile?
		INC limitProjectile  ;;projectiles limitation related
		DeactivateCurrentObject

I wanted to modify the "Reaction_02.asm" script (in "Routines\System\AI_Reactions" folder) that correspond to the "Destroy Me" in the Object Details solid/edge reactions, but did have succes checking the objct type (the code is needed only for player weapon).
So I made modified the unused "Reaction_03.asm" script:
Code:
;; DESTROY ME AND LIMIT (FOR WEAPON)

  INC limitProjectile      ;;projectiles limitation related
  DeactivateCurrentObject

And in "Project Labels", I rename it to "Destoy Me (Player Weapon)", reassign this reaction to my Melee/projectile object.

Voilà. It should work (2 bullets at a time)
 

WolfMerrik

New member
This is VERY awesome, and something I was looking to do for my own game.
Games like Megaman (I am now realizing) didn't limit the number of shots for the sake of difficulty, but hardware limitations.
 

WolfMerrik

New member
dale_coop said:
Exactly, WolfMerrick, need to make a lot of compromises to have a game that runs well.

Totally!

And even then, a lot of games STILL suffered from slowdown.
That being said, games like Megaman just wouldn't be the same without it.
 
Following along until your forth step.
HandleObjectCollisions.asm doesn't have any mention of MonsterHurting at all, around those lines, or in general. Are you sure that's the right file? Making all of the other changes made my project no longer compile ><
 

dale_coop

Moderator
Staff member
I wrote those scripts for the 4.0.0... and didn't updated it for 4.0.11. A lot of scripts have changed (and will change in the next version maybe).

The script "CreateSimpleProjectileWithMotion.asm" doesn't exist anymore.
If you are making a Adventure game, you need to use the "a_create_projectile.asm" script, and add the line related to "limitProjectile" at the equivalent places

For the MonsterHurting part, it's now in the "AdventureGame_Base\HurtingWinLoseDeath\Adventure_HandleHurtMonster.asm", the place to add the line is at the end of that script.

I am at my job now... but could make an update to this tutorial (for 4.0.11), tonight, if you need.
 
My understanding of ASM is still pretty limited. I understand what this code is trying to do, but I don't really get how it's doing it.

I wasn't able to get this to function on the platformer module. I'm already using your duck and shoot script, so that change made sense to me. If I were to guess, I don't know if it's important where in the initload.asm I put that line of change, so I kinda just threw it somewhere.

The first three things SHOULD be the only things I need to do to get it to work. The last 2 parts are just how it handles hitting bad guys, right?

EDIT: Heyo! Made some progress. I had 2 copies of the shooting script, 1 asm, and 1 txt file... I was modifying the text file.. >.< I keep getting caught up by the dumbest things. I have it limited to 2 shots now, but it never "refreshes" the amount. I think I can probably figure that out from here though.

EDIT2: And got there. After getting it limited to 2 bullets, it was a matter of finding out where the increment them again (Which was the point of the reaction type changes) Which I changed in the scripts, but modified the wrong label, so was a big confused at first, but all fell into place in the end. Thanks!
 

Gazimaluke

Member
Thanks Dale_cooper. I was looking for a script to do this. I want to have only 3 shots on screen like in Mega Man. Even if Mega Man did it to have less slowdowns I feel that three shots is max of your not aiming for a weapon that is supposed to be some automatic rifle.
 

Gazimaluke

Member
I have implemented this in my 4.0.11 project and while I got my character to shoot (which I didn't manage with any of the shooting scripts in 4.0.11) I have problems with the limitation part. It says limitProjectile is an unknown label. What have I missed? I am commenting out those lines for now so the game compiles.
 

scunsion

New member
Gazimaluke said:
I have implemented this in my 4.0.11 project and while I got my character to shoot (which I didn't manage with any of the shooting scripts in 4.0.11) I have problems with the limitation part. It says limitProjectile is an unknown label. What have I missed? I am commenting out those lines for now so the game compiles.

I am stuck in a similar spot, my game is compiling but I don't think I've got the LDA limitProjectile is the right spots. I'm using shootWeapon.asm from the platform module.
 

Gazimaluke

Member
scunsion said:
I am stuck in a similar spot, my game is compiling but I don't think I've got the LDA limitProjectile is the right spots. I'm using shootWeapon.asm from the platform module.

I would like to use shootWeapon.asm too. But for some reason I couldn't get it working at all.
 

scunsion

New member
http://nesmakers.com/viewtopic.php?f=28&t=747

I followed along with this thread to get it working. Have you tried that yet?
 

dale_coop

Moderator
Staff member
Have you declare the variable limitProjectile in the systemVariables.asm? And initialized it to 02 in the initLoads.asm?

Another possibility (since the 4.0.11) is to declare the variable directly in the NESMaker, in « Project Settings > User variables »)
Add one variable, rename it to limitProjectile and I tot to 02.
 

dale_coop

Moderator
Staff member
For the plateform module in 4.0.11:

1/ declare the variable: in the "Project settings", in the user variables tab, add a new variable name it "limitProjectile" with an "initial value" set to "2".

2/ modify the shootWeapon.asm, like that:
Code:
	LDA limitProjectile
	BNE canShootWeapon
	JMP doneShooting
canShootWeapon:
	LDA Object_movement,x
	AND #%00000111
	ORA #%00000010	
	STA temp3
	CMP #%000000010
	BNE notRightForProjShoot
	LDA Object_x_hi,x
	CLC
	ADC #$18
	STA temp
	JMP gotDirForShoot
notRightForProjShoot:
	LDA Object_x_hi,x
	sec
	sbc #$18
	STA temp
gotDirForShoot:
	LDA temp3
	TAY
	LDA DirectionMovementTable,y
	ORA temp3
	STA temp3

	LDA Object_y_hi,x
	STA temp1

	GetCurrentActionType player1_object
	CMP #$01
	BEQ continueShooting
	CMP #$02
	BEQ continueShooting 

	ChangeObjectState #$03, #$08

continueShooting:
	CreateObject temp,temp1,#$03, #$00
	LDA temp3
	STA Object_movement,x
	
	DEC limitProjectile

doneShooting
	RTS

3/ modify the "\PlatformGame_Base\HurtWinLoseDeath\Platform_HandleHurtMonster.asm" script, at the end of the script, add the line:
Code:
	INC limitProjectile  ;;projectiles limitation related

4/ modify the unused "Routines\System\AI_Reactions\Reaction_03.asm" script:
Code:
;; DESTROY ME AND LIMIT (FOR WEAPON)

 	INC limitProjectile      ;;projectiles limitation related
 	DeactivateCurrentObject
And in "Project Labels", I rename "React03" to "Destoy Me (Player Weapon)" in "Monster Edge Reaction" and in "Monster Solid Reaction".

5/ For the Melee/projectile object, in its "object details", select "Destoy Me (Player Weapon)" for Edge and Solid object reaction.

And that should be it.
 

dale_coop

Moderator
Staff member
Maybe you already declare the limitProjectile variable in the SystemVariables.asm script ?
If you did, you don’t need to do it again (don’t need the 1/)

OR
maybe you still have the "a_create_projectile.asm" script in your "Scripts > input scripts"? You don't need it anymore, so remove it (right-click > remove)
 

PortableAnswers

New member
Hello, I am using the Adventure Module in 4.0.11 and I am not sure how to go about modifying the a_create_projectile.asm script. Here's my current script:
Code:
createWeaponProjectile:
 LDA gameHandler
    AND #%00100000
    BEQ notNPCstate_proj
 JMP doneShooting
 notNPCstate_proj
 LDA weaponsUnlocked
 AND #%00000010
 BNE canShoot
 JMP doneShooting
canShoot:
    LDX player1_object
    GetCurrentActionType player1_object
    CMP #$01    ;; if the Player is walking/running
    BEQ isNowShooting  ;; keep it walking/running
    CMP #$02    ;; else if is already shooting...
    BNE notAlreadyShooting
    JMP doneShooting
notAlreadyShooting:
    ;;; don't attack if already attacking.
    ;;; do we have to check for hurt here?
    ;;;;; Here, we WOULD create melee
    ChangeObjectState #$02, #$02
    LDA Object_movement,x
    AND #%00001111
    STA Object_movement,x
    LDA #$00
    STA Object_h_speed_hi,x
    STA Object_h_speed_lo,x
    STA Object_v_speed_hi,x
    STA Object_v_speed_lo,x
isNowShooting: 
    ;; the script continues from here
    
    LDA Object_x_hi,x
    STA temp
    LDA Object_y_hi,x
    STA temp1
 
    LDA Object_movement,x
    AND #%00000111
    STA temp2
    CMP #%00000110
    BEQ setLEFTOffsetProjectile
    CMP #%00000010
    BEQ setRIGHTOffsetProjectile
    CMP #%00000100
    BEQ setUPOffsetProjectile
    CMP #%00000000
    BEQ setDOWNOffsetProjectile
    JMP doneShooting
    
setLEFTOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    SBC #$-13    ;;<<-- horizontal offset of your weapon when your player facing left (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    ADC #$11    ;;<<-- vertical offset of your weapon  when your player facing left(change the value to adjust from #$00 to #$0F or more)
    STA temp1
    JMP continueCreatingProjectile
    
setRIGHTOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    ADC #$13    ;;<<-- L/R - horizontal offset of your weapon when your player facing right (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    ADC #$11    ;;<<-- U/D - vertical offset of your weapon when your player facing right (change the value to adjust from #$00 to #$0F or more)
    STA temp1
    JMP continueCreatingProjectile

setUPOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    ADC #$07    ;;<<-- horizontal offset of your weapon when your player facing up (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    SBC #$-00    ;;<<-- vertical offset of your weapon when your player facing up (change the value to adjust) from #$00 to #$0F or more
    STA temp1
    JMP continueCreatingProjectile

setDOWNOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    ADC #$07    ;;<<-- horizontal offset of your weapon when your player facing down (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    ADC #$16    ;;<<-- vertical offset of your weapon when your player facing down (change the value to adjust from #$00 to #$0F or more)
    STA temp1
    JMP continueCreatingProjectile
    
continueCreatingProjectile:
    CreateObject temp, temp1, #$03, #$00
 
    ;;;; x is now the newly created object's x.
    LDA Object_movement,x
    ORA temp2
    STA Object_movement,x
    LDY temp2
    LDA directionTable,y
    ORA Object_movement,x
    STA Object_movement,x
    ;;PlaySound #sfx_shoot
 
doneShooting:
RTS


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

dale_coop

Moderator
Staff member
Maybe something like that:
Code:
createWeaponProjectile:
 LDA gameHandler
    AND #%00100000
    BEQ notNPCstate_proj
 JMP doneShooting
 notNPCstate_proj
 LDA weaponsUnlocked
 AND #%00000010
 BNE canShoot
 JMP doneShooting
canShoot:
    LDX player1_object
    GetCurrentActionType player1_object
    CMP #$01    ;; if the Player is walking/running
    BEQ isNowShooting  ;; keep it walking/running
    CMP #$02    ;; else if is already shooting...
    BNE notAlreadyShooting
    JMP doneShooting
notAlreadyShooting:
    ;;; don't attack if already attacking.
    ;;; do we have to check for hurt here?
    ;;;;; Here, we WOULD create melee
    ChangeObjectState #$02, #$02
    LDA Object_movement,x
    AND #%00001111
    STA Object_movement,x
    LDA #$00
    STA Object_h_speed_hi,x
    STA Object_h_speed_lo,x
    STA Object_v_speed_hi,x
    STA Object_v_speed_lo,x
isNowShooting: 
    ;; the script continues from here
	LDA limitProjectile          ;; limit projectiles
	BNE canCreateProjectile  ;; limit projectiles
	JMP doneShooting           ;; limit projectiles
canCreateProjectile:    
    LDA Object_x_hi,x
    STA temp
    LDA Object_y_hi,x
    STA temp1
 
    LDA Object_movement,x
    AND #%00000111
    STA temp2
    CMP #%00000110
    BEQ setLEFTOffsetProjectile
    CMP #%00000010
    BEQ setRIGHTOffsetProjectile
    CMP #%00000100
    BEQ setUPOffsetProjectile
    CMP #%00000000
    BEQ setDOWNOffsetProjectile
    JMP doneShooting
    
setLEFTOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    SBC #$-13    ;;<<-- horizontal offset of your weapon when your player facing left (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    ADC #$11    ;;<<-- vertical offset of your weapon  when your player facing left(change the value to adjust from #$00 to #$0F or more)
    STA temp1
    JMP continueCreatingProjectile
    
setRIGHTOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    ADC #$13    ;;<<-- L/R - horizontal offset of your weapon when your player facing right (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    ADC #$11    ;;<<-- U/D - vertical offset of your weapon when your player facing right (change the value to adjust from #$00 to #$0F or more)
    STA temp1
    JMP continueCreatingProjectile

setUPOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    ADC #$07    ;;<<-- horizontal offset of your weapon when your player facing up (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    SBC #$-00    ;;<<-- vertical offset of your weapon when your player facing up (change the value to adjust) from #$00 to #$0F or more
    STA temp1
    JMP continueCreatingProjectile

setDOWNOffsetProjectile:
    LDA Object_x_hi,x
    CLC
    ADC #$07    ;;<<-- horizontal offset of your weapon when your player facing down (change the value to adjust from #$00 to #$0F or more)
    STA temp
    LDA Object_y_hi,x
    CLC
    ADC #$16    ;;<<-- vertical offset of your weapon when your player facing down (change the value to adjust from #$00 to #$0F or more)
    STA temp1
    JMP continueCreatingProjectile
    
continueCreatingProjectile:
    CreateObject temp, temp1, #$03, #$00
 
    ;;;; x is now the newly created object's x.
    LDA Object_movement,x
    ORA temp2
    STA Object_movement,x
    LDY temp2
    LDA directionTable,y
    ORA Object_movement,x
    STA Object_movement,x
	
	DEC limitProjectile  ;; limit projectiles
	
    ;;PlaySound #sfx_shoot
 
doneShooting:
RTS


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

I couldn't test (not home), but tell me if it doesn't work, I could try later and fix it.
 
So there's a bit of a bug with this script, where if you spam the shoot button while transitioning screens, it's possible to "lose" bullets over the course of the level.

Won't matter as much once the scrolling update is released (I imagine), but wondering if there's a place where I can "Reload" when a new screen loads? I tried looking for a place, but nothing I found bore any fruit.
 
Top Bottom