How to... ?

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.
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

How to... ?

Post by Mon Ful Ir »

I'm an okay-ish RTC coder looking to create my next dungeon in DSB, now that we have a (rather good!) editor program for DSB dungeons.

I'd like to re-use a whole lot of the graphics that I've created (or at least, ripped from other games and converted to RTC). However, I'm struggling because ESB doesn't handle graphics.

As I understand it, RTC-compatible dungeon graphics in .png format should be directly importable into DSB--I believe the scale, and the "hot pink" background, will work in DSB in the same way as they would in RTC. Is that right?

If so, please could someone explain in very simple terms how to:-

1) Clone a creature, and give the cloned creature different graphics in such a way as I can use both the old creature and the new one;
2) Clone an item, and give the cloned item different graphics in such a way as I can use both the original item and the new one?

Thanks in advance

MFI
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

Mon Ful Ir wrote:I'm struggling because ESB doesn't handle graphics.
Yes, this is probably its biggest weakness at this point.
Mon Ful Ir wrote:RTC-compatible dungeon graphics in .png format should be directly importable into DSB--I believe the scale, and the "hot pink" background, will work in DSB in the same way as they would in RTC. Is that right?
Yes. Almost all graphics that will work in RTC will work in DSB.

So, here's a simple walkthrough on how to import graphics:

This first step needs to only be done once (per dungeon); in your custom dungeon's directory, create a file called startup.lua and add the following to it:

Code: Select all

lua_manifest = {
    "graphics.lua"
}
This step is not strictly necessary, but it will allow us to put all of our graphics importation stuff into a separate file. It also allows us to add more source code files to the custom dungeon simply by adding another filename to the lua_manifest. ("graphics.lua, "code.lua", "new_spells.lua" etc.)

In graphics.lua, a basic graphics importation command looks like this:

Code: Select all

gfx.something = dsb_get_bitmap("SOMETHING")
Don't specify a file extension as DSB will figure it out. If your organization scheme is something past the days of DOS, you can also use a longer scheme:

Code: Select all

gfx.something = dsb_get_bitmap("SHORTNAME", "path/to/actual/file.ext")
In this case, since you're specifying a path, you need an extension. The short name is still essential because this is how DSB will refer to the file once a graphics.dsb is compiled. There is no rule that the short names have to be in all caps, it's just a convention I've been using, by the way.

Once your graphics have been entered into the gfx table, you can use them in custom objects. You'll need to create (or edit, if you already did) the file objects.lua, also in your custom dungeon's directory. This file is always automatically parsed-- you don't need to add it to your lua_manifest.

So, let's say we've loaded a graphic that we entered into the gfx table as gfx.new_apple_icon, with the intention of replacing the icon of an apple. Add the following line to objects.lua:

Code: Select all

obj.new_apple = clone_arch(obj.apple, {
   icon = gfx.new_apple_icon
} )
What clone_arch does is make an exact copy of the object archetype, and then merge the provided table of changes into that copy. In this case, the table only has one entry, so all that changes is the icon. Let's say we wanted to make our new apple heavier, give it a different look in the dungeon, and raise its nutritional value. Something like this would work:

Code: Select all

obj.new_apple = clone_arch(obj.apple, {
   icon = gfx.new_apple_icon,
   dungeon = gfx.new_apple,
   mass = 8,
   foodval = 1000
} )
The process of creating a monster, wallitem, etc. or anything else based on an existing one is the same as the process for items. All object properties can be discerned by looking at base/objects.lua, I'd think. It is a little more arcane than the RTC approach to object creation, but, on the other hand, all properties are 100% there and editable, as opposed to having to worry about cloning and inherent properties. It's perfectly possible to define objects completely from scratch in DSB, as well, as many of them are in base/objects.lua. I should point out, having said that: clone_arch is just a convenience, as there is no real "cloning" in DSB and all object archetypes are independent entities. That is to say, clone_arch creates a simple copy, and there is no real sense of "inheritance."

Sorry if this seems messy but it's really not so bad once you get the hang of it. All of this has already been done in the DSB test_dungeon if you'd like an example of it in use. :)

One final note: When your dungeon is ready to go, all you have to do is add a "Compile=1" to line to the first section of dsb.ini and a dungeon.dsb and graphics.dsb will be created, which are compiled (and compressed/obfuscated) versions of your dungeon and graphics. You can hide your Lua code from prying eyes with the LuaC compiler.
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Thank you very much for this prompt and clear explanation.
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Okay, here's thirty-odd monsters in rtc format: dungeon.lua, startup.lua, objects.lua, graphics.lua and a folder full of all the necessary graphics.

NB: The monsters don't behave as expected yet, and not all my creatures are in this file--there are quite a lot more to upload. When all works properly, I would like to make a proper release of this file as a shared resource for dungeon designers. In time, I would like my ghouls to temporarily paralyze you by touch, the wights and wraiths to drain experience points, etc., but at the moment I'm afraid they're just basically screamers with variant graphics. The "dungeon" is just a small zoo for looking at them.

(removed -- use a later file version please!)

Edited to add: The brown spider looks grey because I'd made a mistake, but I've found that and fixed it on my file.

RTC had a flag to make some of the monsters look semitransparent. Is this possible in DSB?
Last edited by Mon Ful Ir on Tue Dec 07, 2010 7:24 pm, edited 1 time in total.
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

Oh, this is good. :)
I hope you don't mind if I steal a couple of these myself, actually. :D
Mon Ful Ir wrote:RTC had a flag to make some of the monsters look semitransparent. Is this possible in DSB?
Not at present. DSB had support for alpha channels from very early on, so I never saw the need. If it'd help, I can certainly look into it, though. I don't remember exactly how I've got things set up so I'm not sure just now how much trouble it would be to add.
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

I certainly don't mind you using them! Some are ripped from Conflux with Zyx's permission, others from DM-like games (particularly Dungeon Hack and the ESB series).

I'm afraid I don't understand alpha channels. A flag in the ESB interface would certainly help me if it isn't technically difficult. But I could also get off my lazy arse and figure them out, and I've got plenty of other technical questions I need to ask you as well!

Please can you tell me the best way to create custom attacks for monsters? Do I set up a separate attacks.lua to release with my files?

I will need:-

1) A temporary paralysis effect from the ghoul's attack. It should grey out one character so that the character isn't available to swing weapons or cast spells for, say, 30 seconds.

2) An experience drain effect from the wight's and wraith's attacks. Ideally it should scale correctly, so that the character loses one experience level; one hit should take a novice down to a neophyte, or a mon master down to a pal master. (A double-level drain for the yet-to-be-released spectre would be good too...)

3) The mindflayer ideally needs a touch attack that kills (fixed 10k damage) and a ranged attack that drains WIS and mana from everyone in the party, ideally with death when WIS is at zero, if that's technically possible. (I can see function wisdom_damage in damage.lua. Do I need to write a variant function, and if so can I do it without breaking anything else?)

4) Here's a more complicated one:- I've got graphics for cockatrices and medusae and basilisks, and I want them to turn characters to stone. This couldn't be done in RTC at all, but I wonder if it might be doable in DSB with a variant of function sys_character_die from damage.lua?

The idea is that petrifaction is a different kind of death. It duplicates death, but the dead character leaves a statue instead of bones and their picture turns into a statue instead of a skull. Then there are either altars of depetrifaction (like altars of vi, but for statues instead of bones), or else ideally, you can read a scroll that turns one statue (randomly-selected if there are several) back into a living character, the scroll being consumed in the process.

(If it's technically possible, this attack is eventually going to be for the cockatrice and basilisk. The medusa version would ideally be even more complicated. The cockatrice and basilisk versions are touch attacks but ideally the medusa version would be a ranged zap that a character can reflect if they have a mirrored shield. The reflect would be an "attack" for the shield so you'd have to have it in the character's right hand and click it at the correct moment to make it work.)

I'll have even more questions when I get round to making Things, I'm afraid.
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

Wow, this is complicated. The good news is that, yes, DSB can do almost all of this. :D

The best way to do 1 and 2 would be to add a special_attack method to the monster's archetype. By default, it has a 50% chance of occurring, but you can set special_chance in the archetype to change this percentage. The special_attack is a function take takes the following parameters: special_attack(monster_arch, monster_id, target_position, target_char, damage_type, damage_amount) and is executed after the character takes normal damage from an attack.

Alternatively, you can create an attack function that entirely replaces the monster's attack. This one looks like: attack_function(target_position, target_char, monster_arch, monster_id) and it returns three parameters: a damage type (usually HEALTH), the amount of damage done, and a "zone" to attack (in the case of causing injuries)

I'll get to some of the more complicated stuff later. I've got to run now. I hope this helps, though. :)
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

I know it's really complicated, but that's why I wanted to switch to DSB--I wanted to do things that RTC can't do!

Right, so reading the files, my theory about the paralysis is that it calls one of the idleness functions, but I'm afraid I can't figure out the code for these things. Sorry...
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

I'll try walking you through the first effect, and maybe it will clarify matters some.

There are a few ways to handle doing the paralysis, but probably the best general purpose method is to create a condition, just like poisoning. Something like:

Code: Select all

C_PARALYSIS = dsb_add_condition(INDIVIDUAL, nil, nil, 5, paralysis_func)
This adds a condition called C_PARALYSIS that, when active, will run a function called paralysis_func every 5 ticks.

So, let's define paralysis_func. Note that this code needs to go above the previous line, because paralysis_func needs to already be defined at the time it gets added to the condition.

Code: Select all

function paralysis_func(who, strength)
   local ppos = dsb_char_ppos(who)   
   dsb_set_idle(ppos, 6)
   if (strength > 1) then
      return strength - 1
   else
      return 0
   end
end
Every 5 ticks, this function will set the character position's idleness to 6 (so that the person will never be freed up) and decrease the strength by 1, which causes the paralysis to eventually wear off, in a number of seconds equal to the strength value, because DSB runs at 5 ticks per second.

Now, let's block magic. Many of the effects you want are best achieved by overriding some of the sys_* functions. For example, blocking magic would be best accomplished by writing a new sys_forbid_magic that overrides the base (empty) one, and provides some situations under which magic is forbidden, like paralysis.

Code: Select all

function sys_forbid_magic(ppos, who)
   local paralyzed = dsb_get_condition(who, C_PARALYSIS)
   if (paralyzed) then
      return true
   end
   return false
end
This checks the paralyzed state for the character attempting to use magic, and if the condition is active, forbids magic.

Finally, we need to set up a monster that can paralyze. As mentioned before, a special_attack will do that nicely.

Code: Select all

function ghoul_special_attack(arch, id, ppos, who, dtype, damage)
   local paralyzed = dsb_get_condition(who, C_PARALYSIS)
   if (not paralyzed) then paralyzed = 0 end
   paralyzed = paralyzed + 30
   if (paralyzed > 90) then paralyzed = 90 end
   dsb_set_condition(who, C_PARALYSIS, paralyzed)
end
This code checks if the character is paralyzed already, and if not, starts with a strength of 0. Then, it adds 30 to the paralysis strength, which, as we saw above, means 30 seconds. It puts a cap on it to keep things from getting out of hand, and then sets the paralysis to the new value.

Adding this special attack to a monster's archetype is as simple as setting the special_attack property to ghoul_special_attack. Using special_chance will change the percentage, so for example to create a ghoul with a 20% chance of paralysis do:

Code: Select all

obj.ghoul = {
   -- Other stuff...
   special_attack = ghoul_special_attack,
   special_chance = 20,
   -- More other stuff....
}
I hope this helps. :D
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Thank you, Sophia. (Amber?)

This code goes in object.lua?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

Mon Ful Ir wrote:Thank you, Sophia. (Amber?)
That's me. :D
Mon Ful Ir wrote:This code goes in object.lua?
It can. DSB isn't really picky about how you organize things, but sometimes it's not a good idea to bloat your objects.lua file with lots of code, so most of it could also go somewhere else, like another file that you add to your lua_manifest. Your mentioned suggestion of attacks.lua is also good. The only thing that has to go in objects.lua is, of course, the definition of obj.ghoul.
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

That makes sense. :)

In the meantime I've been busily setting up more graphics and items, which I'll share with you tomorrow in case it helps.
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Here's a file similar to the other one, but with more content.

(removed -- use a later file version please)

There are about a dozen extra monsters and a few of what dsb calls "things":- weapons (a hammer and a spear), armour (brigandine chest and legs, with male-female versions of each, and a female version of ordinary leather), some food (berries, fruit, an egg, a heart), a bottle and a chalice (with full and empty versions of the chalice). Maybe the bottle contains a genie? :) There are also graphics for some new keys, but I'm saving them til I upload the wallitems and doors.

You can also see my attacks.lua. I've tried editing it a bit to see if I could vary what happens, but everything I tried seemed to break the code, so it's back to a straight copy/paste of what you wrote.
Last edited by Mon Ful Ir on Tue Dec 07, 2010 7:25 pm, edited 1 time in total.
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

Mon Ful Ir wrote:You can also see my attacks.lua. I've tried editing it a bit to see if I could vary what happens, but everything I tried seemed to break the code, so it's back to a straight copy/paste of what you wrote.
Oh, what happened? Maybe it's some odd bit of Lua syntax that you're just not getting. What are you trying to change?
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

When the paralysis took effect, I was trying to make it print a message on the screen: "<WHOEVER> IS PARALYZED". So after some careful poring over various lua files in base, I added two lines of code to function_ghoul_attack:

local whoname = dsb_get_charname(who)

and

dsb_write(system_color, whoname .. " IS PARALYZED")

When I did, the ghoul stopped paralyzing anyone and no message appeared on the screen. Sorry -- I may be too dumb to write lua. :)
User avatar
Joramun
Mon Master
Posts: 925
Joined: Thu May 25, 2006 7:05 pm
Location: The Universe

Re: How to... ?

Post by Joramun »

Could you post the full code of your function ? I could check it.
What Is Your Quest ?
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Sure.

Code: Select all

function ghoul_special_attack(arch, id, ppos, who, dtype, damage)
   local paralyzed = dsb_get_condition(who, C_PARALYSIS)
   local whoname = dsb_get_charname(who)
   if (not paralyzed) then paralyzed = 0 end
   paralyzed = paralyzed + 30
   dsb_write(system_color, whoname .. " IS PARALYZED")
   if (paralyzed > 90) then paralyzed = 90 end
   dsb_set_condition(who, C_PARALYSIS, paralyzed)
end
User avatar
Joramun
Mon Master
Posts: 925
Joined: Thu May 25, 2006 7:05 pm
Location: The Universe

Re: How to... ?

Post by Joramun »

Syntax looks correct.

System_color might be a transparent color for all I know. Try to see in "magic.lua" what is done in the "create_potion" function for colors.

However, this doesn't explain why the attack doesn't work anymore.
What Is Your Quest ?
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

The code for potions in magic.lua is:

Code: Select all

function create_potion(atype, ppos, who, pow, skill, delay)
	local flask = find_arch_in_hand(who, "flask",
		dsb_get_charname(who) .. " NEEDS AN EMPTY FLASK IN HAND FOR POTION.")
	
	if (flask) then
		dsb_swap(flask, atype.potion)
		exvar[flask] = { power = pow }
	else
		return true
	end
	
	return false, flask
end
User avatar
Joramun
Mon Master
Posts: 925
Joined: Thu May 25, 2006 7:05 pm
Location: The Universe

Re: How to... ?

Post by Joramun »

My mistake. The color is correct.
What Is Your Quest ?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

The problem isn't with the attack, or with the dsb_write call. It's that the testing character is level 15 fighter with 200 dexterity. The monster simply does not hit the character often enough to reliably test anything. ;) I reduced the character to a mere mortal and the additional text works fine.
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Ah, so simple! Thank you. :)

Developing more today, and experimenting, I've created a new attack method, but when I did it broke all the other attack methods. So I've finished up copying all the attack methods from methods.lua into my local attacks.lua to make everything work. It's a solution, but was there a better way?

Also, any suggestions on the experience point drain?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

Mon Ful Ir wrote:I've created a new attack method, but when I did it broke all the other attack methods. So I've finished up copying all the attack methods from methods.lua into my local attacks.lua to make everything work. It's a solution, but was there a better way?
There most certainly is. :D

I have a feeling you copied the syntax in methods.lua exactly, which doesn't work in this case, because that method defined the whole table at once, and all you wanted to do was add to the table.

Please permit me to digress into a brief lesson on Lua syntax. Code like this defines the entire table tbl at once:

Code: Select all

tbl = { a = 12, b = "text" }
Anything that was in tbl before is now gone, because you've completely overwritten tbl with a brand new table. If you want to add to an existing table, you have to specify an element to add, like this:

Code: Select all

tbl.x = "hello"
Placing this line after the previous line of code will result in a table with members a = 12, b = "text", and x = "hello".

So this means if you want to add a "SLAP" method to the method_info table, the proper syntax is something like:

Code: Select all

method_info.SLAP = {
   -- method stuff goes here...
}
Incidentally, you can also encapsulate method info inside of a weapon's archetype, if you think that method is really only relevant to that one weapon.

Code: Select all

obj.magic_sword = {
   -- Other stuff goes here...
   method_info = {
      SWING = {
         -- Custom "SWING" method for this sword goes here...
      }
   },
  -- More stuff goes here...
}
Mon Ful Ir wrote:Also, any suggestions on the experience point drain?
This may be a D&D-ism that isn't quite as applicable to DM. Things like subskills and the stat increases on level up make it quite a bit more messy, to be sure. DSB doesn't include any elegant way to "level down" a character precisely because I could never quite figure out how to do it in a reasonable fashion, actually. ;)
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Thank you.

So I wrote:

Code: Select all

--Player attacks
method_info.PUMMEL = {

	PUMMEL = {
		xp_class = CLASS_NINJA,
		xp_sub = SKILL_MARTIALARTS,
		xp_get = 19,
		idleness = 16,
		stamina_used = 12,
		power = 60,
		req_luck = 42,
		ddefense = -10,
		enhanced_critical_hit = true
	}
}	
Then I ran it, and all was fine until I actually tried to trigger the effect. Then I got a ctd with the following error message:-

Lua function PUMMEL:base/methods.lua.412:attempt to perform arithmetic on field 'xp_get' (a nil value)
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

The second table is redundant. :)

Try this:

Code: Select all

method_info.PUMMEL = {
      xp_class = CLASS_NINJA,
      xp_sub = SKILL_MARTIALARTS,
      xp_get = 19,
      idleness = 16,
      stamina_used = 12,
      power = 60,
      req_luck = 42,
      ddefense = -10,
      enhanced_critical_hit = true
}

By the way, I just released a new version of DSB. It has a few minor enhancements and bugfixes, so at your convenience you might want to grab it. :)
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Thank you for your patience and your revised DSB release. :)

On the experience drain... I suppose the program could save a snapshot of the character's gained stats and subskills at each levelup, so a leveldown reverts to a previous snapshot, but I think it would be a lot easier to implement a different nasty touch attack! Say, steal 5 vitality a hit or something.

Let me see if I can figure out the code for that.

Edit: I do believe I've got it. :)

Code: Select all

function wight_special_attack(arch, id, ppos, who, dtype, damage)
   local new_vit = dsb_get_stat(who, STAT_VIT) -50
   dsb_set_stat(who, STAT_VIT, new_vit)
end
Was there a more elegant way?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: How to... ?

Post by Sophia »

Mon Ful Ir wrote:Was there a more elegant way?
No, that looks good.

Next, I'll do a tutorial for how to do the mindflayer's ranged attack that drains wisdom and mana. It will build off what you already know about how to drain stats, and also give me a chance to introduce some of the new easier-to-use mechanics for creating custom spells that I added in DSB 0.45.

The projectile, added to objects.lua, looks something like this:

Code: Select all

obj.psychic_projectile = clone_arch(obj.desewspell, {
   name="PSYCHIC BLAST",
   dungeon=gfx.lightning,
   flying_away=gfx.lightning,
   flying_toward=gfx.lightning,
   flying_side=gfx.lightning_side, 
   flying_hits_nonmat=false,   
   on_location_explode=psychic_explode_square
} )
So it's mostly of an exact copy of a Des Ew spell, except for the part about looking like a lightning bolt. Of course, I've also removed the part where it hits and damages non-material monsters. Instead, when it explodes, it calls the psychic_explode_square function. We need to provide that function, of course, probably somewhere in one of the files loaded in our lua_manifest.

Code: Select all

function psychic_explode_square(lev, xc, yc, range, dmgpower, hit_type)
    local p_at = dsb_party_at(lev, xc, yc)
    if (p_at) then
        local base_dmg = calc_fireball_damage(range, dmgpower)
        local ppos
        for ppos=0,3 do
            local who = dsb_ppos_char(ppos)
            if (valid_and_alive(who)) then
                local dmg = magic_damage(ppos, who, base_dmg, true)
                do_damage(ppos, who, MANA, dmg * 0.75)
                
                local wis = dsb_get_stat(who, STAT_WIS)
                wis = wis - dmg
                if (wis < 10) then
                    dsb_set_bar(who, HEALTH, 0)
                else
                    dsb_set_stat(who, STAT_WIS, wis)
                end
            end
        end
    end
end
This function is a bit longer, so I'll walk through it. The first line checks if the party is at the location of the explosion. If not, we obviously don't need to do anything. If the party is there, we compute the basic damage, using the same formula as an exploding fireball, via calc_fireball_damage. Then, we iterate over each of the four party positions. First we check to see if the character at that location is a valid, living character by calling valid_and_alive. If it is, then we compute the damage based on that character's Anti-Magic by calling magic_damage, and damage the mana 75% of the returned value. The DM magic damage formula is optimized for damaging health, and mana tends to be lower, so the 25% reduction is to balance things a bit. We then apply the damage to wisdom. DSB stats are 10x internally, so the damage value tends to work pretty well as-is with wisdom. If the value is going to drop below 10 (i.e., below 1 displayed), the character is killed.

Finally, to give this attack to a monster, we can just set it as the missile_type. Here's a CSB demon who uses this attack instead of a fireball. (and, as such, can no longer shoot down doors)

Code: Select all

obj.psychic_demon = clone_arch(obj.demon2, {
	missile_type = "psychic_projectile",
	door_opener = nil	
} )
I hope this helps. :D
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Yes, that helps enormously! Thank you.

I thought the mind blast deserved a bit more in the way of special effects than the default lightning bolt graphic, so it shoots a sort of pinkish-purple blob at people.

(removed -- use a later file version please)

I probably want it to hurt quite a bit more than it does at the moment. The current version takes about five or six hits to kill a novice-level character with 40 WIS. Presumably that's just a case of upping the missile_power parameter to about 250?

Incidentally there are a few more custom monsters and objects in the file as well.
Last edited by Mon Ful Ir on Tue Dec 07, 2010 7:25 pm, edited 1 time in total.
User avatar
Trantor
Duke of Banville
Posts: 2466
Joined: Wed Mar 09, 2005 4:16 am
Location: Berlin, Germany
Contact:

Re: How to... ?

Post by Trantor »

Sorry for being off-topic, but I just want to state that this thread is a great lesson for everyone who is curious about the magic of DSB. It shows just how creative you can be with DSB, and how to put the creativity in a dungeon. And Mon Ful Ir, I'm really looking forward to the thing you are building!
Mon Ful Ir
Adept
Posts: 221
Joined: Sat Jan 07, 2006 1:54 am
Location: Britain

Re: How to... ?

Post by Mon Ful Ir »

Thanks for the vote of confidence, Trantor.

Mindflayer touch attack is a beautifully simple thing, provided you're not the one being touched. It looks like this:-

Code: Select all

function mindflayer_touch(arch, id, ppos, who, dtype, damage)
   dsb_set_bar(who, HEALTH, 0)
end
I can and will write several other specials (e.g. shadows will drain STR, etc.) But I'm afraid the petrifaction business is still quite beyond me.
Post Reply