[MOD] LABYRINTH OF LIES - v3.6 Release

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
eLPuSHeR
Posts: 676
Joined: Tue Jan 08, 2013 7:42 pm

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by eLPuSHeR »

If you placed some markings on your map, you have to remove them first. At least the ones, marking the place.
Intel i7 5960X
Gigabye GA-X99-Gaming 5
8 GB DDR4 (2100)
GeForce GTX 970 (Gigabyte)
minmay
Posts: 2780
Joined: Mon Sep 23, 2013 2:24 am

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by minmay »

Hey Akroma, I was bored and decided to look at the cause of the projectile spell crash. Take a look at the move_effect function in fxScripts:

Code: Select all

function move_effect(timer)
   local e = projectiles[timer.id]
   local p = findEntity(e.projectile_id)
   local fx = findEntity(e.effect_id)
   
   if not p then
      if e.onHitEffect then
         local ohfx = spawn('fx',e.level,e.px,e.py,e.facing)
         ohfx:setParticleSystem(e.onHitEffect)
         ohfx:translate(0, 1, 0)
         local light = getLightPreset(e.onHitEffect)
         if light then
            ohfx:setLight(unpack(light))
         end         
      end
        
      projectiles[timer.id] = nil
      timer:deactivate()
      timer:destroy()
      fx:destroy()  
      return
   end
   e.px = p.x
   e.py = p.y 
   fx:translate(e.x,0,e.y)
end
The crash, if you recall, occurs at "ohfx:setParticleSystem(e.onHitEffect)". Specifically, a crash occurs if the ohfx entity hasn't been added to the map. Since you have ohfx spawn in the same place as e, ohfx won't be added to the map if e hasn't been added to the map. e is not added to the map if the projectile hits a monster capsule as soon as it's created, like in the "attacking spider" case I mentioned earlier.
Now, fixing this the correct way - making the particle effect, without a crash, even if the projectile hasn't been added to the map - would require refactoring the code in a few places, which I don't volunteer to do. Of course, it's easy enough to use a simple hack to avoid the crash: change "if e.onHitEffect" to "if e.onHitEffect and e.level". Then the hit effect won't appear if e hasn't been added to the map, which, while still a bug by any reasonable definition, is preferable to crashing.

Other bugs (I'm not going to try to play this version, just poke through the dungeon.lua):
SpoilerShow
You probably want to take a look at this thread because in the current version, your pressure plate in Akroma's Workshop can be used to get infinite stats.
I would also very strongly recommend incorporating the fixed entity iterators so that players cannot cheat or otherwise break the game by making map notes.
On the same topic, you seem to have typos in partyDisableScripts.traits() and partyDisableScripts.skills(): the former has "party:getChampion(1):addTrait("poison_resistant",false)", you probably wanted "i" instead of "1". The latter trains fire magic to 40 instead of 50 like all the other skills.
It looks like you forgot about the Aetherwrought items bug.
akroma222 wrote:Yes indeed, the game lags a bit in the Ancient Ruins - especially where the mummies are found... I am unsure as to why this is :cry:
This is because it's filled with poison clouds which are tremendously GPU-intensive for some reason, even when behind walls. Easy to fix by changing the greater poison bolts to regular poison bolts, or just getting rid of them altogether since the party likely has 100 poison resistance by then anyway.

edit: casting Ice Healing always crashes:

Code: Select all

mod_assets/scripts/objects.lua:2675: attempt to call field 'iceHealing' (a nil value)
edit2: the description for Guardian Stave still claims that the staff will disappear after 60 seconds and upon contact with other champions, even though it's permanent now.

edit3:
SpoilerShow
It looks to me like Silence and Force Field will not expire correctly if you leave the level because you use "allEntities(party.level)" to find the zones. In addition to being slow, cumbersome, and susceptible to the aforementioned allEntities bug. A much easier way to do this is to add the IDs of the entities you want to destroy to a table, then iterate through that table and destroy them when the spell expires. Additionally, Force Field thinks you're wielding the Runewand of Elements even if you aren't (and never creates a wisp portal without 40 staff defence skill - this is not reflected in the description!), and the wisp portal is only destroyed if you are still standing on it when the force field expires! Furthermore, the spell isn't blocked by monsters correctly: it can spawn several force field squares before encountering the monster and stopping. You need to do two loops (or something similar) there, I'm afraid.
I also notice that you have a (copied to multiple scripts!) list of all the monster names in your mod, and check entities against it to see if they are monsters. This is not necessary: you can simply check if the entity is a member of the "Monster" class instead. Much easier! Here's what your forcefieldScript currently looks like:

Code: Select all

allMonstersList = {"amber_slime","ancient_horde","ancient_warrior","big_wing_wyvern","blood_warrior",
		"bone_slime","cardinal_klaus","crab","crab_diseased","crowern","crowern_diseased","cube","cultist","daniv_uggardian_air",
		"daniv_uggardian_earth","daniv_uggardian_fire","daniv_uggardian_ice","daniv_uggardian_black",
		"dark_elf_temple_skeleton_archer","dark_elf_temple_skeleton_archer_patrol",
		"dark_elf_temple_skeleton_warrior","dark_elf_temple_skeleton_patrol","dark_lizard",
		"dark_wyvern","desert_crab","dragon_ice","dragon_ice_spawner1","dragon_ice_spawner2","dragon_ice_spawner3","dragon_ice_spawner4",
		"dragon_ghost","dragon_shadow","dream_stealer","exotic_crab","exotic_crab_blue",
		"exotic_crab_green","exotic_crab_purple","exotic_crab_purple_recurring_01","exotic_crab_purple_recurring_02",
		"exotic_crab_purple_recurring_03","exotic_crab_purple_recurring_04","exotic_crab_purple_recurring_05",
		"fire_lizard","flame_wyvern","flydragon","ghostly_horde","gold_warrior","goromorg_yellow_gem","goromorg_orange_gem","goromorg_mind_stone",
		"goromorg","goromorg_deathlord","green_lizard","green_slime","herder","herder_big","herder_small","herder_swarm","herder_dark_small",
		"herder_dark_big","herder_dark","high_elf_temple_skeleton_archer","high_elf_temple_skeleton_archer_patrol",
		"high_elf_temple_skeleton_warrior","high_elf_temple_skeleton_patrol","ice_lizard",
		"ice_slime","isgardian","laguardian","leki_beholder_black","leki_beholder_green","leki_beholder_red",
		"leki_beholder_yellow","leki_ghoul","leki_slugomorg_melee","leech_worm","living_tree",
		"liche","maggot_slime","marble_goromorg","marble_goromorg_shadow1","master_uggardian","mine_shrakk_01","mine_shrakk_02",
		"mine_shrakk_03","mine_shrakk_04","mine_shrakk_05","molt_slime","mummy_grunt","ogre","hill_ogre",
		"ogre_jungle","ogre_nohammer","ogre_northern","ogre_red_horn","red_slime","scavenger",
		"scavenger_swarm","scavenger_black","scavenger_black_swarm","scavenger_red",
		"scavenger_red_tooth","scavenger_red_tooth_swarm","scavenger_red_swarm","scavenger_red",
		"shrakk_torr","shrakk_torr_bee","shrakk_torr_diseased","sin_eater","skeleton_archer","skeleton_archer_patrol",
		"skeleton_archer_shadow","skeleton_archer_shadow_fire","skeleton_dark","skeleton_dark_tricky","skeleton_ghost","skeleton_patrol",
		"skeleton_warrior","slug","snail","snail_diseased","snail_diseased_counter1","snail_blue_green","snail_green/brown",
		"snail_purple/red","snail_rainbow","spider","spiderblack","spider_dark_orange","spider_diseased",
		"spider_green","spider_northern","spider_poisonshot","spider_red","spider_tropical",
		"spider_lightning","spider_fire","spider_ice","stone_slime05","stone_slime06",
		"stone_slime10","stone_slime11","tentacles","tentacles_diseased","tentacles_horror","tentacles_ghost",
		"tentacles_water","tentacles_waterlord","trash_slime","uggardian","urgardian",
		"venom_wyvern","warden","warden_exploding","warden_noflail","water_slime","wisp_dark" , "wisp_light" , "wyvern"}
		

function monsterThere(level,eggs,why)
  for i in entitiesAt(level,eggs,why) do
    if isInTable(allMonstersList,i.name)
    then
      return true
    end
  end
  return false
end

function isInTable(table, element)
  for _,value in pairs(table) do
    if value == element then
      return true
    end
  end
  return false
end

function checkPosition(caster,x,y,direction,skill)

	local dx,dy = getForward(party.facing)
	if (party.x == 0)
	or (party.x == 31)
	or (party.y == 0)
	or (party.y == 31) then
		return false
	else
		return true
	end
end

function castForceField(caster,x,y,direction,skill)
	local dx,dy = getForward(party.facing)
	local f = findEntity("timer_forcefield")
	local s = caster:getSkillLevel("staves")
	if checkPosition(caster,x,y,direction,skill) == false then
		playSound("spellfizzle1")
		hudPrint("Not enough space to cast Force Field..!!")
		return false
	end
	if f ~= nil then
		hudPrint("Force Field is already activated..")
		playSound("spellfizzle1")
		return false
	end
	if f == nil then
		for i = -1, 1 do
			for j = -1, 1 do
				if monsterThere(party.level,party.x+i,party.y+j) then
    				hudPrint("A monster is in the way of field initialisation...")
					playSound("spellfizzle1")
					return false
				else
      				spawn("force_field", party.level, party.x+i,party.y+j, party.facing)
					spawn("force_field_fx", party.level, party.x+i,party.y+j, party.facing)
					spawn("party_blocker", party.level, party.x+i,party.y+j, party.facing)
				end
			end
		end
	end
	if s >= 40 then
		spawn("wispPortal1", party.level, party.x,party.y, party.facing)
		hudPrint("Staff Defence skill extends Force Field's duration and creates a temporary Wisp Portal inside...!!")
		spawn("timer",party.level,party.x,party.y,party.facing,"timer_forcefield")
        	:setTimerInterval(25)
        	:addConnector("activate", "forcefieldScript", "stopForceField")
        	:activate()
		playSound("force_field")
		hudPrint("ForceField has been activated, monsters and their missile attacks can not reach you..!!")
		party:playScreenEffect("teleport_screen")
	else
		hudPrint("The Runewand of Elements creates a temporary Wisp Portal inside the Force Field...!!")
		spawn("timer",party.level,party.x,party.y,party.facing,"timer_forcefield")
        	:setTimerInterval(15)
        	:addConnector("activate", "forcefieldScript", "stopForceField")
        	:activate()
		playSound("force_field")
		hudPrint("ForceField has been activated, monsters and their missile attacks can not reach you..!!")
		party:playScreenEffect("teleport_screen")
	end
end

function stopForceField()
	local f = findEntity("timer_forcefield")
	if f ~= nil then
		f:destroy()
	end
	for i in allEntities(party.level) do
    	if i.name == "force_field" or i.name == "force_field_fx" or i.name == "party_blocker" then
			i:destroy()
		end
	end
	for w in entitiesAt(party.level, party.x, party.y) do
		if w.name == "forcefieldWispPortal" then
			w:destroy()
		end
	end
	party:playScreenEffect("teleport_screen")
	playSound("buff_down1")
	hudPrint("The Force Field has dissapated...")
end
Here's a quick "fixed" version. I assume the intent was for either 40 staff defense skill or the runewand to amplify the spell; that's the behaviour I went with. This means you'll still want to update the spell's description to mention the staff defence bonus. This version should be a bit more compact, and fixes all the aforementioned bugs. I couldn't resist fixing a couple of spelling errors too...

Code: Select all

function monsterThere(level,eggs,why)
  for i in entitiesAt(level,eggs,why) do
    if i.class == "Monster" then
      return true
    end
  end
  return false
end

function checkPosition(caster,x,y,direction,skill)
	local dx,dy = getForward(party.facing)
	if (party.x == 0)
	or (party.x == 31)
	or (party.y == 0)
	or (party.y == 31) then
		return false
	else
		return true
	end
end

forcefieldIDs = {}

function castForceField(caster,x,y,direction,skill)
	local dx,dy = getForward(party.facing)
	local f = findEntity("timer_forcefield")
	local s = caster:getSkillLevel("staves")
	if checkPosition(caster,x,y,direction,skill) == false then
		playSound("spellfizzle1")
		hudPrint("Not enough space to cast Force Field..!!")
		return false
	end
	if f ~= nil then
		hudPrint("Force Field is already activated..")
		playSound("spellfizzle1")
		return false
	end
	if f == nil then
		for i = -1, 1 do
			for j = -1, 1 do
				if monsterThere(party.level,party.x+i,party.y+j) then
    				hudPrint("A monster is in the way of field initialisation...")
					playSound("spellfizzle1")
					return false
				end
			end
		end
		for i = -1, 1 do
			for j = -1, 1 do
    			forcefieldIDs[#forcefieldIDs+1] = spawn("force_field", party.level, party.x+i,party.y+j, party.facing).id
				forcefieldIDs[#forcefieldIDs+1] = spawn("force_field_fx", party.level, party.x+i,party.y+j, party.facing).id
				forcefieldIDs[#forcefieldIDs+1] = spawn("party_blocker", party.level, party.x+i,party.y+j, party.facing).id
			end
		end
	end
	
	local hasRunewand = false
	for slot = 7,8 do
		local item = caster:getItem(slot)
		if item and item.name == "sceptre_of_elements" then
			hasRunewand = true
			break
		end
	end
	
	local duration = 15
	if s >= 40 or hasRunewand then
		duration = 25
		forcefieldIDs[#forcefieldIDs+1] = spawn("wispPortal1", party.level, party.x,party.y, party.facing).id
		local amplifier = (s >= 40) and "Staff Defence skill" or "The Runewand of the Elements"
		hudPrint(amplifier.." extends Force Field's duration and creates a temporary Wisp Portal inside...!!")
	end

	spawn("timer",party.level,party.x,party.y,party.facing,"timer_forcefield")
        	:setTimerInterval(duration)
        	:addConnector("activate", "forcefieldScript", "stopForceField")
        	:activate()
	playSound("force_field")
	hudPrint("Force Field has been activated, monsters and their missile attacks cannot reach you..!!")
	party:playScreenEffect("teleport_screen")
end

function stopForceField()
	local f = findEntity("timer_forcefield")
	if f ~= nil then
		f:destroy()
	end
	for i,id in pairs(forcefieldIDs) do
		local e = findEntity(id)
		if e then
			e:destroy()
		end
	end
	forcefieldIDs = {}
	party:playScreenEffect("teleport_screen")
	playSound("buff_down1")
	hudPrint("The Force Field has dissipated...")
end
You may also want to address the fact that timers run slower if you are not on their level. jKos' LoG Framework can handle this for you, although make sure not to pass it a timer interval that isn't divisible by 0.1 (take a look at timers.lua line 326 if you want to know why).

While doing this I also noticed that your "party_blocker" doesn't work as intended at all: it checks the square in front of the party instead of the square that they are moving to. This is a one-line fix: in your party.onMove hook, you have the line "local dx,dy = getForward(party.facing)". This should be "local dx,dy = getForward(direction)".

Let me know if you'd like me to rewrite more.
edit4: in addition, from the description, apparently force field is supposed to block projectiles. It doesn't do this - you have it defined as a Blocker. It appears you wanted to define it as a Blockage instead, since you have given it health, evasion, onProjectileHit, etc. fields. However, this will make it block projectile spells as well.

Unrelated bug: extinguishing a mage light will cause a duplicated entity ID crash next time you cast the spell. This is because you made extinguish destroy the mage light, but not the corresponding timer. Here is a fixed version of torch_script:

Code: Select all

function torchlight(caster,x,y,dir,skill)
	local dx,dy = getForward(party.facing)
	if spell_light then spell_light:destroy() end
	if spell_light_timer then spell_light_timer:destroy() end
    local s = skill
   	spawn("spell_torchlight", party.level, party.x, party.y, party.facing, "spell_light")
   	spawn("timer", party.level, party.x, party.y, party.facing, "spell_light_timer")
   	playSound("enflame_01")
   	spell_light_timer:setTimerInterval(25*s)
   	spell_light_timer:addConnector("activate", "spell_light", "deactivate") 
   	spell_light_timer:activate()
end
edit5: destroying an explosive mine with Extinguish will also cause a crash if you try to detonate the mine afterwards. It also does more damage than it's supposed to because of your BurstSpell entities and doesn't work on the edge of the map. Here are fixed versions of those two spells:

Code: Select all

function explosive_mine(caster, x, y, direction, skill)
	if mine then
		hudPrint("You must detonate the mine already placed...")
		return false
	end

	spawn("volcanobomb_lamp", party.level, party.x, party.y, party.facing, "mine")
	hudPrint("You have prepared the explosive mine...")
	playSound("set_explosive_magic")
end

function detonate(caster, x, y, direction, skill)
	if not mine then
		hudPrint("You must first set the Explosive Mine before detonating it....")
		return true
	end
	
	explosives_ord = caster:getOrdinal()
	local originator = 2 ^ (explosives_ord+1)
	for dx = -1,1 do
		for dy = -1,1 do
			local nx, ny = mine.x+dx, mine.y+dy
			if nx >= 0 and nx <= 31 and ny >= 0 and ny <= 31 then
				spawn("fx", mine.level, nx, ny, mine.facing)
					:setParticleSystem("detonation")
					:setLight(3,1,1,40,5,1,false)
					:translate(0,1.5,0)
				damageTile(mine.level, nx, ny, mine.facing,originator+1,'fire',skill*5)
			end			
		end
	end
	mine:destroy()
	party:shakeCamera(0.4, 2)
	spawn("fx", party.level, party.x, party.y, party.facing)
		:setParticleSystem("earthquake_dust")	
end
Of course you will want to generalize it for the similar spells (vapor snare, freezing trap) that have the same bugs.

edit6: you have the code for the deadly vapors -> elemental maelstrom upgrade commented out, but the scroll's description still mentions it even though it doesn't exist.

edit7: Create Wall will crash if you cast it again before the wall expires, because you try to spawn it with the same id.

edit8: I'm sure I reported this already for an earlier version, but placing pyre stones on fireplaces that are already lit will create another light source anyway. Furthermore, cold stones do not consistently extinguish them.

edit9: Using Teleport twice in quick succession (very easy with gnome stones) will cause a crash because you delay destroying the previous teleporter.

edit10: partyDisableScripts.paralyzedCheck uses champion:getStat("resist_cold"). This does not include cold resistance from equipment or stats. You want to use champion:getResistance("cold") instead.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by akroma222 »

Hey everyone,
version 3.5 is in the works, fortunately I will have some rewriting work from minmay this time around.
The bugs prior to minmays post above have already been sorted out
will keep you all posted
Thanks again

Akroma
TRANG
Posts: 69
Joined: Tue Apr 02, 2013 3:20 am

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by TRANG »

hello, great work.

i´m stuck level 6 "take all the time you need"
i press the 2 bottons but nothing happends, need help

Thanks
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by akroma222 »

Hey TRANG
Highly likely you are not pressing them fast enough.
Most of the timed puzzles are very tight on the timing (no room for mistakes or turning around)
Try a bit faster!!

Also, is TRANG a reference to Wizardry's T'rang spider race??? Love that game.

Akroma
TRANG
Posts: 69
Joined: Tue Apr 02, 2013 3:20 am

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by TRANG »

akroma222 wrote:Hey TRANG
Highly likely you are not pressing them fast enough.
Most of the timed puzzles are very tight on the timing (no room for mistakes or turning around)
Try a bit faster!!

Also, is TRANG a reference to Wizardry's T'rang spider race??? Love that game.

Akroma

Thanks AKroma for your hint, love this mod.

Yes, TRANG is in honor to this race in Wizardry series, i,m a fan of all D.W. Bradley work
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by akroma222 »

Hi Everyone,

ANOTHER CALL FOR PLAYTESTERS!!

Very kindly, minmay has completed a massive amount of rewriting for us
The list of fixes is unbelievable... now, we suspect we may have something close to completion.
But we anticipate the possibility of some minor bugs...
As such, another round of playtesting is required for version 3.5

I will be taking down the current version from nexus and will port this message there
Please let me know if you are interested in having (another?) play test run through

Thanks all for your patience and support :D

Akroma
mpuppetier
Posts: 16
Joined: Tue Sep 02, 2014 11:20 am

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by mpuppetier »

akroma222 wrote:Hi Everyone,

ANOTHER CALL FOR PLAYTESTERS!!

Very kindly, minmay has completed a massive amount of rewriting for us
The list of fixes is unbelievable... now, we suspect we may have something close to completion.
But we anticipate the possibility of some minor bugs...
As such, another round of playtesting is required for version 3.5

I will be taking down the current version from nexus and will port this message there
Please let me know if you are interested in having (another?) play test run through

Thanks all for your patience and support :D

Akroma
Hi Akroma,
is this mod for power users? I ask you this because i'm not a good player :-) .
Thank you for this mod!
Sorry for my bad english :-)
User avatar
RMariano
Posts: 287
Joined: Mon Apr 02, 2012 1:16 pm
Location: Florida, USA
Contact:

Re: [MOD] LABYRINTH OF LIES - RELEASE (v3.4.2)

Post by RMariano »

akroma222 wrote:Hi Everyone,

ANOTHER CALL FOR PLAYTESTERS!!

Very kindly, minmay has completed a massive amount of rewriting for us
The list of fixes is unbelievable... now, we suspect we may have something close to completion.
But we anticipate the possibility of some minor bugs...
As such, another round of playtesting is required for version 3.5

I will be taking down the current version from nexus and will port this message there
Please let me know if you are interested in having (another?) play test run through

Thanks all for your patience and support :D

Akroma

WHERE is 3.5 for downloading? Nexus sez NO FILES....
Regards,

RMariano
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: [MOD] LABYRINTH OF LIES - TESTING for v3.5

Post by akroma222 »

minmay and I are just patching up a few things last minute
If you are keen to playtest then I can send you the drop box invite! :D
Im pretty sure I already have your email RMariano... but just message it to me again to be sure

mpuppetier - did you want to help playtest?
Send me your email via private message if you do
My mod is a little harder than the original game - but there are walkthrough videos to help you! :D
Post Reply