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.


Topics - wizard_wizzle (aka ZeldaHistorian)

Pages: 1 [2] 3
16
Development / Fading out overlay in different map
« on: 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
« on: 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
« on: 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)
Code: [Select]
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?
« on: 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
« on: 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 :)

Code: [Select]
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

21
Development / Thought experiment: Beamos
« on: July 29, 2015, 03:58:13 AM »
Hi all!

I'd really like to include beamos in my game, and I think other people might too - but it's a little too high level to wrap my head around. So, I thought I'd present the idea to the community and see what we can come up with!

The beamos statue is easy, you'd want a sprite with 8 directions so it can follow the hero, then just check and see when the hero is too close and start firing a beam. The beam itself is where it gets tricky! My thought is that the beam would an enemy breed of its own which is generated by the beamos statue (probably in a continuous stream). What I'm thinking of is an 8x8 sprite that can be created over and over again so that the beam can go in any direction. They move toward the hero in a line (somehow) and terminate being generated after a certain time. I'm not entirely sure how to implement this though...

Maybe I'm over (or under) thinking this and there's a better way? Let's brainstorm! :)

22
Bugs & Feature requests / Segmentation fault?
« on: July 06, 2015, 04:41:33 AM »
I have a new bug that's popped up in my game, and I'm not sure if it's an engine problem or something else. I have the following code in one of my dungeons, and when it gets to this point in the game, it crashes with a Segmentation Fault:

Code: [Select]
for enemy in map:get_entities("keese") do
  enemy.on_dead = function()
    if not map:has_entities("keese_rupees") and not game:get_value("b1119") then
      chest_rupees:set_enabled(true)
      bridge_rupees:set_enabled(true)
      sol.audio.play_sound("chest_appears")
    end
  end
end

I haven't changed anything with this code recently, and the fault would've just started appearing in Solarus 1.4.2. Any ideas?

23
Development / Side scrolling functionality
« on: June 25, 2015, 04:24:13 AM »
As a proof-of-concept, I've been figuring out how to build side-scrolling functionality with Solarus (like the sections of Link's Awakening). I can get jumping, gravity and movement pretty well down, but the part I can't figure out is enemy collisions.

I'd like to have it work like Mario where if you jump on certain enemy's heads, they are hurt, but I can't figure out how to detect that the hero has touched only the top of the enemy. If the hero touched the side of the enemy, the hero should be hurt.

I'm guessing that this can't be accomplished with the built-in enemy class, but even with a custom entity and add_collision_test(), I don't see how to detect what was touching what.

EDIT (1/18/21): Don't use this - it's old and there are much better versions out there now. Check out the one PhoenixII54 posted on 1/18/21.
https://gitlab.com/zeldaforce/zelda-alttd/-/blob/dev/data/scripts/maps/sideview_manager.lua

24
Development / Item is not saved
« on: June 09, 2015, 03:03:56 AM »
Occasionally  I've gotten error messages like the following while running my game:

Error: In on_started: [string "items/arrow.lua"]:13: Item 'bow' is not saved
Error: In on_started: [string "hud/rupees.lua"]:26: Item 'rupee_bag' is not saved

It doesn't seem to happen all of the time, and sometimes the "Item" mentioned is different. These items are calling self:set_savegame_variable() in their on_created() functions. Is there something else I'm doing wrong?

25
Development / Collision tests and movement
« on: April 10, 2015, 05:01:22 PM »
I have the snippet of code below where I'm essentially trying to re-create block pushing in a custom entity (in order to additional functionality for the block). The problem I'm having having is that the block doesn't start moving until after the hero has stopped pushing and has moved away from the block - rather than actually pushing the block. Is this the expected behavior and I'm doing something wrong? Is there a way to have the movement start as the hero is pushing?

Code: [Select]
  self:add_collision_test("touching", function(self, other)

    if other:get_type() == "hero" then
      local m = sol.movement.create("path")
      m:set_ignore_obstacles(true)
      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)

26
Development / Hookshot
« on: February 17, 2015, 04:20:07 AM »
Is it defined in the API what entities the hookshot attaches to? What's the best way to force the hookshot to attach to a tile or entity, or is this even possible?

27
Development / Custom Entity: Moving platform [Solved with code]
« on: January 31, 2015, 05:14:26 PM »
How would someone recommend implementing moving platforms (over water or holes only) in Solarus? I've tried a dynamic tile with movement applied, but I can only get it to traverse what the hero could and not water. I've tried a custom entity, but I can't get it to be traversable by the hero - if the platform sits on water, the hero just jumps into the water rather than walking on the platform. I'm probably just doing something wrong, but was hoping for some direction either way.

28
Development / Quicksand custom entity
« on: January 19, 2015, 04:38:08 PM »
I'm looking to make a custom entity which behaves like quicksand (think Link to the Past's desert temple) - when the hero approaches it, he's slowly dragged into the center, then when he reached the center, he sinks (behavior like a hole, probably). I can't seem to figure it out. Any thoughts?

This is what I have so far, which isn't even close to working:
Code: [Select]
local entity = ...
local map = entity:get_map()
local hero = map:get_entity("hero")

-- Quicksand: entity which slows the hero until
-- he finally falls in

function entity:on_created()
  self:create_sprite("entities/quicksand")
  self:set_size(32, 32)
  self:set_origin(16, 16)
  ex, ey, el = self:get_position()
  self:get_sprite():set_animation("quicksand")
end

function entity:on_update()
  self:add_collision_test("overlapping", function()
    if hero:get_walking_speed() >= 8 then hero:set_walking_speed(hero:get_walking_speed()-1) end
    m = sol.movement.create("target")
    m:set_target(ex, ey)
    m:start(hero)
  end)
end

29
Bugs & Feature requests / cmake error on Ubuntu
« on: August 23, 2014, 03:34:18 PM »
When I go to compile solarus 1.3, I get a cmake error stating that OPENAL can't be found, but according to my system it's installed. Is something wrong with cmake or my system? I've compiled before, so unless something has changed, I'm confused  :-\

Error output:
Code: [Select]
CMake Error at /usr/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:108 (message):
  Could NOT find OpenAL (missing: OPENAL_LIBRARY)
Call Stack (most recent call first):
  /usr/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:315 (_FPHSA_FAILURE_MESSAGE)
  /usr/share/cmake-2.8/Modules/FindOpenAL.cmake:97 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
  CMakeLists.txt:18 (find_package)

OPENAL installation:
Code: [Select]
sudo apt-get install libopenal*
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Note, selecting 'libopenais2' for regex 'libopenal*'
Note, selecting 'libopenais-dev' for regex 'libopenal*'
Note, selecting 'libopenal0a' for regex 'libopenal*'
Note, selecting 'libopenal-dev' for regex 'libopenal*'
Note, selecting 'libopenal1' for regex 'libopenal*'
Note, selecting 'libopenafs-dev' for regex 'libopenal*'
Note, selecting 'libopenal-data' for regex 'libopenal*'
Note, selecting 'libopenais-legacy-dev' for regex 'libopenal*'
libopenafs-dev is already the newest version.
libopenal-data is already the newest version.
libopenal-dev is already the newest version.
libopenal1 is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 30 not upgraded.

30
Your projects / Zelda: Book of Mudora
« on: August 08, 2014, 01:53:58 AM »
My full Zelda game, Book of Mudora, is done! The release includes Solarus 1.5(.1), the pre-release that Christopho posted to fix the software surface memory leak) for Windows, and other platforms are available at http://www.solarus-games.org/

Download: https://sites.google.com/site/zeldabom/download

Trailer: https://www.youtube.com/watch?v=wk13ltcilDM

Thanks everyone for your help, and enjoy!

Pages: 1 [2] 3