Roof Fading script

Started by MetalZelda, March 26, 2018, 05:45:06 PM

Previous topic - Next topic
March 26, 2018, 05:45:06 PM Last Edit: March 31, 2018, 03:12:57 PM by MetalZelda
This was a script I had in mind some times ago and decided to put this to my project, this was done in 2 hours of hard debugging and getting right values in February 2018, it was revised yersteday and now use userdata rather than dynamic tiles.
This is hardly based on Project Zelda Engine's system, this time, you don't have to cut and make graphics for this, you just need to do some boring stuffs using table, programmers love tables, everyone love tables

A little resumé of what it does in glorious glitchy hypercam 4 which does not render any justice to the video
https://www.youtube.com/watch?v=9H0unEaBCwY

As you might see, this is a cool "room transition", if you have a hugeload of rooms in only 1 maps this is a cool workaround, this works excellently on inside type tilesets. I personnaly use it on Houses and Dungeons

For this script, you need :
- [Multi Events] by Christopho (http://forum.solarus-games.org/index.php/topic,784.0.html)
- Create a folder called "roof_texture" in /sprites and put all your desired roof texture in there


To use this script, you need :
- Open main.lua
- C/P this code in main.lua, remember to change path_of_the_script to the path of this script
Code (lua) Select

local map_metatable = sol.main.get_metatable("map")
require(path_of_the_script)(map_metatable)


Let's talk real deal will ya

Code (lua) Select
--[[
  Fadable rooms
  Made by MetalZelda
  Inspired by: Project Zelda Engine
  Feb.2018 - Rev Mar.2018
  Version 1.6
 
  REQUIRED:
 
  - [Multi Events] by Christopho
    (http://forum.solarus-games.org/index.php/topic,784.0.html)

  Simulate multiple rooms by hiding one using a table

  {
    texture = {
src = "texture_path",
opacity = 0 - 255,
}
    x = x position of the roof
    y = y position of the roof
    width = horizontal lenght of the roof
    height = vertical lenght of the roof
    color = {r, g, b} (color of the roof)
  }
 
  color can be omnitted if using a texture
  texture can be omnitted if using a color preset
 
  You can combine both by using a semi-transparent texture and apply a color, the color will be drawn bellow

  Trigger zone is defined by the script bellow
  Usually: rooms.under = (x >= rooms.x - 9 and x <= rooms.x + rooms.width + 9) and (y >= rooms.y - 6 and y <= rooms.y + rooms.height + 23)
]]

return function(map)
  -- This is the incrementation value, 8 is faster enough
  local opacity_increment = 8

  map:register_event("on_started", function(map)
    -- If nothing exists on the rooms table means that there are nothing to display, the scripts stops here.
    if map.fade_rooms == nil then
  return
end

-- Store additionnal data on the roof table such as surface, color and opacity (default = 255) that can be automatically set by the script
for num, rooms in ipairs(map.fade_rooms) do
  rooms.surface = sol.surface.create(rooms.width, rooms.height)
 
  if rooms.color then
    rooms.surface:fill_color(rooms.color)
  end
 
  if rooms.texture then
    local texture_surface = sol.surface.create("roof_texture/" .. rooms.texture.src .. ".png")
    local texture_width, texture_height = texture_surface:get_size()

if rooms.texture.opacity then
      texture_surface:set_opacity(rooms.texture.opacity)
end

-- Get the total pixels to cover
local total = ((rooms.width * rooms.height) /  (texture_width * texture_height))

local x = 0
local y = 0
 
for i = 1, total do
  -- Draw the texture on the right place
  texture_surface:draw(rooms.surface, x, y)
 
  -- Increment next value
  x = x + texture_width
 
  if x >= rooms.width then
    x = 0
    y = y + texture_height
  end
end    
  end
 
  rooms.opacity = 255
end
  end)
 

  map:register_event("on_draw", function(map, dst_surface)
    -- To avoid errors, if there is nothing to draw, abort.
    if map.fade_rooms == nil then
  return
end

    for _, rooms in ipairs(map.fade_rooms) do
  local cam_x, cam_y = map:get_camera():get_position()
  rooms.surface:draw(dst_surface, rooms.x - cam_x, rooms.y - cam_y)
 
  local opacity = rooms.opacity
 
  -- Get player position, current layer is not a necessary parameter.
  local x, y = map:get_hero():get_position()
 
  -- Define the rule of being under a roof for any roof.
  rooms.under = (x >= rooms.x - 9 and x <= rooms.x + rooms.width + 9) and (y >= rooms.y - 6 and y <= rooms.y + rooms.height + 23)
 
  -- Define opacity variation for roof
  if rooms.under or rooms.force_under then
    rooms.opacity = rooms.opacity > (opacity_increment - 1) and rooms.opacity - opacity_increment or 0
  else
    rooms.opacity = rooms.opacity < (255 - opacity_increment) and rooms.opacity + opacity_increment or 255
  end
 
  -- Don't need to update any opacity if the game is paused.
  if map:get_game():is_paused() then
    rooms.opacity = opacity
  end
   
  rooms.surface:set_opacity(rooms.opacity)
end
  end)
 
  function map:dim_room_surface(i, bool)
    if bool == nil then
  bool = self.fade_rooms[i].force_under == nil and true or (not self.fade_rooms[i].force_under)
end
    self.fade_rooms[i].force_under = bool
  end
end


You might have a hero that have other size than Link, you can change the trigger range in here
Code (lua) Select
rooms.under = (x >= rooms.x - 9 and x <= rooms.x + rooms.width + 9) and (y >= rooms.y - 6 and y <= rooms.y + rooms.height + 23)

I did everything I've done but nothing work, give monney back

This is what you should do in your map script in order to make this to work
Let's have the video example above

You can use this texture for testing
https://i.imgur.com/0BwDrP8.png

and rename it "forest_roof_txt0.png"

Code (lua) Select

local map = ...

local fade_roofs = {
  {
    texture = {
      src = "forest_roof_txt0",
      opacity = 120
    },
    x = 80,
  y = 256,
    width = 272,
    height = 200,
  color = {56, 40, 40}
  },

  {
    x = 80,
  y = 16,
    width = 272,
    height = 200,
  color = {56, 40, 40}
  },
}

map.fade_rooms = fade_rooms


As you can see, there are 6 needed parameters

Code (lua) Select

{
  texture = {src = src of the image, opacity = opacity (0 - 255}
  x = x position of the roof
  y = y position of the roof
  width = horizontal lenght of the roof
  height = vertical lenght of the roof
  color = {r, g, b} (color of the roof)
}


If you forget one of them, your computer might explode and then stuff in red will appear, Diarandor might send you cats, you've been warned.

Errors might not exists since everything is generated by the user.

If the script don't work:
- One of your map script use the map:on_started() function rather than map:register_event("on_started")
- One of your map script use the map:on_draw() function rather than map:register_event("on_draw")
- Bad script path

Credits:
Not needed, you are free to decide.

Nice work! ;D
Quote from: MetalZelda on March 26, 2018, 05:45:06 PM
If you forget one of them, your computer might explode and then stuff in red will appear, Diarandor might send you cats, you've been warned.
I'll be preparing my cats, just in case. :-\
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

March 26, 2018, 08:41:01 PM #2 Last Edit: March 26, 2018, 09:02:26 PM by MetalZelda
 
Quote from: Diarandor on March 26, 2018, 07:42:57 PM
Nice work! ;D
Quote from: MetalZelda on March 26, 2018, 05:45:06 PM
If you forget one of them, your computer might explode and then stuff in red will appear, Diarandor might send you cats, you've been warned.
I'll be preparing my cats, just in case. :-\

:P

I fixed something odd, instead of keeping the same opacity within map:get_game():is_paused() I used a return which will only draw 1 surface.
Now it works perfectly, I might update it someday to give proper functions such as freezing entities when opacity = 255, possibility to fade the opacity manually (in case of camera movement)

The use of the script should be just this line
Code (lua) Select
require(path_of_the_script)
instead of
Code (Lua) Select
local map_metatable = sol.main.get_metatable("map")
require(path_of_the_script)(map_metatable)

because you can get metatables inside any script.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Updated script

#1 - User can now use a texture for the roof rather than a static color by using these parameters

Code (lua) Select

  texture = {
    src = "source_file_name",
    opacity = opacity,
  }


The best way is to use a 8x8, 16x16, 8x16 pattern, the script will do the rest
You can combine both texture and color, using a semi transparent texture and apply a color underneath is possible

#2 - You can dim any roof surface you want by using

Code (lua) Select
map:dim_room_surface(i, bool)

where i = the identifier number of the roof
           bool = true or false

Useful for camera movements