[DSB Tutorial 4] Custom Methods and Monsters

This forum is for the Lua scriptable clone of DM/CSB called Dungeon Strikes Back by Sophia. Use DSB to build your own highly customised games.

Moderator: Sophia

Forum rules
Please read the Forum rules and policies before posting.
Post Reply
User avatar
Sophia
Concise and Honest
Posts: 4239
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

[DSB Tutorial 4] Custom Methods and Monsters

Post by Sophia »

Lua Tables: A Crash Course!
Before we begin, let's talk briefly about Lua tables. Lua tables are defined within { }'s, with a comma-delimited list of elements. { } alone is an empty table, which isn't useful by itself, but is necessary to create a table if you want to add elements to it. Each table can have an arbitrary number of elements, which are accessed via the syntax table[element]. If the name of an element is a string, a short form with a dot can be used. That is, table["thing"] and table.thing are identical.

The following code creates a new table, t, and sets the element x equal to 1.

Code: Select all

t = { x = 1 }
You can then modify the value of x by setting t.x.

Please note the following important distinction.

Code: Select all

-- The following line of code adds an element y to the table t.
t.y = 2

-- The following line of code creates a new table, with a single element y = 2.
-- Any previous table stored in t is gone, as this overwrites t with a COMPLETELY NEW table, containing ONLY the element y.
t = { y = 2 }
Attack Methods!
Creating a custom Thing is the same as creating a custom Wallitem or any other type of object. Just add an entry to the obj table, either by defining the new archetype explicitly or by using clone_arch to base it on an existing one.

Here is a clone of a normal sword. It simply adds "(MAGIC)" to its description if examined, and will inflict a bit of extra damage in battle.

Code: Select all

obj.sword_magic = clone_arch(obj.sword, {
   shortdesc = "MAGIC",
   base_tpower = 40
} )
That's not so special, though. Let's add the "DISRUPT" method to our magic sword, so that it can harm nonmaterials just like a vorpal blade. That will make it truly magical.

Here are the methods for a normal obj.sword:

Code: Select all

-- You don't need to copy this code. It is already defined in the base code.
obj.sword.methods = {
   { "SWING", 0, CLASS_FIGHTER, method_physattack },
   { "PARRY", 1, { CLASS_FIGHTER, SKILL_DEFENSE }, method_physattack },
   { "CHOP", 2, { CLASS_FIGHTER, SKILL_BASHING }, method_physattack }
}
As you can see, the code defines four things: the name of the method, the required level, the required skill (and, optionally, a subskill), and the function invoked to carry out the method. We'll get rid of "PARRY" and replace it with "DISRUPT". Naturally, we'll want to change the skill required to wizard, too.

Here's a new magic sword that does that:

Code: Select all

obj.sword_magic = clone_arch(obj.sword, {
   shortdesc = "MAGIC",
   base_tpower = 40,
   methods = {
      { "SWING", 0, CLASS_FIGHTER, method_physattack },
      { "CHOP", 2, { CLASS_FIGHTER, SKILL_BASHING }, method_physattack },
      { "DISRUPT", 3, { CLASS_WIZARD, SKILL_DES }, method_physattack }
   }
} )
Creating A New Method!
As long as you only use attack methods that have already been defined in DM, that's all you need to do. What if you want to create an entirely new attack method, though? You'll have to fill in some method_info in order to tell the DSB base code about your new attack method, such as how much experience it gives, whether it uses a charge from the item, and so on. You can either modify the global method_info table, or create a method_info table inside of your new weapon's properties to define methods that are local to that weapon.

For example, let's create a "door opener" object that shoots zo spells.

Code: Select all

obj.door_opener = {
    name = "DOOR OPENER",
    type="THING",
    class="MAGIC",
    mass = 8,
    icon=gfx.icons[65],
    dungeon=gfx.dragon_spit,
    methods = {
        { "SWING", 0, CLASS_FIGHTER, method_physattack },
        { "ZO", 2, { CLASS_WIZARD, SKILL_AIR }, method_shoot_spell }
    },
    def_charge=10,
    convert_deplete="door_opener_x",
    spell_power=150,
    fit_chest = true,
    fit_sheath = true
}
While we're here, take a look at that convert_deplete property. That tells DSB what the object should turn into when all of its charges are depleted. We'll need to define that object, too.

Code: Select all

obj.door_opener_x = clone_arch(obj.door_opener, {
    methods = {
        { "SWING", 0, CLASS_FIGHTER, method_physattack },
    }
} )
In this form, it will sort of work, but DSB will spit out errors because the "ZO" method is unknown. Let's remedy that by adding a method_info entry to our door_opener.

Code: Select all

obj.door_opener.method_info = {
   ZO = {
      xp_class = CLASS_WIZARD,
      xp_sub = SKILL_AIR,
      xp_get = 30,
      idleness = 35,
      stamina_used = 4,
      mana_used = 70,
      missile_type = "zospell",
      ddefense = -7,
      charge = 1
   }
}
Creating A Monster!
Now that we can create new attack methods, let's create some new creatures to beat up on with the attack methods.

As usual, clone_arch is our best friend. That allows us to create a monster very similar to the one we want to modify, only changing a few basic properties. Useful things to mess around with include act_rate, how fast the monster can act; hp, the monster's base hit points; quickness which determines how easily it hits party members and base_power which determines how hard it hits when it does; and attack_type, which controls the sort of melee attack the monster uses. Monsters that shoot things have missile_type and missile_power.

For example, here's a swamp slime that shoots fireballs instead of poison. Extra dangerous!

Code: Select all

obj.fireslime = clone_arch(obj.swampslime, {
   missile_type = "fireball"
) }
While the monster AI is somewhat arcane and difficult to modify, there are a few simple boolean variables that allow you to alter monster AI in interesting ways. These booleans are:
:arrow: hover: The monster will float over pits and triggers.
:arrow: stupid: The monster is exceptionally dim-witted. It won't use any clever tactics, and will frequently blunder into danger.
:arrow: crafty: The monster will try to flank the party members and attack from interesting directions.
:arrow: smart: The monster will coordinate attacks with other monsters.
:arrow: swarmy: The monster will move around quickly, rapidly forming and disbanding groups and attempting to surround the party.
:arrow: paranoid: The monster will do everything it can to avoid being in a place where it can be attacked.
:arrow: pounces: The monster will pause briefly and then spring forth, moving and then attacking almost immediately.
:arrow: counterattack: The monster will immediately respond with its own melee attack when it is attacked in melee, unless it has just attacked.

You can use these properties simply by setting them to true.

Code: Select all

obj.mummy.counterattack = true -- Makes mummies fiercer
You can also learn about other useful monster properties by reading a monster's object definition in base/objects.lua. Most of the properties are reasonably self-explanatory if you have a grasp of the fundamentals of how DSB works.

Next time, we'll delve into even more complicated mechanics and Lua code.
User avatar
Kesa
Journeyman
Posts: 67
Joined: Fri Sep 10, 2010 11:44 pm

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by Kesa »

Oooo this is very good to know thank you Sophia good work as always ^.^
User avatar
ian_scho
High Lord
Posts: 2806
Joined: Fri Apr 07, 2006 8:30 am
Location: Zaragoza, Spain

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by ian_scho »

Oohh, some of those monster attributes are relatively new... And nasty! Great work.
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by Gambit37 »

Excellent stuff, this is really beginning to make things clearer for me about both the possibilities, and the "how to...". Thanks Sophia. Why I didn't ask you for tutorials in the first place, and just moaned for a year, I don't know :)

In terms of which files to put new code in, does it matter? For neatness, I'd like to have new code for say a monster in its own lua file/folder with all associated sounds and gfx there too. Keeps things neat and easy to find. Is that OK? Can I also spread stuff over my drive and when I compile, it will all be incorporated into the final file successfully?
User avatar
ian_scho
High Lord
Posts: 2806
Joined: Fri Apr 07, 2006 8:30 am
Location: Zaragoza, Spain

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by ian_scho »

Gambit37 wrote:For neatness, I'd like to have new code for say a monster in its own lua file/folder with all associated sounds and gfx there too. Keeps things neat and easy to find. Is that OK?
And it'll be better for the rest of us if you release your source material as well!
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by Gambit37 »

Yep, I will do, but only after I've released the finished game. Although, I doubt there will be anything major in my code that isn't already posted as an example/discussion on the forum. I'm a copy and paste kinda guy :-)
User avatar
ian_scho
High Lord
Posts: 2806
Joined: Fri Apr 07, 2006 8:30 am
Location: Zaragoza, Spain

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by ian_scho »

Great stuff. What I really meant to say is IF you release your source material AND it's all nice and tidily organised - all the better for others to learn and reuse :P
User avatar
zoom
Grand Master
Posts: 1819
Joined: Tue Sep 23, 2003 1:27 am
Location: far away but close enough

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by zoom »

Code: Select all

obj.door_opener.method_info = {
   ZO = {
      xp_class = CLASS_WIZARD,
      xp_sub = SKILL_AIR,
      xp_get = 30,
      idleness = 35,
      stamina_used = 4,
      mana_used = 70,
      missile_type = "zospell",
      ddefense = -7,
      charge = 1
   }
}
why isn´t it
charge = true
or something like that (boolean?!)

as I understand it, there is no way to have an item´s action use up more than one charge (eg. 2 charges)
because:
when I have the action use up 2 charges and have 5 charges left, then it won´t ever trigger "convert_deplete":

...take a look at that convert_deplete property.
That tells DSB what the object should turn into when all of its charges are depleted

-->OR IT GOES NEGATIVE?

--------------------------------------------------------------------------------------------------------------------------------------------
I was thinking about -albeit complicated - 2 actions that all use up different amounts of charges.
If one of these actions can´t be used anymore(using 2 points and just one left) technically
this would require a change to "item with only action1 left(the one that uses up one charge"

As I see it right now, the simplest way would be to not allow actions that use up multiple charges.
-------------------------------------------------------------------------------------------------------------------------------------------
just stick to actions that use up one charge each.




probalby some spoiling things ahead:

(I was also musing on different types of charges on one item maybe.
I am questioning whether this really makes sense...so thinking aloud.

Holy Cleric power, magical force..
Spoiler
So you could have fury that regenerates charges over time, re- usable fireballing.
but have a standard wand that once depleted is used up for good. (as is)
Spoiler
or have cleric levels charge holy weaponry also over time or by spell;
so I would need the opposite of convert_deplete... more a convert_recharge,
or just remove the item and substitute it with another I honestly do not know at this point
Spoiler
Also an evil vampiric weapon comes to mind that uses up health to charge itself.
Even when it is fully charged, but then a little less.
So it should lose charges by itself(inventory) and get charges through health by the wielder(in hand)
Is /would that already be doable some way?
User avatar
Sophia
Concise and Honest
Posts: 4239
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by Sophia »

Items that use multiple charges are allowed because it isn't really any more difficulty to implement and it adds flexibility. If all anyone ever uses is "charge = 1" then that's fine, and if that's the only option that makes sense, that's fine too.

All of that spoilered stuff is quite doable. :D
User avatar
zoom
Grand Master
Posts: 1819
Joined: Tue Sep 23, 2003 1:27 am
Location: far away but close enough

Re: [DSB Tutorial 4] Custom Methods and Monsters

Post by zoom »

ah ok, then all is fine. ;) THank you for the answers to virtually every question I had! :shock:
^___EDIT: I meant this is really great!!!!!!!!!!!:D

Does there already a table with item properties exist? Someone requested this back then...Gambit?

why a table?
in case of the magic sword which is built from an clone_arch of a sword,
I do not really get information on the sword itself when looking at the code of magic sword. I fear I end up with spaghetti code all over the place with cross referencing !

How should one proceed when adding items, is there some method to keep things tidy?
(this table or list I mentioned earlier would be a text file telling me what Items there already are in the dungeon or something like that.
Basically I could also scroll up and search for the entry "sword" I guess.hmm)
Post Reply