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 - Diarandor

Pages: [1] 2 3
1
General discussion / Design of graphs of dungeons
« on: April 17, 2017, 05:58:19 pm »
This video explains a bit how to make a dungeon graph, which is useful to design a dungeon. It is not exactly a tutorial, but it is interesting.
https://youtu.be/fqKGl6exyyY

2
Hi @Christopho! I need some help. I have a problem with my rain script. I don't kow if this is a bug or something I did wrong. I think the problem started when I began refactoring my code, but I am not sure. My (unfinished) rain script is this one:

Code: Lua
  1. -- Rain manager script.
  2. --[[
  3. To add this script to your game, call from game_manager script:
  4.     require("scripts/weather/rain_manager")
  5.  
  6. The functions here defined are:
  7.     game:get_rain_type(world)
  8.     game:set_rain_type(world, rain_type)
  9.  
  10. Rain types: nil (no rain), "rain", "storm".
  11. --]]
  12.  
  13. -- This script requires the multi_event script:
  14. require("scripts/multi_events")
  15. local rain_manager = {}
  16.  
  17. local game_meta = sol.main.get_metatable("game")
  18. local map_meta = sol.main.get_metatable("map")
  19.  
  20.  
  21. -- Default settings. Change these for testing.
  22. local rain_enabled = true -- Do not change this property, unless you are testing.
  23. local lightning_enabled = false
  24. local rain_speed = 100 -- Default drop speed 100.
  25. local drop_max_distance = 300 -- Max possible distance for drop movements.
  26. local drop_delay = 10 -- Delay between drops, in milliseconds.
  27. local drop_sprite_id = "test/rain"
  28.  
  29. -- Initialize rain on maps when necessary.
  30. game_meta:register_event("on_map_changed", function()
  31.   if self ~= nil then
  32.     local map = self:get_map()
  33.     rain_manager:update_rain(map)
  34.   end
  35. end)
  36.  
  37. -- Get the raining state for a given world.
  38. function game_meta:get_rain_type(world)
  39.   local rain_type = self:get_value("rain_state_" .. world)
  40.   return rain_enabled and rain_type
  41. end
  42. -- Set the raining state for a given world.
  43. function game_meta:set_rain_type(world, rain_type)
  44.   -- Update savegame variable.
  45.   self:set_value("rain_state_" .. world, rain_type)
  46.   -- Check if rain is necessary: if we are in that world and rain is needed.  
  47.   local current_world = self:get_map():get_world()
  48.   local rain_needed = (current_world == world) and rain_enabled and rain_type
  49.   if (not rain_needed) then return end -- Do nothing if rain is not needed!
  50.   -- We need to start the rain in the current map.
  51.   local map = self:get_map()
  52.   rain_manager:start_rain(map)
  53. end
  54.  
  55.  
  56. -- Create rain if necessary when entering a new map.
  57. function rain_manager:update_rain(map)
  58.   -- Get rain state in this world.
  59.   local world = map:get_world()
  60.   local rain_type = map:get_game():get_rain_type(world)
  61.   -- Start rain if necessary.
  62.   if rain_type == "rain" then
  63.     self:start_rain(map)
  64.   elseif rain_type == "storm" then
  65.     self:start_storm(map)
  66.   end
  67. end
  68.  
  69. -- Define function to create splash effects.
  70. -- If no parameters x, y are given, the position is random.
  71. local function create_drop_splash(map, x, y)
  72.   local max_layer = map:get_max_layer()
  73.   local min_layer = map:get_min_layer()
  74.   local camera = map:get_camera()
  75.   local cx, cy, cw, ch = camera:get_bounding_box()
  76.   local drop_properties = {direction = 0, x = 0, y = 0, layer = max_layer,
  77.     width = 16, height = 16, sprite = drop_sprite_id}
  78.   -- Initialize parameters.
  79.   local x = x or cx + cw * math.random()
  80.   local y = y or cy + ch * math.random()
  81.   local layer = max_layer
  82.   while map:get_ground(x,y,layer) == "empty" and layer > min_layer do
  83.     layer = layer - 1 -- Draw the splash at the lower layer we can.
  84.   end
  85.   -- Do not draw splash over some bad grounds: "hole" and "lava".
  86.   local ground = map:get_ground(x, y, layer)
  87.   if ground ~= "hole" and ground ~= "lava" then
  88.     drop_properties.x = x
  89.     drop_properties.y = y
  90.     drop_properties.layer = layer
  91.     local drop_splash = map:create_custom_entity(drop_properties)
  92.     assert(drop_splash ~= nil)
  93.     local splash_sprite = drop_splash:get_sprite()
  94.     splash_sprite:set_animation("drop_splash")
  95.     splash_sprite:set_direction(0)
  96.     function splash_sprite:on_animation_finished() drop_splash:remove() end
  97.   end
  98. end
  99.  
  100. -- Define function to create drops.
  101. -- If no parameters x, y are given, the position is random.
  102. local function create_drop(map, x, y)
  103.   local max_layer = map:get_max_layer()
  104.   local min_layer = map:get_min_layer()
  105.   local camera = map:get_camera()
  106.   local cx, cy, cw, ch = camera:get_bounding_box()
  107.   local drop_properties = {direction = 0, x = 0, y = 0, layer = max_layer,
  108.     width = 16, height = 16, sprite = drop_sprite_id}
  109.   -- Initialize parameters.
  110.   drop_properties.x = x or cx + cw * math.random() + 30
  111.   drop_properties.y = y or cy + ch * math.random() - 100
  112.   drop_properties.layer = max_layer
  113.   local drop = map:create_custom_entity(drop_properties)
  114.   local m = sol.movement.create("straight")
  115.   m:set_angle(7 * math.pi / 5)
  116.   m:set_speed(rain_speed)
  117.   local random_max_distance = math.random(1, drop_max_distance)
  118.   m:set_max_distance(random_max_distance)
  119.   m:set_ignore_obstacles()
  120.   function m:on_finished() drop:remove() end
  121.   function m:on_obstacle_reached() drop:remove() end
  122.   function drop:on_removed()
  123.     local x, y = drop:get_position()
  124.     create_drop_splash(map, x, y)
  125.   end
  126.   m:start(drop)
  127. end
  128.  
  129.  
  130. -- Start rain in the current map.
  131. function rain_manager:start_rain(map)
  132.   local max_layer = map:get_max_layer()
  133.   local min_layer = map:get_min_layer()
  134.   local camera = map:get_camera()
  135.   local drop_properties = {direction = 0, x = 0, y = 0, layer = max_layer,
  136.     width = 16, height = 16, sprite = drop_sprite_id}
  137.   -- Initialize random seed for positions.
  138.   math.randomseed(os.time())
  139.  
  140.   -- Start timer to draw rain drops.
  141.   sol.timer.start(map, drop_delay, function()
  142.     -- Create drops on random positions.
  143.     create_drop(map)
  144.     -- Repeat loop.
  145.     return true
  146.   end)
  147. end
  148.  
  149. -- Stop rain in the current map.
  150. function rain_manager:stop_rain(map)
  151.  
  152. end
  153.  
  154. -- Return rain manager.
  155. return rain_manager
  156.  

The problem appears when leaving a map with rain to another (where there is no rain, but this is probably not important). The bug appears in the console (no crash) at lines 92-93, because the entity "drop_splash" does not exist in that moment. I know that this can be fixed with an extra condition "if drop_splash ~= nil then blablabla end", but I'd like to know why does this happen.

I had the same problem at lines 31-32, because the "self" variable does not exist sometimes, and the condition "if self ~= nil then" fixed this. Why do not these variables exist when these events are called? Is this a bug?
Thanks in advance for the help.

3
Your scripts / Animated sprites for dialogs (custom dialog script)
« on: January 08, 2017, 11:39:57 am »
I was asked by @Porksteak to explain how to use the animation sprites of my custom dialog box:
https://github.com/Diarandor/repository/blob/master/data/scripts/dialog_box.lua
https://www.youtube.com/watch?v=CRRcZjAwMw8
My old script does not explain how to use this feature (I forgot to add these explanations). I post this here so anyone will know how to use it:

An example would be this dialog:
Code: Lua
  1. dialog{
  2.   id = "old_man.thanks",
  3.   animation = "talking",
  4.   animation_sprite = "dialog_old_man",
  5.   text = [[
  6. Thanks for saving my
  7. cats, young man.
  8. See you later!
  9. ]]
  10. }
  11.  

The (optional) sprite of the character has to be located in the path given by the concatenated string:
"dialogs/" .. dialog.animation_sprite
and the animation used is the one given by the string: dialog.animation

4
Your projects / A Zelda game by Kory Toombs
« on: December 05, 2016, 06:30:03 am »
Hi! I found a Zelda game made with the Solarus engine by Kory Toombs, this is the website:
https://rpgmaker.net/games/9214/
I thought it would be a good idea to create a topic about this; but I have not played this game so I know nothing about it.

5
Your scripts / Raft script
« on: November 08, 2016, 11:15:00 pm »
Hi! I was asked by @Porksteak in a personal message if I could share the platform-raft script that I use in this video:
https://www.youtube.com/watch?v=gIKvf_0hIpU

So here goes the code. But note that some parts of the code are a bit old and could be improved (for instance, I should use "require" instead of "load_file" in the raft script, to make the code faster), and some things of the script may require other scripts. My raft script requires my platform script to work, so I include both scripts here. It is recommended that you study the code to make another script that suits better for your purposes, and remove unnecesary things from my code (for instance, you probably do not need the raft to move secondary heroes or custom entities, so you should delete these parts of the code and other similar things).

generic_platform.lua script:
Code: Lua
  1. -- Platform: entity which moves in either horizontally or vertically (depending on direction)
  2. -- and carries the hero on it.
  3. local entity = ...
  4. local map = entity:get_map()
  5. local game = entity:get_game()
  6. local hero = map:get_hero()
  7.  
  8. entity.can_save_state = true
  9.  
  10. local time_stopped = 1000
  11. local is_moving = false
  12. -- Remark: speeds bigger than 12 give problems for water platforms (rafts) when trying to enter or go out. No problem above holes.
  13. entity.speed = 50 -- Set speed.
  14.  
  15. function entity:on_created()
  16.   --self:create_sprite("entities/platform")
  17.   self:set_size(32, 32)
  18.   self:set_origin(16, 13) -- Important: the 32x32 sprite must have center in (16,13).
  19.   self:set_modified_ground("traversable")
  20.  
  21.   -- Set dynamic solid ground position for the hero to avoid problems.
  22.   sol.timer.start(entity, 10, function()
  23.     -- Do nothing if hero is not on solid ground.
  24.     local is_hero_on_solid_ground = map:is_solid_ground(hero:get_ground_position())
  25.     if hero.is_jumping or not is_hero_on_solid_ground then return true end
  26.     -- Save or clear solid ground position on this platform.
  27.     if map.current_hero_platform ~= entity and self:is_on_platform(hero) then
  28.       map.current_hero_platform = entity
  29.       self:save_hero_position() -- Save solid ground on the platform.
  30.     elseif map.current_hero_platform == entity and (not self:is_on_platform(hero)) then
  31.       map.current_hero_platform = nil
  32.       hero:reset_solid_ground() -- Clear solid ground.
  33.     end
  34.     return true
  35.   end)
  36.  
  37.   -- Custom function.
  38.   if entity.on_custom_created then
  39.     entity:on_custom_created()
  40.     return
  41.   end
  42.  
  43.   -- Initialize properties.
  44.   self:set_can_traverse("jumper", true)
  45.   self:set_can_traverse_ground("hole", true)
  46.   self:set_can_traverse_ground("deep_water", true)
  47.   self:set_can_traverse_ground("traversable", true)
  48.   self:set_can_traverse_ground("shallow_water", true)
  49.   self:set_can_traverse_ground("wall", false)
  50.  
  51.   -- Start movement.
  52.   local direction = self:get_direction()
  53.   local m = sol.movement.create("path")
  54.   m:set_path{direction * 2}; m:set_speed(entity.speed)
  55.   m:set_loop(true); m:start(self)
  56.   is_moving = true
  57.  
  58. end
  59.  
  60. -- Function to save hero position on the platform.
  61. function entity:save_hero_position()
  62.   hero:save_solid_ground(function()
  63.     --[[ When the hero reappears, the camera moves towards the new position,
  64.     which produces a delay, and the platform has already moved when the hero appers.
  65.     To fix this problem, change the position of the hero directly, so the movement
  66.     will be instantaneous with no delay. To avoid this we must not call
  67.     "hero:get_solid_ground_position()", or there will be problems with platforms.
  68.     --]]
  69.     local x, y, layer = entity:get_center_position()
  70.     -- Change position at next cycle to avoid engine problems (keep this timer!).
  71.     sol.timer.start(self, 1, function()
  72.       hero:unfreeze()
  73.       hero:set_blinking(true, 1000)
  74.       hero:set_invincible(true, 1000)
  75.       hero:set_position(x, y, layer)
  76.     end)
  77.     return x, y, layer
  78.   end)
  79. end
  80.  
  81.  
  82. -- Update shifting variables for the translation.
  83. local function get_shifts()
  84.   local direction = entity:get_direction()
  85.   local dx, dy = 0, 0 -- Variables for the translation.
  86.   if direction == 0 then dx = 1 elseif direction == 1 then dy = -1
  87.   elseif direction == 2 then dx = -1 elseif direction == 3 then dy = 1 end
  88.   return dx, dy
  89. end
  90.  
  91. -- Get movable entities that were on the previous position of the platform.
  92. function entity:get_movable_entities()
  93.   local movable_entities = {}
  94.   for other in map:get_entities_in_rectangle(entity:get_bounding_box()) do
  95.     -- Check only entities that can be moved, including the hero.
  96.     if other.moved_on_platform or other:get_type() == "hero" then
  97.       -- Check if the entity was on the platform before the movement.
  98.       if entity:was_on_platform(other) and entity:is_on_platform(other) then
  99.         -- Exclude portable entities unless they are on the ground.
  100.         if (not other.is_portable) or other.state == "on_ground" then
  101.           table.insert(movable_entities, other)
  102.         end          
  103.       end
  104.     end
  105.   end  
  106.   return movable_entities
  107. end
  108.  
  109. -- Return true if an entity is on the platform.
  110. -- IMPORTANT: This function is only used in the script generic_portable.lua.
  111. function entity:is_on_platform(other)
  112.   local x, y, layer = other:get_ground_position()
  113.   return entity:overlaps(x, y)
  114. end
  115.  
  116. -- Return true if an entity was on the platform before the movement.
  117. function entity:was_on_platform(other)
  118.   local dx, dy = get_shifts()
  119.   local ox, oy, oz = other:get_ground_position()
  120.   local bx, by, w, h = entity:get_bounding_box()
  121.   local pbx, pby = bx-dx, by-dy -- Previous position of bounding box (before the movement).
  122.   return ox >= pbx and ox < pbx+w and oy >= pby and oy < pby+h
  123. end
  124.  
  125. function entity:on_obstacle_reached(movement)
  126.   --Make the platform turn back.
  127.   local direction = self:get_direction()
  128.   movement:stop(); is_moving = false
  129.   movement = sol.movement.create("path")    
  130.   direction = (direction+2)%4
  131.   self:set_direction(direction)
  132.   movement:set_path{direction * 2}
  133.   movement:set_speed(entity.speed)
  134.   movement:set_loop(true)
  135.   sol.timer.start(self, time_stopped, function()
  136.     movement:start(self)
  137.     is_moving = true  
  138.   end)
  139. end
  140.  
  141. -- Move the movable entities that were on the platform before the movement.
  142. function entity:on_position_changed()
  143.   -- Get the movable entities that were on the platform before the change of position.
  144.   local dx, dy = get_shifts() -- Variables for the translation.
  145.   local movable_entities = entity:get_movable_entities()
  146.   local ex, ey, ez = self:get_position()
  147.   local bx, by, w, h = self:get_bounding_box()
  148.   local pbx, pby = bx-dx, by-dy -- Previous position of bounding box (before the movement).
  149.   for _, other in pairs(movable_entities) do
  150.     local ox, oy, oz = other:get_position()
  151.     -- Move the entity with the platform.
  152.     if not other:test_obstacles(dx, dy, oz) then
  153.       other:set_position(ox + dx, oy + dy, oz)
  154.     end
  155.   end
  156. end
  157.  

raft.lua script:
Code: Lua
  1. local entity = ...
  2. -- Raft entity.
  3.  
  4. sol.main.load_file("entities/generic_platform")(entity)
  5. local sea_foam_sprite -- Foam sprite for the raft.
  6. entity.speed = 20 -- Set speed.
  7.  
  8. function entity:on_custom_created()
  9.   -- Set custom properties.
  10.   time_stopped = 1000
  11.   self:set_can_traverse_ground("deep_water", true)
  12.   self:set_can_traverse_ground("wall", false)
  13.   self:set_can_traverse("jumper", false)
  14.   self:set_can_traverse_ground("hole", false)
  15.   self:set_can_traverse_ground("traversable", true)
  16.   self:set_can_traverse_ground("shallow_water", false)
  17.   self:set_can_traverse_ground("grass", false)
  18.  
  19.   -- Customize movement.
  20.   local direction = self:get_direction()
  21.   local m = sol.movement.create("path")
  22.   m:set_path{direction * 2}; m:set_speed(entity.speed)
  23.   m:set_loop(true); m:start(self)
  24.   is_moving = true
  25.  
  26.   -- Start the sea foam and wavering.
  27.   self:add_sea_foam()
  28.   self:start_wavering() -- Start moving raft sprite to simulate the waves.
  29. end
  30.  
  31. ----------------- Raft functions:
  32.  
  33. -- Add the sea foam sprite.
  34. function entity:add_sea_foam()
  35.   -- Remark: The variable sea_foam_sprite is already local in this script!
  36.   sea_foam_sprite = self:create_sprite("things/platform")
  37.   sea_foam_sprite:set_animation("sea_foam")
  38.   sea_foam_sprite:set_xy(-8,24)
  39. end
  40.  
  41. -- Make the sprite move up and down.
  42. function entity:start_wavering()
  43.   local sprite = self:get_sprite()
  44.   -- Define vectors with the shifts of each "frame" of the sprite and time for each pause between "frames".
  45.   local raft_dy = {0,-1,-2,-1} -- Shifts for the "y" coordinate of the sprite.
  46.   local entities_dy = {1,-1,-1,1} -- Shifts for the "y" coordinate of position of entities.
  47.   local pause_time = {200,1000,200,1000} -- Pause times between "frames".
  48.  
  49.   -- Move the movable entities located over the platform, if possible.
  50.   local function shift_entities(dy_shift)
  51.     local movable_entities = entity:get_movable_entities()
  52.     local x, y, z = self:get_position()
  53.     local bx, by, w, h = self:get_bounding_box()
  54.     for _, something in pairs(movable_entities) do  
  55.       if entity:is_on_platform(something, bx, by, w, h) then    
  56.               local sx, sy, sz = something:get_position()
  57.         -- Move only entities that can be moved.
  58.         local needs_move = false
  59.         if something:get_type() == "hero" then
  60.           if something:get_animation() ~= "walking" then
  61.             needs_move = true
  62.           end
  63.         elseif something:get_sprite() then
  64.           if something:get_sprite():get_animation() ~= "walking" then
  65.             needs_move = true
  66.           end
  67.         end
  68.         -- Check for obstacles.
  69.         local found_obstacles = something:test_obstacles(0, dy_shift, sz)
  70.         -- Finally check if the entity is not in the "bad border" to move it without getting out the platform.
  71.         if needs_move and (not found_obstacles) then
  72.           if (sy + dy_shift) >= by+2 and (sy + dy_shift) <= by+h-3 then sy = sy +dy_shift end
  73.           something:set_position(sx, sy, sz)
  74.         end
  75.       end
  76.     end
  77.   end
  78.  
  79.   -- Shift sprite and move entities.
  80.   local function set_frame_loop(frame_nb)
  81.     -- Shift the sprite. Shift entities above the rift, if possible.
  82.     sprite:set_xy(0, raft_dy[frame_nb])
  83.     shift_entities(entities_dy[frame_nb])
  84.     -- Restart the loop.
  85.     frame_nb = (frame_nb %4) +1 -- Next frame index.
  86.     sol.timer.start(entity, pause_time[frame_nb], function() set_frame_loop(frame_nb) end)
  87.   end
  88.  
  89.   -- Start the wavering loop.  
  90.   set_frame_loop(1)
  91. end
  92.  

6
General discussion / Poll: Crystal platforms vs mushrooms
« on: October 16, 2016, 02:02:27 pm »
Hi solarusiens!
I was thinking that for the project Children of Solarus we could use mushrooms that go up/down instead of crystal platforms. That would make the game more different from Zelda ALTTP, which would be nice. But I do not know if you like the idea, so I made this poll. Which option do you prefer?

7
Hi! One of the many things I will be working on is the creation of new free enemies with original art and fully scripted. I will keep adding them to the sample quest, and many of them are planned to be used in the project Children of Solarus. Some of my current work is here:
https://github.com/Bertram25/ChildrenOfSolarus/issues/29

Feedback wanted: If you have some cool and original idea of some type of enemy you want, then post it here. If I like the idea, I might make them when I get free time (but please, be patient). If the behavior is a bit complicated I might not do it, because I prefer to focus more on making free art than coding strange things, so think of basic stuff (no bosses or similar things); but also try to think of enemies with different and new original behaviors too, so that we will have more variety of enemies. Try to give as much details as possible, for the graphic part and also the behavior of the enemy.

Here you can also share your own original enemies, with both sprites and code, and maybe a link to some video to show them in action.
Quest makers, I challenge you to make something cool and post it here!!! hehehe! :D

8
Game art & music / Did you know about ZREO?
« on: July 28, 2016, 07:18:36 am »
Greetings!

I'm pretty sure that many of you have already heard about ZREO ("Zelda Reorchestrated"), which is a team of many people that make covers and orchestrated versions of the music of Zelda games. I thought they deserved to be mentioned here since we all are Zelda fans here. If you are interested, you can listen to their music in their official website and their youtube channel:

http://www.zreomusic.com/
https://www.youtube.com/user/ZREOTeam/
https://twitter.com/zreomusic

9
General discussion / Overworld maps: screen size or bigger?
« on: July 22, 2016, 09:57:12 pm »
Hi pals! Just by curiosity, I would like to know if you prefer screen-sized overworld maps like in Zelda games of the gameboy, or bigger overworld maps like in A Link To The Past. I mean overworld maps, not for levels/dungeons. I may take into account these opinions when I start mapping someday; but that will be in the far far future (probably Mercuri's Chest will be finished before then, hahah). Anyway, this may be interesting info for new developers too. You can put your opinion and discuss about this.

PS: I personally have preference for small overworld maps that are screen-sized and very dense (i.e., with many things on them: entities, secrets, easter eggs, etc), like in Link's Awakening. However, I prefer bigger maps for dungeons, like the oracle games did. I may change my mind depending on your opinions.

Let the poll and discussion begin! :D

10
General discussion / chip music vs non-chip music?
« on: June 18, 2016, 03:46:14 am »
Hi comrades!

Some time ago I made a few compositions with Famitracker. These are 16-bit music.
I was wondering if it would be better to try to remake these songs with LMMS (so the sounds would have "higher quality", i.e., it will be non-chip music).

Well, 8/16-bit music was a limitation of old consoles, but it is nowadays a style with a lot of charm (in the same way pixel art is for the graphics). There are impressive compositions made with 16-bit style in recent games (you can listen to Shovel Knight OST for instance), so chip music should not be considered bad quality music. (Unfortunately, many people do not understand this style of music of video games nowadays.)

Since I need to take a decision, I opened this poll. You can change your vote if you change your mind.
I will post later some of my few and rudimentary compositions. :P

11
Hi pals! I am a very curious person, and I was wondering which elements of the gameplay of a Zelda-like game are more important for most of the players (which is quite subjective to each one's opinion), so I created this poll.

The result can be useful to quest makers in order to make a game with balanced gameplay/mechanics according to what most of the people want.

You can vote for 2 options, to choose the 2 options you think are more important. I think it is a bit hard to choose since all elements are very important in my opinion.

PS: do not vote random, please! :)

12
Development / Fixing direction and walking/stopped animations
« on: April 07, 2016, 02:56:49 am »
Hi, here is part of a script I made to (re)define some functions of the metatable of the hero. In this piece of code a few functions which allow fixing direction and walking and stopped animations are defined. The trick I am using was an idea that MetalZelda posted in an older topic (http://forum.solarus-games.org/index.php/topic,448.0.html). It was not possible until now that Christopho has improved solarus in the development version of 1.5.

My custom functions:
-The direction fix allows to walk sideways, which is useful for some weapons. The following functions are defined:
Code: Lua
  1. hero:set_fixed_direction(direction)
  2. hero:get_fixed_direction()
-The fixing animation function allows to simplify some code in case you are changing the stopped/walking animations of the tunic of the hero for some purposes. In my case, I was changing to a jumping tunic (for a custom jump) and a carrying tunic (for a custom carry that allows carrying custom entities). This now can be done without changing the tunic sprite, using the functions:
Code: Lua
  1. hero:set_fixed_animations(stopped_animation, walking_animation)
  2. hero:get_fixed_animations()

The code can be put in some script apart. Be careful since it may override some function or event of the hero metatable in case you have defined it elsewhere. The code is here:
Code: Lua
  1. local hero_meta = sol.main.get_metatable("hero")
  2.  
  3. -- Function to set a fixed direction for the hero (or nil to disable it).
  4. function hero_meta:set_fixed_direction(direction)
  5.   self.fixed_direction = direction
  6.   if direction then
  7.     self:get_sprite("tunic"):set_direction(direction)
  8.   end
  9. end
  10. -- Function to get a fixed direction for the hero.
  11. function hero_meta:get_fixed_direction()
  12.   return self.fixed_direction
  13. end
  14. -- Function to set fixed stopped/walking animations for the hero (or nil to disable it).
  15. function hero_meta:set_fixed_animations(stopped_animation, walking_animation)
  16.   self.fixed_stopped_animation = stopped_animation
  17.   self.fixed_walking_animation = walking_animation
  18. end
  19. -- Function to get fixed stopped/walking animations for the hero.
  20. function hero_meta:get_fixed_animations()
  21.   return self.fixed_stopped_animation, self.fixed_walking_animation
  22. end
  23.  
  24. -- Initialize events to fix direction and animation for the tunic sprite of the hero.
  25. -- To do it, we redefine the on_created and set_tunic_sprite_id events using the hero metatable.
  26. do
  27.   local function initialize_fixing_functions(hero)
  28.     -- Define events for the tunic sprite.
  29.     local sprite = hero:get_sprite("tunic")
  30.     function sprite:on_animation_changed(animation)
  31.       local fixed_stopped_animation = hero.fixed_stopped_animation
  32.       local fixed_walking_animation = hero.fixed_walking_animation
  33.       local tunic_animation = sprite:get_animation()
  34.       if tunic_animation == "stopped" and fixed_stopped_animation ~= nil then
  35.         if fixed_stopped_animation ~= tunic_animation then
  36.           sprite:set_animation(fixed_stopped_animation)
  37.         end
  38.       elseif tunic_animation == "walking" and fixed_walking_animation ~= nil then
  39.         if fixed_walking_animation ~= tunic_animation then
  40.           sprite:set_animation(fixed_walking_animation)
  41.         end
  42.       end
  43.     end
  44.     function sprite:on_direction_changed(animation, direction)
  45.       local fixed_direction = hero.fixed_direction
  46.       local tunic_direction = sprite:get_direction()
  47.       if fixed_direction ~= nil and fixed_direction ~= tunic_direction then
  48.         sprite:set_direction(fixed_direction)
  49.       end
  50.     end
  51.   end
  52.   -- Initialize fixing functions when the hero is created.
  53.   function hero_meta:on_created()
  54.     initialize_fixing_functions(self)
  55.   end
  56.   -- Initialize fixing functions for the new sprite when the sprite is replaced for a new one.
  57.   local old_set_tunic = hero_meta.set_tunic_sprite_id -- Redefine this function.
  58.   function hero_meta:set_tunic_sprite_id(sprite_id)
  59.     old_set_tunic(self, sprite_id)
  60.     initialize_fixing_functions(self)
  61.   end
  62. end

13
Game art & music / Original art
« on: February 06, 2016, 03:02:41 pm »
Greetings! I'm gonna upload some of my (unfinished) sprites to devianart.
It may take between 1 and 3 years of work until I have finished all of this since I am doing this in my free time as a hobby.
You can download them from here: http://diarandor.deviantart.com/
but you need to have a devianart account and login there to see images.

At present I have only uploaded a few sprite sheets, but I will keep uploading things from time to time. These sprites will probably be used for the game "Children of Solarus" of the Solarus Team.

14
Development / Unfinished scripted boots
« on: January 15, 2016, 10:00:26 am »
Hi! I want to share my script for the boots item. It's not finished yet, but it can help others.
The aim of this script is to allow to combine the boots with other non built-in items, like a custom jump/feather, a custom sword, and maybe others. The behaviour will be the same as in Link's Awakening, and fully customizable.

It remains to add the collision detection with custom entities that can be broken with the boots,
which can be easily done by using the new functions
Code: [Select]
map:get_entities_in_rectangle(x,y,width,height)
entity:has_collision(collision_test, other_entity)
when Solarus 1.5 is released.

Code: Lua
  1. --[[
  2. Unfinished script for the boots item.
  3. The aim is to allow to combine the boots with other non built-in items,
  4. like the jump/feather and the sword, and maybe others.
  5. --]]
  6. local item = ...
  7.  
  8. local speed = 250
  9.  
  10. function item:on_created()
  11.   self:set_savegame_variable("possesion_feather")
  12.   self:set_variant(1)
  13.   self:set_assignable(true)
  14. end
  15.  
  16. function item:on_obtained()
  17.   local hero_index = item:get_game():get_hero():get_index()
  18.   local inventory = item:get_game():get_inventory()
  19.   inventory:add_item(hero_index, item)
  20. end
  21.  
  22. -- Function to start the running sequence before the movement.
  23. function item:on_using()
  24.   local game = self:get_game()
  25.   local hero = game:get_hero()
  26.   -- Get slot associated to this item.
  27.   local command = "item_1"
  28.   if game:get_item_assigned(2) == item then command = "item_2" end
  29.   local can_start_run = false
  30.   -- Start running animation.
  31.   hero:set_animation("running")
  32.   -- Timer to check if the command button is being pressed enough time to use the boots.
  33.   local timer = sol.timer.start(item, 1000, function() can_start_run = true end)
  34.   -- Check if the command button is being pressed enough time to use the boots.
  35.   sol.timer.start(item, 1, function()
  36.     if not game:is_command_pressed(command) then
  37.       timer:stop()
  38.       hero:set_animation("stopped")
  39.       item:set_finished()
  40.       return false
  41.     elseif can_start_run then
  42.       item:start_running()
  43.       return false
  44.     end
  45.     return true
  46.   end)
  47. end
  48.  
  49. -- Function to start the running movement.
  50. function item:start_running()
  51.   local game = self:get_game()
  52.   local hero = game:get_hero()
  53.   local dir = hero:get_direction()
  54.   local dirs = {[0]="right",[1]="up",[2]="left",[3]="down"}
  55.   local command_dir = dirs[dir] -- Current direction.
  56.   -- Create movement and check for collisions with walls.
  57.   local m = sol.movement.create("straight")
  58.   m:set_speed(speed)
  59.   m:set_angle(dir*math.pi/2)
  60.   m:set_smooth(true)
  61.   function m:on_obstacle_reached()
  62.     item:smash_wall()
  63.     return  
  64.   end
  65.   m:start(hero)
  66.   -- Check for commands pressed to interrupt movement or use weapons.
  67.   local is_using_other_item = false
  68.   sol.timer.start(item, 1, function()
  69.     -- Stop movement if some direction command (different from
  70.     -- the current direction) is pressed.
  71.     local interrupt = false
  72.     for _,str_dir in pairs(dirs) do
  73.       interrupt = interrupt or
  74.         (game:is_command_pressed(str_dir) and command_dir ~= str_dir)
  75.     end
  76.     if interrupt then
  77.       m:stop()
  78.       hero:set_animation("stopped")
  79.       item:set_finished()
  80.       return false
  81.     end
  82.    
  83.     -- TODO: Check if custom items (feather, sword,...) are used, for a combined use.
  84.     --[[
  85.     if game:is_command_pressed("attack") and (not is_using_other_item) then
  86.       is_using_other_item = true
  87.       game:simulate_command_pressed("attack")
  88.     end
  89.     --]]
  90.    
  91.     -- Keep checking.
  92.     return true
  93.   end)
  94. end
  95.  
  96. -- Function for the crash effect against walls.
  97. function item:smash_wall()
  98.   -- Crash animation and sound.
  99.   local hero = self:get_game():get_hero()
  100.   sol.audio.play_sound("boots_crash")
  101.   hero:set_animation("hurt")
  102.  
  103.   -- TODO: detect collision with custom entities (to break them). To do
  104.   -- when some functions (like map.get_entities_in_rectangle and hero.has_collision)
  105.   -- are made in Solarus 1.5.
  106.   --[[
  107.   -- Call a collision event if the hero crashes with a destructible entity.
  108.   local x, y, width, height = hero:get_bounding_box()
  109.   for e in map:get_entities_in_rectangle(x, y, width, height)
  110.     if hero:has_collision("facing", other_entity) then
  111.       if other_entity.on_boots_crash ~= nil then
  112.         other_entity:on_boots_crash()
  113.         break
  114.       end
  115.     end
  116.   end
  117.   --]]
  118.  
  119.   -- Create bounce movement.
  120.   local dir = hero:get_direction()
  121.   dir = (dir+2)%4
  122.   local m = sol.movement.create("straight")
  123.   m:set_speed(75)
  124.   m:set_angle(dir*math.pi/2)
  125.   m:set_smooth(true)
  126.   m:set_max_distance(12)
  127.   m:start(hero)
  128.   function m:on_obstacle_reached()
  129.     hero:set_animation("stopped")
  130.     item:set_finished()
  131.   end
  132.   function m:on_finished()
  133.     hero:set_animation("stopped")
  134.     item:set_finished()
  135.   end
  136. end

15
Development / Start the sword attack from an item script?
« on: January 10, 2016, 11:29:51 am »
Hi! I was trying to script a weapon menu like the one in Link's awakening (but with 3 slots and any weapon could be assigned to each of them). I wanted to make it possible to unassign the sword of the attack button (with the possibility of assigning other items to the attack button), but also I want the possibility of assigning the sword to other buttons, is it possible? The problem that I have is that I don't know how to start the built-in sword attack from an item script...

(Note that calling the command "game:simulate_command_pressed("attack")" is not a solution since the sword would be already unassigned from the attack command.)

Could this be possible with solarus 1.5 using some access to the sword sprite? And in that case how?

Pages: [1] 2 3