Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - wizard_wizzle (aka ZeldaHistorian)

#1
Development / Hero sprite error new to 1.6?
January 09, 2019, 04:13:11 AM
I discovered something in my game today that wasn't in 1.5, so I think it may be a bug introduced in 1.6. I may a couple of maps in my game where there are a number of dynamic entities of water tiles that I disable at one point in the game (basically you drain an entire lake, and this is how it's accomplished). Now with 1.6, when I move from the top map to the bottom map, the "splashing" animation shows for a short time immediately after the transition, and then returns to the normal "walking" animation. This didn't happen in 1.5 - the transition was seamless and the player wouldn't suspect there was ever water there. Oddly enough, the same thing does not happen when moving from the bottom map to the top map, so maybe it only occurs when the hero is facing down?
#2
Development / NPC routines
December 06, 2017, 04:41:41 AM
Hey all,

I've been thinking recently about how to create more interesting NPC routines in Lua without it being too complicated. Right now I'm on the idea of passing routines as a table from the NPC script to another scripts that parses it and stores it to be executed on the regular. I'm a little fuzzy on the details though, so I thought I'd throw my thoughts here!

Code (lua) Select

local routine = { [08]="to_shop", [10]="to_house", [13]="to_mill" }
function entity:on_created()
  self:set_routine(self, routine)
end

Here is where I thought about encoding the routine as a nested table - with time (hours) in brackets and waypoint entity in quotes. Then I can parse that table out to get the individual parts of the routine.

Code (lua) Select
  for k,v in pairs(routine) do
    game:add_routine(k, npc:get_name(), v)
  end


I think my next step would be to create a new table, or several tables, organized by hour so the game easily parse the correct table at the correct time (the add_routine routine I'm playing around with up there). If this table contains the entity name and waypoint entity name, then the movement should be able to be created pretty easily.

My main issue right now is the structure/format of the routine tables organized by time. I'm not an expert on Lua tables and I'm not sure how to make this without a bunch of if/then statements which would be best to avoid.

Anyway, I'd love to hear thoughts on the idea, and especially the execution thereof!
#3
General discussion / PC Gamer article
September 18, 2017, 07:49:53 PM
PC Gamer did an awesome little article on our own Christopho and his excellent engine, Solarus! If you haven't seen it, I highly recommend the read!  :D

http://www.pcgamer.com/zeldas-most-dedicated-fan-game-developers-built-an-engine-anyone-can-use/

Great to see good work recognized, and we all know that Christopho has done some great work with Solarus!
#4
It appears, and the API confirms, that the "normal" video mode actually stretches the image by a factor of 2. Is it possible to just have the game run un-stretched? If there's not currently, I really think this should be added as a feature soon. Currently it would be pretty much impossible to use higher resolution resources when making games.
#5
Development / Enemies not piling up
May 26, 2017, 02:36:48 AM
In my game my enemies have a bad habit of "piling up" on each other, which makes it much easier to kill several of them with one hit. I was trying to avoid this with the code below, but I've now traced the code to some random crashes I've been having, so I need to take it out. I'd still like to find a way to not have the enemies pile up, and my guess is this was a stupid way in the first place and there's some obvious answer I've missed. So, my hope is the community can save me from my own stupidity again :)

Code ("lua") Select
function enemy:on_collision_enemy(other_enemy, other_sprite, my_sprite)
  if enemy:is_traversable() then
    enemy:set_traversable(false)
    sol.timer.start(200, function() enemy:set_traversable(true) end)
  end
end
#6
When I create a text surface, I can draw it near a custom entity by using draw_visual from on_post_draw, but when I try to apply a fade_in or fade_out to that surface (which the api says is general to all drawables) it doesn't seem to do anything. Is this a bug? Has anyone else tried this and succeeded?
#7
Development / Equipment items as a class
October 13, 2016, 03:08:59 PM
I've been thinking about equipment items and if it would be possible to extend them to work more like a class in an RPG, so you could give custom stats and such to items. The ultimate extension would be to allow for a sort of crafting system where you could customize the item and it would be saved with the custom stats and sprite.

My thought is this should be possible by creating an item script for each type of item, say a sword or dagger or axe, then using variants to cover the different sprites. Then I'm wondering if it's possible to create a function in the item script that's called after item_create that passes and sets the stats and saves the item. The condition I see is that you'd still only be able to have one type of each item, or at least one variant, right?

Any other interesting ideas anyone has about extending the built in items? Or is this something that's better handled by ditching the built in items and using custom entities?
#8
I'd like a script to detect when the map is undergoing a scrolling transition - is that possible? This may be related to Solarus issue #989 (https://github.com/solarus-games/solarus/issues/989), but my screen overlay for map tone scrolls with the map when the hero hits the teletransporter. This is not the desired behavior since all of the lights that I've drawn on the surface move when they should stay stationary. My contingency plan is to disable drawing of those lights at the moment of screen scrolling, but I can't figure out if that's possible.
#9
Bugs & Feature requests / Video/hardware acceleration
August 22, 2016, 02:18:24 PM
Is there a way from code or settings to disable video/hardware acceleration by default? It looks like you can do it from the launcher, but I'd like to not give the option and just disable it for my game by default if possible. Thanks!
#10
Development / Failed to create software surface
July 31, 2016, 01:52:18 AM
I'm using a modified version of Satoh's code that was posted at http://forum.solarus-games.org/index.php/topic,676.15.html to make the day/night system I had work with the new blend modes introduced in 1.5. It uses the map metatable to force a night overlay to drawn on all maps when it's night time. The problem is that after 10 to 15 minutes of game play at night (an overlay with blend modes being drawn) my game crashes with the fatal error "Failed to create software surface". I'm assuming that my code is just inefficient and the repeated re-drawing is causing memory issues, but I'm not sure how to improve it. Hopefully someone here will have an idea that can help me improve me code! And thanks for looking!

Code ("lua") Select
  function map_metatable:on_draw(dst_surface)
    local game = self:get_game()
    local hour_of_day = (time_counter / 3000)
    -- Put the night (or sunrise or sunset) overlay on any outdoor map if it's night time.
    if (hour_of_day >= 19.6 or hour_of_day <= 7.4) and
    (game:is_in_outside_world() or (self:get_world() == "dungeon_2" and self:get_id() == "20") or
  (self:get_world() == "dungeon_2" and self:get_id() == "21") or (self:get_world() == "dungeon_2" and self:get_id() == "22")) then
      local x,y = game:get_map():get_camera():get_position()
      local w,h = game:get_map():get_camera():get_size()
     
      if draw_counter >= 15 then
        shadow:clear()
        if hour_of_day >= 19.6 and hour_of_day < 20 then
          t[1] = 255; t[2] = 255; t[3] = 255
          -- Dusk
          if t[1] >= 2 then
            t[1] = t[1] - 2 -- Red: Goal is 0 (fade to black, which is the same as fading in for this blend mode)
          else
            game:set_value("time_of_day", "night")
            game:set_value("hour_of_day", 20)
          end
          if t[2] >= 3 then
            t[2] = t[2] - 3 -- Green: Goal is 0
          else
            game:set_value("time_of_day", "night")
            game:set_value("hour_of_day", 20)
          end
          if t[3] >= 4 then
            t[3] = t[3] - 4 -- Blue: Goal is 0
          else
            game:set_value("time_of_day", "night")
            game:set_value("hour_of_day", 20)
          end
          shadow:fill_color(t)
        elseif hour_of_day >= 20 and hour_of_day <= 21 then
          -- Sunset
          if t[1] >= 32 then t[1] = t[1] - 3 end -- Red: Goal is 32 (from 255)
          if t[2] >= 64 then t[2] = t[2] - 2 end -- Green: Goal is 64 (from 255)
          if t[3] >= 128 then t[3] = t[3] - 1 end  -- Blue: Goal is 128 (from 255)
          shadow:fill_color(t)
        elseif hour_of_day >= 6 and hour_of_day <= 7 then
          -- Sunrise
          t[1] = (182*(hour_of_day-6))+18 -- Red: Goal is 182 (from 32)
          t[2] = (62*(hour_of_day-6))+66 -- Green: Goal is 126 (from 64)
          t[3] = (37*(1-(hour_of_day-6)))+87 -- Blue: Goal is 91 (from 128)
          shadow:fill_color(t)
        elseif hour_of_day > 7 and hour_of_day <= 7.4 then
          -- Dawn
          if t[1] <= 253 then
            t[1] = t[1] + 2 -- Red: Goal is 255 (fade to white, which is the same as fading out for this blend mode)
          else
            game:set_value("time_of_day", "day")
            game:set_value("hour_of_day", 7.5)
          end
          if t[2] <= 252 then
            t[2] = t[2] + 3 -- Green: Goal is 255
          else
            game:set_value("time_of_day", "day")
            game:set_value("hour_of_day", 7.5)
          end
          if t[3] <= 251 then
            t[3] = t[3] + 4 -- Blue: Goal is 255
          else
            game:set_value("time_of_day", "day")
            game:set_value("hour_of_day", 7.5)
          end
          shadow:fill_color(t)
        else
          -- Night
          shadow:fill_color({32,64,128,255})
          game:set_value("time_of_day", "night")
        end
       
        lights:clear()
        for e in game:get_map():get_entities("torch_") do
          if e:get_sprite():get_animation() == "lit" and e:get_distance(game:get_hero()) <= 250 then
            local xx,yy = e:get_position()
            local sp = sol.sprite.create("entities/torch_light")
            sp:set_blend_mode("blend")
            sp:draw(lights, xx-32, yy-32)
         end
        end
        for e in game:get_map():get_entities("night_") do
          if e:is_enabled() and e:get_distance(game:get_hero()) <= 250 then
            local xx,yy = e:get_position()
            local sp = sol.sprite.create("entities/torch_light")
            sp:set_blend_mode("blend")
            sp:draw(lights, xx-24, yy-24)
          end
        end
        for e in game:get_map():get_entities("lava_") do
          if e:is_enabled() and e:get_distance(game:get_hero()) <= 250 then
            local xx,yy = e:get_position()
            local sp = sol.sprite.create("entities/torch_light_tile")
            sp:set_blend_mode("blend")
            sp:draw(lights, xx-8, yy-8)
          end
        end
        for e in game:get_map():get_entities("warp_") do
          if e:is_enabled() and e:get_distance(game:get_hero()) <= 200 then
            local xx,yy = e:get_position()
            local sp = sol.sprite.create("entities/torch_light_tile")
            sp:set_blend_mode("blend")
            sp:draw(lights, xx-16, yy-16)
          end
        end
        for e in game:get_map():get_entities("poe") do
          if e:is_enabled() and e:get_distance(game:get_hero()) <= 200 then
            local xx,yy = e:get_position()
            local sp = sol.sprite.create("entities/torch_light")
            sp:set_blend_mode("blend")
            sp:draw(lights, xx-32, yy-32)
          end
        end
        -- Slowly drain magic when using lantern.
        if magic_counter >= 50 then
          game:remove_magic(1)
          magic_counter = 0
        end
        if not game:is_suspended() then magic_counter = magic_counter + 1 end
        draw_counter = 0
      end
      draw_counter = draw_counter + 1

      if game:has_item("lamp") and game:get_magic() > 0 then
        local xx, yy = game:get_map():get_entity("hero"):get_position()
        local sp = sol.sprite.create("entities/torch_light_hero")
        sp:set_blend_mode("blend")
        sp:draw(lights, xx-64, yy-68)
      end

      lights:draw_region(x,y,w,h,shadow,x,y)
      shadow:draw_region(x,y,w,h,dst_surface)
    end
  end
#11
Bugs & Feature requests / Universal Windows App
June 26, 2016, 08:40:46 PM
I'm wondering if it would be possible in a future release (1.6?) to enable the Solarus engine as a Universal Windows App (UWA), which should allow games to be run on XBox One as well as Windows 10. It looks like it would require SDL version 2.0.4 (not sure what Solarus is using currently) and development in Visual Studio 2015. I just think it would be really cool to be able to play our games on XBox!

https://msdn.microsoft.com/en-us/library/hh875012.aspx
#12
Development / Hole into teletransporter
June 17, 2016, 04:42:16 PM
In the past, I was able to place a teletransporter over a hole so that when the hero fell into the hole, he was transported to a new map. This no longer appears to work in 1.5dev - was this intentional? Is it possible to get the old behavior back?

Also Christopho, I was wondering if there was any estimate on the release of 1.5? I wanted to release the full version of my game soon, but wanted it to run on Solarus 1.5

Thanks!
#13
Bugs & Feature requests / Flying enemies and walls
April 14, 2016, 02:48:15 PM
I have enemies where I've set enemy:set_obstacle_behavior("flying") and enemy:set_layer_independent_collisions(true) that are traversing walls that are set to block enemies - is this the expected behavior? Is there a way I can change this if it is?
#14
I get multiple "libpng warning: iCCP: known incorrect sRGB profile" errors when displaying a menu. I'm guessing this is related to my pause_submenus.png file, but the error does not specify. I also haven't been able to manipulate the image to eliminate the error - I use gimp, and have searched the internet for solutions to no avail. Anyone have any insight into this?

In a future version, can the engine at least specify the file that's throwing the error?
#15
Development / Expanding item_1 and item_2 commands
February 09, 2016, 01:41:48 AM
I'm thinking it should be possible, probably using metatables, to expand the item_1 and item_2 commands and include item_3 and even item_4, for when more items are needed. But I'm wondering, does modifying the metatable of existing functions expand them or overwrite them? For example, would the code below work? If not, I could create a custom function similar to each of the built-in ones for each of the item slot functions.

Code (lua) Select

local game_metatable = sol.main.get_metatable("game")
function game_metatable:get_item_assigned(slot)
  if slot == 2 then
    return game:get_value("slot_2_item")
  elseif slot == 3 then
    return game:get_value("slot_3_item")
  end
end


I'm also not 100% sure how the button mapping part would work. Is game:get/set_command_keyboard_binding() expandable or configurable?

Just brainstorming and wanted others' thoughts...
#16
Development / Fading out overlay in different map
December 13, 2015, 09:23:49 PM
I have a surface that I'm using as an overlay, but it only exists on two maps. What I'd like to have happen is that when you enter one of the two maps, the overlay fades in (it's fog, so it's for effect) and then when you leave, it fades out. I can get the fade in to work just fine. I've tried to use the teletransport:on_activated event to call the fade_out, but so far I can't get it to work. I'm assuming the surface is automatically attached to the map because when you leave the map, the surface overlay immediately disappears. Is it possible to have this fade out instead?
#17
Development / Menu help
November 08, 2015, 12:47:47 AM
At the request of my brother, I've created a new warp menu for my game. Everything basically works, but I have a couple things that aren't working as well as they could, and I was hoping I could get some help.

1) The caption (the last part of on_draw) is not displaying, and I don't know why. This is based off of christopho's map submenu. I've checked that there is text in the variables (and there is) and I've tried to change the draw coordinates to no avail.

2) I can't figure out how to change the HUD icons. I've frozen the hero when the menu starts so you don't move around when trying to interact with the menu, but that's also frozen the HUD. I would like the attack icon to be "Confirm" (validate) and the pause icon to be "Back".

Code (lua) Select

local game = ...
local warp_menu = {}  -- The warp menu.
local initial_point
local initial_y = 10
local index

-- Warp point name, Companion point, Warp to map, Coordinate x on minimap, Coordinate y on minimap, Name of warp.
warp_points = {         -- Intentionally Global!
  b1500 = { "b1501", "133", 166, 102, "Old Kasuto" },
  b1501 = { "b1500", "46", 178, 220, "Hidden Village" },
  b1502 = { "b1503", "51", 90, 194, "Kakariko City" },
  b1503 = { "b1502", "11", 162, 372, "Ordon Village" },
  b1504 = { "b1505", "72", 2, 228, "Gerudo Camp" },
  b1505 = { "b1504", "66", 208, 178, "Goron City" },
  b1506 = { "b1507", "82", 50, 346, "Beach" },
  b1507 = { "b1506", "37", 218, 266, "Lost Woods" },
  b1508 = { "b1509", "60", 4, 180, "Snowpeak" },
  b1509 = { "b1508", "88", 15, 25, "Calatia Peaks" },
  b1510 = { "b1511", "56", 160, 150, "Septen Heights" },
  b1511 = { "b1510", "139", 178, 126, "Three Eye Rock" },
  b1512 = { "b1513", "57", 184, 150, "Zora's Domain" },
  b1513 = { "b1512", "93", 34, 40, "Rito Town" },
  b1514 = { "b1515", "34", 120, 258, "Lake Hylia" },
  b1515 = { "b1514", "13", 210, 365, "Floria Peninsula" }
}

function game:on_warp_started(point)
  initial_point = point
  if not sol.menu.is_started(warp_menu) then sol.menu.start(game:get_map(), warp_menu) end
end

function warp_menu:on_started()
  game:get_map():get_hero():freeze()
  self.hero_head_sprite = sol.sprite.create("menus/hero_head")
  self.hero_head_sprite:set_animation("tunic" .. game:get_item("tunic"):get_variant())
  self.background_surfaces = sol.surface.create("pause_submenus.png", true)
  self.background_surfaces:set_opacity(192)
  self.cursor_sprite = sol.sprite.create("menus/pause_cursor")
  self.caption_text_1 = sol.text_surface.create{
    horizontal_alignment = "center",
    vertical_alignment = "middle",
    font = "fixed",
    font = menu_font,
    font_size = menu_font_size,
  }
  self.caption_text_2 = sol.text_surface.create{
    horizontal_alignment = "center",
    vertical_alignment = "middle",
    font = "fixed",
    font = menu_font,
    font_size = menu_font_size,
  }

  -- Show a world map.
  self.caption_text_1:set_text(sol.language.get_string("map.caption.warp"))
  self.outside_world_minimap_size = { width = 225, height = 399 }
  self.world_minimap_img = sol.surface.create("menus/warp_map.png")
  self.world_minimap_movement = nil

  -- Initialize the cursor and scroll map to initial point.
  for k, v in pairs(warp_points) do
    if k == initial_point then
      index = k
      self:set_cursor_position(v[3], v[4])
      if v[4] >= 133 then initial_y = v[4] - 133 + 10 else initial_y = 0 end
      self.world_minimap_visible_xy = {x = 0, y = initial_y }
    end
  end
end

function warp_menu:on_command_pressed(command)
  if command == "left" or command == "up" then
    self:previous_warp_point()
    handled = true
  elseif command == "right" or command == "down" then
    self:next_warp_point()
    handled = true
  elseif command == "action" or command == "attack" then
    for k, v in pairs(warp_points) do
      if k == index and game:get_value(v[1]) then
        game:start_dialog("warp.to_"..v[2], function(answer)
          if answer == 1 then
            sol.menu.stop(warp_menu)
            game:get_map():get_hero():set_animation("ocarina")
            sol.audio.play_sound("ocarina_wind")
            game:get_map():get_entity("hero"):teleport(v[2], "ocarina_warp", "fade")
          end
        end)
      end
    end
  elseif command == "pause" then
    sol.menu.stop(warp_menu)
  end

  return true
end

function warp_menu:next_warp_point()
  if index == "b1500" then index = "b1501"
  elseif index == "b1501" then index = "b1502"
  elseif index == "b1502" then index = "b1503"
  elseif index == "b1503" then index = "b1504"
  elseif index == "b1504" then index = "b1505"
  elseif index == "b1505" then index = "b1506"
  elseif index == "b1506" then index = "b1507"
  elseif index == "b1507" then index = "b1508"
  elseif index == "b1508" then index = "b1509"
  elseif index == "b1509" then index = "b1510"
  elseif index == "b1510" then index = "b1511"
  elseif index == "b1511" then index = "b1512"
  elseif index == "b1512" then index = "b1513"
  elseif index == "b1513" then index = "b1514"
  elseif index == "b1514" then index = "b1515"
  elseif index == "b1515" then index = "b1500" end

  -- Move cursor and scroll map to new warp point.
  for k, v in pairs(warp_points) do
    if k == index and game:get_value(v[1]) then
      self:set_cursor_position(v[3], v[4])
      if v[4] >= 133 then initial_y = v[4] - 133 + 10 else initial_y = 0 end
      self.world_minimap_visible_xy = {x = 0, y = initial_y }
    end
  end
end

function warp_menu:previous_warp_point()
  if index == "b1500" then index = "b1515"
  elseif index == "b1501" then index = "b1500"
  elseif index == "b1502" then index = "b1501"
  elseif index == "b1503" then index = "b1502"
  elseif index == "b1504" then index = "b1503"
  elseif index == "b1505" then index = "b1504"
  elseif index == "b1506" then index = "b1505"
  elseif index == "b1507" then index = "b1506"
  elseif index == "b1508" then index = "b1507"
  elseif index == "b1509" then index = "b1508"
  elseif index == "b1510" then index = "b1509"
  elseif index == "b1511" then index = "b1510"
  elseif index == "b1512" then index = "b1511"
  elseif index == "b1513" then index = "b1512"
  elseif index == "b1514" then index = "b1513"
  elseif index == "b1515" then index = "b1514" end

  -- Move cursor and scroll map to new warp point.
  for k, v in pairs(warp_points) do
    if k == index and game:get_value(v[1]) then
      self:set_cursor_position(v[3], v[4])
      if v[4] >= 133 then initial_y = v[4] - 133 + 10 else initial_y = 0 end
      self.world_minimap_visible_xy = {x = 0, y = initial_y }
    end
  end
end

function warp_menu:set_cursor_position(x, y)
  self.cursor_x = x
  self.cursor_y = y
  if y > 133 then
    if y <399 then self.world_minimap_visible_xy.y = y - 51 else self.world_minimap_visible_xy.y = 399 end
  end

  -- Update the caption text.
  for k, v in pairs(warp_points) do
    if k == initial_point then self.caption_text_2:set_text(sol.language.get_string(v[5])) end
  end
end

function warp_menu:on_draw(dst_surface)
  -- Draw background.
  local width, height = dst_surface:get_size()
  self.background_surfaces:draw_region(320, 0, 320, 240, dst_surface, (width - 320) / 2, (height - 240) / 2)

  -- Draw the minimap.
  self.world_minimap_img:draw_region(self.world_minimap_visible_xy.x, self.world_minimap_visible_xy.y, 255, 133, dst_surface, 48, 59)

  -- Draw the warp points.
  for k, v in pairs(warp_points) do
    if game:get_value(v[1]) then -- Only those that have been discovered are shown.
      local point_visible_y = v[4] - self.world_minimap_visible_xy.y
      if point_visible_y >= 10 and point_visible_y <= 133 then self.hero_head_sprite:draw(dst_surface, v[3] + 40, point_visible_y + 51) end
    end
  end

  -- Draw the cursor.
  if self.cursor_y >= (10 + self.world_minimap_visible_xy.y) and self.cursor_y <= (133 + self.world_minimap_visible_xy.y) then
    self.cursor_sprite:draw(dst_surface, self.cursor_x + 48, self.cursor_y + 55 - self.world_minimap_visible_xy.y)
  end

  -- Draw caption (Not working currently for some reason).
  local width, height = dst_surface:get_size()
  self.caption_text_1:draw(dst_surface, width / 2, 200)
  self.caption_text_2:draw(dst_surface, width / 2, 213)
end

function warp_menu:on_finished()
  game:get_map():get_hero():unfreeze()
end
#18
Development / Scrolling credits
September 05, 2015, 01:10:34 AM
I'm trying to get a scrolling credits screen figured out, and I've hit a roadblock. How I'd like to do it is have a table with all of the credit text, then loop through each piece of text and display it on screen as it's own line, which would start at the bottom of the screen and slowly move up. My thought was to create a text surface for each line and apply a path movement north, then detect when it hits the top of the screen and destroy that surface. My problem is that I can't get the loop to create the surfaces and the separate loop to draw each surface working correctly. Help please?

Pseudo-code: Where should I put the code that turns text into text surfaces (in on_started right now)

local credits = { "Thank you for playing!" , "" , "CREDITS", "" }

function map:on_started(destination)
  map:get_game():set_hud_enabled(false)
  map:get_hero():set_position(-100, -100)
  map:get_hero():freeze()

  for i, line in ipairs(credits) do
    sol.timer.start(self, 4000, function()
      line_text = line
      line = sol.text_surface.create()
      line:set_text(line_text)
      local m = sol.movement.create("path")
      m:set_xy(camera_height, camera_width/2)
      m:set_path({2,2})
      m:set_loop(true)
      m:set_speed(32)
      m:start(line)
  end
end

function map:on_draw(dst_surface)
  for i, line in ipairs(credits) do
      local text_x, text_y = line:get_xy()
      if text_x < 100 then line:fade_out() end
      line:draw(dst_surface, text_x, text_y)
  end
end
#19
Development / Shaders?
August 27, 2015, 11:57:20 PM
Is there any information about what's currently available in the engine concerning shaders? I believe there was an experimental implementation, but I'm not sure if it was ever completed/tested/documented? If I can help in any way, I'm happy to do so!

I need to implement more advanced lighting in my game, and I'm getting to the point where I can't put it off much longer and need to come up with something. I would require multiple light points in an otherwise dark room, and thought shaders would be the only way to manage this. If anyone knows of another way, I would love to hear ideas! :)
#20
Development / Custom code debugging
August 25, 2015, 03:52:37 AM
Alright - I can't tell if I coded something wrong here, or if there's an error in the engine. I have a cane that generates ice blocks. These blocks can either fill empty pits (another custom entity, which works correctly), freeze water so the hero can walk on it, or enable lava to be walked on. Pushing the block onto water or lava isn't working at all, and the collision detection when creating a new block on top of lava or water is hit or miss. The lava and deep water are both set up as dynamic tiles, and neither set_traversable_by() or set_can_traverse() seem to work for the block. Below is my code, any help would be appreciated :)


local entity = ...
local map = entity:get_map()
local pushing = false
local block_on_switch = false

-- Ice block: special block made of ice that can fill an
-- ice pit, turn lava solid, and freeze water.

function entity:on_created()
  self:set_size(16, 16)
  self:snap_to_grid()
  self:set_modified_ground("ice")
  self:set_traversable_by("hero", false)
  self:set_traversable_by("dynamic_tile", true)
  self:set_traversable_by("custom_entity", true) --to allow pushing block into pit
  self:set_can_traverse("dynamic_tile", true)
  self:create_sprite("entities/ice_block")

  self:add_collision_test("facing", function(self, other)
    if other:get_type() == "hero" and not pushing then
      pushing = true
      local m = sol.movement.create("path")
      m:set_ignore_obstacles(false)
      m:set_snap_to_grid(true)

      if other:get_direction() == 0 then m:set_path({0,0})
      elseif other:get_direction() == 1 then m:set_path({2,2})
      elseif other:get_direction() == 2 then m:set_path({4,4})
      elseif other:get_direction() == 3 then m:set_path({6,6}) end
      m:start(self, function()
pushing = false
      end)
    end
  end)

  self:add_collision_test("overlapping", function(self, other)
    local lava_crust, ice_patch
    if other:get_type() == "dynamic_tile" then
      local tsx, tsy = other:get_size()
      local tpx, tpy, tpl = other:get_position()
      local sx, sy, sl = self:get_position()
      self:clear_collision_tests()
      self:remove()
      if map:get_ground(sx,sy,sl) == "lava" then
        if (sx > tpx-32) and (sx < tpx+tsx+32) and (sy > tpy-32) and (sy < tpy+tsy+32) then
          lava_crust = map:create_custom_entity({ x = sx, y = sy, layer = sl, width = 32, height = 32, direction = 0 })
          lava_crust:snap_to_grid()
          sol.audio.play_sound("freeze")
          lava_crust:create_sprite("entities/lava")
          lava_crust:set_modified_ground("traversable")
          lava_crust:set_traversable_by("hero", true)
          lava_crust:set_traversable_by("enemy", true)
  sol.timer.start(map, 15000, function()
    lava_crust:remove()
  end)
        end
      elseif map:get_ground(sx,sy,sl) == "deep_water" then
        if (sx > tpx-16) and (sx < tpx+tsx+16) and (sy > tpy-16) and (sy < tpy+tsy+16) then
          ice_patch = map:create_custom_entity({ x = sx, y = sy, layer = sl, width = 32, height = 32, direction = 0 })
          sol.audio.play_sound("freeze")
          ice_patch:create_sprite("entities/ice")
          ice_patch:set_modified_ground("ice")
          ice_patch:set_traversable_by("hero", true)
          ice_patch:set_traversable_by("enemy", true)
  sol.timer.start(map, 15000, function()
    ice_patch:remove()
  end)
        end
      end
    elseif other:get_type() == "switch" then
      block_on_switch = true
      other:set_activated(true)
      if other:on_activated() ~= nil and not other.active then
        other:on_activated()
        other.active = true
      end
      sol.timer.start(map, 1000, function()
        if block_on_switch then
          return true
        else
          block_on_switch = false
          other:set_activated(false)
          if other:on_inactivated() ~= nil and other.active then
            other:on_inactivated()
            other.active = false
          end
        end
      end)
    elseif other:get_type() == "hole" then
      sol.audio.play_sound("hero_falls")
      self:remove()
    elseif other:get_type() == "fire" then
      sol.audio.play_sound("ice_melt")
      self:remove()
    elseif other:get_type() == "explosion" then
      sol.audio.play_sound("ice_melt")
      self:remove()
    else
      block_on_switch = false
    end
  end)
end

function entity:on_removed()
  self:get_sprite():set_animation("destroy")
end