2 Players Adventure Game tutorial (2 Players Single Screen module - NESmaker 4.1.5)

dale_coop

Moderator
Staff member
Required that you installed the Two Players core and the 2players modules: http://nesmakers.com/viewtopic.php?f=41&t=2496.
Notes: In this tutorial I will go quickly through the parts you should already known (from the basics tutorial videos). I will focus on the 2 players specificities.


NEW PROJECT
Open NESmaker, start a new project ("Project > New"). Choose "Create Blank TileSet", give a name for your project GraphicAssets folder and select the "2 players TopDown Adventure" module.




PLAYERS
Set your Player object (size/graphics, "persistant", "player", "health", "speed", "acceleration", action steps/animations and a bounding box).



This Player will remain the main player, refered later as "Player 1". Select it and rename it as "Player 1".
Nothing else particular here. Set it as usual.

The player 2 is, by default, the last object of the Game Objects list. Here, in your project, it's currently labeled "Effect 7". Select this object and rename it as "Player 2".



Note: if you want to use another object than this one, you can modify the "OBJ_PLAYER_2" User Constant value (in "Project Settings > User Constants"), by default the value is 15 (= the 0...15th object).

Then, set this player like you would do for a another classic Player (size/graphics, "persistant", "player", "health", "speed", "acceleration", action steps/animations and a bounding box).




MONSTERS
Create your monsters/NPCs (and monster group) as usual.


ASSETS / TILES
Create your graphic assets as usual, in "Graphic Banks > Graphic Bank 1 > Assets".
Some precisions:
- Warp To Screen tiles warp the player.
- Checkpoints save your progression in the game, until you loose all your lives or reboot the game.
- Get Key tiles are use to make a key (you can also you a game object for that). This tile triggers the screen, so don't forget to set the screen-type value in your "Screeen Infos".
- Locked doors are solid until you get a key. Then, it's removed and become walkable. This tile triggers the screen, so don't forget to set the screen-type value in your "Screeen Infos".
If you want to use another tile graphic when unlocked, modify the "TILE_INDEX_PRIZE_OFF" user constant value to the index of the tile from the BckCHR_XX.bmp you want to use.
If you want to use another type, for exemple, a warp tile when unlocked, modify the "COL_OPENDOOR" user constant value to "2".
- Monster locks are solid until you there is no monster on the screen.
If you want to use another tile graphic when removed, modify the "TILE_MONSTER_LOCK_OFF" user constant value to the index of the tile from the BckCHR_XX.bmp you want to use.
If you want to use another type, for exemple, a warp tile when removed, modify the "COL_MONSTER_LOCK_OFF" user constant value to "2".


SCREENS
Set your screen as usual. Define the Player 1 starting point on your main screen.



The second Player will be spawn just next to the Player 1 (not too far, to avoid collision issues. we don't want him to spawn on a solid or death tile). However, you can defined the offset of the Player 2 spawn position by changing the "PLAYER_2_OFFSET_STARTING" User Constant, in "Project Settings > User Constants".
(Notes: there also another constant named "PLAYER_2_OFFSET_TRANSITIONS" that is used on screen transitions, but I'd strongly suggest to keep this one to "0", else you will have serious issues during screen transitions)

Notes: In the "Screen Infos", the "cutscene" flag doesn't do anything, except... when this is set, the players' inputs are disabled. So if you use this flag (with maybe "hide hud") you could design some cutscene screens (I used that for my game... I didn't remove that flag).


PLAYER WEAPON
The weapon is only available when the Weapon 1 is unlocked. You can get it from a NPC. Or set it unlocked from start, via the "Project info" dialog.
By default, this module is set to use the sprite based weapon, because it uses less memory.

- Sprite Based Weapon:
The idea is a sprite (tile) is drawn next to the player, when he's in attacking state (action step 3).
To set the Sprite Weapon tile used, opn the "Project Settings > User Constants" and modify the "SPRITE_WEAPON_V" value (the tile used when the player is attacking vertically) and the "SPRITE_WEAPON_H" value (the tile used when the player is attacking horizontally). The weapon is a not animated 8x8 tile (using the Sub 2 palette).


(The tiles used for the sprite weapon are the 8 and 9)

The action step (animation) used when attacking with the weapon is the action step 3.
The input script to use with will be the "b_create_weapon_sprite.asm" script (in the "Basic_NoScroll_TwoPlayers\ModuleScripts\InputScripts\Adventure\" folder).

If you need a bigger or an animated weapon... I'd suggest to switch to a Melee Object Weapon.

- Melee Object Weapon:
In order to use an object instead of a sprite for the Weapon, you need to disable the sprite based weapon first. Go to "Project Settings > User Constants" and set the "SPRITE_WEAPON_V" & "SPRITE_WEAPON_H" constants to "0".
By default, the object used is the Melee object (01). However, you could change for another object by modifying the "OBJECT_PLAYER_MELEE" constant.


Now, set your Melee object: "player weapon", edge/solid reaction" to "DestroyMe". Animation type if you have animations.


For the action step 0, End Action to "DestroyMe" with a timer of "1"
And don't forget to set the bounding box.
The input script to use with will be the "b_create_melee_object.asm" script (in the "Basic_NoScroll_TwoPlayers\ModuleScripts\InputScripts\Adventure\" folder).
The action step (animation) used when attacking with the weapon is the action step 3 (defined in the script).


PLAYER WEAPON OFFSET
To set the origin position / offset, go to "Game Objects", click on the "Melee/Projectile" button to display "Melee".



And set the position for each facing direction.


PLAYER PROJECTILES
The magic/projectile is only available when the Weapon 2 is unlocked. You can get it from a NPC. Or set it unlocked from start, via the "Project info" dialog.
By default in this module, the object used is the Projectile Source object (02). However, you could change for another object by modifying the "OBJECT_PLAYER_PROJECTILE" constant.
Set the projectile object as usual (size/graphics, "player weapon", "speed", "acceleration" and a bounding box)



The input script to use with will be the "a_create_projectile_adventure.asm" script (in the "Basic_NoScroll_TwoPlayers\ModuleScripts\InputScripts\Adventure\" folder).
The action step (animation) used when attacking with magic/projectile is the action step 3 (defined in the script).


PLAYER DEATH
When any player dies, it uses the Player Death object, by default it's the "Effect 0" object (08). It's defined by the "OBJ_PLAYER_DEATH" constant in "Project Settings > User Constants". Select this object and rename it to "Player Death".
Because both players maybe not use the same graphics/animation... each uses a different action step.
The Player 1 uses the Action Step 0 (like it works in the Basic modules) and the Player 2 the Action Step 1.
Set your Player Death:
For Action Step 0 (corresponding to the player 1), End Animation to "Restart Game", with a animation speed.
For Action Step 1 (corresponding to the player 2), End Animation to "Restart Game", with a animation speed.


And don't forget the bounding box.


PLAYER VICTORY
When the level complete/win is executed (if using a Collectable tile), this object is displayed. By default it's the "Effect 2" object (10). It's defined by the "OBJ_PLAYER_VICTORY" constant in "Project Settings > User Constants". Select this object and rename it to "Player Victory".
Like the Player Death object, the Player Victory object uses separate action steps for Player 1 and Player 2.
Set your Player Victory:
For Action Step 0 (corresponding to the player 1), End Animation to "GoToWarp", with a animation speed.
For Action Step 1 (corresponding to the player 2), End Animation to "GoToWarp", with a animation speed.


And don't forget the bounding box.


MONSTER DEATH
Set your monster death as usual. Like in tha Basic modules, by default, it uses the "Effect 1" game object (09).
For Action Step 0, End Animation to "DestroyMe", with a animation speed… And don't forget the bounding box.


MONSTER DROPS
By defaut the monster drops are disabled. If you want you monsters to drop random items when they die, in the "Proejct Settings > User Constants", define the "OBJ_MONSTER_DROP_ITEM1", "OBJ_MONSTER_DROP_ITEM2" and "OBJ_MONSTER_DROP_ITEM3" constants. For example, if you want your monster to drop an Health Pickup, or Charge Pickup or a Currency Pickup… just set the constants to "4", "5" and "7".
If "0" for all, no object will be drop.


MONSTER PROJECTILES
When your monster objects are set to "Shoot Forward" or "Shoot at Player", by default, it creates the Projectile object (03). It's defined by the "OBJ_MONSTER_PROJECTILE" constant in "Project Settings > User Constants".

- Shoot Forward:
The shoot forward/straight uses the Action Step 0. Set your projectile object to "Monster Weapon", give it a "Speed" and "Acceleration", edge/solid reaction" to "DestroyMe".
Set nothing for Action Step 0.


And don't forget the bounding box.

- Shoot at Player:
The shoot at Player uses the Action Step 1. Set your projectile object to "Monster Weapon", give it a "Speed" and "Acceleration", edge/solid reaction" to "DestroyMe".
For Action Step 1 set the "Use aimed Physics" (because shoot at player physics code is different).


And don't forget the bounding box.


TWO PLAYERS MODE
The 2 players modules can play in "1 player" mode (only the player 1, like basic modules) or in "2 players" mode.
This is defined by a User Variable named "player2Mode", in the "Project Settings > User Variables".
If the value is "0": it's 1 player only.
If the value is "1": it's 2 players.
This variable can be set via a input script "SelectionStartScreen.asm" script (in the "Basic_NoScroll_TwoPlayers\ModuleScripts\InputScripts\" folder).


START MENU / SELECTION

So, in order to be able to select the mode ( 1 player or 2 players mode), the Start Screen has a SELECTION system.
First, in the "Project Infos" dialog, uncheck the "skip Start Screen".
By default, a cursor/selector is displayed on the Start Screen. This cursor position reflects the value of the "player2Mode" variable.
The sprite used as a cursor is the tile 127 (the last 8x8 tile of the GameObjectTiles.bmp"), you can change for another one by modifying the "STARTSCREEN_CURSOR_TILE" user constant.
There are two position items, the first one is for the 1 player mode and the second for the 2 players mode.



The position of the first item, is defined by the "SELECTION_POS_X" and the "SELECTION_POS_Y" user constants, it's the pixel coord on the screen.
The input script to use with the selection will be the "SelectionStartScreen.asm" script (in the "Basic_NoScroll_TwoPlayers\ModuleScripts\InputScripts\" folder).
And the "StartGame.asm" to validate and start the game.


INPUT S SCRIPTS / INPUTS EDITOR

Now you have set all your objects, monsters, graphic assets and screens… we'll see how to assign input scripts, that is slightly different than it's in the Basic modules.

First, in the "Scripts > Input Scripts", add all the scripts we will need for our inputs:
- from the "Basic_NoScroll_TwoPlayers\ModuleScripts\MovementScripts\Adventure" folder, take all the scripts.
- from the "Basic_NoScroll_TwoPlayers\ModuleScripts\InputScripts\Adventure" folder, take the "a_create_projectile_adventure.asm" and the "b_create_weapon_sprite.asm" scripts, if you use the sprite based weapon (or the "b_create_melee_object.asm" one, if you want to use the Melee Object).
- from the "Basic_NoScroll_TwoPlayers\ModuleScripts\InputScripts" folder, take all the "SelectionStartScreen.asm", "StartGame.asm" and the "b_activate_text_box.asm" scripts.

Now, go to the "Input Editor".
All the scripts need to be assign either to the "Player 1" and/or the the "Player 2" as Target (no more NULL).
So, for example with the "StartMovingPlayerDown.asm", select "MainGame" for Game State, "Player 1" for Target, "StartMovingPlayerDown.asm" for Script to Run, "Hold" and the Down direction button. And click on "Add".
Now, set "Player 2" as Target. And click on "Add".
Your player 1 can go down. Your player 2 can go down.


Do exaclty same for all the Movement scripts… and the weapons scripts.

For the SelectionStartScreen and the GameStart scripts, I'd suggest to just assign them to the "Player 1" inputs.


Voilà, it should be ready to Export & Test.
Let's me know if something is not clear and need more informations.
 

TolerantX

New member
The Monster drops... What are drops 1 2 and 3 and where can we define them (*what they are, what they do, and where the sprite is located as well)?
 

jcramer

New member
not sure what I'm doing wrong, but when I press A or B to use a weapon, the game crashes, just disappears. What causes that to happen?
 

dale_coop

Moderator
Staff member
Interesting... maybe a wrong value/object in X or Y register...?
Are you using custom scripts for weapon? or the two players core folder ones?
 

jcramer

New member
no custom codes, i'm just using what came with the 2 player core. I'm talking with joe rossi about it right now in the fb group.
 

dale_coop

Moderator
Staff member
Ok, so the problem was the scripts: ChangeToIdleAnimation.asm and ChangeToIWalkingAnimation.asm
Don't use them, guys (in fact, they are not needed anymore... I don't know why I didnt removed them :p)
I will fix them and update the bundle in the next few days.
 

jcramer

New member
I have a question, is it possible to do the trick with the 4 npc's that send you to 4 different screens (like troll burner saves christmas) in the 2 player module??
 

dale_coop

Moderator
Staff member
Humm... yep, you could implement the trick explained here: http://nesmakers.com/viewtopic.php?p=9717#p9717 But the code would be slightly different.
Here 's a quick tutorial for the 4.15 Two Players module:

1/ In the "Project Settings > User Variables", add a new variable named "TextIDScreen" with initial value "0".

2/ Make a new script named "HandleTextBox_openShopWarps.asm", with that:
Code:
HandleTextBox:

;; textboxHandler
 ; 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
  ;7 = Textbox is active.
   ;    6 = Black box is being created, will then create text.
    ;        5 = Attribute update to black.
     ;           4 = text is being created.
      ;             = loop to 5 if more text.
       ;             3 = Black box is being created, with then restore NT
        ;                 2 = Attributes to main NT
         ;                     1 = restore NT
          ;                          0 = check for "more" text.
			


	LDA textboxHandler
	AND #%10000000
	BNE textboxIsActive
	RTS ;; textbox is inactive.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
textboxIsActive:
	LDA updateNametable
	BEQ notAlreadyWritingToNT
	RTS
notAlreadyWritingToNT
	;HideSprites
;; DO TEXT BOX STUFF.
	;; Which text box stuff to do is determined by the textboxHandler byte.
	;; if it is active, but all other bits are inactive, that means we have just activated and we need to turn
	;; this system on.
	LDA textboxHandler
	AND #%01111111
	BNE textboxSettingsAlreadyOn
	;;; get textbox settings
 ;; skip resetting the offset.
	LDA #$00
	STA updateNT_offset
	STA updateHUD_offset

	STA updateNT_H_offset
	STA updateNT_V_offset
	
	;;; zero out the things offsets and start creating the blackout box.
	LDA #%11000000
	STA textboxHandler ;; flow right into the next.
textboxSettingsAlreadyOn:
	
	LdA textboxHandler
	AND #%01000000
	BEQ notCreatingBlackBox
	;;;; CREATE THE BLACK BOX.
	;;;; The frist phase is to create the black box.
	;;;; no matter what color the text box will be, or which palette it will use
	;;;; it will always first create a box of "blanks" so it can be changed to whatever
	;;;; background attribute you'd like without noticing the attribute change.
	JSR CreateBlackBox
	;;; now the black box has been created.
	
notCreatingBlackBox:
	LDA textboxHandler
	AND #%00100000
	BEQ notSettingTextboxAttributes
	JSR isWritingTextboxAttributes
	RTS
	
	;;; set textbox attributes.
notSettingTextboxAttributes:
	LDA textboxHandler
	AND #%00010000
	BEQ notUpdatingTextboxText
	;; updating textbox text.
	JSR isWritingTextToTextbox

	RTS
notUpdatingTextboxText:
	LDA textboxHandler
	AND #%00001000
	BEQ notErasingTextboxText
	JSR CreateBlackBox
	RTS
notErasingTextboxText:
	LDA textboxHandler
	AND #%00000010
	BEQ notRestoringNametables2
;	JSR CheckForEndOfTextString
;	LDA gameHandler
;	AND #%00100000
;	BEQ notRestoringNametables2 ;; because we have finished.
	JSR RestoreNametableData
notRestoringNametables2
	RTS
	

	
	
	
	
	
	
	
	
	
	
	
	
	
getUpdateTileOffsetPosition:
	LDA #BOX_1_ORIGIN_X
	CLC
	ADC updateNT_H_offset
	STA tileX
	
	LDA #BOX_1_ORIGIN_Y
	CLC
	ADC updateNT_V_offset
	STA tileY
	JSR coordinatesToMetaNametableValue
	;;; spits out updateNT_pos as low and updateNT_pos+1 as hi of address to write.
	;;; right now, this is in terms of a single nametable, starting at $20 as the high top left corner high byte.
	
	

	
;;;; FOR HITE BYTE:
;;;; Take columnTracker and divide by 2 so you get a value 0-16
;;;; Add that number to BOX_1_ORIGIN_X.
;;;; If the sum is less than 16, this should stay in the same nametable.
;;;; Otherwise, it should cross nametables.
	
	LDA updateNT_pos+1
	AND #%00000011 ;; 0,1,2 or 3
	clc
	adc #$20
	STA updateNT_pos+1
	RTS
	
	

	
	
isWritingTextToTextbox:
	;;; already in bank 17.
	;; we need to get positioning.
	LDA #BOX_1_ORIGIN_X
	ASL
	CLC
	ADC updateNT_H_offset
	STA temp3
	AND #%00011111
	STA tileX
	
	LDA #BOX_1_ORIGIN_Y
	ASL
	CLC
	ADC updateNT_V_offset
	STA tileY
	
	JSR coordinatesToNametableValue
	;JSR checkNTforNewTile
	;; temp has position value.
	;LDA temp
	;STA updateNT_pos
	
	
	
	LDY textVar ;; what string
	LDA screenText,y
	TAY
	LDA stringsTableLo,y
	STA temp16
	LDA stringsTableHi,y
	STA temp16+1
	LDY textboxOffsetHold
	LDA (temp16),y
	
	;; this is where we determine if this is a special character or a normal letter/number to update.
	CMP #_END
	BNE +
;;;; END:
EndText:
	;; this is and _END value.
	;; it turns off writing to the textbox.
	
	LDA textboxHandler
	AND #%01111111
	STA textboxHandler
	;;;;; textbox handler stays on the same state
	;;;;; but deactivates.
	;;;;; it will start again if bbutton is pressed again
	;;;;; on state 00001000, which will begin the 'turn off' process.
	
	JMP doneTextUpdate
+
	CMP #$FE ;; is it a new line?
	BNE notANewLine_text
;;;; NEW LINE:


	LDA #$00
	STA	updateNT_H_offset
	INC updateNT_V_offset
	INC textboxOffsetHold
	
	JMP doneTextUpdate
notANewLine_text:

	CMP #_ENDTRIGGER
	BNE notEndTrigger
	;; is an end trigger
	INC textboxOffsetHold ;; get the very next value.
	LDY textboxOffsetHold
	LDA (temp16),y
	STA temp
	;;;; this now has the trigger to change.
	TriggerScreen temp
	JMP EndText
notEndTrigger:

	CMP #_ENDITEM 
	BNE notEndItem
	;;; gives player an item.
	INC textboxOffsetHold ;; get the very next value.
	LDY textboxOffsetHold
	LDA (temp16),y
	TAY
	;;; this now has the bit to flip in BOSSES DEFEATED constant.
	LDA ValToBitTable_inverse,y
	STA temp
	ORA weaponsUnlocked
	STA weaponsUnlocked	
	TriggerScreen screenType ;; will flip the current screen type
	;PlaySound #SFX_DO_TRIGGER
	JMP EndText
	
notEndItem:
;; begin check for warps -->> : 
	CMP #_ENDSHOP
	BNE notEndShop
	;; keep the Text Index of the NPC
	LDY textVar
	LDA screenText,y
	STA TextIDScreen
	JMP EndText
notEndShop:
;; <<-- end check for warps
;; The rest of the normal code from here:

	CMP #_MORE
	BNE notMoreText
	LDA #%10000000
	STA textboxHandler
	;; flip a more text flag.
	LDA #$01
	STA moreText
	INC textboxOffsetHold
	JMP EndText
notMoreText:
;;;; NORMAL VALUE
		;;;;; The look up was a normal letter, number, or other hud value.
	CLC 
	ADC #$C0
	STA updateHUD_fire_Tile	
	
	LDA updateNT_pos
	STA updateHUD_fire_Address_Lo
	LDA updateNT_pos+1
	STA updateHUD_fire_Address_Hi
	INC updateNT_H_offset
	INC textboxOffsetHold
doneTextUpdate:	

	RTS
	
	
	
	
	
	
	
	
	
	
	
CreateBlackBox	
	LDX #$00
	
;;; DRAW METATILE 1
	;; this macro SETS it to change on the next vblank update.
	;; starting at address hi-lo, with the tile in the third argument.
	;; if it sees #BLANK_TILE, it will create a meta tile of four blank tiles.
	;; if it sees any other value, it will create a metatile starting with 
	;; that index as the top left corner.
	
	;;;;;;; IF THE GAME DOES NOT SCROLL:
	;;;;;;; You can simply read the box value, do a little math, to get the offset
	;;;;;;; of the address for the top left corner, and skip the whole business of
	;;;;;;; finding the offset based on the scroll.
	
	;;;;;;; IF THE GAME DOES SCROLL:
	;;;;;;; YOu will need to get the offset value so it is at the box value position
	;;;;;;; compared to the CAMERA rather than zero.
	
	;;;;;;; Fortunately, we already have tables set up for columnTableLo and columnTableHi
	;;;;;;; which we use to handle the column for scrolling.  
	;;;;;;; we can use the columnTracker value to help determine the proper offset.
	
	;;;;;;; There can only be 32 columns.
	
	;;;;;;; And we will use updateNT_offset to continue this over frames, 
	;;;;;;; and to handle tile to offset.
	;;;;;;; this will be set to zero wherever HandleTextBox is activated.
	;;;;;;; It needs to, in some way, be boolean (like a key press, or using a boolean var).
	; LDA #$00
	; STA updateNT_H_offset
	; STA updateNT_V_offset
	;; THESE ALSO MUST BE SET IN THE BOOL VAR PLACE
	;; Whatever code is calling this must also set these to zero.

	
	
	
	LDA #$00
	STA tilesToWrite
	LDA #$04
	STA dummyVar2
DoLoopThing:
	JSR getUpdateTileOffsetPosition
	SetMetaTileToChange updateNT_pos+1, updateNT_pos, #BLANK_TILE

 	INC updateNT_H_offset
	LDA updateNT_H_offset
	CMP #BOX_1_WIDTH
	BEQ ++
	DEC dummyVar2
	LDA dummyVar2
	BEQ +
	JMP DoLoopThing
++ ;; width has been reached.
	;; now to test the height, and to move h pos back to the left.

	
	BEQ dontEndCreatingBlackBox
	JMP EndCreatingBlackBox
dontEndCreatingBlackBox:
	
	LDA #$00
	STA updateNT_offset
	STA updateHUD_offset
	STA updateNT_H_offset
	INC updateNT_V_offset


+	

	LDA #$01
	STA updateNametable  ;; turn on write.
	
	LDA updateNT_V_offset
	CMP #BOX_1_HEIGHT
	BCS turnOffCreatingTextBox
	
	LDA updateNT_H_offset
	CMP #BOX_1_WIDTH
	BEQ turnOffCreatingTextBox
	JMP EndCreatingBlackBox
turnOffCreatingTextBox:
	
	;;;;;;;;;;;;;;;;;;;;;;;;;;
	;;; Setup text specifics
	LDA #$00
	STA stringGroupOffset
	STA updateNT_H_offset
	STA updateNT_V_offset
	
	LDA #BOX_1_ORIGIN_X
	ASL
	CLC
	ADC temp
	CLC
	ADC #H_PAD_TEXTBOX
	STA tileX
	LDA #BOX_1_ORIGIN_Y
	ASL
	CLC
	ADC #V_PAD_TEXTBOX
	STA tileY
	
;	LDA #$01
;	STA writingText ;; turn on writing text.
	LDA moreText
	BEQ +
	LDA #$00
	STA moreText
	JMP ++
+
	LDA #$00
	STA textboxOffsetHold
++
	STA updateNT_H_offset
	STA updateNT_V_offset

	LDA textboxHandler
	AND #%00001000
	BEQ continueToUpdatingAttributes
	;;; is turning textbox OFF, so no writing to text.
	;;; will have to allot for changing attributes back with the
	;;; bit 00000100
	LDA #%10101000 ;; turn on attribute update
	STA textboxHandler
	LDA #$00
	STA updateNT_H_offset
	STA updateNT_V_offset
	STA updateNT_offset
	STA updateNT_compensation

;	LDA xScroll_hi

;	AND #%00000001
;	BEQ oddToEven2
;	LDA #$27
;	JMP gotNtDeets2
;oddToEven2:
;	LDA #$23
;gotNtDeets2:
;	STA updateNT_tableLeft
;	STA updateNT_details

	;LDA columnTracker
	LDA #BOX_1_ORIGIN_X
	LSR
	TAY
	LDA attrColumnTableHi,y
	STA updateNT_tableLeft
	STA updateNT_details

	RTS
continueToUpdatingAttributes:
	LDA #%10001000
	STA textboxHandler
	LDA #$00
	STA updateNT_H_offset
	STA updateNT_V_offset
	STA updateNT_offset
	STA updateNT_compensation
	
	
;	LDA xScroll_hi

;	AND #%00000001
;	BEQ oddToEven
;	LDA #$27
;	JMP gotNtDeets:
;oddToEven:
;	LDA #$23
;gotNtDeets:
;	STA updateNT_tableLeft
;	STA updateNT_details
	
	;LDA columnTracker
	LDA updateNT_H_offset
	CLC
	ADC updateNT_offset
	ASL
	AND #%00011111
	LSR 
	TAY
	LDA attrColumnTableHi,y
	STA updateNT_details
	
	LDA #%10100000
	STA textboxHandler
	;;;;;;;;;;;;;;;;;;;;;;;;;;;
	RTS
EndCreatingBlackBox:	
	LDA #$01
	RTS
	
	
	
	
RestoreNametableData:

	

	;;; FIRST we need to find the metaNametale value from the ROM.
	;;;;;;;;;;LESSER PRIORITY;;;;;;;;;;;;;;
	;;; THEN we need to check it againt collision type to / screen state to see if it should be 
	;;; change (for instance, a tile that changes at night / saved / changes if no monsters, if there are no monsters, etc)
	;;; THEN, we should probably always just restore the hud at the end.
	;;; the problem is, the data we need to fetch is in bank 16, then screen bank, 
	;;; while we are currently in bank 17 with this routine.
	;;; so restoration of nametable, or at least analysis of whate tiles to write, will have to happen OUTSIDE of this routine
	;;; We handle it in HandleBoxes, which will populate updateTile00-03, and respect paths.
	;;; And we handle POSITION to update here.

	LDX #$00
	LDA #$00
	STA tilesToWrite
	
	JSR getUpdateTileOffsetPosition
	
	

	LDA updateNT_pos
	STA temp
	LDA updateNT_pos+1
	STA temp1
	

	SetTileToChange temp1, temp, updateTile_00
	LDA temp
	CLC
	ADC #$01
	STA temp2
	LDA temp1
	ADC #$00
	STA temp3
	
	
	SetTileToChange temp3, temp2, updateTile_01
	
	LDA temp
	CLC
	ADC #$20
	STA temp2
	LDA temp1
	ADC #$00
	STA temp3
	
	
	SetTileToChange temp3, temp2, updateTile_02
	
	LDA temp
	CLC
	ADC #$21
	STA temp2
	LDA temp1
	ADC #$00
	STA temp3
	
	SetTileToChange temp3, temp2, updateTile_03
	INC tilesToWrite
	LDA #$01
	STA updateNametable
	
	INC updateNT_H_offset
	LDA updateNT_H_offset
	CMP #BOX_1_WIDTH
	BNE dontReturnToGame
	LDA #$00
	STA updateNT_H_offset
	INC updateNT_V_offset
	LDA updateNT_V_offset
	CMP #BOX_1_HEIGHT
	BNE dontReturnToGame
	LDA #$00
	STA textboxHandler
	STA updateHUD_offset
	LDA gameHandler
	AND #%11011111
	STA gameHandler
	;ShowSprites

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; check to see if there is behavior after a text box.

;;;; THIS WOULD WARP YOU TO A SCREEN AFTER TEXTBOX.
	LDA TextIDScreen 
	CLC
	BEQ +
		STA warpToScreen
		LDA #$00
		STA TextIDScreen
		STA newGameState
		LDA warpMap
		STA currentMap
		CLC
		ADC #$01
		STA temp
		GoToScreen warpToScreen, temp, #$02
		LDA #$00
		STA playerToSpawn
		; LDX player1_object
		; CPX #$FF
		; BEQ	++
		; DeactivateCurrentObject
		; ++
		; LDX player2_object
		; CPX #$FF
		; BEQ	++
		; DeactivateCurrentObject
		; ++		
		; LDA #$01
		; STA loadObjectFlag
		LDA mapPosX
		STA newX
		LDA mapPosY
		STA newY
	+
	; LDA #$01
	; STA activateWarpFlag
	; PlaySound #SND_ENTER
	; LDX player1_object
	; LDA Object_x_hi,x
	; STA mapPosX
	; LDA Object_y_hi,x
	; STA mapPosY
	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
	
	
dontReturnToGame:

	RTS
	
	
	
	
	
	
	
	
isWritingTextboxAttributes:
	;; handle all four quadrants of the attribute.
	
	
	RTS


3/ Assign the "HandleTextBox_openShopWarps.asm" script to the "Handle Text Box" element in the "Projet Settings > Script Settings".

4) Make some NPC monster/objects and put them on the screen

5) Set your Texts, for the screen warps. If you want a warp to Screen 16 (X=0, Y=1) then set your "Text 16"... and a warp to Screen 25, set your "Text 25" (X=9,Y=1)... using the text index corresponding the screen index you want.

And for each Text you set, chose the "Open Shop" action (currently not used so we will use it for the warp to the textindex screen).

6) Add all those warp Text to a Text Group:

And assign the Text Group to your main screen:


Now, the multi warps should work.
 

jcramer

New member
Took me a while to wrap my head around the logic of it, but here it is, multi warps in 2 player mode. Thanks for your help! I have one more question and I should be good to run with it and build levels... Can I use hurt tiles in the 2 player core?
https://www.youtube.com/watch?v=lPd6TKtlj0Y&feature=youtu.be
 

dale_coop

Moderator
Staff member
Wow jcramer, it's awseome! Great video, the game looks fantastic.
About the hurt tiles... not sure it is compatible with the 2 players core. Which script you wanted to use?
 

dale_coop

Moderator
Staff member
Ok, did some tests.... (it's my lunch time).
Here's a Player Hurt Tile script you can use with the 2 players modules:
Code:
	CPX player1_object
	BNE +
	JSR continueWithPlayerHurtTile
	+
	CPX player2_object
	BNE +
	JSR continueWithPlayerHurtTile
	+
	JMP doneWithPlayerHurtTile


continueWithPlayerHurtTile:	
	LDA #TILE_SOLID
	STA tile_solidity

	LDA Object_status,x
	AND #HURT_STATUS_MASK ;; if the monster is hurt, it can't hurt us
	BEQ +
	JMP doneWithPlayerHurtTile
	+
	
	LDA Object_health,x
	CLC
	SEC
	SBC #$01 ;; subtract other's strength
	CMP #$01
	BCS goWithPlayerHurtTile
	
	;PlaySound #SND_HURT_PLAYER
	JSR HandlePlayerDeath
	JMP doneWithPlayerHurtTile
	

goWithPlayerHurtTile:
	STA Object_health,x
	;;dale_coop player2:
	LDA player2Mode
	BEQ +
	CPX player2_object	
	BNE +
	LDA Object_health,x
	STA myHealth2
	;; update HUD :
	STA hudElementTilesToLoad
	UpdateHud HUD_myHealth2
    ;; TURN ON handling the hud
	JMP ++
	+
	LDA Object_health,x
	STA myHealth1
	;; update HUD :
	STA hudElementTilesToLoad
	UpdateHud HUD_myHealth1
    ;; TURN ON handling the hud
	++
	
	LDA Object_status,x
	ORA #%00000001
	STA Object_status,x	

	LDA #HURT_TIMER
	STA Object_timer_0,x
	ChangeObjectState #$00,#$02 ;; uses idle for hurt state.
	
	PlaySound #SND_HURT_PLAYER
	
	LDA selfCenterX
	STA recoil_selfX
	LDA selfCenterY
	STA recoil_selfY
	LDA selfCenterX
	CLC
	ADC Object_h_speed_hi,x	
	STA recoil_otherX
	LDA selfCenterY
	CLC
	ADC Object_v_speed_hi,x	
	STA recoil_otherY

	JSR DetermineRecoilDirection


doneWithPlayerHurtTile:
 

jcramer

New member
Thanks, I appreciate your feedback, there's a lot I want to do with this game. I'm not sure exactly which script, I'm looking for a tile that's similar to the death tile, but only takes 1 hit point instead of instant death.
 

RicePixel

New member
So I was able to successfully get the module to work in my game but I am curious on how to get player two to use a different colour scheme. Both characters show up using the same colour palette and I can't seem to change player 2's colours in NESMAKER.
 

dale_coop

Moderator
Staff member
All the "Game Objects" use the same sub-palettes: the ones assigned to the "Player" object.
You can assign 2 different sub-palettes to that object (one sub-palette for "Sub 1" and one for "Sub 2").
Then you have to be creative to use one or the other... or a mix... hen designing your players (and all your game objects).
 

RicePixel

New member
Thanks, I was confused trying to get it to work but the outcome is sick. Now I can make my game with two players in mind. Thanks for making this module.
 

Attachments

  • game.gif
    game.gif
    124.6 KB · Views: 2,879

RicePixel

New member
I'm a little confused on the weapon set up. I followed the https://www.youtube.com/watch?v=wH6G296onhs&t=4825s and https://www.youtube.com/watch?v=j4TlI6ppx08&t=194s for reference on getting an NPC to give me a sword. what I really want to get down first is the text box to appear and then have the NPC give me the sword and then have it appear in my HUD for both players.

game_000.png

Right now I have my HUD set up to have a spot for player 1: health, weapon, and projectile. The coin and keys portion i'm assuming is a shared element between players.

I'm using the b_create_weapon_sprite.asm to initiate the text box from the NPC and have him give me the weapon.

inputs.PNG

Here is the monster set up as an NPC

monster.PNG

The HUD with a text box

hud.PNG

The monster also has the dialogue set up as well.

text.PNG

I'm not sure what I am missing to get the text box to appear. The monster has a bounding box, I have a bounding box but when I got near him and press b nothing happens.
 
Top Bottom