top of page
Search

Project .sys//CRASH Development Log 5: Things Work Like Expected (For Once)

Welcome, welcome! First things first, you'll notice a change in the naming of the development logs! No longer are we NES Development Log. I figure after a few months it was time to at least give the project a working title, so for now I've been referring to it as .sys//CRASH, trying to tie into the cyberpunk theming. Whether that name will stick in the long run, who knows. But for now, we can at least call it that.


So, moving on to the task at hand, we had two tasks to tackle this past week, how did they go?


Week 2: July 21st - 27th

  • NPC Interaction

  • Pause Menu


NPC Interaction:

I opted to start with the NPC interactions because I figured between the two, it had to be the easier one, right?


Right.


Where to begin? I honestly wasn't sure, but when I'm in doubt about how to do something with NESmaker, my first instinct is to look to the "Learn" page on their website and see if any hints exist within their tutorial videos. And my guess would be if any tutorial would have NPC interactions in it, it would be the Adventure base. After all, all Zelda-style games need a source of your starting item!


And I was right. Not even 15 minutes into their basic level adventure tutorial, we learn just how to set up an NPC and associated text box. First step first, create a NPC. Unfortunately, here the Spriter's Resource fails us, as it doesn't actually have any of the overworld/town NPC assets. That means no town citizens, no king, no princess, and even no Garland for the first dungeon. But that's fine. This process is to learn how to make each of the individual tools to make our own game, rather than 1-for-1 recreating the original Final Fantasy. After all, I'm pretty sure Square Enix wouldn't appreciate us doing that anyways. So, for now, we can replace the town NPCs with the default enemy from the tutorial project: a little crab. Of course, we have to do some edits to his details. Change him from an enemy to a NPC, disable all his actions (so we can test properly), and place him on the map for interaction.


Then, we set up our text box location in the hud...



Write our dialogue that we need, and apply it to a group. Then, we just apply that group of text to the screen we need it on.



It does seem that, in the case of how the default interactions can be handled without custom scripting, that we are limited to 4 npcs with one interaction on a single screen, 1 NPC with 4 boxes of text, or any combination of the above, but limited to 4 max NPCs with 4 max boxes of text split between them. Next step, set up our interaction script. Thankfully, we have a fully pre-packaged script ready in the adventure game assets. Just assign the script to our A button press, and if it sees a NPC in front of us, we get...




Oh no... Okay, easy fix, and I even figured this one out myself! Turns out, the NPC dialogue uses the HUD system for the game. So, despite the fact that I'm creating a game type without a hud, if I want NPC dialogue on a screen, I need to use a "Double Main", rather than a "Double Main, no HUD" screen type. From there, I can hide the HUD on the screen itself and we get:


Ah, that's much better. While the font is off, and I'm not 100% sure how they managed to do both upper and lower case letters with just one font set, that's not needed for building the core systems. Nor is creating the custom textbox background.



So, that's that. Honestly, compared to how EVERYTHING else on this project has gone, this little item was super simple, barely an inconvenience.



Pause Menu

And here is where everything started to blur together. There's a reason this development log is so delayed. As I moved forward, I started to realize how interconnected the rest of the systems of this project would be, and as I jumped back and forth between them all, my deadline approached and I found myself too busy to update the devlog. So, rather than doing an individual post for each of the weeks that have passed, I'll just keep moving forward from here.


So, our first step in creating the pause menu was finding a way to store our position on warping to the pause menu, and returning to that position afterwards. Thankfully, we were able to find a hero that had already accomplished this. Thanks to NESmaker forum member Subotai, the scripting of this part wasn't difficult at all.


By loading the player object, we can store the object's current screen in a temporary screen variable, alongside our player's current x and y position on that screen, once that is done, we simply warp to our pause menu screen. That pause menu can be set to disable the player sprite, and once we warp there, as long as the screen type is set to a different game state (in the case, menu rather than main game), the player controls will be ignored in favour of controls set for the menu.


But how do we create a menu that can be navigated? Thankfully we have a saviour here as well in the form of user SciNEStist. First, we create the graphics of our intended menu, so we can know where everything will be sitting on the screen. Then, we make a note of the x and y coordinates of everywhere we want a cursor to be able to move to.


In a handy existing subroutine called extratables, we can add these values as a table calling for the x and y coordinates separately, tied to a variable we will increment with each selection. We can then add code to our existing "sprite pre-draw" subroutine that, if the game sees we are in the menu game state, will draw a specific sprite to whatever value on the freshly created menu table is associated with the correct menu option selected.


This was where we encountered our first little roadbump. The scrip that SciNEStist creates for navigating the menu simply cycles forward through the options, but we need a menu that can go forward or backwards. Since the forward option references the maximum value and if reached sets it to the minimum before incrementing the value, I realized we could do the opposite (compare to the minimum before setting to the maximum and then decrementing) to allow a backwards option, and then assigned these functions to the up and down arrow presses for the input.


Finally, we just needed a script to choose an option and execute an action. Tying this script to A, we just compare the value of which option we have selected, and choose to have it do a specific function when the values match. For our menu, it wasn't too difficult to figure out what we needed it to do. When we hit A, we need it to select an option. For our demonstration, we wanted the status option to allow us to select between the playable characters to see their status. This required adding a second table to our tables, alongside a second variable tracking which menu state we were in, drawing the cursor to a different set of locations depending which menu version we were on.


Now, by entering the menu we set our state to the first value, and can navigate between the five menu selections. If we select status, our menu state updates, and our cursor will only navigate between our four select-able players. If we choose one, it will warp us to the status screen. In return, pressing B will decrement our menu state value, returning us from the status to the menu screen, and from the character select to the five main menu option.


This leaves one final task to accomplish: updating the information on screen. Drawing in player sprites was fairly simple to figure out. We already had a "player class" variable within our player variables that we set up at the start. By checking for this in the sprite pre-draw, we can draw in the appropriate sprite from our game objects asset. However, beyond this it gets tricky.


My first attempt to get player values to draw to screen was through what I thought was the most simple method: the HUD. The HUD can display values in digits, and the digits can be tied to a variable. However, as it turns out, the HUD natively represents every value with the hexadecimal value, which is what the code uses behind the screen, and to get the value converted to and displayed in decimal was a process that required more knowledge than I possess or was able to learn in time. So, we opted to shelve the display of information for later, to come back to if enough time remained.


At the very least, we had a menu that would store the player's location data, allow us to view and navigate it, and when exited would return us to our exact position. Ignoring the inability to display data outside of sprite assets, a job accomplished successfully!


Week 3: July 28th - August 3rd

  • Shops

  • Resurrection Building

  • Save Point/Inn

    • Save system


Week three is where we, honestly, encountered the most problems, and they tie into one key factor: SAVING.


As it turns out, at least within the core modules, I couldn't find a built-in save function. I know some modules have continue points for continuing upon death within a single load, and I know saving is possible (other people have accomplished it for games they have created), but it is a step beyond my existing powers. It requires thorough understanding of not only Assembly, but of data banks and how to store values within them efficiently to store all the player data and reload it.


As such, after a week of searching and testing, I had to make an executive decision to cut saving from the demo project. Wasting more time on saving for a demo would only negatively impact the rest of the game.


So, we turned to shops, and alongside that the resurrection building. In modern game design for JRPGs, a resurrection building would not be a separate location, it would be tied to the Inn/save point, reviving and healing player characters at the same time. However, in Final Fantasy, the save point heal would not resurrect a dead player character, you had to pay to revive them. This is a function I'm still trying to determine if I want to keep in the final project or not. While I think tying the resurrection of dead allies to the healing from a save is more in line with modern JRPG design philosophy, having to pay to resurrect dead allies does fit within the narrative concepts of a cyberpunk setting, what with the rampant capitalist dystopia.


However, that is a decision for later. Our primary function here is to get the shops, res building, and inn to a state of working. Our first objective, storing the player location, is already accomplished, we figured out the process for that in the menu creation. However, warping to multiple screens based on our position is a different matter. By default, NESmaker handles warps through hard-coded values on each warp in/out, set in each screen's settings. We needed multiple options on a single screen, so... creating a new script it is.


First, we had to create a new script and assign that script to a "tile", so a "shop warp" tile could be placed on the screen collision just as solid tiles are. Now, we had to have that tile realize the player had hit it to activate (a function we were able to steal from the existing warp tiles that function based off of the warp in/out values set on each individual screen). Then, we could have the tile compare our game object's current screen value to a list of known values that we have set (screens that have shops). If we are on a screen with a shop, it knows which potential end points we have. If there are multiple, we compare our player coordinates with those of the shop tiles. Since for our demo screen we had 2, I compared the player y coordinate to a designated value of half the screen's height. If we were in the top half of the screen, we'd warp to the shop screen, and in the bottom half to the "inn", which for testing I set to be the status screen.


Navigation and selection within the shop itself was just a variation of the menu scripts: navigate up and down between options, open up subsequent menu options with the A button, backwards with B, and if we needed to store a value (eg: decrementing money when an item is purchased, store us as having an item, etc), we can update the appropriate variable upon selection. Eg: If we select a "knife", we can subtract the cost from our money variable, set a variable for us owning the item, and if we equip it, we can add the associated value to our appropriate attribute variables.

As for the actual shop functionality of showing items available for purchase and adding them to an inventory? This ties back into the problems we were having with updating on-screen values. Since we spent most of this week trying and failing to get saving functioning, I opted to leave this exact functionality for later. The core functions of the shop, being able to navigate, select options, increment and decrement appropriate variables, and leave, were added successfully.


Week 4: August 4th - 10th

  • Combat System

    • Targeting/Action Selection

    • EXP

    • Death

  • Random Encounters

  • Boss Encounter


Going into this week, I knew these tasks were going to take me the longest time, as it was the most in-depth topic, with a lot of inter-connecting variables. I assigned myself a week, followed by a week for the start menu. But, with the saving function removed, I decided I needed to give myself more time for this and, since the start menu would no longer need to deal with the save system, week 4/5 can now look like


Week 4 and 5: August 4th - 17th

  • Combat System

    • Targeting/Action Selection

    • EXP

    • Death

  • Random Encounters

  • Boss Encounter


The best place I figured out where to begin was with the EXP system. Without the ability to grow and improve, the combat system would be rather plain.


But, how do we implement an EXP system? I figured the best place to start would be with modifying the pickup/powerup scripts. Turns out, this was a good place to begin. This would allow us to test our code efficiently, since we could give ourselves experience points by just stepping onto a power-up item.


As I mentioned earlier, given how interconnected everything was, I found myself bouncing back and forth between topics over all the weeks, and it is actually in trying to test the EXP system that I encountered the issue with the HUD not displaying variables effectively. I would track that the HUD value would change, but not what the value would show as. Bring in: Mesen. An emulation tool, Mesen has the functionality that we need: display of the memory values in real time.


Whenever we test our game with NESmaker, it creates a .asm file, alongside a .txt file with all the info of the asm file, including where in memory each variable is stored. By looking through the .txt file for what memory location our variables will be stored to, we can monitor that location with Mesen's debug tools and see if our variables are updating correctly.


And adding EXP was rather a simple process. Upon running the script when the powerup is picked up, we simple increment the EXP value on our player by a specific amount.


But how do we level up, and how do we ensure that EXP doesn't get counted or added multiple times?


My solution, I think, was pretty efficient. When we gain EXP from a source (for testing our powerups, for the project from defeating enemies), the EXP value is added to a "EXPtoAdd" Variable. This stores the value until it is needed. Once we run the level up function, we add this EXP to our player's EXP variable, and then we take a look at our level variable.


Once we know our level, we compare our current exp to the exp value associated with the next level. If it matches or exceeds to threshhold value, we increment our level to the next value and run the comparison again for the next threshold value. This allows us to potentially level up multiple times if a high enough EXP value is obtained at once.


But, how do we improve? Improvement is integrel to leveling up. This would, normally, be as simple as just adding a value to the associated variable (eg: increase the strength variable by 1). However, we want variability.


Enter the doGetRandomNumber subroutine. I managed to find this subroutine referenced in the random movement function for enemies in the adventure module. At any time, we can ask our scripts to jump over to a different subroutine script and run it before continuing by using the JSR function. By asking the script to get a random number, and restricting it within a set value, assigned in binary at the same time, we can get a random value between 0 and the selected limit.


So, on level up, we can do this multiple times, and compare it to a value we decide. Want a value to increase on a specific level? Just do it normally. Want a 50% chance? Ask for a random number between 0 and 1, and if the value is 1, give the attribute the boost. Want a stat boost to have some variability? Before we add the value, we choose a base amount, and how much variation we want. Then, just run the random number, add our base value and the random value together, and then increment our variable by that amount.


And we have that working. In our level up script, we added functionality for the strength variable to be incremented by 0-5 on each level up. And this value changes depending on the seed of the random number function, which changes upon each boot-up. So, by running the level up function, our outcome values are slightly randomised.


Now, before we can implement combat, we need to be able to ENTER combat. So, random encounters.


We can do this quite simply with a tile created to run the random encounter variable. When the player is on the random tile, the random number function will run, and if the random number is 0, it will transport the player into combat. In addition, if combat is initiated, before the teleport, the function will roll a random value between 0 and 2. If 0 is rolled, 1 enemy will be added to combat. If 1 is rolles, two will be added, etc.


We do encounter a small glitch here. Unfortunately, due to how the base tile code runs, the random encounter trigger runs constantly if the player is on the tile, rather than just once as the player enters the tile. I was unable to find a way to run the script once per tile in the time I had allotted. In addition, due to how quickly the script runs, and due to running constantly, the enemy selection variable is run multiple times, ensuring three enemies are always selected for combat. However, when it comes to glitches, these are fairly small, and can be fixed once I determine how to run the script only a single time per tile.


Once we are on the combat screen, the rest of the system is pretty simple. Navigation through the combat screen is nearly identical to both the shop and menu screens: table of locations, increment and decrement, change value when a second menu type is needed. When we enter combat, we can draw our sprites as we do for the menu: based on the class variable. Enemies are drawn only if they have been added to combat, and health values are set upon implementation. When you select an enemy for combat, the script will grab our damage value, subtract any defense value the enemy has, and subtract the result from the enemy's health. If the enemy's health drops to 0 or less, it will be killed and its EXP value added to our EXPtoAdd variable. Otherwise, it will run the random number variable to select its target, then deal its variable damage, minus our defenses, to our HP. If our HP value drops to 0 or below for all enabled party members, the game ends.


If all enemies are defeated in combat, the level up script will run, checking EXP values and leveling up the player and the associated variabled.


You know, beyond a few glitches and some issues with the core functionality of NESmaker that I didn't have the time to learn how to brute force past, the past few weeks of progress actually went SMOOTHLY, which is more than I can say about everything else in this project.


Finally, that brings us to:


Week 6: August 18th - 24th

  • Custom Art and Sound Assets


I should have given myself more time for this. The problem is thus: I am not an artist, and the restrictions of the NES make the art creation process even mroe difficult. Each sprite is only 16x16 pixels, and within those 16x16 sprites, we can only have 3 distinct colours (plus black as transparancy). This means the amount of detail we can use is pretty low, and making low-detail sprites look good is a skill I have very little experience in. However, I did what I could with the time allotted to me. Starting with our overworld assets. While there is still room to improve, and spaces within our allotted tilesets to add more assets, I wanted to ensure that the core sprites we needed exist: the walls, some ruins for random battles, buildings and a city to denote places the player can't walk through and a town to enter, roads, ground types.


We also had to determine a colour palette for our area. Since the starting area is supposed to be inside a dome, I opted to use a dark purple to represent the ground coloured by the light through the dome, a lighter purple for where metal has been coloured by that light, and a dark grey for other details.


We also had to determine a colour palette for our player sprites. We have opted for two sets: one focused on greys and black for metal-forward designs, and a white with pink highlights for more cyber-tech inspired designs.


With our overworld sprites in functional shape, we moved on to the town sprites



and a player asset



And with that, all we have to do is put it all together, which I will detail... in the next post. This one is long enough as it is.

3 views0 comments

Recent Posts

See All

Comentários


bottom of page