Announcement: Be excellent to each other.


Caravel Forum : DROD RPG Boards : RPG Architecture : Skills Smorgasbord (26 skills for you to use)
New Topic New Poll Post Reply
Poster Message
kieranmillar
Level: Smitemaster
Rank Points: 2670
Registered: 07-11-2014
IP: Logged

File: Skills Smorgasbord.drh (11.1 KB)
Downloaded 60 times.
License: Public Domain
icon Skills Smorgasbord (+5)  
There was a hold. In this hold you had 3 classes with up to 10 skills each. It got too complicated and it died.

Instead of having all this effort go to waste, I've stripped most of the skills out of the hold and released them into a new one in the hope that others may be able to use them or learn form them if they wish. A number of issues previously encountered by people when trying to do similar things have been worked around, but it can get a bit complex. The majority of the scripting can be found inside a single 559 line script, with each monster also requiring 180+ lines of code! (Obviously this is in part because there are so many scripts in a single hold. Implementing only one or two of these would massively reduces the amount of code).

Here's a taster of what you will find:
* Skills that allow you to directly change monster's stats and behaviours.
* A multiple choice option menu to select your active skills from at any time via the special command key. You do not take hot tile or enemy attack damage as you navigate these!
* Buffs that last for multiple fights before expiring, and can be manually "shrugged".
* Trigger scripting after killing a monster on the same turn that it dies, including post-combat bonuses that are awarded immediately.
* An inventory level with a comprehensive display of all of your learned skills and active buffs, with descriptions for each by walking over the wubbas that represent them.

The skills that you'll find here vary wildly in the complexity of how they are implemented from incredibly straightforward to horribly complex, but should give you some idea of the sorts of things that are possible.

Please note that two of the buff skills are designed to expire when you pick up a health potion, but this doesn't actually work as there is no proper way to check for this (checking to see if the player's HP is larger than it was last turn is not robust enough to work in all cases, I'm sure you can figure out why). However I have kept these in because I thought there might still be something useful to gain from them. You can instead manually shrug these two buffs by going into the inventory and walking into the wubba representing that buff.

=============
Documentation
=============


Things you should know
-------------

Before we go into the structure of how this scripting system works, it's important to know some particular quirks of the RPG scripting system which will explain a lot about why the scripts work as they do:
* The only way for a script to affect a monster's stats and behaviours is for the monster to execute the code on itself, you cannot change the stats of other characters. So every turn, each monster will check the values of two variables to see if their coordinates match what is in those variables. If it matches, then that monster knows it's being attacked and then executes the skill on itself. This means all this code has to appear in every monster, but hey that's what default scripts are for!
* All skills that deal damage to monsters do not reduce its HP directly, but instead set the _Explosion variable and then build an explosion on top of the enemy and deal the damage that way. This is for two reasons, 1) setting a monster's HP variable to zero or less is what the game uses to figure out if a character is a friendly NPC or something you can get into a fight with, therefore monsters would become invincible instead of dying! 2) So that you get a damage number to fly out of its head in the same way you do when you hit a monster.
* Getting to trigger scripting on the same turn that an enemy dies has always been a problem in RPG due to the fact that the events that check for winning a fight wait until the next turn before executing, the same with the Imperative: Die if you want to force a monster to die. Instead, when we win a fight with a monster we intervene at the last possible moment immediately after the killing blow using the monster's "Each Defend" command, making the monster unkillable, executing the code we need, then faking the monster's death by generating a blood splat and sound where the monster is standing, and then making the monster disappear and ending the script. The REP and GR is still awarded automatically because the game still considers it as winning a fight, despite them monster never actually dying.
* Every turn, each monster resets its imperatives and behaviours, and then immediately repopulates them based on what is needed that turn. This is how we turn off monster attacks while e.g. navigating the skills menu.

Start of game scripts
-------------

Enter the TEST level of the hold and look at the character in the top-left corner (0, 0). This character holds some important code that I thought I'd explain first.
* The special command key is treated by the game as a secret 4th equipment slot. To use it, you "equip" a character via the Equipment command, and then that character can use its "Each Use" command defined in its default scripting.
* The Class variable represents which of the 3 classes you want the player to be: 1 = Fighter, 2 = Mage, 3 = Thief. In this example hold it only really affects which page of skills we start on when we press the special command key.
* The AllowCrossClassSkills variable is set to 1 to allow us to use the active skills of the other classes when we press the special command key. Note that all it does is toggle access to the pages of the skill menu, any passive skills from other classes will still work if this is set to zero, you just won't be able to choose to use the active skills.
* The Skill_ variables are the flags for each skill: 1 = On, 0 = Off. This also determines if it shows up in the inventory. There is one exception, Skill_LockedDoorReclaim, where the skill is entirely handled by the entity generated on the next line: Global_LockedDoorReclaim. So don't generate that entity if you want to turn off the skill. Conversely, there is no harmful effect if you leave Global_CombatWatcher generated even if you turn off Skill_DefOnHitBuff.

The Skills
-------------

Finally, this is why you're reading this post. Here's a description of the skills and the things you need to know.

Fighter

Strike First When Unarmed (Passive)
This skill works by having each monster check if you have the skill and either have no sword or are on oremites, and if so, it gives itself the Attack Last behaviour. Note that this does not work correctly with disarm tokens. You could make this skill an "Always strike first" skill by just having the enemy give itself the Attack Last behaviour if you have the skill, and ignore the other checks, and this would let you use disarm tokens etc. And you'd be right, EXCEPT that many skills that target enemies still need to be able to tell if you are currently wielding a weapon in order to set the correct range and this runs up to exactly the same problems, so in general I'd advise you just avoid disarm tokens if you are using some of these skills for your own project.

Buff: +2 Attack per monster kill, expires when you collect a health potion (100 REP)
OK so this skill doesn't actually expire when you collect a potion because there was no way to get that to work robustly, but I left this in as an example of a skill that ups your stats after every fight. The skill keeps track of how much attack you've currently got from this skill so it knows how much to remove when the buff goes away (currently by looking at the buff in the inventory screen). (Also the skill gives you 2 attack when you cast it to provide feedback that it's working).

Buff: +2 Defense per hit you take in a fight (5 fights) (100 REP)
The defense for this buff gets added via each monster's "Each Attack" command, adding defense each time it hits you, this includes hits that do no damage. Unfortunately the Each Attack command will also trigger if a monster can attack outside of combat, such as a goblin or Evil Eye, therefore we need to figure out if the monster is attacking because you are in a fight or not. To do this, the Global_CombatWatcher character sets the variable InAFight to 1 when the event "wait for monster engaged" gets triggered, and otherwise sets it to zero each turn (monsters also set it to zero when they die). This way the variable only has a value of 1 when you are actually in a fight in progress. Note that we also have to check if we had more attack than the monster's defense, to prevent the game from counting fights with monsters that get aborted because neither of us can damage each other, otherwise this would be a source of inifinite stat farming.

Create Speed Potion (500 REP)
Its a lot safer to put the accessory directly into the player's accessory slot rather than try to build it on the floor, so the script puts it directly into the player's accessory slot only if it is currently empty. If you don't do this you run the risk of overwriting other equipment either in inventory, or equipment slots on the floor, and it's an enormous pain to check for these in a way that is robust.

Convert X HP to 2 Attack (100 REP) (HP Cost scales per use)
A very straightforward skill, you'll need to set the starting cost before using the skill for the first time. It's important to check that the player has enough HP as setting the player's HP to zero or less doesn't kill you and causes odd behaviour.

+10 HP per fight (Passive)
Not much to say here.

Convert 3 DEF to 2 ATK (250 REP)
This skill does prevent you from going to zero defence or less, but there's no actual problems if the player or any monsters have negative DEF, they just take increased damage.

Buff: +5 ATK and DEF, can be stacked. (1 Fight) (25 REP)
In practice increasing the player's stats for just one fight in a manner that can be repeated isn't all that different to repeatedly reducing the monster's attack and defense, except in certain edge cases that aren't always that important. Still, it's here if you want an alternate approach.

Hot tile damage halved (Passive)
You need to change the _HotTile variable at the moment the skill is gained. It is also changed during the "Wrap-Up" section of the Command Key script as we need to set the hot itle damage to zero temporarily when pressing the command key so we don't take damage while navigating the menus.

Mage

Summon Flame 2 tiles ahead (25 damage) (25 REP)
A basic fireball spell that indiscriminately builds an explosion 2 tiles ahead. Note that this has all sorts of implications, it can break crumbly walls (a way to destroy ones next to oremites!), trigger orbs on the other side of walls and destroy items, but you also need to watch out as any friendly NPCs will need to be given Imperative Unkillable unless you want them to get destroyed too. The friendly citizen in the TEST level is an example of one you can blow up with this (the other attack spells only work on monsters as they rely on the monster having code to handle them, this one doesn't).

Lower Enemy Attack by 15 (25 REP)
All of the skills that directly target an enemy will be explained in detail in the following section.

Double damage of Summon Flame (Passive)
Alright I admit this was a filler skill. Nothing much to say here. Note that the description for summon flame in the inventory also changes a bit if you have this.

Halve Enemy HP (200 REP)
All of the skills that directly target an enemy will be explained in detail in the following section.

Buff: Next HP Potion restores double (50 REP)
Another skill that is supposed to cancel when you pick up an HP potion but doesn't, you'll have to manually remove it from the inventory screen. It just changes the internal _ItemHPMult variable and you need to remember to change it back again.

+2 REP per fight (Passive)
Not much to say here. Rather than change the monster's REP value the monsters just increase your REP by 2 when they die.

Transmute Gem (50 REP)
Turns Attack gems into Defense gems and vice versa in the tile you are facing. Pretty straightforward in implementation.

Buff: Immune to swipes and stabs (1 Fight) (100 REP)
Essentially makes monsters not attack or stab you when you stand in front of them or under their swords. Works almost identically to how we stop them from hitting you while navigating a menu. Internally this is referred to as an "environmental" buff because it originally affected hot tiles too. Note that this does not affect aumtlich beams, but can easily be made to disable monster beams in an identical way, by only giving the monster the Beam Attack behaviour if this buff is not present (or menu not open, see MonTemplateAttack character to see how this works).

Thief

Reclaim key when locking a door (Cost Scales)
This skill is entriely "reactive" and is handled solely by the Global_LookedDoorReclaim global script that you need to generate when you gain this skill. The skill waits for you to lock a door then lets you buy the key back for REP by checking what door type you are standing on, and the cost scales so you need to set the initial cost. This implementation has all types of key cost the same. Note that it does not check if you used a skeleton key but this could be added by comparing your key counts to those from the previous turn. In the full hold the plan was to just not have any skeleton keys.

Lower Enemy Defense by 10 (25 REP)
All of the skills that directly target an enemy will be explained in detail in the following section.

Distract Enemy (50 REP)
All of the skills that directly target an enemy will be explained in detail in the following section, but it is worth noting here that what this skill does is make an enemy face away from you then gives it the Evil Eye's Surprised From Behind behaviour. It then pauses the monster's script execution for a turn so you have the chance to strike it before it resets its behaviours. For monsters that do not always turn to face you (like Evil Eyes) the original direction is not stored so they will remain facing their new direction. This is a feature, not a bug, I swear! :lol Note that this skill is referred to internally as "Backstab".

Convince Enemy to Hit Itself (100 REP)
All of the skills that directly target an enemy will be explained in detail in the following section.

+2 GR per fight (Passive)
Not much to say here. Rather than change the monster's GR value the monsters just increase your GR by 2 when they die.

Convert 100 GR to 250 REP
Not much to say here.

Grab item from 3 tiles ahead (100 REP)
After this skill has checked to see if there is actually a grabbable item on the tile 3 tiles ahead, it slows down the cutscene (you are always in a cutscene with a very fast time between turns when the skill menu is open), then waits a turn, then disables your weapon and moves you onto the tile, then moves you back and gives you your weapon back. The player appears to jump to the tile 3 tiles ahead smoothly because that tweening is something done during cutscenes. We disable the player's weapon to avoid accidentally triggering a fight. Note that this skill will collect items underneath monsters and NPCs and on doors. The reason why we wait a turn after changing the cutscene speed is because it takes a turn to take effect for some reason.

Convert 3 yellow keys to 1 green key (50 REP)
Not much to say here.

Pick lock (500 REP)
Will open any door or door in front of you, including greckle gates and black or red doors. You can toggle doors with scripting by using "Activate Item At" on the door.

The MonTemplate Characters
-------------

While this example hold places these characters directly in the room, that is not what they are for. These monsters hold the scripting for three types of monster, and are there for you to copy/paste the code into other monsters to use as their default scripting. This code is necessary to get many of the skills to work. The three types of monster templates are basic monsters, monsters that attack you when you stand in front of them (like seep and waterskippers) and monsters that stand still holding a sword.

All of the characters largely work the same way, they just have a different set of behaviours that need to be set each turn, so it should be easy to tweak them for other monsters.

The majority of the script is a loop that runs each turn, first setting the behaviours, then checking for having a skill used on them. It checks this by seeing if the two values in the EnemyHitBySkill_X and EnemyHitBySkill_Y variables are the same as its X and Y co-ordinates. The variable EnemyHitBySkill_Type is set to hold a different number based on the skill that was used so that the monster knows what skill it is being hit by.

If the skill being used was to drop its Attack or Defense, then it casts Game Effect Jitter on itself 3 times. This effect makes the character or monster on that tile shake, and the more times you apply it during a single turn,the more vigorously it shakes. This is to provide visual feedback that the skill hit.

The Distract enemy skill sets its orientation to the same one as the player, then makes it wait a turn so that you have a chance to kill it before the loop runs again and the behaviours are reset.

The Defend section is where we deal with the monster dying during a fight. Each time the monster is hit by us, it checks to see if it has reached zero HP from that fight then makes itself unkillable so that the fight ends but the monster won't die, so that we can continue running scripting. We do it with the Each Defend command instead of using something like Event Monster Stabbed because this way it occurs immediately and not on the following turn. We also set the imperative right now instead of earlier on so that explosions and similar can still kill the enemy without worrying about having to trigger any more scripting. Most of the scripting in this section is pretty simple, but at the end we can't use Imperative Die to finally kill the monster because it waits a turn, so instead we simulate the monster's death with a Game Effect and then make the monster disappear. When you win a fight against a monster with Imperative Unkillable, you still get awarded the REP and GR so no extra intervention is needed there. If you make the monster look like a rock golem or something, you might want to change the type of effect used here.

The Command Key Script
-------------

Lastly, I need to explain the overall structure of this massive script because it's very imposing, but the structure is quite simple, there are just lots of labels all over the place.

When we press the special command button, we enter a very fast cutscene and set hot tile damage to zero and a variable called Player_Immunity to 1. This variable is checked by monsters to turn off their attacking or sword stabbing damage (or more accurately, not enable it that turn). The next thing that happens is we populate the skill menu. Most of the rest of the script is just labels that contain the scripting for each of those skills. The labels are hopefully pretty descriptive so just look at what label the code is under and the scripting should make sense.

Very very important to note here, there is a label called "Wrap-up" and we must ALWAYS send the script to that label any time we want to end the script. That is because we need to do important things like disable the cutscene and reactivate hot tiles and monster attacks, so you'll see an awful lot of Go To "Wrap-up" commands

Note that gem transmutation, lock picking, and item grabbing all have an extra label associated with them, called things like "Pick That Lock!" or "Grab That Item!". This is because these skills require checking a tile for the presence of certain things, and so we need a whole bunch of checks in a row and we need somewhere to send the code if one of these checks is successful.

Towards the end, just before the final "wrap-up" label there is a label called "Check for Enemy". All of the skills that directly target an enemy work in a similar way so to prevent lots of code duplication a bunch of the code for those skills gets sent here. What these skills will do is check if you have enough REP to use the skill in the first place, then set the EnemyHitBySkill_Type variable to something unique to that skill, then send the code to this label.

The "Check for Enemy" section checks the appropriate tile for a valid enemy. It sets the distance based on if you are holding a sword, doing the same checks to see if you are on oremites as monsters do for setting the Attack Last behaviour for the Strike First While Unarmed skill. This means that unless you change the methods used here you cannot use disarm tokens as there is no easy way to check if the player has a weapon but it is also disabled.

In the final part of the script, the "Wrap-up" section, you immediately get thrown into a loop called "Wrap-up Loop: Enemy Being Hit". This loop exists as a failsafe for the scripts that try to directly target a monster. Unfortunately there is no easy way to check for a target that can correctly handle the skills being used against them, you can only check if the tile has a monster or NPC, and this includes friendly NPCs. Therefore this script waits for 4 turns to see if a monster has reset the EnemyHitBySkill_Type variable and therefore know if the skill use was successful or not before wrapping things up. Try using one of those skills against the friendly NPC in the TEST level to see this in action. Note that this is also why the monster's code is the place where we deduct the REP cost for using the skill, because we can't do that from here because there is the possiblity that the skill might still fail.

Lastly you'll notice if we choose to go to the inventory then we save that until after the wrap-up just to ensure everything gets wrapped up properly before trying to go to a new level which would prematurely end the script with the cutscene and player immunity still active.

=============

Hopefully somebody out there might find this useful. If you have any questions or comments let me know, I'm happy to help.
11-12-2016 at 09:15 PM
View Profile Send Private Message to User Show all user's posts High Scores This architect's holds Quote Reply
New Topic New Poll Post Reply
Caravel Forum : DROD RPG Boards : RPG Architecture : Skills Smorgasbord (26 skills for you to use)
Surf To:


Forum Rules:
Can I post a new topic? No
Can I reply? No
Can I read? Yes
HTML Enabled? No
UBBC Enabled? Yes
Words Filter Enable? No

Contact Us | CaravelGames.com

Powered by: tForum tForumHacks Edition b0.98.8
Originally created by Toan Huynh (Copyright © 2000)
Enhanced by the tForumHacks team and the Caravel team.