Editor Tutorials on YouTube - part 15 is out

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
User avatar
Skuggasveinn
Posts: 562
Joined: Wed Sep 26, 2012 5:28 pm

Editor Tutorials on YouTube - part 15 is out

Post by Skuggasveinn »

I've created some tutorials for the new Dungeon Editor
Please note that I'm just learning this stuff myself, and I've not seen the lua code behind the assets so I reserve the right to be complete wrong about what I'm talking about :D


Part 1 - https://youtu.be/vMMBC9B2qjM GUI and new features
Part 2 - https://youtu.be/eDaeqUUOuSc Elevations inside dungeons
Part 3 - https://youtu.be/6cv3P8dxCgY Coordinates and level transition
Part 4 - https://youtu.be/hVpY60Ptjdk Creating Water and Reflections
Part 5 - https://youtu.be/bLwSL8mhJOk Outdoor scenario
Part 6 - https://youtu.be/dxonfsoRYOY Bossfight
Code from part 6
SpoilerShow

Code: Select all

function startBrothersBossFight()
	boss_fight_brothers.bossfight:addMonster(skeleton_commander_1.monster)
	boss_fight_brothers.bossfight:addMonster(skeleton_commander_2.monster)
	boss_fight_brothers.bossfight:activate()
end

function startMedusaBossFight()
	boss_fight_medusa.bossfight:addMonster(medusa_1.monster)
	boss_fight_medusa.bossfight:activate()

end
Part 7 https://youtu.be/-YlAZwqcptc Firetrap
Code from part 7
SpoilerShow
the firetrap code

Code: Select all

function startmagmacontdown()
	magma_countdown.bossfight:addMonster(magma_golem_1.monster)
	magma_countdown.bossfight:activate()
	timer_1.timer:start()

end

timecount = 1

function shakeitbaby()
	party.party:shakeCamera(0.05,60)
	dungeon_fire_pit_1.particle:enable()
	dungeon_fire_pit_2.particle:enable()
	dungeon_fire_pit_3.particle:enable()
	dungeon_fire_pit_4.particle:enable()
	dungeon_fire_pit_5.particle:enable()
	dungeon_fire_pit_6.particle:enable()
	dungeon_fire_pit_7.particle:enable()
	dungeon_fire_pit_8.particle:enable()
	dungeon_fire_pit_9.particle:enable()
	dungeon_fire_pit_10.particle:enable()
	dungeon_fire_pit_11.particle:enable()
	
end


function hurtgolem()


  if timecount == 1 then

  elseif timecount == 2 then


  elseif timecount == 3 then
    magma_golem_1.monster:setHealth(950)
		
  elseif timecount == 4 then
    magma_golem_1.monster:setHealth(900)
		
  elseif timecount == 5 then
    magma_golem_1.monster:setHealth(850)

  elseif timecount == 6 then
	magma_golem_1.monster:setHealth(800)
	
  elseif timecount == 7 then
	magma_golem_1.monster:setHealth(750)
  
  elseif timecount == 8 then
	magma_golem_1.monster:setHealth(700)
	
  elseif timecount == 9 then
	magma_golem_1.monster:setHealth(650)
	
  elseif timecount == 10 then
	magma_golem_1.monster:setHealth(600)
	
  elseif timecount == 11 then
	magma_golem_1.monster:setHealth(550)
	
  elseif timecount == 12 then
	magma_golem_1.monster:setHealth(500)
	
  elseif timecount == 13 then
	magma_golem_1.monster:setHealth(450)
	
  elseif timecount == 14 then
	magma_golem_1.monster:setHealth(400)
	
  elseif timecount == 15 then
	magma_golem_1.monster:setHealth(350)
	
  elseif timecount == 16 then
	magma_golem_1.monster:setHealth(300)
	
  elseif timecount == 17 then
	magma_golem_1.monster:setHealth(250)
	
  elseif timecount == 18 then
	magma_golem_1.monster:setHealth(200)
	
  elseif timecount == 19 then
	magma_golem_1.monster:setHealth(150)
	
  elseif timecount == 20 then
	magma_golem_1.monster:setHealth(100)
	
  elseif timecount == 21 then
	magma_golem_1.monster:setHealth(50)
		
  elseif timecount == 22 then
	magma_golem_1.monster:setHealth(0)
	
  elseif timecount == 23 then
	magma_countdown.bossfight:deactivate()
	magma_golem_1.monster:die();
    die = true;
	spawn("flame_wave", 1, 17, 24, 1, 0)
	spawn("flame_wave", 1, 17, 26, 1, 0)
	spawn("flame_wave", 1, 18, 25, 1, 0)
	spawn("flame_wave", 1, 19, 24, 1, 0)
	spawn("flame_wave", 1, 19, 26, 1, 0)
	spawn("flame_wave", 1, 20, 25, 1, 0)
	spawn("flame_wave", 1, 21, 24, 1, 0)
	spawn("flame_wave", 1, 21, 26, 1, 0)
	spawn("flame_wave", 1, 22, 25, 1, 0)
	spawn("flame_wave", 1, 23, 24, 1, 0)
	spawn("flame_wave", 1, 23, 26, 1, 0)
	timer_1.timer:stop()
	
  	timecount = 1
   	return
  end
    timecount = timecount + 1
end
The lever puzzle code

Code: Select all

function firetrappuzzle1()

	--local count1 = firecounter_1.counter:getValue()
	--local count2 = firecounter_2.counter:getValue()
	--local count3 = firecounter_3.counter:getValue()

	if firecounter_1.counter:getValue() == 0 and
	firecounter_2.counter:getValue() == 1 and
	firecounter_3.counter:getValue() == 0 then

	--hudPrint("firecounter_1 has "..count1.." in value")
	--hudPrint("firecounter_2 has "..count2.." in value")
	--hudPrint("firecounter_3 has "..count3.." in value")
	mine_door_spear_1.door:open()

	else
	mine_door_spear_1.door:close()
	--hudPrint("firecounter_1 has "..count1.." in value")
	--hudPrint("firecounter_2 has "..count2.." in value")
	--hudPrint("firecounter_3 has "..count3.." in value")
	end
	
end


function firetrappuzzle2()

	--local count1 = firecounter_1.counter:getValue()
	--local count2 = firecounter_2.counter:getValue()
	--local count3 = firecounter_3.counter:getValue()

	if firecounter_1.counter:getValue() == 1 and
	firecounter_2.counter:getValue() == 0 and
	firecounter_3.counter:getValue() == 0 then

	--hudPrint("firecounter_1 has "..count1.." in value")
	--hudPrint("firecounter_2 has "..count2.." in value")
	--hudPrint("firecounter_3 has "..count3.." in value")
	mine_door_spear_2.door:open()

	else
	mine_door_spear_2.door:close()
	--hudPrint("firecounter_1 has "..count1.." in value")
	--hudPrint("firecounter_2 has "..count2.." in value")
	--hudPrint("firecounter_3 has "..count3.." in value")
	end
	
end

function resetdoors()
	
	if mine_door_spear_1.door:isOpen() == true or
	mine_door_spear_2.door:isOpen() == true then
	mine_door_spear_1.door:close()
	mine_door_spear_2.door:close()
	
	else
	
	end
	
end
Part 8 https://youtu.be/T9vM91bLUY8- Buried Treasures
Code from part 8
SpoilerShow
how we spawn stuff that's bound to the coordinates of the script entity

Code: Select all

function hiddencorpse()
      self.go:spawn("floor_corpse")
      self.go:spawn("skull")
      self.go:spawn("rapier")
      hudPrint("You have found a buried body")
      for i = 1, 4, 1 do
      party.party:getChampion(i):gainExp(250)
      end
      hudPrint("250 exp")
      playSound("secret")
end
How we assign the treasure map texture to our scroll entity

Code: Select all

treasure_map_1.scrollitem:setScrollImage("mod_assets/textures/treasure_map_1.dds")
Part 9 https://youtu.be/lRJCie3uWw0 Day and Night cycle
Code from part 9
SpoilerShow

Code: Select all

function whattimeisit()  -- prints out the current time of day for debug
	wtii = GameMode.getTimeOfDay()
	hudPrint(""..wtii.."")
end


function nightbridge()  -- turnes the bridge on during night
	if GameMode.getTimeOfDay() > 1.04 and GameMode.getTimeOfDay() < 1.97 then
	magic_bridge_1.controller:activate()
	magic_bridge_2.controller:activate()
	else
	magic_bridge_1.controller:deactivate()
	magic_bridge_2.controller:deactivate()
	end
end

function movetime()   -- moves the time forward by 0.0001
	wtii = GameMode.getTimeOfDay()
	GameMode.setTimeOfDay(wtii + 0.0001)
end

function fireflies()   -- enables light and particales on fireflies during the night
	if GameMode.getTimeOfDay() > 1.04 and GameMode.getTimeOfDay() < 1.97 then
	forest_fireflies_1.particle:enable()
	forest_fireflies_1.light:enable()
	forest_fireflies_2.particle:enable()
	forest_fireflies_2.light:enable()
	else
	forest_fireflies_1.particle:disable()
	forest_fireflies_1.light:disable()
	forest_fireflies_2.particle:disable()
	forest_fireflies_2.light:disable()
	end
end
Part 10 http://youtu.be/WfAi31AScgw - Alcove Puzzles
code from part 10
SpoilerShow
Alcove that counts how many consumables you have placed.

Code: Select all

function checkItems(alcove)
	local count = 0
	
	for v,i in alcove:contents() do
	if i :hasTrait("consumable") then
	count = count + 1
	end
end

	if count >= 3 then
	dungeon_secret_door_1.door:open()
	else
	dungeon_secret_door_1.door:close()
	end
end
Alcoves the need to correct figures placed into the correct alcoves.

Code: Select all

function surfaceContains(surface, item)
	for v,i in surface:contents() do
	if i.go.name == item then return true
	end
end
end

function openPowerGemDoor()
	if surfaceContains(dungeon_alcove_2.surface, "figure_ogre") and
	surfaceContains(dungeon_alcove_3.surface, "figure_crowern") and
	surfaceContains(dungeon_alcove_4.surface, "figure_skeleton") and
	surfaceContains(dungeon_alcove_5.surface, "figure_snail") then
	dungeon_door_iron_barred_1.door:open()
	else
	dungeon_door_iron_barred_1.door:close()
	end
end
Part 11 https://youtu.be/tCwR1VXa4Xg - Breakable Walls
code from part 11 -- Download the breakable walls, sound and scripts to use within your dungeon here https://www.zorglubb.net/grimrock/dropz ... _walls.zip
SpoilerShow
The 3 walls needed to create the breakable wall

Code: Select all

defineObject{
   name = "dungeon_breakable_wall",
   baseObject = "base_obstacle",
   components = {
      {
         class = "Model",
         model = "mod_assets/models/sx_dungeon_breakable_wall_hard.fbx",
      },
	   
       {
         class = "Obstacle",
         hitSound = "impact_blunt",
         hitEffect = "hit_dust",
      },
      {
         class = "Health",
         health = 15,
         spawnOnDeath = "dungeon_breakable_wall_damaged",
		 onDie = function(self)
               playSound("wall_breaking")
			   party.party:shakeCamera(0.02,2)
        end,
      },
      {
         class = "Controller",
      },
   },
   placement = "wall",
   automapTile = "wall",
   editorIcon = 120,
}

defineObject{
   name = "dungeon_breakable_wall_damaged",
   components = {
      {
         class = "Model",
         model = "mod_assets/models/sx_dungeon_breakable_wall_damaged.fbx",
      },
       {
         class = "Obstacle",
         hitSound = "impact_blunt",
         hitEffect = "hit_dust",
      },
      {
         class = "Health",
         health = 15,
         spawnOnDeath = "dungeon_breakable_wall_broken",
		 onDie = function(self)
               playSound("wall_breaking")
			   party.party:shakeCamera(0.02,2)
        end,
      },
      {
         class = "Controller",
      },
   },
   placement = "wall",
   automapTile = "grassy_ground",
   editorIcon = 120,
}

defineObject{
   name = "dungeon_breakable_wall_broken",
   components = {
      {
         class = "Model",
         model = "mod_assets/models/sx_dungeon_breakable_wall_broken.fbx",
      },  
       {
         class = "Controller",
      },
   },
   placement = "wall",
   editorIcon = 120,
}
The sound defenition

Code: Select all

defineSound{
	name = "wall_breaking",
	filename = "mod_assets/sounds/sx_wallbreaking.wav",
	loop = false,
	volume = 1.00,
	minDistance = 2,
	maxDistance = 2,
}
Part 12 https://youtu.be/7L8Epmsqg_Q - Creating our own Weapons
code from part 12 -- Download the Heartseeker asset and scripts here https://www.zorglubb.net/grimrock/dropz ... seeker.zip
SpoilerShow
The Heartseeker and the Elemental Bow

Code: Select all

defineObject{
      name = "heartseeker",
      baseObject = "base_item",
      components = {
      {
         class = "Model",
         model = "mod_assets/models/heartseeker.fbx",
      },
      {
         class ="Item",
         uiName = "Heartseeker",
         gfxAtlas = "mod_assets/textures/items_atlas.dds",
         gfxIndex = 0,
		 GfxIndexPowerAttack = 1,
         secondaryAction = "slice",
         weight = 2.7,
         impactSound = "impact_blade",
         traits = { "bow", "missile_weapon" },
         description = "Sublime Longbow obviously made with love and care."
      },
      {
         class = "RangedAttack",
         attackPower = 5,
         accuracy = 10,
		 Ammo = "arrow",
         attackSound = "swipe_bow",
         cooldown = 2.0,
         baseDamageStat = "dexterity",
         damageType = "physical",
         --requirements = {"missile_weapons" ,3},
      },
	{
        class = "MeleeAttack",         
        name = "slice",
		uiName = "Slice",
		repeatCount = 0,
		attackPower = 26,
		swipe = "horizontal",
		attackSound = "swipe_special",
		baseDamageStat = "dexterity",
        cooldown = 0.2,
        energyCost = 5,
		--requirements = { "accuracy", 2},
                
        },
   }
}

defineObject{
        name = "elemental_bow",
        baseObject = "base_item",
        components = {
   {
        class = "Model",
        model = "mod_assets/models/heartseeker.fbx",   
        },
        {
              class ="Item",
              uiName = "Bow of the Elements",
			  gfxAtlas = "mod_assets/textures/items_atlas.dds",
              gfxIndex = 0,
			  GfxIndexPowerAttack = 1,
              weight = 2.7,
              impactSound = "impact_blade",
              secondaryAction = "elementalstorm",
              traits = { "bow", "missile_weapon" },
              description = "Sublime Longbow obviously made with love and care."
        },
        {
              class = "CastSpell",
			  spell = "fireball",
              cooldown = 2.2,

        },
        {
              class = "CastSpell",
			  name = "elementalstorm",
			  uiName = "Elemental Storm",
			  chainAction = "elementalstorm1",
		      chainActionDelay = 0.2,
			  spell = "fireball",

        },
        {
              class = "CastSpell",
			  name = "elementalstorm1",
			  uiName = "Elemental Storm",
			  chainAction = "elementalstorm2",
		      chainActionDelay = 0.2,
			  spell = "frostbolt",

        },
        {
              class = "CastSpell",
			  name = "elementalstorm2",
			  uiName = "Elemental Storm",
			  chainAction = "elementalstorm3",
		      chainActionDelay = 0.2,
			  spell = "poison_bolt",
        },
		{
              class = "CastSpell",
			  name = "elementalstorm3",
			  uiName = "Elemental Storm",
			  chainAction = "elementalstorm4",
		      chainActionDelay = 0.2,
			  spell = "lightning_bolt",
        },
        {
              class = "CastSpell",
			  name = "elementalstorm4",
			  uiName = "Elemental Storm",
			  spell = "darkbolt",
        },
   }
 }   
Part 13 - https://youtu.be/b9h7nCI1rQk Simple animations for custom 3D objects

Part 14 - https://youtu.be/xAj65MM2lww Occluders

Part 15 - https://youtu.be/jPUXngUUT9Y How to load the main campaign into the editor

Playlist link https://www.youtube.com/playlist?list=P ... B7joLG52Nc

Hope that this will help someone get started.
Maybe I will add to these in the future.

Skuggasveinn.
Last edited by Skuggasveinn on Tue Jul 09, 2024 2:46 am, edited 29 times in total.
Link to all my LoG 2 assets on Nexus.
Link to all my LoG 1 assets on Nexus.
RixSolstice
Posts: 3
Joined: Thu Oct 16, 2014 3:18 am

Re: Editor Tutorials on YouTube

Post by RixSolstice »

my god, this is just awesome. Would mods maybe sticky this for a while?
User avatar
cromcrom
Posts: 549
Joined: Tue Sep 11, 2012 7:16 am
Location: Chateauroux in a socialist s#!$*&% formerly known as "France"

Re: Editor Tutorials on YouTube

Post by cromcrom »

Thank you so much for these great tuts, they are amazing :-)
A trip of a thousand leagues starts with a step.
User avatar
Drakkan
Posts: 1318
Joined: Mon Dec 31, 2012 12:25 am

Re: Editor Tutorials on YouTube

Post by Drakkan »

thanks for vidoes Skugg, please do more ! :)
Breath from the unpromising waters.
Eye of the Atlantis
User avatar
antti
Posts: 688
Joined: Thu Feb 23, 2012 1:43 pm
Location: Espoo, Finland
Contact:

Re: Editor Tutorials on YouTube

Post by antti »

Hey, could you make a youtube playlist of the videos for easier linking? While we're still working on the official modding guide, it's good to have something to link to for the more impatient modders on twitter and elsewhere :)
Steven Seagal of gaming industry
User avatar
Mysterious
Posts: 226
Joined: Wed Nov 06, 2013 8:31 am

Re: Editor Tutorials on YouTube

Post by Mysterious »

Hi Skuggs the videos are grate :)

I tried the joining of levels as you said but now I am have a problem.

Here are the levels so far:

0,0,0 start
0,0,1 down
1,0,0 right
-1,0,0 left + exit object (just like your video)

The problem is how do you make a level join at the bottom or top etc.... with exit object? I tried this as a new level to join with (left)
-1,0,-1 left down (This does not work for some reason it just stops me on the left level, I have put the 2 exit objects on both levels but to no avail lol.

I am trying hard to figure out how each level can join to each other using the Exit Object, but am having problems with the x,y,z thing. Thxs for any help :)
User avatar
Skuggasveinn
Posts: 562
Joined: Wed Sep 26, 2012 5:28 pm

Re: Editor Tutorials on YouTube

Post by Skuggasveinn »

The original topic has been update with a link to a playlist.
Mysterious wrote: The problem is how do you make a level join at the bottom or top etc.... with exit object? I tried this as a new level to join with (left)
-1,0,-1 left down (This does not work for some reason it just stops me on the left level, I have put the 2 exit objects on both levels but to no avail lol.
I am trying hard to figure out how each level can join to each other using the Exit Object, but am having problems with the x,y,z thing. Thxs for any help :)
When going up and down you use stairs, the easiest way is to place stairs in the same grid on both levels,then the party will just go up and down, you can also use the custom target field for stairs then you can simply choose where the party comes out, but personally I like how AH did this in the main campaign, everything just flows naturally between levels.

If you are having problems with how the coordinates stack up (or maybe my rumblings didn't make sense in the video :) ) I created a picture that hopefully explains this in more detail.
Image

Hope that helps.

Skuggasveinn.
Link to all my LoG 2 assets on Nexus.
Link to all my LoG 1 assets on Nexus.
User avatar
Ciccipicci
Posts: 154
Joined: Mon Oct 08, 2012 12:55 am

Re: Editor Tutorials on YouTube

Post by Ciccipicci »

Thanks both for the vids and the pic.
User avatar
Mysterious
Posts: 226
Joined: Wed Nov 06, 2013 8:31 am

Re: Editor Tutorials on YouTube

Post by Mysterious »

Hi Skuggs.

Thank you for the picture it makes sense now I have created mulitiple ways around the map :)
A100N
Posts: 15
Joined: Sun Oct 19, 2014 1:53 pm

Re: Editor Tutorials on YouTube

Post by A100N »

I would have asked for a tutorial for the scripts :(
for LoG 2
Post Reply