I DO NOT TAKE CREDIT FOR THISCreator: Richard
Info From:
http://www.richinnovations.com/rm2k/YouTube:
http://www.youtube.com/user/furdabip/Website:
http://www.richinnovations.com/Explanation of How I Did My ABS:I am getting tired of all these people constantly asking me about the ABS for my unfinished RM2K project. So, I have decided to assemble this bare bones explanation of how it works so that you too may explore RM2K fully and rip it off as best you can.
First Off:The system is COMPLICATED, and it gets MORE complicated the more ideas I think up and impliment. There are 441 common events that control every aspect of my project, THUS FAR. There are common events for the weapon fire and control, variable setting and control, managing Max's sprite for when he attacks/uses magic, detecting the menu press/item & magic use, showing the HUD, managing magic regen, managing the menu/freezing enemies when the menu is up, damage display for when you/the enemy is hit, managing the custom level system, managing the custom inventory, managing the three status effects, showing the enemy HP bar, showing the magic range when a spell is equipped, showing the level up text when a level occurs, managing the shop system, managing map transitions, detecting and managing climbing, cutscene skipping, managing the save point system & custom save information, managing treasure chests, the game clock, managing the achievements you can get in the game, showing the EXP and Lucre bar when you kill an enemy, the ice platforming events for walking over water, managing the follower script for when you have people tailing you around, spawning enemies, managing enemy stats & deaths, playing sound effects, enemy commands, enemy physical and magical damage, detecting player death, managing enemy dropped items, and managing status effects on enemies. Now, why did I just list off all the different groups of common events I have? Simple. To emphasize this isn't some copy/paste task, or something to be taken lightly. This WILL take you a shitton of time to complete if you do decide to copy it.Let us begin.
How the Weapon Works:The weapon is an event that is on EVERY map. I have a base map with 80 events on it I
copy/paste when I want to create a new map. Each event is used in the system, and is controlled by common events. Since they're controlled by common events, they have to be the same event ID across ALL maps. Now. The way the weapon works is with a common event set to parallel process so that I can use an Enter Password to detect if the player has pushed the attack button. If they have, and all other factors add up (the weapon isn't currently firing, the weapon is enabled to fire on that specific map, the weapon isn't going through it's "cooldown" phase after it was fired last, the player isn't currently walking on an ice platform, the player isn't climbing, the player isn't in the menu, the player isn't moving, the player isn't currently using magic, the player isn't in a shop & the player has a directional equipped), then the weapon event sets it's position at the player's position, changes it's graphic to match the currently equipped weapon, and moves along a specific path according to the directional equipped, and the direction the player is facing. As an example, the first directional you get, facing up, goes along the path of;
<>Start Slip Through
<>Up
<>Up
<>Up
<>Down
<>Down
<>Down
<>Change graphic (to a blank one)
<>Stop Slip Through
<>Switch [Weapon cooldown trigger] ON
There are 4 directions for each directional, all hardcoded to follow a specific path from the player. That is 32 hardcoded paths for the weapon to follow. Now, the detect fire parallel process also detects if the cooldown has triggered. If it has, then it turns off the weapon firing trigger, waits 0.2 secs, and turns off the cooldown. Since we've already established that the weapon won't fire unless the cooldown's off, the waiting before turning it off satisfies the basic logic of waiting for the cooldown. :-p. Now, that is only ONE piece of the puzzle. So what if we move an event? It's not going to know how to hit an enemy. It's just going to move along it's predefined path. That's where a second parallel process comes in, which constantly sets variables to the weapon's current position, among other variables it updates every frame. We use that in the enemy logic to see if the weapon position is the same as the enemy position, and fire off an enemy damaged common event if so. That's it for how it fires. The meat of how the weapon works is 100% in the enemy logic, and NOT in the weapon itself. The weapon firing is just what gets the weapon on the map to bemdetected.
How the Enemies Work:The way the enemies work is entirely by common events. The sprites are 20 events on every map, with 20 additional events for enemy item drops. Each of those enemies have 12 switches and 29 variables to control the AI. Each AI is independently controlled by a common event specifically coded to work with that enemy. This means for each map, there can be a maximum of 20 enemies. What this also means is that since RM2K REALLY sucks for object oriented programming (or any programming, really), AI can't be controlled by some universal set of rules. Each enemy event is copy/pasted with all of the relevant information changed to reflect that specific enemy number. BEYOND that, there's 20 events for each enemy dropped item, 20 events for each status effect affliction, removal, and control (of which there are 3 status effects, making 180 total), 20 events to spawn the enemy, 40 events to control damage they have done to them (both physical and magical), and 20 events to control their death. Luckily I was able to work setting the stats (HP, MP, Str, etc, etc [17 total]) into one variable based on the type of enemy being spawned. The commands that power the enemies are in 3 groups; Position & Hit Detection, Movement, and Actions. The position and hit detection set the enemy's range from the player (enemy x minus player x [absolute value if < 0] plus enemy y minus player y [same if < 0]), counts down a hit counter that triggers when the enemy does an action, to give the enemy a cooldown before it is able to attack again, and a movement counter so that the enemies can have variable speeds, and sees if the enemy position and weapon position match (therefore the weapon hit the enemy) to call the "damaged" event for that enemy. The one thing this section does NOT do is detect magic damage, which is calculated when the player casts magic, and not every frame. The Movement section has a big fork for each enemy (so basicly "if enemy ID is 1 [a rat], then do the movement protocols for the rat enemy - if not, move on"), since each enemy has a different movement speed. So, it's basicly "Can the enemy move?" Yes: [do event movement commands] - No: [count down the pause variable, skip moving]. Now, some enemies have the same movement all the time (rats, bats), so it doesn't matter. But the rest of the enemies move based on how close they are to you, or other specific things. Since I set the range in the position and hit detection part, I can check how close the enemy is, and run one set of movement commands if they are close to you, or another if they are not. As an example, the slime enemies move in a random direction slowly unless they are within 4 squares of you, at which point they start moving towards you fast. The Actions section is where everything happens. The "logic" behind the AI. I can't specifically go into detail about how it works, except to give you a few actual examples. The Rats, the very first enemy you fight, have a simple logic;
[Is the enemy within 1 square of me?]
: [Is my attack available?]
<>Set a random variable from 1 to 100.
[Is this variable less than or equal to 4?]
<>Call damage event.
[END]
[END]
[END]
This basicly gives the rat a 1 out of 25 chance (4%) that it will attack the player when they are within 1 square of it, every frame (I am not entirely sure how many frames per second there are, but I think it's 20). This basicly gives the idea that the rat doesn't REALLY want to attack you, but it will if you get close. So, altogether with the movement, the rat wanders around aimlessly, and if you stand next to it, it might get upset and bite you. Tah dah! Enemy AI. :-D As you can imagine, higher logic such as magic, and MP usage, and other effects are entirely possible. The bat uses MP to cast blood suck, which takes damage off you and restores the bat slightly (used very rarely). A fork controls it so it doesn't happen if the bat doesn't have the MP to do so. The wolf uses Howl, which increases his Str by 2 each time he uses it. Basicly anything you want. Now how the enemies are spawned are how any basic "function" works when using RM2K; in normal programming, functions take on parameters, and do stuff with them to get some end result. In RM2K, you set those parameters by setting variables before the event is called. Thus, I have it setup so all I do is set the enemy ID (which controls which enemy logic and graphic it'll use), the X and Y of it, and then call the spawn function. The spawn function runs through all the variables for each enemy, checks which ones are dead/not being used, and calls that specific enemy's spawn event. The way I use that, is an auto-run event that I put on whatever map I want the enemies on that uses a basic "ENEMIES SPAWNED?" switch to spawn them, then stop itself once it has. Complicated mess that I simplified for myself, basicly. :-). Now, the enemy drops. As I said before, each enemy event has a corresponding enemy event that works with it as it's drop (or, conceivably, anything else I can program in, like, as an idea; a knife thrown by the enemy acting as it's graphic). Each enemy has an item it will drop, and the percentage it will drop that item. Of course, enemies can have NO drop as well. When the enemy dies, a random variable is set, and if it's at or below the drop percentage, it drops!
How the Menu Works:Since there are only 2 buttons in RM2K that can be detected, I use one for firing the weapon, and one for using an item or opening the menu. If you hold the button down for 2 seconds, it opens the menu. If you just press it, it uses the equipped item. If you have magic equipped instead, pressing it shows the area of effect the magic will have, and holding it for 1 second "charges" the magic to be used, and fires it off. Because of this, I show pictures in the bottom left corner to indicate what will happen if you release the button, from the menu, to an item, to a magic icon. How it specifically works to call up the menu and such is it is a parallel event that detects if you're holding the button, and if you are, increases a variable. It then displays the icon or target zone or whatever depending on the value of that variable. If at anytime you release the button, the script checks how long you held it for (based on the value of the variable), and casts the magic, uses the item, or opens the menu. Now, the menu itself is NOT on another map screen like in other CMS's I've seen. Instead, it is all done on the same map, working within the limitations of the 20 picture limit. Because it's all done on the same map, I have an event that triggers when the map is open that is nothing but an auto-run with a 0.0 wait, basicly freezing the entire game just to do the menu functions. That does NOT stop parallel events though, such as enemies. For that, enemies have built in logic to check if the menu is open, and simply bypass processing their actions if so. The menu functions, and picture displays of course rely on the switches being set if it's open as well. As for how the menu itself works, it's just variables that store what "position" the cursor is at, and giant forks to control where to move it, or what to do based on that. I really can't simplify it further. The main menu position controls what category you're on - the sub menu position controls what part of the main menu you're on - the pop-up position controls which pop-up option you're on if you've selected an item, and the final confirm position controls if you're on yes or no for a drop/use confirm. So, if you're at main menu position 0, you're in the Items menu. If the sub menu position is anything other than 0, you're actually inside that menu. If not, then the up/down keys control which main menu you're on instead of navigation within the Items menu. If you then select an item, it brings up the pop-up position menu, with controls specifically if you're in that. Then further if you're in a yes/no dialog. If you need any further instructions on how that is setup, then you need to mess around with RM2K longer, and teach yourself a thing or two. One thing to note is that I have 4 specific "display number" functions that will display a 3-digit number at a specific location. Let me tell you that programming those was the best thing I could have done. I use them in all the menus, and on the HUD for displaying HP/MP. They basicly all do the same thing, which is split the number into hundreds, tens, and ones, and displays pictures based on them, but each one displays them using different Pictures numbers. The first using 2, 3, 4, the next using 5, 6, 7, and so on. In case "How do I split a number into it's separate digits?" is one of your questions, it's just simple math. You take the number, and divide it by the higher tens for that digit. So for 999, take that and divide it by 100. You get 9. Bingo, your first digit. To get the middle, simply modular divide the number by the first digit's tens, so, 999 % 100, which leaves a remainder of however many is below that. In this case, 999 divided by 100 is 9 with the remainder being 99. So, now we take that 99, and do the same thing with that tens we want. So, divide it by 10. Now we have our second digit. In this case, the number is 999, so simply modular dividing it by 10 will give us the remaining digit without the need to divide it once again.
As an example, in actual RM2K code;
<>Variable Ch:[0003:Third Digit] Set, 123
<>Variable Ch:[0001:First Digit] Set, Var.[0003]val.
<>Variable Ch:[0001:First Digit] / , 100
<>Variable Ch:[0002:Second Digit] Set, Var.[0003]val.
<>Variable Ch:[0002:Second Digit] Mod , 100
<>Variable Ch:[0002:Second Digit] / , 10
<>Variable Ch:[0003:Third Digit] Mod , 10
Now variable 0001 = the first digit, variable 0002 = the second digit, and variable 0003 = the third digit. You can deconstruct a 6 digit number the same way;
<>Variable Ch:[0006:Sixth Digit] Set, 987654
<>Variable Ch:[0001:First Digit] Set, Var.[0006]val.
<>Variable Ch:[0001:First Digit] / , 100000
<>Variable Ch:[0002:Second Digit] Set, Var.[0006]val.
<>Variable Ch:[0002:Second Digit] Mod , 100000
<>Variable Ch:[0002:Second Digit] / , 10000
<>Variable Ch:[0003:Third Digit] Set, Var.[0006]val.
<>Variable Ch:[0003:Third Digit] Mod , 10000
<>Variable Ch:[0003:Third Digit] / , 1000
<>Variable Ch:[0004:Fourth Digit] Set, Var.[0006]val.
<>Variable Ch:[0004:Fourth Digit] Mod , 1000
<>Variable Ch:[0004:Fourth Digit] / , 100
<>Variable Ch:[0005:Fifth Digit] Set, Var.[0006]val.
<>Variable Ch:[0005:Fifth Digit] Mod , 100
<>Variable Ch:[0005:Fifth Digit] / , 10
<>Variable Ch:[0006:Sixth Digit] Mod , 10
And you should be able to see how that works.
How Magic Works:Magic is one of the simplest things in my game. When magic is cast, if it's a curing spell,
then it heals for however much it's supposed to, or removes whatever statuses it's supposed to. If it's a damaging spell, then it calculates it's damage based on the element of the spell, and the element of the enemy (same element = 0 damage, strong vs = 150%, weak vs = 50%), checks all 20 enemies to see if they're alive, and within the spell's range, and then calls the magic damage calculation function and enemy magical damage function if so. If the enemy is not in range (as set in the individual enemy commands mentioned above), it skips them. When a spell is cast, the player is frozen for a bit using the same method used for freezing events as used in the menu system. They also can't attack, climb, or do whatever other actions they normally could, since when magic is being used, a switch is on that other events can check and cancel whatever commands they would normally do if magic wasn't being cast. Also, the main character's graphic changes when magic is being cast, and along with the graphic for when he is throwing a weapon, that is all controlled by another parallel process that constantly checks for the switches that are triggered when these things happen and changes the sprites as necessary. They also change based on what armor the player is wearing, so it's a big fork for which armor and which stance to display. :-)
How the Shop Works:The shop is the only feature that takes place on another map, instead of all within the same one the player is on. Because of this, when the shop is called, the player's current X, Y, Map, BGM and direction is saved to go back to it when they're done. The REASON why the shop is on another map is because of the numbers needed to display the Lucre the player has, as well as the selling/buying price. To make it all on the same map as the menu would mean coding a giant new menu-like system for it. And I wanted to be a little bit lazier with the shop. :-D. There's not really much to say, except it's basicly the same as the menu with it's menu and sub positions, pop-up positions, etc. The way it works in the end is setting variables to item IDs and calling the shop menu, since all the items in the game all have their own IDs for what they are, and the shop and menu use these to display information about it (a picture), as well as to determine their use when used/equipped/etc.
How the Level, Stats & Damage Calcs Work:The level system is theoretically limitless, as the limit is so high that there's no easy way
to reach max. The max level is 999, however, with each level giving the player 4 points to
use to increase their stats. Each stat maxes at 999, and the HP and MP stats increase by 2 for each point. These specifics are NOT concrete, as balancing issues may make me change it all later. But, if you go from starting stats - 40 HP/MP, and 14 Str/Def/Mag/Wis, at level 999, you will still not have gained enough points to max out every stat. You'd be short by 908 points. :-D. How the EXP system works, is based on what level you're currently trying to get to. Right now (and I plan on keeping it), once you hit level 100, the EXP needed for the next level maxes at 99,999, and every additional level past that requires that much EXP. However, the game is short enough that I don't plan on the player ever even reaching that far. Again, balancing issues might change all of that. Already the system can easily be overpowered early on. Anyway, the formula I use for calculating EXP needed for the next level is as such;
x = ( [current level] * ( [current level] * 100 / 31 ) / 100 )
x = x * x
[new EXP] = ( [current level] + [current level] + x + 20 )
So, at level 1, the EXP needed is 22, 24 at 2, 26 at 3, 28, 30, 33, 35, 40, 42, 49 at 10 to
99 at 15, 204 at 20, 470 at 25, 864 at 30, and so on to 99443 at 99, and 99999 at 100.
This is specific EXP needed, which resets when you gain a level. So after you gain to level 2, you then need 24 more EXP to get to level 3, and so on.
Now onto how stats affect damage, the calculations involved, how they affect magic, etc. First off, physical damage is affected by Str and Def. For SOME reason the most common thing I am asked is "how do I calculate damage and stuff?" - the simple (and usually scourned) answer is; there is no universal formula to figure that out! I just messed around until the formula I used worked in a way I liked. I didn't spend years researching it, I just threw something together until it started calculating out the damage I'd expect from the stats at specific points. It really is something you have to figure out yourself. Or, you can use the RM2K damage calculations which can be found in the manual. Just search for the "combat calculation" page, which is under the "Material Data" category in the index. However, as I said, physical damage is affected by the person attacking's Str, and the person defending's Def, regardless of if it's a monster or player. It's then affected by a random chance between 90% and 110% of the calculated damage, and finally affected by the element the player is (equipped boost), and the element the enemy is. So the basic calculation is;
[damage] = ( [Strength] * 80 / 100 ) - ( [Defense] * 40 / 100 )
If the calculation is less than 0, it's minimizes at 0, and if it's higher than 999, it maxes
at 999.
Now, Magic works the same way calculation wise, but each spell has a power that affects the actual damage done. The first level spells do 80% of the normal damage, while the second level spells do 200% of the normal damage. The non-elemental spells, however, do 120% damage for the first level, and 300% for the second level. Of course, the magic damage is based off of Magic instead of Strength, and Wisdom instead of Defense. The same elemental rules apply, in that the same element = no damage, strong vs = 150% damage, and weak vs = 50% damage.
Conclusion:Hopefully now you won't need to ask me a bunch of questions about how the system works. I am NOT going to write an actual step-by-step tutorial on how I did it, as that is absurd. The systems I use were not made to be generic. They are very specific to my game and my designs. If/when I release the game, you are more than welcome to look at the code I used and try to copy it however you want, but I guarantee that it will not be entirely useful to you. So, good luck with your own complicated systems.