Sleep and Ladders

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
Post Reply
Maethalion
Posts: 7
Joined: Sat Oct 04, 2014 3:36 am

Sleep and Ladders

Post by Maethalion »

Hey everyone,

Just got into modding Grimrock, and two of the features I was looking for (sleep & ladders - hence the title) I found hints at, but nothing "complete."

So I thought I would share a few of the things I made in a "complete" format so someone else can just copy & paste.

SLEEP
Create a script_entity with the ID "sleep" following source/body

Code: Select all


function start(self, receiverID, callback, delay, name)
	
	if not name then name = "timer_spawn_"..receiverID end
	
	local t = spawn("timer", self.level, self.x, self.y, 0, name)
    t:setTimerInterval(delay)
    t:addConnector("activate", receiverID, callback)
    t:addConnector("activate", t.id, "deactivate") 
	t:addConnector("activate", t.id, "destroy") 
    t:activate()
	
	return t
end

The parameters are the following:

Code: Select all


self (don't pass this in, it just shows up, is this a Lua thing?)
receiverID - the ID of the script entity (or other object) to call when the timer finishes
callback - the name of the function to call on the receiver when the timer finishes
delay - how long (in seconds) to delay for
name [optional] - the unique ID of the timer.  You should supply this (see example below)

then, when you want to call sleep in another script, you can simply do this

Code: Select all


function doSomething()
  print("starting timer")
   timer =  sleep:start(self.id, "_callback", 10, "a_unique_id_for_the_timer_you_make")
end

function _callback()
   print("timer finished")
end
The sleep:start(...) function also returns the timer in case you want to stop or restart it. If you manually stop it (outside of letting it activate) remember to destroy it before calling sleep:start(...) again. Note that "self.id" and "_callback" could be something different like "wooden_door_1" and "open" - they don't have to refer to the calling script_entity

LADDERS
Hoookay, so this one is a bit of a cop-out, since I'm not supplying models. You can get some awesome ladders from EOB (DJ, JKos, Tom, Bifrost, Thomson, Wallasaurus, montagneyaya) and other places. I'll just show how to wire it up without making someone fall screaming down a hole (and w/o excessive scripts, timers, and teleports copied all over)

Add the following to your objects.lua (in addition to your ladder definitions)

Code: Select all

cloneObject{
	name = "dungeon_fake_pit",
	baseObject = "pressure_plate_hidden" -- using this as the base object has the nice benefit of tilting the camera down slightly
	model = "assets/models/env/dungeon_pit.fbx", -- you can use another pit model for temple or prison
	hidden = false,
	editorIcon = 40, -- pit icon
}

defineParticleSystem{
   name = "screen_wipe",
   emitters = {
      -- glow
      {
         spawnBurst = true,
         emissionRate = 20,
         emissionTime = 0,
         maxParticles = 20,
         boxMin = {0,0,0},
         boxMax = {0,0,0.2},
         sprayAngle = {0,360},
         velocity = {0,0},
         texture = "assets/textures/particles/glow.tga",
         lifetime = {2, 2},
         colorAnimation = false,
         color0 = {0.0, 0.0, 0.0},
         opacity = 1,
         fadeIn = 1,
         fadeOut = 1,
         size = {5, 5},
         gravity = {0,0,0},
         airResistance = 0.3,
         rotationSpeed = 1,
         blendMode = "Translucent",
         objectSpace = true,
      }
   }
}

Then, create a script_entity in a "global" area (like the top or bottom floor - you only need one of these) with the ID "ladder" and the following body:

Code: Select all


-- Ladder Change Function.

dlevel = self.level
dx = self.x
dy = self.y
df = self.facing

function setDestination(ignore,x,y,f,level)
	dx = x
	dy = y
	df = f
	dlevel = level
end

function activate()
	playSound("party_enter_stairs")
	party:playScreenEffect("screen_wipe")
	stopParty:freezeParty() -- search for cMove for this explanation
	sleep:start(self.id, "_teleport", 0.8, "ladder_timer_1")
end

function _teleport()
	t = spawn("teleporter", party.level, party.x, party.y, df, _teleportID(self.id))
	t:setTriggeredByParty(true)
	t:setChangeFacing(true)
	t:setInvisible(true)
	t:setSilent(true)
	t:setHideLight(true)
	t:setScreenFlash(false)
	t:setTeleportTarget(dx,dy,df,dlevel)
	t:activate()
	sleep:start(self.id, "_finish", 0.1, "ladder_timer_2") -- note the need for a unique timer ID here.  The first timer still exists during this callback.
end

function _finish()
	t = findEntity(_teleportID(self.id))
	t:deactivate()
	t:destroy()
	stopParty:thawParty()  -- search for cMove for this explanation
end

function _teleportID(objectID) -- shortcut for a unique ID for the teleporter
	return "teleporter_"..objectID
end

Note that when suppling level, you can omit, set a floor number, or relative "up" or "down" like a regular Teleport object. Then, when you want to use it, just connect a new script_entity to the "dungeon_fake_pit"s activate() with the following body: (or on the ladder_up's activate)

Code: Select all

function onStep()
	ladder:setDestination(party.x+1,party.y,party.facing,party.level) -- set the destination like you would for a teleport
	ladder:activate()
end
and that's it! Just make sure to always set the destination before activating it (hence why you need to call it from a script, not a connector)

What the script does is start fading the screen to black, freezes the party, waits until the screen is black, teleports the party, fades the screen to normal, and unfreezes the party. It's a much smoother transition that mimics the stairs transition (sound, black screen) and isn't as jarring as a plain invisible teleport. It's also pretty clean wherever you want to use it. Just keep in mind not to let the player activate this more than once per transition or it gets all screwy.

When I first started doing the ladder transition, I had a timer, script_entity, and teleporter for EACH ladder. now it's just a global script_entity, and one for each ladder. Much easier to maintain.

CAVEAT
I can't figure out how to get the "screen_wipe" particle to continue to generate after teleportation. It doesn't smooth out like I want it to.
User avatar
Isaac
Posts: 3185
Joined: Fri Mar 02, 2012 10:02 pm

Re: Sleep and Ladders

Post by Isaac »

What's the specific purpose for the sleep function? I've only just skimmed it, but Grimrock has sleeping as a built in feature.

Of the ladders, there is also alternative method seen in the ORRR2 mod, that includes the models for ladders on the temple wallset that might work with your scripts. If not, then perhaps these can work: https://www.dropbox.com/sh/a0mvdresh57f ... czpDa?dl=0
Raw assets and generic textures. Users should define and assign the materials to suit.

Image
These were used in an unreleased mod that included ladders.
Last edited by Isaac on Sat Oct 04, 2014 6:29 am, edited 2 times in total.
User avatar
SnowyOwl47
Posts: 148
Joined: Fri Sep 12, 2014 10:41 pm

Re: Sleep and Ladders

Post by SnowyOwl47 »

The purpose for sleep is well in some dungeons people have made you sleep for severale purposes, such as camping or sleeping at an in or let's say they needed to make you get knocked out and then you woke up In a jail cell.

The way I see what your doing is very complicated for a sleep but I guess that works, try doing something like this:

Code: Select all

function sleep()
     party:rest()
end
function wake up()
     party:wakeUp(false)
end
Then simply use a timer that is an entity to call the wakeUp feature. It saves you a lot of time and takes away a whole lot coding.

Now for the ladders you'd have to go to your dungeons mod_assets and write in your objects.lua something like this:

Code: Select all

defineObject{
     name = "dungeon_ ladder",
     class = "Pit",
     model = "your path",
     trapDoorModel = "you other path",
     openAnim = "your other,other path",
     closeAnim = "your others, others, other path",
     placement = "floor",
     editorIcon = 36,
     -- Then here you'd add your complicated scripting on the ladder
}
That should about do it for a start I'm not exactly sure how the heck you'd do that but it will be very complicated that's for sure!


Edit: lol I see you already have some very complicated stuff written for the ladder I just skimmed through it the first time :P
Maethalion
Posts: 7
Joined: Sat Oct 04, 2014 3:36 am

Re: Sleep and Ladders

Post by Maethalion »

What's the specific purpose for the sleep function? I've only just skimmed it, but Grimrock has sleeping as a built in feature.
The sleep:start(...) function isn't intended to make the party rest. It's intent is to "Do A. Wait y seconds. Do B." The Cinematics page uses the "sleep" terminology to wait a number of seconds.

Code: Select all

-- simple one image cinematic
enableUserInput()
startMusic("assets/samples/music/intro.ogg")

-- show the image
showImage("assets/textures/cinematic/intro/page01.tga")
fadeIn(2)
sleep(4)
fadeOut(4)
unfortunately, the sleep(#) function doesn't appear to be available in a script_entity (I get an error about referencing a global table value or something)

Also, Isaac, thanks for pointing out the ladders from ORRR2. I was going through it last night and it is INCREDIBLY intricate and involved. I tried to make a "test" area but it blew up the mod. :D
Last edited by Maethalion on Sat Oct 04, 2014 2:21 pm, edited 1 time in total.
Maethalion
Posts: 7
Joined: Sat Oct 04, 2014 3:36 am

Re: Sleep and Ladders

Post by Maethalion »

-- Then here you'd add your complicated scripting on the ladder
How exactly do I do this? I was looking at this site but there doesn't seem to be an "onActivate" hook for... well, anything.
User avatar
Isaac
Posts: 3185
Joined: Fri Mar 02, 2012 10:02 pm

Re: Sleep and Ladders

Post by Isaac »

Maethalion wrote: unfortunately, the sleep(#) function doesn't appear to be available in a script_entity (I get an error about referencing a global table value or something)
Make sure it's not just a case sensitive error, and that the 'self' parameter is the ID of the sleep script. I tried your code on a test level, and it worked as expected. I even called the sleep [start] function from a script triggered by a button.

Code: Select all

-- Called by a wall button connected to a script named 'job'.
function button()
Sleep.start(Sleep, "job", "work", 5, "timer_2")
-- "work" simply hudPrints a message.
end
This command called the "work" function after the delay, and the message was printed to the screen.
Also, Isaac, thanks for pointing out the ladders from ORRR2. I was going through it last night and it is INCREDIBLY intricate and involved. I tried to make a "test" area but it blew up the mod. :D
Since you have the OORR2 installed, take a look at the orrrManager:waitForSeconds() function; located @level (1,2,21) in the "TIME" section. (Lines 2025 to 2079)
Maethalion wrote:
-- Then here you'd add your complicated scripting on the ladder
How exactly do I do this? I was looking at this site but there doesn't seem to be an "onActivate" hook for... well, anything.
Do you mean how to trigger the script when the party teleports?
What you can do is place hidden plates under the active teleporter, set to trigger on deactivate. Once the party leaves the tile, the plate calls your script.

Check out each of the stairs in my room in the OORR2. They all use teleporters to be able to work with the map layout. "Foundry"; lower middle room, top three floors.
User avatar
Komag
Posts: 3658
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Sleep and Ladders

Post by Komag »

Maethalion, I hope you stick around for Grimrock 2 editing - you obviously have a strong talent for coding and building useful tools and functions :)
Finished Dungeons - complete mods to play
Maethalion
Posts: 7
Joined: Sat Oct 04, 2014 3:36 am

Re: Sleep and Ladders

Post by Maethalion »

Komag wrote:Maethalion, I hope you stick around for Grimrock 2 editing - you obviously have a strong talent for coding and building useful tools and functions :)
Coding is my day job :D (I'm clueless on modeling tho - and GMT doesn't work on a mac) and I certainly will. Preordered it a few days ago - I didn't realize it was even in the works!
Isaac wrote:Since you have the OORR2 installed, take a look at the orrrManager:waitForSeconds() function; located @level (1,2,21) in the "TIME" section. (Lines 2025 to 2079)
So it looks like you have a master timer for background tasks that cycles every 's' seconds incrementing the count for tasks in it's Table and then executing them when their delay is up? That's really cool and must save a TON on resources.

Can I do this?

Code: Select all

cloneObject{
    doSomething = function()
        print("something")
    end
}
And then add a connecter to "doSomething" in the Editor? (or call it from a script_entity?) I want to build it into a re-usable object with needing as few "other" parts as necessary.

I had the idea of the players following tunnels that were dug through some ruins, and "stairs" didn't seem to really fit in - hence ladders. I also wanted to make a "cave-in" staircase. It looks like LoG2 has a ton of "natural" tilesets that would work great as a natural cave, so I'll wait for those. :D
User avatar
Isaac
Posts: 3185
Joined: Fri Mar 02, 2012 10:02 pm

Re: Sleep and Ladders

Post by Isaac »

Maethalion wrote:
Komag wrote:Maethalion, I hope you stick around for Grimrock 2 editing - you obviously have a strong talent for coding and building useful tools and functions :)
Coding is my day job :D (I'm clueless on modeling tho - and GMT doesn't work on a mac) and I certainly will. Preordered it a few days ago - I didn't realize it was even in the works!

So it looks like you have a master timer for background tasks that cycles every 's' seconds incrementing the count for tasks in it's Table and then executing them when their delay is up? That's really cool and must save a TON on resources.
It's amazing that that mod runs at all. To get a map that dense to function, we had to do custom replacement geometry, and write scripts that dynamically erase and rewrite the map on the fly as the player moves about the level. You can spot it happening whenever there is a brief, repeatable hiccup in the frame rate.
_____
Can I do this?

Code: Select all

cloneObject{
    doSomething = function()
        print("something")
    end
}
And then add a connecter to "doSomething" in the Editor? (or call it from a script_entity?) I want to build it into a re-usable object with needing as few "other" parts as necessary.
I don't believe so... A lot of things in LoG1 are hard coded, and AFAIK the only thing's you can define are official object classes. Jkos, Xanathar, and Diarmuid would know for certain.
I had the idea of the players following tunnels that were dug through some ruins, and "stairs" didn't seem to really fit in - hence ladders. I also wanted to make a "cave-in" staircase. It looks like LoG2 has a ton of "natural" tilesets that would work great as a natural cave, so I'll wait for those. :D
Check the assets of the OORR2... there are quite a lot of custom models, and I know there are caved in stairs for the tunnel wallset.
Post Reply