Adding functionality to the text system.

Post Reply
User avatar
chronicleroflegends
Posts: 189
Joined: Thu Sep 06, 2018 3:51 am

Adding functionality to the text system.

Post by chronicleroflegends » Mon Jul 22, 2019 12:28 am

Hello everybody, I have been experimenting with the text system, and I had requests to make a tutorial if I figured this out so here goes:

Is the text character limit way too small for what you need in your game? Wish you could extend it?
Do you want to do a custom action at the end of your textbox? not just win the game or trigger your screen. Want to make that action be -anything-?

This tutorial is for you!

[Difficulty: Advanced - basic understanding of ASM6502. Some small parts of code will need to be customized to your game]
[Dependancies: Autotext variable (for extended text boxes) If you do not have, see additional tutorial at the end.]
[WARNING: Whenever you are modifying existing scripts, please always make a backup of the original]

Note: This partially replaces the currently implemented inventory system for nesmaker so this should be treated as a temporary solution until the RPG module improves this the right way. If you do this, you will not be able to flip weapon bits for the player by just selecting them from the drop down menu. You will have to add a small block of code for each
item you want the player to unlock. (Don't worry, its easy. Very small copy-paste block of code)

So what to do:

We are going to be modifying the text end actions scripts. Currently all these let you do is win the game, unlock a weapon, or trigger a screen (by default)
First we are going to make it where we can have our own custom actions.

Open your handle text box script, and find this block of code:

Code: Select all

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
    ORA weaponsUnlocked
    STA weaponsUnlocked
    
    JMP EndText
We are hijacking this part for our own needs.
comment out this part:

Code: Select all

TAY
    ;;; this now has the bit to flip in BOSSES DEFEATED constant.
    LDA ValToBitTable_inverse,y
    ORA weaponsUnlocked
    STA weaponsUnlocked
Now that we have that commented out we still have in the accumulator variable at this point in our code an integer. This will be a number 0-15 that normally reflects which weapon bit to flip.
BUT as you are unlikely to use all 15 of them, we can use it as an indicator to do whatever we want.

So the first thing we are going to add is the ability to flip our weapon bits again!
(Huh, why?) Well you may want to use SOME of them for their intended purpose, right?
Anyways, add this block of code after the one you commented out:

Code: Select all

    ;; Do a specific thing based on which 'item' given
    
    ;; Give player a weapon/inventory item
    CMP #$00
    BNE +
    TAY
    ;;; this now has the bit to flip in BOSSES DEFEATED constant.
    LDA ValToBitTable_inverse,y
    ORA weaponsUnlocked
    STA weaponsUnlocked
    JMP EndText
  +:
    ;; Didn't hit a match, do nothing
    JMP EndText
This will flip weapon bit 0, or #%00000001. BUT only if it gets 0 as the response.
It will not do anything for any other number.
If you have any weapon unlocks linked to text in your game, now is your chance to get them working again.
Just paste

Code: Select all

    CMP #$00
    BNE +
    TAY
    ;;; this now has the bit to flip in BOSSES DEFEATED constant.
    LDA ValToBitTable_inverse,y
    ORA weaponsUnlocked
    STA weaponsUnlocked
    JMP EndText
  +:
After the +: in the code above, and change the CMP #$00 to the correct weapon number/bit

Now, for ease of remembering, I suggest modifying your labels.
The labels for that drop-down menu are located in Project Labels>Magic Types
00 is Melee
01 is Projectile
Etc.

Now for the fun stuff, custom actions.
As an example, lets make our textboxes longer.
This we can do by making the end of one textbox lead directly into another.
So you can make 1 textbox seem to be the length of 4.
So if you wanted 1 -really- long textbox on the screen, you would split the text between all 4 in the text group, and have the first three have this end action.
add this after the last +: in your new code (change the CMP #$01 to whatever number you want it to be, you just have to remember which it is for the dropdown menu.)

Code: Select all

;; Extend text box
    CMP #$01
    BNE +
    ;; Set the autotext flag  ;; AUTOTEXT DEPENDANCY
    LDA #$01
    STA autotextEnable 
   
    ;; Advance text =============
    ;; Select the next text box
    LDA textVar
    CLC
    ADC #$01
    STA textVar

    ;; activate the text-box:
    LDA gameHandler
    ORA #%00100000
    STA gameHandler
    LDA #%10000000
    STA textboxHandler
    
    JMP EndText
  +:
Now your textbox should flow automatically into the next text entry in the group. I have not tested what happens if you use it on entry 4, so treat that as undefined behavior.

In a similar method to just above, you can add any action you want to the end of the textbox. Just make sure each action has a unique CMP # and it must end with JMP EndText +:

BONUS TUTORIAL:
If you do not already have Autotext enabled, and you need the variable:

Step 1)
add user variable: autotextEnable
default value 0

Step 2)
in your input scripts you should have an activate textbox script. Near its start should be this block. Add the indicated lines.

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PART 1: Determine if the text box is already drawn          
;; Especially when using button commands to activate a textbox, we want the first push
;; to activate it, while the second push begins the deactivate process.
;; Bit 4 determines if the box is currently drawn to screen or if there is no box
;; on screen, which tells the game whether to start the box-draw, or start the
;; restoration of nametable draw.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        LDA textboxHandler
        AND #%00010000               
        BEQ checkToTurnTheTextboxOn ;; start textbox
        ;; start nametable restoration
        ;; first, disable input:
        LDA gameHandler
        ORA #%00100000
        STA gameHandler
        ;; Then zero out offsets in case they are not set to zero.
        LDA #$00
        STA updateNT_offset
        STA updateNT_H_offset
        STA updateNT_V_offset
        STA autotextEnable ;; Reset auto-text flag   ;;; --- ADD THIS LINE ---
        ;;; flipping bit 7 starts the textbox code on next frame.
        ;;; Also flipping bit 3 puts it in "restore nametable" mode.
        LDA #%10001000
        STA textboxHandler
        ;;; Return from subroutine - textbox is now being
        ;;; overwritten by nametable data.
        RTS
       
    checkToTurnTheTextboxOn:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; PART 2: Check for NPC collision
;; In most standard NPC cases, you want to check an npc_collision flag
;; to see if you are colliding with an NPC or not.  This flag gets set in the
;; Object collision scripts if the object you are colliding with an object tagged
;; as an NPC. 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
        ;; Check to see if we are in an autotext  ;;-- Add all of this -----------------------
        LDA autotextEnable
        BEQ +
        LDA gameHandler
        ORA #%00100000
        STA gameHandler
        LDA #%10000000
        STA textboxHandler
        RTS
      +: ;;--------------------------------------------------------------------------------------------
      
        LDA npc_collision
        BEQ doneWithTextboxToggle ;; if it is zero, skip turning on textbox.
        

This should get autotext working for you.
(Hint: you can automatically activate text from just about anywhere using the same method as the text extension above. I like using monster actions.)

I hope this tutorial helps some of you out. If you notice any problems, or ways this could be improved please reply. I'm not the best programmer, and I am sure there are ways to improve or extend this.
~Do you believe in legends? ~
My Games: Nix: The Paradox Relic
User avatar
Artix
Posts: 19
Joined: Wed Nov 21, 2018 3:41 am
Location: Tampa, Floridas
Contact:

Re: Adding functionality to the text system.

Post by Artix » Mon Jul 22, 2019 2:06 am

This is fantastic Chronicleroflegends!
User avatar
dale_coop
Posts: 4206
Joined: Fri Feb 16, 2018 7:05 am
Location: France

Re: Adding functionality to the text system.

Post by dale_coop » Mon Jul 22, 2019 11:51 am

Awesome!
Great tutorial, chronicleroflegends. Thanks for sharing <3
-----
Sorry about my poor english
All I need: A Damn Fine Cup of Coffee
My games: PRESS START GAME / UNDERGROUND ADVENTURE / UNDERGROUND ADVENTURE (Arcade version - Byte-Off-2019)
User avatar
Bucket Mouse
Posts: 325
Joined: Wed Mar 07, 2018 2:25 am

Re: Adding functionality to the text system.

Post by Bucket Mouse » Mon Oct 07, 2019 9:34 am

Okay, I found a problem. This script as-is works for the Autotext tile, but it does not work for NPC dialogue.
It completely ignores the textVar addition part and repeats the previous text in an endless loop.

This doesn't happen with Autotext, it only happens with NPC. The culprit is in HandleObjectCollisions, specifically here:

Code: Select all

	;;;; enables a button to be used to activate a textbox.
	LDA Object_ID,x
	STA textVar
	;LDA gameHandler
	;ORA #%00100000
	;STA gameHandler
You have to put something in there that will skip around this command whenever the textVar addition is in progress.
Since we already have a variable I used that:

Code: Select all

LDA #$01
    CMP autotextEnable 
	BEQ skipOverwrite

	;;;; enables a button to be used to activate a textbox.
	LDA Object_ID,x
	STA textVar
	;LDA gameHandler
	;ORA #%00100000
	;STA gameHandler

	skipOverwrite:
This solves the problem but introduces another one: textVar never changes back, so all the dialogue for multiple characters on one screen will be identical.

To fix THAT problem I had to unflag our variable when the textbox has vanished, so I put this right after RestoreNameTableData in HandleTextBox:

Code: Select all

    LDA #$00
    STA autotextEnable 
Works now. So that's what you do.
Post Reply