Author Topic: [WIP] Ceiling dropping effect (ALTTP)  (Read 932 times)

PhoenixII54

  • Newbie
  • *
  • Posts: 37
    • View Profile
[WIP] Ceiling dropping effect (ALTTP)
« on: October 02, 2017, 10:01:07 pm »
Hi, in my attempts to reproduce famous effects from ALTTP to compensate the missing effects in Zelda : Mystery of Solarus, here is one of the major ones :

When you fall in e hole that has a floor below, you end up in the said room, falling from the ceiling and dropping onto the floor, after doing a few turns oaround yourself.

Be prepared, besause this is the puropse of this script.
Code: Lua
  1. --Ceiling dropping system (WIP)
  2. --Reproduces the "fall from uper floors" effects
  3.  
  4. --Usage : Call this script from any game launching system or use the event manager script to set the metatables then do your maps as usuel
  5.  
  6. --Extracting actual destination and ground from teletransporters since map;on_started(destination) dosen't take special destinations in account, then stirong it to a savegame variable lCan be useful for dungeons like Skull Dungeon (Level 3 of ALTTP, which has many hole entrances).
  7. --Note, here, everything is in a single script, but in a real project you may have multiple file (one for each metatable)
  8.  
  9. local teletransporter_meta=sol.main.get_metatable("teletransporter")
  10. local map_meta=sol.main.get_metatable("map")
  11.  
  12. function teletransporter_meta:on_activated()
  13.   local game=self:get_game()
  14.   local ground=self:get_map():get_ground(game:get_hero():get_position())
  15.   game:set_value("tp_ground",ground)
  16. end
  17.  
  18. --the actual trigger
  19. function map_meta:on_started(destination)
  20.   local hero=self:get_hero()
  21.   local game=self:get_game()
  22.   local x,y=hero:get_position()
  23.   local ground=game:get_value("tp_ground")
  24.   if ground=="hole" then
  25.     --Falling from the ceiling
  26.     hero:set_visible(false)
  27.     hero:freeze()
  28.     --disabling teletransoprters to avoid
  29.     local disabled_teletransoprters={}
  30.     for t in self:get_entities_by_type("teletransporter") do
  31.       if t:is_enabled() then
  32.         disabled_teletransporters[#disabled_teletransporters+1]=v
  33.         t:set_enabled(false)
  34.       end
  35.     end
  36.     --Creating a "stunt actor" moving vertically from the ceiling
  37.     local falling_hero=self:create_custom_entity({
  38.       name="falling_link",
  39.       x=x,
  40.       y=math.max(y-100,24),
  41.       direction=0,
  42.       layer=self:get_max_layer(),
  43.       sprite=hero:get_tunic_sprite_id(),
  44.       width=24,
  45.       height=24,
  46.     })
  47.     falling_hero:get_sprite():set_animation("stopped")
  48.     falling_hero:set_can_traverse_ground("wall",true)
  49.     falling_hero:set_can_traverse_ground("empty",true)
  50.     falling_hero:set_can_traverse_ground("traversable",true)
  51.  
  52.     --Creating a reception platform (prevents the hero from falling into consecutive holes during the animation)
  53.     local platform=self:create_custom_entity({
  54.       name="platform",
  55.       direction=0,
  56.       layer=layer,
  57.       x=x,
  58.       y=y,
  59.       width=32,
  60.       height=32,
  61.       sprite="entities/shadow",
  62.     })
  63.     platform:bring_to_front()
  64.     platform:get_sprite():set_animation("big")
  65.     platform:set_modified_ground("traversable")
  66.  
  67.     --Creating the actual movement for the stunt actor
  68.     local movement=sol.movement.create("target")
  69.     movement:set_target(x,y)
  70.     movement:set_speed(96)  --The falling speed.
  71.     --Spinning the stunt actor on itself
  72.     sol.timer.start(falling_hero, 100, function()
  73.       falling_hero:set_direction((falling_hero:get_direction()+1)%4)
  74.       return true
  75.     end)
  76.     movement:start(falling_hero, function()
  77.       --Movement is now complete, restoring the disabled teletransoprters and getting rid of the temporary entities
  78.       sol.audio.play_sound("hero_lands")
  79.       platform:remove()
  80.       falling_hero:remove()
  81.       hero:set_visible(true)
  82.       hero:unfreeze()
  83.       for _,t in pairs(disabled_teletransporters) do
  84.         t:set_enabled(true)
  85.       end
  86.     end)
  87.     --]]
  88.   end
  89. end
  90.  

Hope it will be useful, but it may have have bugs, so don't hasitate to report them to me. And remember, it is not fully finished so expect changes to happpen.
Remember that you may want to modify this script to make it compatible with Christopho's Multi-event script, which i don't use (yet) in my experiments to keep total control over my tests.

Anyway, enjoy !

edit#1 : Actually finished the v1.0 version, with ground detection on teletransportation.
Update (2017/10/23) : Modified the script to remove the extra sprite requirement and to add more flexibility. This is now likely a final version unless someone finds a more efficient way.
« Last Edit: October 23, 2017, 05:00:28 pm by PhoenixII54 »

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: [WIP] Ceiling dropping effect (ALTTP)
« Reply #1 on: December 17, 2017, 03:39:42 pm »
I like this script, I'm using it but it have the limitation to be only available for the hero

I am currently working on this kind of script as well, this time, all entities are able to use this ability (enemies, hero, custom entities)

This is not perfect as it might lead to problems currently but it mostly works
Entity's real position remains intact, only their sprites are being moved

Code: Lua
  1. local object = {}
  2.  
  3. -- Falling from ceiling
  4. -- Works with any type of entity
  5. -- Version 0.1 - MetalZelda
  6.  
  7. --[[
  8.   Make it work:
  9.  
  10.   - Save this script anywhere you want
  11.   - In any script (metatable script is better):
  12.  
  13.   Example: I want to make this available for the hero
  14.   local fall_manager = require("path_to_the_script")
  15.   fall_manager:create("hero")
  16.  
  17.   Recommended way to make this work:
  18.   -> in main.lua
  19.  
  20.   local fall_manager = require("path_to_the_script")
  21.   local entities_fall_compatibility = { "hero", "enemy", "npc"}
  22.   for _, entities in ipairs(entities_fall_compatibility) do
  23.     fall_manager:create(entities)
  24.   end
  25.  
  26.  
  27.   Careful, it only work with map entities
  28.  
  29.   To active it, simply call
  30.     - hero:fall_from_ceiling(height, sound, callback) where
  31.          
  32.           height = the height of the falling things (must be positive)
  33.           sound = any sound you wanna play when the falling animation starts
  34.           callback = what to do when it finished (text, cutscene, death, etc)
  35.          
  36.         - Remember that you can implement it anywhere else, the target only need to be an entity / sprite
  37. ]]
  38.  
  39. function object:create(meta)
  40.   local object_meta = sol.main.get_metatable(meta)
  41.   local currently_falling = false
  42.  
  43.   function object_meta:fall_from_ceiling(height, sound, callback)
  44.     currently_falling = true
  45.        
  46.         if meta == "hero" then
  47.           -- This means that self returns the hero entity, avoid him from moving.
  48.           self:freeze()
  49.         end
  50.        
  51.         -- Get the current object position
  52.         local cx, cy, clayer = self:get_position()
  53.         local map = self:get_map()
  54.        
  55.         -- Draw a shadow in the entity's real position
  56.         local shadow = map:create_custom_entity({
  57.           x = cx,
  58.           y = cy,
  59.           layer = clayer,
  60.           width = 16,
  61.           height = 16,
  62.           sprite = "entities/shadow",
  63.           direction = 0
  64.         })
  65.        
  66.        
  67.         local first_active_sprite = nil
  68.        
  69.     -- Depending on things, obejct might have different sprite that is synchronized to him
  70.         for sprite_name, sprite in self:get_sprites() do
  71.           sprite:set_xy(0, -height)
  72.          
  73.           if first_active_sprite ~= nil then
  74.             first_active_sprite = sprite_name
  75.           end
  76.         end
  77.        
  78.         local target_sprite = self:get_sprite(first_active_sprite)
  79.        
  80.         if sound ~= nil then
  81.           sol.audio.play_sound(sound)
  82.         end
  83.        
  84.         local movement = sol.movement.create("straight")
  85.         movement:set_max_distance(height)
  86.         movement:set_angle(3 * math.pi / 2)
  87.         movement:set_speed(300)
  88.         movement:set_ignore_obstacles(true)
  89.         movement:start(target_sprite, function()
  90.           -- Movement finished, disable the falling movement
  91.           first_active_sprite = nil
  92.           currently_falling = false
  93.  
  94.           sol.audio.play_sound("hero_lands")
  95.          
  96.           if meta == "hero" then
  97.             self:unfreeze()
  98.           end
  99.          
  100.           if callback ~= nil then
  101.             callback()
  102.           end
  103.          
  104.           shadow:remove()
  105.         end)
  106.        
  107.         local entity = self
  108.        
  109.         -- Notify the game to synchronize all sprites during the freefall movement if any
  110.         function movement:on_position_changed()
  111.           local x, y = target_sprite:get_xy()
  112.          
  113.           local animation = shadow:get_sprite():get_animation()
  114.           local current_height = -y
  115.          
  116.           -- Adding some shadow stuff here
  117.  
  118.           if current_height == height / 1.5 then
  119.             if animation ~= "demi" then
  120.                   shadow:get_sprite():set_animation("demi")
  121.                 end
  122.           elseif current_height == height / 4 then
  123.             if animation ~= "big" then
  124.                   shadow:get_sprite():set_animation("big")
  125.                 end
  126.           end
  127.          
  128.           -- Depending on things, obejct might have different sprite that is synchronized to him
  129.           for _, sprite in entity:get_sprites() do
  130.             sprite:set_xy(x, y)
  131.           end
  132.          
  133.         end    
  134.   end
  135. end
  136.  
  137.  
  138. return object

This way, you can still use the ability to start the animation on the player when falling from a hole (using map:on_started(destination)), plus you can use it to create falling enemies
Plus, sprites synchronised to an entity will follow the falling movement (hero's shield for example)
You can also make a timer to make the hero to change direction a la ALTTP, there is a local variable that return whever or not the entity is falling or not

Upcoming update will include ground detection, mostly to use a different landing sound depending on the terrain
« Last Edit: December 17, 2017, 07:24:06 pm by MetalZelda »

PhoenixII54

  • Newbie
  • *
  • Posts: 37
    • View Profile
Re: [WIP] Ceiling dropping effect (ALTTP)
« Reply #2 on: December 18, 2017, 09:01:35 pm »
Nice work ! i'm actually relizing Link was not the only entity that could fall from ceilings (there were the blobs in the Dungeon 6's last rooms, plus the primed bombs dropping with a wrong lever pulling). I don't think i would have been able to make a better version myself, so if you manage to finish your enhancements, then credits shall go to you. 8)

Diarandor

  • Hero Member
  • *****
  • Posts: 1026
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: [WIP] Ceiling dropping effect (ALTTP)
« Reply #3 on: December 18, 2017, 11:12:34 pm »
Credits should go to both of you:
PhoenixII54 + MetalZelda = MetalPhoenix  ;D XD
“If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you.”