Thursday, December 15, 2016
Modular Programming
Modular programming is like taking an algorithm, shattering it into a thousand pieces, and then burying each piece in a different location. Maybe it's more efficient. Maybe it's more versatile. I don't know. I imagine that it would make it harder for a hacker to copy/steal the code. But in RPG Maker's case, the user is intended to go in and fiddle with the code to make the program do what the user needs it to do, and this modular programming approach makes it extremely difficult to figure out how anything works. It's like a million tiny functions that look so simple, you can't imagine them accomplishing anything; but you know that together, somehow, they power a complex and robust program. But good luck finding the handful of grains in that sandbox that perform the behavior you wish to modify...
Sunday, May 8, 2016
Dragonfaith (MV) Alpha 2.0 - Greendale
My last release for Dragonfaith on RPG Maker MV contained little more than the prologue - which isn't much, but you gotta start somewhere. This release adds in the first town, which is fully explorable. I've renamed it "Greendale Village" in honor of my favorite album from one of my favorite bands, to give it a little more personality. The first town in my RPG is thematically inspired by many classic video games whose first stages are green, grassy stages (Super Mario Bros. 3 is one of the more prominent and memorable examples). The idea is to start the game off somewhere calm and unthreatening, before throwing the player into progressively more intimidating locales (e.g., forest, cave, mountain, desert, volcano, tundra). Greendale also represents the protagonist's hometown - a gentle, welcoming village to fight for and dream of returning to later on - and subtly introduces the player to a prominent theme of the game - the importance of nature and the conflict between living with it, and becoming victim to it. So, go ahead and explore!
I actually have a bit more of the game done already, but as I think I've explained before, getting the combat working is putting a hold on me releasing that just yet. I think I'm going to eventually have to just live with releasing parts of this game in a more and less unfinished capacity, just to get things moving along, because I'm not going to be able to fit all the pieces together neatly like a puzzle until I have the whole thing from start to finish at least storyboarded and constructed in some kind of outline format. I tell you, my OCD and perfectionism is wreaking havoc with my productivity on this project, but I'm trudging forward, however slowly at times. If you have the time and the inclination to check out this latest release, as always, let me know your impressions, if there are any bugs, and any comments or suggestions you might have. It's a work in progress, and there's always room for improvement.
Dragonfaith (MV) Alpha 2.0
Download (~130 MB): Windows | Mac
Sunday, April 3, 2016
Dragonfaith (MV) Alpha 1.0 - Prologue
Here is my first release of Dragonfaith for RPG Maker MV. To temper your expectations, it's pretty much just the prologue. But we gotta start somewhere, right? I actually have a bunch more stuff done already, but it's not presentable just yet. Actually, I'm finding that the limitations of the combat (which is one aspect I'm having considerable trouble with, given that the default numbers are so out of wack, and there's so much to account for that I'm not sure I'll even have a clear plan of attack until the skeleton of the game has been put together) is keeping me from putting more of the game together for release.
I just don't know how much sense it makes to give you demos of an increasingly greater portion of the game before I've added any real combat in. You'll already be bored of the locations and the story by the time I need you to test the combat balance, which is an important (and conceivably tedious) aspect of the testing process. On the other hand, it could be years (I don't want it to take that long, but I'm trying to be realistic here) before I even get some semblance of the combat working, assuming I devote my time and effort to the other stuff I feel needs to be in place first, and I'd really hate to go that long without showing you any of what I do accomplish (you'd be forgiven for thinking I've given up on the game, although that most certainly is not the case).
I'll either have to think of a non-standard way of showcasing those aspects of the game, or else just suck it up and live with the idea of releasing it in a very non-polished format (which is bound to drive my OCD and perfectionism bonkers, although we are dealing with early alphas here (as sad as it is to call them "early" given that the game has already been in development for two years - although that has everything to do with having to upgrade it to the newest version of RPG Maker released just at the end of last year)).
Anyhow, without further ado, here is the first release of Dragonfaith for RPG Maker MV:
Dragonfaith (MV) Alpha 1.0
Download (~130 MB): [check sidebar for newest release]
I just don't know how much sense it makes to give you demos of an increasingly greater portion of the game before I've added any real combat in. You'll already be bored of the locations and the story by the time I need you to test the combat balance, which is an important (and conceivably tedious) aspect of the testing process. On the other hand, it could be years (I don't want it to take that long, but I'm trying to be realistic here) before I even get some semblance of the combat working, assuming I devote my time and effort to the other stuff I feel needs to be in place first, and I'd really hate to go that long without showing you any of what I do accomplish (you'd be forgiven for thinking I've given up on the game, although that most certainly is not the case).
I'll either have to think of a non-standard way of showcasing those aspects of the game, or else just suck it up and live with the idea of releasing it in a very non-polished format (which is bound to drive my OCD and perfectionism bonkers, although we are dealing with early alphas here (as sad as it is to call them "early" given that the game has already been in development for two years - although that has everything to do with having to upgrade it to the newest version of RPG Maker released just at the end of last year)).
Anyhow, without further ado, here is the first release of Dragonfaith for RPG Maker MV:
Dragonfaith (MV) Alpha 1.0
Saturday, March 5, 2016
My First Serious Plugin - Peep Skill (MV)
(Download at bottom of post).
I'm happy to report that I've pretty much gotten the hang of scripting in RPG Maker MV. Doesn't mean that any problem that crops up will be easy to solve, or that I will be able to solve any and all problems I encounter (especially the more complex ones, although the fact that there is a nice community of even better scripters than I working on commonly desired features helps a lot), but it means my abilities to get what I want out of this program (and my confidence in being able to do so) are stronger than ever.
I'm fairly confident coding in JavaScript by now - which isn't to say that I know the language back and forth, but I know the basic syntax, and figuring out how to do specific things is as easy as typing a question into Google and surveying the answers. The hardest part remains diving into the - as I said - tens of thousands of lines of code that make up RPG Maker MV, and a) finding the code you need to modify to get the results you want and/or b) trying to understand not so much the JavaScript, but how the actual program RPG Maker has been designed to function.
On the other hand, I haven't had this much of an opportunity to program since I finished my schooling (the barrier of learning a foreign language is surprisingly intimidating, even if most of the logic behind computer programming is the same no matter what language you're using), and I had forgotten just how much fun it is to code (barring all those frustrating times that your code fails, and you assume you've screwed up the logic, when it so frequently ends up being nothing more than a parenthesis or a semicolon out of place). It's the thrill of problem-solving. Some people like to fix things with their hands. Computer programming is the same, except you're using your mind - and that's always been my strongest tool.
So over a couple of weeks I pretty much absorbed myself into programming, and worked out a nice little plugin that I'd like to offer up to the community. It started out with me trying to figure out how to create an enemy that mirrors the player's stats, no matter what they happen to be when the battle is initiated. I couldn't find a way to preload those stats into the enemy's properties in the database, so I opted to run an event at the start of the battle that reads the player's current stats and then feeds them into the enemy (to do this, I made all the enemy's base stats 1, and then added the player's stats minus 1 on top of them).
It was an adequate solution, but in the process of working on it, I wanted to have a nice way to read the enemy's stats in-game to make sure they were what I wanted (and expected) them to be. So I embarked on creating something of a skill akin to the Peep command in Final Fantasy IV (since, to my knowledge, RPG Maker comes with nothing like it by default). It's probably come up in other places (although that's the first one that came to my mind), but basically it's a skill you can use in battle to investigate an enemy's stats (HP, MP, etc.) as well as its strengths and weaknesses (e.g., strong against fire, weak against poison, immune to sleep).
So this plugin started out very basic and functional, but as I went along, I realized how well it presented itself to user customization, and I decided to use it as an opportunity to learn a lot of valuable techniques in scripting for MV - like proper aliasing, utilization of plugin parameters, as well as plugin commands (although I finally opted for notetag functionality over plugin commands, in order to bypass the extraneous step of having to call a common event). It started out as pretty much one big function that did everything I needed it to do, but then I decided to split it up and write it in the format of the rest of RPG Maker's code, which is very modular and method-based.
The end result is a fair-sized monster of a thing (by my standards, that is - it's tiny next to some of those professional-level plugins you can find). And even though I still consider myself to be a beginner - or beginner-intermediate, at best - scripter, it's something I'm pretty proud of. I can't claim that it will be compatible with any and all other plugins, but I don't anticipate it having any significant problems (most of it is contained within a brand new class that I've written). So, if you get a chance to try it out, please tell me how you like it, and if there are any bugs you encounter.
Now, let me briefly describe what my Peep Skill plugin can do. (The plugin itself is fully annotated, so you should be able to figure out how to work it just by reading the description at the top of the file, or through RPG Maker's Plugin Manager). After the plugin is installed, all you gotta do to use it is type <peep> alone or with arguments (see the file for details) in the note box of the skill or item that you want to execute the peep skill when used in battle. When you use it, if successful, it will display on screen a list of the target enemy's properties. You can fully customize which properties are displayed and in what order, choosing from the following options:
Enemy's Name
Current and Max HP and MP
Basic Parameters (Attack, Defense, Magic Attack, Magic Defense, Agility, Luck)
Current States applied (e.g., sleep, poison, mute)
Current Buffs (attack up, agility down, etc.)
Elemental and State strengths, weaknesses, and immunities (all according to the enemy's traits listed in the Database)
Enemy's worth in both experience and gold
Potential drops (with probabilities)
As I said, you can choose any or all of these to be displayed, and you can even format them by adding in blank lines. The plugin is designed to wrap lines that exceed the length of the text box (you have to input the max character limit if you're not using the default font and size). And all of the text prefixes and terminology is modifiable. Plus, you can add the tag <peep:no> to the note box of any enemies that you don't want the player to be able to read the stats of, and even customize the failure message that is displayed! All in all, I'd like to think it's a pretty robust plugin. It does have a few limitations (it only works on enemies, and not actors; it only works on one enemy at a time; and it only works in battle), but hopefully it will be useful for whatever your specific purposes are!
Download: Peep Skill Plugin (for use with RPG Maker MV)
I'm happy to report that I've pretty much gotten the hang of scripting in RPG Maker MV. Doesn't mean that any problem that crops up will be easy to solve, or that I will be able to solve any and all problems I encounter (especially the more complex ones, although the fact that there is a nice community of even better scripters than I working on commonly desired features helps a lot), but it means my abilities to get what I want out of this program (and my confidence in being able to do so) are stronger than ever.
I'm fairly confident coding in JavaScript by now - which isn't to say that I know the language back and forth, but I know the basic syntax, and figuring out how to do specific things is as easy as typing a question into Google and surveying the answers. The hardest part remains diving into the - as I said - tens of thousands of lines of code that make up RPG Maker MV, and a) finding the code you need to modify to get the results you want and/or b) trying to understand not so much the JavaScript, but how the actual program RPG Maker has been designed to function.
On the other hand, I haven't had this much of an opportunity to program since I finished my schooling (the barrier of learning a foreign language is surprisingly intimidating, even if most of the logic behind computer programming is the same no matter what language you're using), and I had forgotten just how much fun it is to code (barring all those frustrating times that your code fails, and you assume you've screwed up the logic, when it so frequently ends up being nothing more than a parenthesis or a semicolon out of place). It's the thrill of problem-solving. Some people like to fix things with their hands. Computer programming is the same, except you're using your mind - and that's always been my strongest tool.
So over a couple of weeks I pretty much absorbed myself into programming, and worked out a nice little plugin that I'd like to offer up to the community. It started out with me trying to figure out how to create an enemy that mirrors the player's stats, no matter what they happen to be when the battle is initiated. I couldn't find a way to preload those stats into the enemy's properties in the database, so I opted to run an event at the start of the battle that reads the player's current stats and then feeds them into the enemy (to do this, I made all the enemy's base stats 1, and then added the player's stats minus 1 on top of them).
It was an adequate solution, but in the process of working on it, I wanted to have a nice way to read the enemy's stats in-game to make sure they were what I wanted (and expected) them to be. So I embarked on creating something of a skill akin to the Peep command in Final Fantasy IV (since, to my knowledge, RPG Maker comes with nothing like it by default). It's probably come up in other places (although that's the first one that came to my mind), but basically it's a skill you can use in battle to investigate an enemy's stats (HP, MP, etc.) as well as its strengths and weaknesses (e.g., strong against fire, weak against poison, immune to sleep).
So this plugin started out very basic and functional, but as I went along, I realized how well it presented itself to user customization, and I decided to use it as an opportunity to learn a lot of valuable techniques in scripting for MV - like proper aliasing, utilization of plugin parameters, as well as plugin commands (although I finally opted for notetag functionality over plugin commands, in order to bypass the extraneous step of having to call a common event). It started out as pretty much one big function that did everything I needed it to do, but then I decided to split it up and write it in the format of the rest of RPG Maker's code, which is very modular and method-based.
The end result is a fair-sized monster of a thing (by my standards, that is - it's tiny next to some of those professional-level plugins you can find). And even though I still consider myself to be a beginner - or beginner-intermediate, at best - scripter, it's something I'm pretty proud of. I can't claim that it will be compatible with any and all other plugins, but I don't anticipate it having any significant problems (most of it is contained within a brand new class that I've written). So, if you get a chance to try it out, please tell me how you like it, and if there are any bugs you encounter.
My plugin in action.
Now, let me briefly describe what my Peep Skill plugin can do. (The plugin itself is fully annotated, so you should be able to figure out how to work it just by reading the description at the top of the file, or through RPG Maker's Plugin Manager). After the plugin is installed, all you gotta do to use it is type <peep> alone or with arguments (see the file for details) in the note box of the skill or item that you want to execute the peep skill when used in battle. When you use it, if successful, it will display on screen a list of the target enemy's properties. You can fully customize which properties are displayed and in what order, choosing from the following options:
Enemy's Name
Current and Max HP and MP
Basic Parameters (Attack, Defense, Magic Attack, Magic Defense, Agility, Luck)
Current States applied (e.g., sleep, poison, mute)
Current Buffs (attack up, agility down, etc.)
Elemental and State strengths, weaknesses, and immunities (all according to the enemy's traits listed in the Database)
Enemy's worth in both experience and gold
Potential drops (with probabilities)
As I said, you can choose any or all of these to be displayed, and you can even format them by adding in blank lines. The plugin is designed to wrap lines that exceed the length of the text box (you have to input the max character limit if you're not using the default font and size). And all of the text prefixes and terminology is modifiable. Plus, you can add the tag <peep:no> to the note box of any enemies that you don't want the player to be able to read the stats of, and even customize the failure message that is displayed! All in all, I'd like to think it's a pretty robust plugin. It does have a few limitations (it only works on enemies, and not actors; it only works on one enemy at a time; and it only works in battle), but hopefully it will be useful for whatever your specific purposes are!
Download: Peep Skill Plugin (for use with RPG Maker MV)
Tuesday, February 16, 2016
Plugin: Terrain Battle Backs (MV)
The struggle to adapt my game to the latest version of RPG Maker continues, in spite of the frustrating limitations of developing a game inspired by classics that were designed for the desktop on a mobile platform.
You might remember my efforts at customizing the battle backgrounds automatically chosen based on terrain type on designated world maps in VX Ace, which I detailed in this post from two years ago (egads, has it really been that long?). That there isn't a built-in, user-friendly way to adjust these choices is one of those things in RPG Maker that amazes me.
Previously, I had opted to run a Parallel Process event on the world map to constantly check the tile ID (and thus, type of terrain) of the spot the player was standing on at any given time, in order to manually override the choice of battle background. It's a testament to how much has changed in the past couple of years that my first instinct this time around was to try and develop a scripted solution that modifies the way the backend code functions, instead.
So, I opened up the hood and jumped into the code. As a potentially relevant side note, MV is programmed in JavaScript. Trying to make sense of the tens of thousands of lines of code - and, particularly, trying to find the parts that do the stuff you want to modify - is no easy task. But I was able to track down the very function(s) that determine which battle background goes with which type of terrain. They are located (for reference) in rpg_sprites.js on lines 2530-2572. I'll copy them here:
Another thing you might notice is the numbers that are being dealt with here. The function takes an argument (named "type") that, as you might guess, corresponds to the terrain-dependent tile ID, which is then evaluated in the switch statement. What's interesting is that these numbers are much smaller than the unwieldy tile IDs we dealt with before, which ran the gamut from 2048-4350. There's a rather obvious reason for this, that I must admit I discovered in an embarrassingly roundabout fashion. Those larger numbers are still relevant, as by using the Get Location Info event command, you'll find in-game that they haven't changed from VX Ace to MV. But for coding purposes, a little bit of math has been performed to make them more palatable. You can find that calculation in another function located on lines 5912-5915 of rpg_objects.js:
But since choosing a battle background doesn't depend on whether you're standing on a "border" tile or a "center" tile (or what have you), you can essentially boil each set of 48 IDs down to a single terrain-dependent index. Which is exactly what the above calculation is doing (note also that if the tile ID doesn't fall into the expected range, the function returns a -1 instead, presumably for fallback purposes). Now, the thing that made me feel stupid for not realizing it sooner was the fact that, after you perform the calculation, what you're left with is nothing more than the placement index (starting at 0) of the tiles as they appear in the editor for the World_A tileset!
To illustrate, where we had this before:
We now have something much simpler (and more predictable!):
I'm not sure if this had crossed my mind before, but the indices (and the tile IDs they correspond to) are all unique. Meaning that, although they're stacked on either of two separate layers - so that a given tile can have both a Layer 1 ID and a Layer 2 ID - the numbers on either layer never overlap. So if you give me a number, I can tell you exactly what type of terrain it corresponds to without knowing whether it's a Layer 1 or a Layer 2 ID. Which, it turns out, is exactly what the functions with the long switch statements that I copied above are doing. So then, you might ask, are those functions evaluating Layer 1 or Layer 2 IDs? And how is that determined? Exploring the functions that call those two functions will answer those questions. You can find them in rpg_sprites.js at lines 2518-2528. Here they are:
If you're paying attention, you'll note that here the function only takes a single argument, whereas before it took three. This is confusing, but the explanation for it is quite simple. The previous autotileType function belonged to the Game_Map class. But here, we're dealing with the Spriteset_Battle class, which has defined its own autotileType function. But before you throw your arms up in frustration, this local version of the function is nothing more than a shortcut to that other version, but with the x and y arguments already predetermined to be the player's x and y map coordinates. You can examine the function yourself. It is located in rpg_sprites.js at lines 2590-2592, which I will reproduce here:
I'm pretty confident, though, that what's going on in these normalName functions is that they're trying to call the corresponding terrainName function first with the Layer 2 ID (giving it precedence). If the tile the player is standing on has no Layer 2 ID (presumably resulting in a "falsey" value), then it calls the function instead using the Layer 1 ID. And then, if for some reason there's no Layer 1 ID either, it falls back to a default (calling a simple function that does nothing more than return the 'Grassland' battleback - whether top or bottom).
---------
Are you with me so far? Because here's where we get to start customizing things. Now that we know which indices correspond to which terrains (see the second image above), it would be a simple matter to just change the names of the battle backgrounds in those functions with the long switch statements, or even to add new cases to designate other battle backgrounds for terrains that the default function doesn't account for.
(Disclaimer: I don't advise changing the original JavaScript files that come packed in with the program. But if you copy the important functions into a new JavaScript file, and make your adjustments there, then you can add it in the same way you do with your other plugins (MV terminology for scripts), and add it to your game via the plugin manager. That way, if there are any problems in the future, you have the simple option of either turning off or getting rid of the plugin completely, and reverting to the game's default functionality).
But in the process of doing this, I hit a little snag, because I like to have a little bit more fine-tuned control over the choice of battle background depending not just on either the Layer 1 or Layer 2 ID, but in some cases the result of their combination. In different cases, the Layer 2 ID might take precedence, whereas in others, the Layer 1 ID will be more important. My way of dealing with this via the eventing solution I used in VX Ace was to simply handle both Layer IDs simultaneously and check them against each other. But the functions we're dealing with here only consider one ID at a time. So what to do?
I tried a few different ways to get around this limitation, but I ultimately decided to modify the function itself to actually take two arguments instead of just one - one for each of the first two Layer IDs. I checked through all the core scripts (Ctrl-F is your friend), to make sure I knew every place the terrainName functions were being called, so as to avoid any discrepancies in the code. And it turns out that the only time the functions come up is in those cases we've already explored here.
(Another disclaimer: if you use another plugin that attempts to use or modify these same functions, you may encounter problems. I'm only a beginner MV scripter right now, so I wouldn't know how to minimize that possibility, e.g. by aliasing or whatever. Feel free to add in some contingency code yourself if you know how to go about doing that).
So all I had to do was change the (type) part of the function to a (type1, type2), and then in the normalName functions where the terrainName functions are being called, replace the first part of the confusing OR evaluation (while preserving the default fallback), so as to call the terrainName function just once with both arguments - one that retrieves the autotileType for Layer 1, and one for Layer 2. This is what the modified functions look like:
In the second function, I've used another conditional to override the texture for any tiles that require the Cliff or Forest1 wall texture, since they tend to crop up over a number of different Layer 1 ID terrains. The rest of the switch statement is again pretty straightforward, although here you'll see that I've designated one of the two desert terrains as a "beach" (as opposed to a landlocked desert) by giving it the Sea wall texture instead of the usual Desert wall texture.
And that's pretty much it! Feel free to take these code snippets and play around with them to suit your purposes. I'd love to make a fully customizable plugin out of what I've done here, but I fear that the individual needs of each user will be so specific as to require a heavily personalized combination of conditionals. Come to think of it, that may be why the original programmers haven't already done it.
Just a few last notes. It should be mentioned that in these examples, I've replaced all of my MV image files with resized versions of the VX Ace graphics (because I like them better). So my filenames may not match yours (although many - but not all - of the battleback filenames have remained the same from VX Ace to MV). Make sure the names you use in your code match the filenames in your img/battlebacks folders (1 and 2), minus the file extensions.
On a related subject, if you want to change the default battle background for use while riding the ship, you'll find that in a separate pair of functions that are really simple to modify. Look for them in rpg_sprites.js at lines 2582-2588.
I don't know how or to what extent the solution I've come up with here will dovetail with an airship encounter system, as I haven't tackled that problem in the MV version of my game yet. But if I have anything to say about that in the future, you can be sure to find it here on this blog!
You might remember my efforts at customizing the battle backgrounds automatically chosen based on terrain type on designated world maps in VX Ace, which I detailed in this post from two years ago (egads, has it really been that long?). That there isn't a built-in, user-friendly way to adjust these choices is one of those things in RPG Maker that amazes me.
Previously, I had opted to run a Parallel Process event on the world map to constantly check the tile ID (and thus, type of terrain) of the spot the player was standing on at any given time, in order to manually override the choice of battle background. It's a testament to how much has changed in the past couple of years that my first instinct this time around was to try and develop a scripted solution that modifies the way the backend code functions, instead.
So, I opened up the hood and jumped into the code. As a potentially relevant side note, MV is programmed in JavaScript. Trying to make sense of the tens of thousands of lines of code - and, particularly, trying to find the parts that do the stuff you want to modify - is no easy task. But I was able to track down the very function(s) that determine which battle background goes with which type of terrain. They are located (for reference) in rpg_sprites.js on lines 2530-2572. I'll copy them here:
Spriteset_Battle.prototype.terrainBattleback1Name = function(type) { switch (type) { case 24: case 25: return 'Wasteland'; case 26: case 27: return 'DirtField'; case 32: case 33: return 'Desert'; case 34: return 'Lava1'; case 35: return 'Lava2'; case 40: case 41: return 'Snowfield'; case 42: return 'Clouds'; case 4: case 5: return 'PoisonSwamp'; default: return null; } }; Spriteset_Battle.prototype.terrainBattleback2Name = function(type) { switch (type) { case 20: case 21: return 'Forest'; case 22: case 30: case 38: return 'Cliff'; case 24: case 25: case 26: case 27: return 'Wasteland'; case 32: case 33: return 'Desert'; case 34: case 35: return 'Lava'; case 40: case 41: return 'Snowfield'; case 42: return 'Clouds'; case 4: case 5: return 'PoisonSwamp'; } };If you're not familiar with switch statements, they're basically extended conditionals, which check the value of a variable - each "case" basically tells the program "if this, then do that". The first thing you should note is that there are in fact two separate functions, corresponding to the two parts of the battle background - the bottom or ground section, and the top or wall section. This should be familiar to you if you've ever worked with the battle backgrounds, or looked at the associated image files that are named in these functions.
Another thing you might notice is the numbers that are being dealt with here. The function takes an argument (named "type") that, as you might guess, corresponds to the terrain-dependent tile ID, which is then evaluated in the switch statement. What's interesting is that these numbers are much smaller than the unwieldy tile IDs we dealt with before, which ran the gamut from 2048-4350. There's a rather obvious reason for this, that I must admit I discovered in an embarrassingly roundabout fashion. Those larger numbers are still relevant, as by using the Get Location Info event command, you'll find in-game that they haven't changed from VX Ace to MV. But for coding purposes, a little bit of math has been performed to make them more palatable. You can find that calculation in another function located on lines 5912-5915 of rpg_objects.js:
Game_Map.prototype.autotileType = function(x, y, z) { var tileId = this.tileId(x, y, z); return tileId >= 2048 ? Math.floor((tileId - 2048) / 48) : -1; };Basically, what this function does is take the tile ID corresponding to a location on the map determined by the x, y, and z (or layer level) coordinates, passed into the function as arguments. It then subtracts 2048 (since, I don't know why, but the IDs start at - and are thus offset by - a base value of 2048), and divides that number by 48. This makes sense because if you take the time to scrutinize, as I have, you'll find that there is a space of 48 numbers between each different type of terrain. These correspond to the various orientations of autotile placement which I have annotated in detail in my previous post for VX Ace.
But since choosing a battle background doesn't depend on whether you're standing on a "border" tile or a "center" tile (or what have you), you can essentially boil each set of 48 IDs down to a single terrain-dependent index. Which is exactly what the above calculation is doing (note also that if the tile ID doesn't fall into the expected range, the function returns a -1 instead, presumably for fallback purposes). Now, the thing that made me feel stupid for not realizing it sooner was the fact that, after you perform the calculation, what you're left with is nothing more than the placement index (starting at 0) of the tiles as they appear in the editor for the World_A tileset!
To illustrate, where we had this before:
We now have something much simpler (and more predictable!):
I'm not sure if this had crossed my mind before, but the indices (and the tile IDs they correspond to) are all unique. Meaning that, although they're stacked on either of two separate layers - so that a given tile can have both a Layer 1 ID and a Layer 2 ID - the numbers on either layer never overlap. So if you give me a number, I can tell you exactly what type of terrain it corresponds to without knowing whether it's a Layer 1 or a Layer 2 ID. Which, it turns out, is exactly what the functions with the long switch statements that I copied above are doing. So then, you might ask, are those functions evaluating Layer 1 or Layer 2 IDs? And how is that determined? Exploring the functions that call those two functions will answer those questions. You can find them in rpg_sprites.js at lines 2518-2528. Here they are:
Spriteset_Battle.prototype.normalBattleback1Name = function() { return (this.terrainBattleback1Name(this.autotileType(1)) || this.terrainBattleback1Name(this.autotileType(0)) || this.defaultBattleback1Name()); }; Spriteset_Battle.prototype.normalBattleback2Name = function() { return (this.terrainBattleback2Name(this.autotileType(1)) || this.terrainBattleback2Name(this.autotileType(0)) || this.defaultBattleback2Name()); };As well as I can figure, these functions run when the game is trying to load a battle and determine which battle background to use. Again, you'll note that there are two separate functions, one for each half of the battle background. They each do essentially the same thing, however, which is to call the long switch functions we've already seen (hereafter referred to as "the terrainName function(s)") to determine which battle background to use based on the terrain corresponding to the index evaluated via the autotileType function (the one with the math that we examined above).
If you're paying attention, you'll note that here the function only takes a single argument, whereas before it took three. This is confusing, but the explanation for it is quite simple. The previous autotileType function belonged to the Game_Map class. But here, we're dealing with the Spriteset_Battle class, which has defined its own autotileType function. But before you throw your arms up in frustration, this local version of the function is nothing more than a shortcut to that other version, but with the x and y arguments already predetermined to be the player's x and y map coordinates. You can examine the function yourself. It is located in rpg_sprites.js at lines 2590-2592, which I will reproduce here:
Spriteset_Battle.prototype.autotileType = function(z) { return $gameMap.autotileType($gamePlayer.x, $gamePlayer.y, z); };So, returning to the normalBattlebackName functions (hereafter referred to as "the normalName function(s)"), when they call the terrainName functions, they're passing in an index corresponding to a tile ID at either the first or second layer, depending on whether the autotileType function is being passed a 0 or a 1 (note that since counters in programming usually start at 0, the 0 corresponds to Layer 1, and the 1 corresponds to Layer 2 - try not to get confused). There's something a little weird going on here, though, because each normalName function is trying to return the value of a call to the corresponding terrainName function (which would be the name of the battle background file associated with the given terrain), but it's tangled up in an OR operator ("||"). Let's take a closer look:
return (this.terrainBattleback1or2Name(this.autotileType(1)) || this.terrainBattleback1or2Name(this.autotileType(0)) || this.defaultBattleback1or2Name());It took me a while to get a firm grasp on what exactly is going on here, even though it's largely intuitive. (Sometimes explicit instructions are helpful). For a detailed explanation of the behavior of JavaScript's OR operator, read this. Suffice to say, the operator responds not just to true/false evaluations, but also to the wishy-washy properties of truthiness/falsiness. Sounds messy, doesn't it?
I'm pretty confident, though, that what's going on in these normalName functions is that they're trying to call the corresponding terrainName function first with the Layer 2 ID (giving it precedence). If the tile the player is standing on has no Layer 2 ID (presumably resulting in a "falsey" value), then it calls the function instead using the Layer 1 ID. And then, if for some reason there's no Layer 1 ID either, it falls back to a default (calling a simple function that does nothing more than return the 'Grassland' battleback - whether top or bottom).
---------
Are you with me so far? Because here's where we get to start customizing things. Now that we know which indices correspond to which terrains (see the second image above), it would be a simple matter to just change the names of the battle backgrounds in those functions with the long switch statements, or even to add new cases to designate other battle backgrounds for terrains that the default function doesn't account for.
(Disclaimer: I don't advise changing the original JavaScript files that come packed in with the program. But if you copy the important functions into a new JavaScript file, and make your adjustments there, then you can add it in the same way you do with your other plugins (MV terminology for scripts), and add it to your game via the plugin manager. That way, if there are any problems in the future, you have the simple option of either turning off or getting rid of the plugin completely, and reverting to the game's default functionality).
But in the process of doing this, I hit a little snag, because I like to have a little bit more fine-tuned control over the choice of battle background depending not just on either the Layer 1 or Layer 2 ID, but in some cases the result of their combination. In different cases, the Layer 2 ID might take precedence, whereas in others, the Layer 1 ID will be more important. My way of dealing with this via the eventing solution I used in VX Ace was to simply handle both Layer IDs simultaneously and check them against each other. But the functions we're dealing with here only consider one ID at a time. So what to do?
I tried a few different ways to get around this limitation, but I ultimately decided to modify the function itself to actually take two arguments instead of just one - one for each of the first two Layer IDs. I checked through all the core scripts (Ctrl-F is your friend), to make sure I knew every place the terrainName functions were being called, so as to avoid any discrepancies in the code. And it turns out that the only time the functions come up is in those cases we've already explored here.
(Another disclaimer: if you use another plugin that attempts to use or modify these same functions, you may encounter problems. I'm only a beginner MV scripter right now, so I wouldn't know how to minimize that possibility, e.g. by aliasing or whatever. Feel free to add in some contingency code yourself if you know how to go about doing that).
So all I had to do was change the (type) part of the function to a (type1, type2), and then in the normalName functions where the terrainName functions are being called, replace the first part of the confusing OR evaluation (while preserving the default fallback), so as to call the terrainName function just once with both arguments - one that retrieves the autotileType for Layer 1, and one for Layer 2. This is what the modified functions look like:
Spriteset_Battle.prototype.normalBattleback1Name = function() { return (this.terrainBattleback1Name(this.autotileType(0), this.autotileType(1)) || this.defaultBattleback1Name()); }; Spriteset_Battle.prototype.normalBattleback2Name = function() { return (this.terrainBattleback2Name(this.autotileType(0), this.autotileType(1)) || this.defaultBattleback2Name()); };All that was left then was to modify the terrainName functions, by manipulating the switch statement(s), and in my case, adding in a couple of extra if/else statements for better flow, to tie the proper battle backgrounds to the proper combination of terrains. Here's what I ended up with (although I may make some more fine-tuned adjustments in the future):
Spriteset_Battle.prototype.terrainBattleback1Name = function(type1, type2) { if (type2 === 29) { return 'Cobblestones2'; } else if (type2 === 37) { return 'Cobblestones4'; } else { switch (type1) { case 4: case 5: return 'PoisonSwamp'; case 8: return 'Ship'; case 10: case 40: return 'Snowfield'; case 16: case 18: switch (type2) { case 17: case 19: return 'Meadow'; case 20: case 21: return 'GrassMaze'; default: return 'Grassland'; } case 24: case 26: return 'Wasteland'; case 32: if (type2 === 33) { return 'Desert'; } else { return 'Sand'; } case 34: if (type2 === 35) { return 'Lava2'; } else { return 'Lava1'; } case 42: return 'Clouds'; default: return null; } } }; Spriteset_Battle.prototype.terrainBattleback2Name = function(type1, type2) { if (type2 === 30 || type2 === 38 || type2 === 41 || type2 === 46) { return 'Cliff'; } else if (type2 === 21 || type2 === 36 || type2 === 44) { return 'Forest1'; } else { switch (type1) { case 4: case 5: return 'PoisonSwamp'; case 8: return 'Bridge'; case 10: return 'Snowfield'; case 16: case 18: if (type2 === 20) { return 'GrassMaze'; } else { return 'Grassland'; } case 24: case 26: return 'Wasteland'; case 32: if (type2 === 33) { return 'Desert'; } else { return 'Sea'; } case 34: return 'Lava'; case 40: return 'Snowfield'; case 42: return 'Clouds'; } } };A couple of notes to help you understand what's going on here. In the first function, I used an overriding if statement to return the appropriate ground textures for map tiles that feature roads (indicated by a Layer 2 ID), no matter what Layer 1 terrain is involved (grass, desert, snow, etc.). The rest of the cases are pretty straightforward, except that I provided some alternatives such as a different lower background for plains (indicated by a Layer 1 ID) versus grassy plains (indicated by a Layer 2 ID), and a similar alternative for ashy wasteland versus cracked lavafield (the subtle difference between the Lava1 and Lava2 battle backgrounds).
In the second function, I've used another conditional to override the texture for any tiles that require the Cliff or Forest1 wall texture, since they tend to crop up over a number of different Layer 1 ID terrains. The rest of the switch statement is again pretty straightforward, although here you'll see that I've designated one of the two desert terrains as a "beach" (as opposed to a landlocked desert) by giving it the Sea wall texture instead of the usual Desert wall texture.
And that's pretty much it! Feel free to take these code snippets and play around with them to suit your purposes. I'd love to make a fully customizable plugin out of what I've done here, but I fear that the individual needs of each user will be so specific as to require a heavily personalized combination of conditionals. Come to think of it, that may be why the original programmers haven't already done it.
Just a few last notes. It should be mentioned that in these examples, I've replaced all of my MV image files with resized versions of the VX Ace graphics (because I like them better). So my filenames may not match yours (although many - but not all - of the battleback filenames have remained the same from VX Ace to MV). Make sure the names you use in your code match the filenames in your img/battlebacks folders (1 and 2), minus the file extensions.
On a related subject, if you want to change the default battle background for use while riding the ship, you'll find that in a separate pair of functions that are really simple to modify. Look for them in rpg_sprites.js at lines 2582-2588.
I don't know how or to what extent the solution I've come up with here will dovetail with an airship encounter system, as I haven't tackled that problem in the MV version of my game yet. But if I have anything to say about that in the future, you can be sure to find it here on this blog!
Subscribe to:
Posts (Atom)