Forcing the players to learn spells before using them.

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
Ixnatifual

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

Post by Ixnatifual »

That's a pretty cool idea.
User avatar
msyblade
Posts: 792
Joined: Fri Oct 12, 2012 4:40 am
Location: New Mexico, USA
Contact:

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

Post by msyblade »

How am I supposed to finish my mod if you guys keep developing useful functions?! Stop it! :x
Currently conspiring with many modders on the "Legends of the Northern Realms"project.

"You have been captured by a psychopathic diety who needs a new plaything to torture."
Hotel Hades
Ixnatifual

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

Post 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.
Last edited by Ixnatifual on Wed Dec 26, 2012 10:19 am, edited 2 times in total.
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

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

Post 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.
Ixnatifual

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

Post 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.
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

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

Post 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!
Ixnatifual

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

Post 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.
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

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

Post 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.
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

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

Post by akroma222 »

This is a damn fine idea :-) Thank you!!
bongobeat
Posts: 1076
Joined: Thu May 16, 2013 5:58 pm
Location: France

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

Post by bongobeat »

thanks for this script!

very useful!!! :)
My asset pack: viewtopic.php?f=22&t=9320

Log1 mod : Toorum Manor: viewtopic.php?f=14&t=5505
Post Reply