Light control (torches / magic) and punishment for lore

Ask for help about creating mods and scripts for Grimrock 2 or share your tips, scripts, tools and assets with other modders here. Warning: forum contains spoilers!
Post Reply
OGDA
Posts: 115
Joined: Tue Oct 28, 2014 5:07 pm

Light control (torches / magic) and punishment for lore

Post by OGDA »

Hello,

there are different threads in the forum searching for controlling spells and different aspects of spell usage and light control for the party which are generally not answered / solved.
For further use I'm creating this thread with some info I found out over the last days.

Following topics are covered:
Completely disabling a spell
Disabling torches only in a certain level / in an area of an level (check if party is carrying torches in hand)
Punish the party for casting the light spell (also only in a certain area) (check when spell is cast)
Removing light / casting darkness

----------------------------------

Completely disabling a spell

In \mod_assets\scripts\init.lua create a duplicate of the party component.
As you can see in the following script, the spell "light" is completely disabled by "return false" (thanks to JKos for helping!)

Code: Select all

defineObject{
	name = "party",
	baseObject = "party",
	components = {
		{
		class = "Party",  
		onCastSpell = function(party,champion,spellName)
			if spellName == "light" then
				return false
			end		  
		end
		}
	},
}
----------------------------------

Disabling torches only in a certain level / in an area of an level

In my case I use a "lore-method": the party gets punished with damage if anyone puts a torch into his hand.
I use the damage party script by Nutjob:
viewtopic.php?f=22&t=8186&p=82799&hilit=damage#p82799

Set up a timer with for example 2 seconds and let it execute the function darkd3checklight in the following script:

The check about party.level == 13 is optional and check which level the party is currently walking in.

Code: Select all

function darkd3checklight()
	if party.level == 13 then
		for i = 1, 2 do
			for k = 1, 4 do
				local champion = party.party:getChampion(k):getItem(i)

				if champion ~= nil and champion.go.name == "torch" then
					dmgParty(20)
				end
			end
		end
	end
end


 function dmgParty(power, _positions, percChance, dmgType, hasSound) --, directionOfAttk removed
       _positions = _positions or {1,1,1,1};
       percChance = percChance or 100;
       power = power or math.random(1,1); -- change this (the 'random function parameters' to an integer|float)to have a different default
       dmgType = dmgType or "physical";
       if hasSound == nil then hasSound = true; end
       local range = string.split(tostring(power), ".");
       local minDmg, maxDmg = nil,nil;
       if #range == 2 then
          minDmg = tonumber(range[1]); maxDmg = tonumber(range[2]);
          if minDmg > 0 and maxDmg > 0 and minDmg <= maxDmg then
             power = nil
          else print("Damage out of range or unrecognized format. "); return false; end
       end

       local _dmgTypes = {cold = 1, fire = 2, physical = 3, poison = 4, shock = 5}
       local _sounds = {"frostbolt_hit" , "fireball_hit", "ogre_impact", "poison_bolt_hit", "lightning_bolt_hit_small"}
       local sound = nil;
       local p = party.party;
       local _percChance = {}

       if type(_positions) ~= "table" then print("_positions must be a four field table."); return false; end
       if type(percChance) == "number" then
          for _,_ in ipairs(_positions) do table.insert(_percChance, percChance); end
       elseif type(percChance) == "table" then _percChance = percChance;
       else print("percChance unrecognized format."); return false; end
       -- if it doesn't exist as a definition lookup
       if type(_dmgTypes[dmgType]) ~= "number" then
          -- attempt to find it as a numerical key
          for k,v in pairs(_dmgTypes) do
             -- and if it's found assign the string reference for damage type
             if dmgType == v then dmgType = k; sound = _sounds[v]; break; end
          end
       end
       -- check if definition lookup failed
       if type(dmgType) == "number" then print('dmgType must be "cold", "fire", "physical", "poison", or "shock" (1, 2, 3, 4, or 5)'); return false; end
       if type(power) ~= "number" and minDmg == nil then print("The power for damage must be a number."); return false; end
       if minDmg == nil then
          if power < 1 then print("The damage power must be higher than zero (0)."); return false; end
       end

       if type(hasSound) ~= "boolean" then
          -- apply supplied string reference
          sound = hasSound
       else
          -- otherwise, get the numerically corresponding sound tbl
          sound = _sounds[_dmgTypes[dmgType]]
       end

       if type(sound) ~= "string" then print('hasSound must be either (true|false) or your own ("string_reference").'); return false; end



       local chance,d = nil,0;

       for position,bDoDmg in ipairs(_positions) do
          chance = _percChance[position];
          if type(chance) ~= "number" then print("percChance must be a number") return false; end
          if chance < 1 or chance > 100 then print("percChance must be a number between 1 - 100"); return false; end
          if bDoDmg ~= 0 and p:getChampion(position):getEnabled() and p:getChampion(position):isAlive() then
             if math.random(1,100) <= chance then
                if power ~= nil then d = rollDamage(power)
                else d = math.random(minDmg, maxDmg) end
                p:getChampion(position):damage(d, dmgType)
             end
          end
       end

       if hasSound ~= false then playSound(sound); end

       return true;

    end
If you only want the party to receive damage for holding a torch in a part of the level, then create a passage with 2 floor_triggers and the following code:

Let the first floor_trigger call "endlightdamage" (it's there for stopping the damage when the party walks back and returns to the previous part of the level).
Let the second floor_trigger call "startlightdamage" (to start the damage check for torches).

At the end of the damagearea you also set up two triggers, the first calling startlightdamage (if the party walks back in to the damage area) and the second at the end to stop the damagecheck.

Code: Select all

lightdamage = 0

function startlightdamage()
	lightdamage = 1
end

function endlightdamage()
	lightdamage = 0
end
So the code from above would be:

Code: Select all

function darkd3checklight()
   if party.level == 13 and lightdamage == 1 then
      for i = 1, 2 do
         for k = 1, 4 do
            local champion = party.party:getChampion(k):getItem(i)

            if champion ~= nil and champion.go.name == "torch" then
               dmgParty(20)
            end
         end
      end
   end
end
----------------------------------

Punish the party for casting the light spell

Put the function from the start again into \mod_assets\scripts\init.lua, but this time don't call "return false" but call a function in a script ("script_entity_88.script:lightcast()")

Code: Select all

defineObject{
	name = "party",
	baseObject = "party",
	components = {
		{
		class = "Party",  
		onCastSpell = function(party,champion,spellName)
			if spellName == "light" then
				script_entity_88.script:lightcast()
			end		  
		end
		}
	},
}
I warn the party by a wall_text that casting light will be punished and is fatal.

In the function I kill the party for casting light.
The if-part is there to make sure, the party is only killed in the certain part of the level (see description above).

Code: Select all

function lightcast()
	if party.level == 13 and lightdamage == 1 then
		dmgParty(4000)
	end
end
----------------------------------

Removing light / casting darkness

When the party enters the area, where light is prohibited, I need to make sure that an existing light spell is not active, so that the party cannot cast light in one level and completely play through the next level, where light is prohibited.

So I give all chars full energy and try to cast darkness with each one right as I enter the area, where light casting will be punished by the other scripts.

That floor_trigger calls this function:

Code: Select all

function darknesscast()

	for i = 1, 4 do
		party.party:getChampion(i):regainEnergy(1000)
		party.party:getChampion(i):castSpell(58)
	end
end
castSpell(1) would be fireburst (rune 1)
castSpell(25) would be light (rune 2, then rune5)
castSpell(58) is darkness (rune 5, then rune 8)

----------------------------------

Kind regards,
Joerg
Post Reply