Solarus Forum

Community => Your scripts => Topic started by: PhoenixII54 on September 05, 2017, 08:46:37 pm

Title: Turtle Rock (Alttp) Pipe system
Post by: PhoenixII54 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
  1. --A simple string splitter, found on the Internet.
  2. --Used for extracting parameters in the sensor name.
  3. --You might want to use your own version to avoid possible license issues
  5. local function string_split(source, delimiters)
  6.   local elements = {}
  7.   local pattern = '([^'..delimiters..']+)'
  8.   string.gsub(source, pattern, function(value)
  9.     elements[#elements + 1] = value
  10.   end)
  11.   return elements
  12. end
  14. --A simple yet powerful pipe system like in A link to the Past Turtle Rock
  15. --Usage : Place a series of sensors on the map, then name them as this :
  16. --pipe_<path_id>_<path_index>
  17. --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.
  18. --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
  19. --as it overwrites the sensors' on_activated event
  21. local sensor_meta=sol.main.get_metatable("sensor")
  23. function sensor_meta:on_activated()
  24.   local name=self:get_name()
  25.   local map=self:get_map()
  26.   local hero=map:get_hero()
  27.   if name~=nil then
  28.     local type=string_split(name,"_")
  30.     if type[1]=="pipe" then
  31.     --We are now in the pipe, either on en end or in the middle of it.
  32.       if not sensor_meta.pipe_active then
  33.         --Actually entering the pipe
  34.         length=map:get_entities_count("pipe_"..type[2])
  35.         hero:freeze()
  36.         hero:set_visible(false)
  37.         --detecting whether we are going in the increasing index order or not
  38.         local reversed=(tonumber(type[3])==length)
  39.         local next
  40.         if reversed then
  41.           next=length-1
  42.         else
  43.           next=2
  44.         end
  45.         --Saving settings in the metatable for later usage
  46.         sensor_meta.pipe_next=next
  47.         sensor_meta.pipe_is_reversed=reversed
  48.         sensor_meta.pipe_length=length
  49.         sensor_meta.pipe_active=true
  51.       else
  52.         --Already in the pipe and continuing the movement
  53.         if sensor_meta.pipe_is_reversed then
  54.           sensor_meta.pipe_next=sensor_meta.pipe_next-1
  55.         else
  56.           sensor_meta.pipe_next=sensor_meta.pipe_next+1
  57.         end
  58.       end
  60.       --Actually start the movement
  61.       if sensor_meta.pipe_next==0 or sensor_meta.pipe_next==sensor_meta.pipe_length+1 then
  62.       --We are about to finish the move : make the hero walk out of the pipe
  63.         local movement=sol.movement.create("path")
  64.         local dir=sensor_meta.pipe_outDir or 0
  65.         local path={dir,dir}
  66.         movement:set_path(path)
  67.         hero:set_visible(true)
  68.         hero:set_direction(dir/2)
  69.         hero:set_animation("walking")
  70.         movement:start(hero,function()
  71.           hero:unfreeze()
  72.           sensor_meta.pipe_active=false
  73.         end)
  74.       else
  75.         --making the quick auto move in the pipe (and bonk in the corners)
  76.         --Feel free to change this sound to your own !
  78.         local movement=sol.movement.create("target")
  79.         local target="pipe_"..type[2].."_"..sensor_meta.pipe_next
  80.         movement:set_target(map:get_entity(target))
  81.         movement:set_speed(192)
  82.         movement:start(hero)
  83.         --Saving the movement direction for when we will leave the pipe
  84.         sensor_meta.pipe_outDir=2*movement:get_direction4()
  85.       end
  86.     end
  87.   end
  88.   --And that(s all folks !
  89. 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.
Title: Re: Turtle Rock (Alttp) Pipe system
Post by: Diarandor 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
Title: Re: Turtle Rock (Alttp) Pipe system
Post by: PhoenixII54 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!
Title: Re: Turtle Rock (Alttp) Pipe system
Post by: MetalZelda on September 07, 2017, 10:01:33 am
Code: [Select]
Wait such thing is possible ?
Title: Re: Turtle Rock (Alttp) Pipe system
Post by: Christopho 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
  1. local entity = map:get_entities(prefix)()
But this is obscure to read, and the parameter 1 is useless and has no effect.
Title: Re: Turtle Rock (Alttp) Pipe system
Post by: PhoenixII54 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
  1. map:get_entity(target)
since  the sensors now use the same name convention.

edit : code is now updated to apply the modification.