Author Topic: Turtle Rock (Alttp) Pipe system  (Read 5772 times)

0 Members and 1 Guest are viewing this topic.

PhoenixII54

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Turtle Rock (Alttp) Pipe system
« on: September 05, 2017, 08:46:37 PM »
Hi !

Have you ever wanted to have those pipes in Crystal Palace of MoS DX move your characters automagically ? Then this script is for you !

Code: ( lua) [Select]
--A simple string splitter, found on the Internet.
--Used for extracting parameters in the sensor name.
--You might want to use your own version to avoid possible license issues

local function string_split(source, delimiters)
  local elements = {}
  local pattern = '([^'..delimiters..']+)'
  string.gsub(source, pattern, function(value)
    elements[#elements + 1] = value
  end)
  return elements
end

--A simple yet powerful pipe system like in A link to the Past Turtle Rock
--Usage : Place a series of sensors on the map, then name them as this :
--pipe_<path_id>_<path_index>
--Warning : you MUST set the indexes to a continuous way (1,2,3,...) or else you will be stuck in the middle of the movement.
--Notice : While it requires nothing but requiring this script in the main file to run, you might want to use en event register like in Christopho's projects
--as it overwrites the sensors' on_activated event

local sensor_meta=sol.main.get_metatable("sensor")

function sensor_meta:on_activated()
  local name=self:get_name()
  local map=self:get_map()
  local hero=map:get_hero()
  if name~=nil then
    local type=string_split(name,"_")
       
    if type[1]=="pipe" then
    --We are now in the pipe, either on en end or in the middle of it.
      if not sensor_meta.pipe_active then
        --Actually entering the pipe
        length=map:get_entities_count("pipe_"..type[2])
        hero:freeze()
        hero:set_visible(false)
        --detecting whether we are going in the increasing index order or not
        local reversed=(tonumber(type[3])==length)
        local next
        if reversed then
          next=length-1
        else
          next=2
        end
        --Saving settings in the metatable for later usage
        sensor_meta.pipe_next=next
        sensor_meta.pipe_is_reversed=reversed
        sensor_meta.pipe_length=length
        sensor_meta.pipe_active=true
     
      else
        --Already in the pipe and continuing the movement
        if sensor_meta.pipe_is_reversed then
          sensor_meta.pipe_next=sensor_meta.pipe_next-1
        else
          sensor_meta.pipe_next=sensor_meta.pipe_next+1
        end
      end
 
      --Actually start the movement
      if sensor_meta.pipe_next==0 or sensor_meta.pipe_next==sensor_meta.pipe_length+1 then
      --We are about to finish the move : make the hero walk out of the pipe
        local movement=sol.movement.create("path")
        local dir=sensor_meta.pipe_outDir or 0
        local path={dir,dir}
        movement:set_path(path)
        hero:set_visible(true)
        hero:set_direction(dir/2)
        hero:set_animation("walking")
        movement:start(hero,function()
          hero:unfreeze()
          sensor_meta.pipe_active=false
        end)
      else
        --making the quick auto move in the pipe (and bonk in the corners)
        --Feel free to change this sound to your own !
        sol.audio.play_sound("bomb")
        local movement=sol.movement.create("target")
        local target="pipe_"..type[2].."_"..sensor_meta.pipe_next
        movement:set_target(map:get_entity(target))
        movement:set_speed(192)
        movement:start(hero)
        --Saving the movement direction for when we will leave the pipe
        sensor_meta.pipe_outDir=2*movement:get_direction4()
      end
    end
  end
  --And that(s all folks !
end

Note: if you find a simpler way, don't hesitate to tell me, i'll be happy to rework my code as a challenge !
Enjoy !

edit : correction of misnamed function call originally using another file.
edit #2 : correction of movement:set_garget :
It used map:get_entities(target)(1), now it uses map:set_entity(target) since now you should have ensured all sensors have a unique ID.
edit #3 : fixed a possible issue when you try to make a pipe with only 1 sensor.
+ fixed comments indentation, removed some typo and removed remaining debug prints.
« Last Edit: September 07, 2017, 02:13:59 PM by PhoenixII54 »

Diarandor

  • Hero Member
  • *****
  • Posts: 1062
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: Turtle Rock (Alttp) Pipe system
« Reply #1 on: September 06, 2017, 02:02:04 AM »
A different way (not necessarily better or worse) is to use streams that freeze the hero, as conveyor belts, and two sensors to start/finish the walking animations (at both sides of the pipe). My approach requires more mapping, though.

That code seems very interesting, for learning purposes, for people who is learning Lua or want to improve skills on coding (and looks very clean, short and polished). Also, I love that word: "automagically" ;D
“If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you.”

PhoenixII54

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Re: Turtle Rock (Alttp) Pipe system
« Reply #2 on: September 06, 2017, 05:28:15 PM »
You know what ? that's what i did in a first version with custom entities instead of the sensors, it worked well too, but wanted something "universal", as in just place any number of sensors carefully named and voila!

Anyways, thanks!
« Last Edit: September 06, 2017, 05:30:40 PM by PhoenixII54 »

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: Turtle Rock (Alttp) Pipe system
« Reply #3 on: September 07, 2017, 10:01:33 AM »
Code: [Select]
movement:set_target(map:get_entities(target)(1))
Wait such thing is possible ?

Christopho

  • Administrator
  • Hero Member
  • *****
  • Posts: 1195
    • View Profile
Re: Turtle Rock (Alttp) Pipe system
« Reply #4 on: September 07, 2017, 10:52:23 AM »
Hum, map:get_entities(prefix) returns an iterator so you can indeed get its first value by calling the result:
Code: (lua) [Select]
local entity = map:get_entities(prefix)()
But this is obscure to read, and the parameter 1 is useless and has no effect.

PhoenixII54

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
Re: Turtle Rock (Alttp) Pipe system
« Reply #5 on: September 07, 2017, 02:00:34 PM »
Actually this is a reminiscence of an experimental way where i used the name to code the output direction when at the end of a pipe, which caused problems since i could''t get the next entity if i was at the very start of the chain, but since then i found that using the direction of the actual movement is way easier, so you can replace it by
Code: ( lua) [Select]
map:get_entity(target)since  the sensors now use the same name convention.

edit : code is now updated to apply the modification.
« Last Edit: September 07, 2017, 02:07:32 PM by PhoenixII54 »