Page 2 of 3

Re: Forcing the players to learn spells before using them.

Posted: Tue Dec 25, 2012 9:16 pm
by Ixnatifual
That's a pretty cool idea.

Re: Forcing the players to learn spells before using them.

Posted: Tue Dec 25, 2012 9:23 pm
by msyblade
How am I supposed to finish my mod if you guys keep developing useful functions?! Stop it! :x

Re: Forcing the players to learn spells before using them.

Posted: Tue Dec 25, 2012 11:16 pm
by Ixnatifual
OK here's my take on a working setup using Grimwold's scripts as a base (I'd have no idea how to accomplish this without those - he's the real hero here, not me), that covers all the standard spells and adds the missing spell scrolls to the collection.

The way it works is, you find a scroll, put it in the inventory of a mage, then right-click it. A sound plays and the mage "learns" the spell and is able to cast it from then on.

First, in your dungeon place a script_entity and name it "spellbook_script." Add to it the following code.

Code: Select all

spellbook = {darkness = 0, enchant_fire_arrow = 0, enchant_frost_arrow = 0, enchant_shock_arrow = 0,
 enchant_poison_arrow = 0, fire_shield = 0, fireball = 0, fireburst = 0, frost_shield = 0, frostbolt = 0,
 ice_shards = 0, invisibility = 0, light = 0, lightning_bolt = 0, poison_bolt = 0, poison_cloud = 0,
 poison_shield = 0, shock = 0, shock_shield = 0}

spellNames = {darkness = "Darkness", enchant_fire_arrow = "Enchant Fire Arrow",
 enchant_frost_arrow = "Enchant Frost Arrow", enchant_shock_arrow = "Enchant Lightning Arrow",
 enchant_poison_arrow = "Enchant Poison Arrow", fire_shield = "Fire Shield", fireball = "Fireball",
 fireburst = "Fireburst", frost_shield = "Frost Shield", frostbolt = "Frostbolt",
 ice_shards = "Ice Shards", invisibility = "Invisibility", light = "Light",
 lightning_bolt = "Lightning Bolt", poison_bolt = "Poison Bolt", poison_cloud = "Poison Cloud",
 poison_shield = "Poison Shield", shock="Shock", shock_shield = "Shock Shield"}

function checkSpellbook(caster, spell)
  if spellbook[spell] == 1 then
    return true
  elseif spellbook[spell] == 0 then
    hudPrint(caster:getName() .. " must learn that spell before casting it.")
    return false
  end
end

function learnSpell(champ, spell, skill, reqSkill)
  if champ:getSkillLevel(skill) >= reqSkill then
    if (spellbook[spell] == 0) then
      if spellNames[spell] ~= nil then
        spellbook[spell] = 1
        -- playSound("scribble")
        hudPrint(champ:getName() .. " scribes the spell \"" .. spellNames[spell] .. ".\"")
       else
         hudPrint(champ:getName() .. " does not know what the spell " .. spell .. " is.")
       end
    else
      hudPrint(champ:getName() .. " already knows that spell.")
    end
  else
    hudPrint(champ:getName() .. " isn't skilled enough to learn that spell.")
  end
end
I've commented out the line that plays a sound since you don't have the nice scribbling sound I found. It's easy to put in one of the default sounds ("discover_spell" for example) or quickly Google for a proper scribbling sound.

Next, open your items.lua and add the following.

Code: Select all

cloneObject {
  name = "scroll_darkness",
  baseObject = "scroll_darkness",
  onUseItem = function(self, champion)
  return spellbook_script.learnSpell(champion, "darkness", "spellcraft", 5)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Darkness.\""             
}

cloneObject {
  name = "scroll_enchant_fire_arrow",
  baseObject = "scroll_enchant_fire_arrow",
  onUseItem = function(self, champion)
    return spellbook_script.learnSpell(champion, "enchant_fire_arrow", "fire_magic", 7)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Enchant Fire Arrow.\""             
}

defineObject {
  name = "scroll_enchant_frost_arrow",
  class = "Item",
  uiName = "Scroll of Enchant Frost Arrow",
  model = "assets/models/items/scroll_spell.fbx",
  gfxIndex = 113,
  scroll = true,
  spell = "enchant_frost_arrow",
  weight = 0.3,
  onUseItem = function(self, champion)
    return spellbook_script.learnSpell(champion, "enchant_frost_arrow", "ice_magic", 7)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Enchant Frost Arrow.\""             
}

defineObject {
  name = "scroll_enchant_lightning_arrow",
  class = "Item",
  uiName = "Scroll of Enchant Lightning Arrow",
  model = "assets/models/items/scroll_spell.fbx",
  gfxIndex = 113,
  scroll = true,
  spell = "enchant_shock_arrow",
  weight = 0.3,
  onUseItem = function(self, champion)
    return spellbook_script.learnSpell(champion, "enchant_shock_arrow", "air_magic", 9)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Enchant Lightning Arrow.\""             
}

defineObject {
  name = "scroll_enchant_poison_arrow",
  class = "Item",
  uiName = "Scroll of Enchant Poison Arrow",
  model = "assets/models/items/scroll_spell.fbx",
  gfxIndex = 113,
  scroll = true,
  spell = "enchant_poison_arrow",
  weight = 0.3,
  onUseItem = function(self, champion)
    return spellbook_script.learnSpell(champion, "enchant_poison_arrow", "earth_magic", 11)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Enchant Poison Arrow.\""  
}

cloneObject {
  name = "scroll_fire_shield",
  baseObject = "scroll_fire_shield",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "fire_shield", "fire_magic", 16)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Fire Shield.\""             
}

cloneObject {
  name = "scroll_fireball",
  baseObject = "scroll_fireball",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "fireball", "fire_magic", 13)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Fireball.\""             
}

cloneObject {
  name = "scroll_fireburst",
  baseObject = "scroll_fireburst",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "fireburst", "fire_magic", 2)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Fireburst.\""             
}

cloneObject {
  name = "scroll_frost_shield",
  baseObject = "scroll_frost_shield",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "frost_shield", "ice_magic", 19)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Frost Shield.\""             
}

cloneObject {
  name = "scroll_frostbolt",
  baseObject = "scroll_frostbolt",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "frostbolt", "ice_magic", 13)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Frostbolt.\""             
}

cloneObject {
  name = "scroll_ice_shards",
  baseObject = "scroll_ice_shards",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "ice_shards", "ice_magic", 3)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Ice Shards.\""             
}

cloneObject {
  name = "scroll_invisibility",
  baseObject = "scroll_invisibility",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "invisibility", "air_magic", 19)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Invisibility.\""             
}

cloneObject {
  name = "scroll_light",
  baseObject = "scroll_light",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "light", "spellcraft", 5)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Light.\""             
}

cloneObject {
  name = "scroll_lightning_bolt",
  baseObject = "scroll_lightning_bolt",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "lightning_bolt", "air_magic", 14)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Lightning Bolt.\""             
}

cloneObject {
  name = "scroll_poison_bolt",
  baseObject = "scroll_poison_bolt",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "poison_bolt", "earth_magic", 7)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Poison Bolt.\""             
}

cloneObject {
  name = "scroll_poison_cloud",
   baseObject = "scroll_poison_cloud",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "poison_cloud", "earth_magic", 3)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Poison Cloud.\""             
}

cloneObject {
  name = "scroll_poison_shield",
  baseObject = "scroll_poison_shield",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "poison_shield", "earth_magic", 13)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Poison Shield.\""             
}

cloneObject {
  name = "scroll_shock",
  baseObject = "scroll_shock",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "shock", "air_magic", 4)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Shock.\""             
}

cloneObject {
  name = "scroll_shock_shield",
  baseObject = "scroll_shock_shield",
  onUseItem = function(self, champion)
   return spellbook_script.learnSpell(champion, "shock_shield", "air_magic", 22)
  end,
  description = "A properly trained mage may scribe spells for personal use by copying the inscriptions written upon magic scrolls. This particular scroll contains a spell called \"Shock Shield.\""             
}
In case you want to put in your own custom sound, you'll want to place that in the mod_assets/sounds folder of your dungeon, then add the following to your sounds.lua. If your file isn't named scribble.wav, change accordingly. I believe both WAV and OGG formats should work.

Code: Select all

defineSound {
    name = "scribble",
    filename = "mod_assets/sounds/scribble.wav",
    loop = false,
    volume = 1,
    minDistance = 1,
    maxDistance = 4
}
I made a few choices on how the system works:
- Scrolls don't disappear on use. Reasons being so the player can continue to use them as reference as well as distribute them amongst multiple mages.
- Requirement for learning a scroll is the same as for casting the spell. I think that makes sense in a lot of ways
- Nobody knows any spells initially. Done to make the early scrolls useful. One might imagine mages know some cheap parlour tricks that aren't relevant to the dungeon.
- Fluffwise, the spells are scribed into an abstract spellbook held by the individual mage. Reasons being D&D is cool.

If you want scrolls to be consumed, just add a "return true" statement to the learnSpellFunction when a spell is learned.
If you want some spells to be known initially by everyone, simply put =1 in place of =0 at the spellbook array in the script_entity after the relevant spells.

Re: Forcing the players to learn spells before using them.

Posted: Wed Dec 26, 2012 3:41 am
by Grimwold
Really nice work expanding on my initial idea... I couldn't have spent anymore time on it on Christmas Eve because, as it was, I went to bed at 3am!

I would suggest creating an array for the "nice" spell names, so you don't have to use multiple if statements and it's easier to add custom spells.

e.g.

Code: Select all

local spellName = {darkness = "Darkness",enchant_fire_arrow =  "Enchant Fire Arrow",enchant_frost_arrow="Enchant Frost Arrow",enchant_shock_arrow="Enchant Lightning Arrow", enchant_poison_arrow="Enchant Poison Arrow",fire_shield="Fire Shield",fireball="Fireball",fireburst="Fireburst",frost_shield="Frost Shield",frostbolt="Frostbolt",ice_shards="Ice Shards", invisibility="Invisibility",light="Light",lightning_bolt="Lightning Bolt",poison_bolt="Poison Bolt",poison_cloud="Poison Cloud",poison_shield="Poison Shield",shock="Shock", shock_shield="Shock Shield"}

if spellName[spell] ~= nil then
  hudPrint(champ:getName() .. " scribes the spell " .. spellName .. ".")
else
  hudPrint(champ:getName() .. " does not know what the spell " .. spell .. " is.")
end
note - I've not had chance to test this.

Re: Forcing the players to learn spells before using them.

Posted: Wed Dec 26, 2012 9:46 am
by Ixnatifual
I didn't go that route since I figured it'd be slower to initialise the whole array every time, but I could be wrong. Or maybe it's so fast that it doesn't matter one bit.

Re: Forcing the players to learn spells before using them.

Posted: Wed Dec 26, 2012 9:59 am
by Diarmuid
Why should it be local and initialized every time? just put the whole spellName array out of checkSpellBook...

BTW, thanks both for fleshing out my suggestion in such a complete script!

Re: Forcing the players to learn spells before using them.

Posted: Wed Dec 26, 2012 10:14 am
by Ixnatifual
Diarmuid wrote:Why should it be local and initialized every time? just put the whole spellName array out of checkSpellBook...
Exactly what I just did. I also tested it on all scrolls it looks like it's working perfectly. Post updated.

Re: Forcing the players to learn spells before using them.

Posted: Wed Dec 26, 2012 11:45 am
by Grimwold
Ixnatifual wrote:
Diarmuid wrote:Why should it be local and initialized every time? just put the whole spellName array out of checkSpellBook...
Exactly what I just did. I also tested it on all scrolls it looks like it's working perfectly. Post updated.
Great stuff. And I agree it really didn't need to be local.

Re: Forcing the players to learn spells before using them.

Posted: Sun Feb 10, 2013 11:16 am
by akroma222
This is a damn fine idea :-) Thank you!!

Re: Forcing the players to learn spells before using them.

Posted: Sun Jul 28, 2013 9:53 pm
by bongobeat
thanks for this script!

very useful!!! :)