Hello,
I would like to add an intermediate animation for chests. "closed" and "open" are the basic animations. I added, in the .dat files, an "opening" animation which it could be in 1 or 2 frames according the size of the chests.
How woud you proceed in lua scripts?
Sorry, I have lost a lot of skills in lua and even about Solarus in general, because I have not worked on it for several months.
Moreover, there are now in the last versions, scripts "features" and "multi_events" which is all the more new and difficult for me.
But instead, I improved my pixel art skills a bit ;) . I will soon update my topic on the project.
If you mean opening as in lifting the lid of the chest, then try changing the number of frames for the "open" animation.
(http://forum.solarus-games.org/index.php?action=dlattach;topic=971.0;attach=530)
you have to go through custom entity
Or, maybe this could help ?
http://www.solarus-games.org/doc/latest/lua_api_chest.html#lua_api_chest_on_opened
@froggy77
MetalZelda is correct. I made a super quick chest opening animation and apparently the chest sprite vanishes with more than one frame.
@Zefk > I had already tried to change the number of frames for the "open" animation. Yes, " the chest sprite vanishes with more than one frame." :(
@MetalZelda > OK, I also think I have to go through custom entity :'(
http://www.solarus-games.org/doc/latest/lua_api_chest.html#lua_api_chest_on_opened (http://www.solarus-games.org/doc/latest/lua_api_chest.html#lua_api_chest_on_opened) is when the chest is already opened. It is above all to choose the treasure.
Thanks for your help!
@froggy77
If you do not mind, I'd like to discuss features for a custom chest with you.
So far my thought process led me to the following. I will be coding this sometime for my Lib. What more features would it need?
entity:custom_chest(treasure, treasure_variant, save_variable, sprite_directory, traversable, closed_animation, open_animation, opening_animation, key)
With default settings it could be called inside a custom entity like this.
entity:custom_chest()
With custom settings it would be more readable like this:
entity:custom_chest(
treasure, --treasure
treasure_variant, --treasure_variant
save_variable, --save_variable
sprite_directory, --sprite_directory
traversable, --traversable
closed_animation, --closed_animation
open_animation, --open_animation
opening_animation, --opening_animation
key) --key
Maybe something like....
Opening mode:
-By hero
-By hero with save variable
-By hero with item required
-increment/decrement item
and maybe these...
http://forum.solarus-games.org/index.php/topic,971.msg5646.html#msg5646
-By entity
-By entity with save variable
-By entity with dummy item required
-increment/decrement dummy item
-By entity overlap
Dialog:
-fail dialog
For your purposes with chests, I recommend to use normal chests in the map editor, just to have compatibility with the map editor. There are several ways to do this:
-Use a script that replaces chests with custom entities when a map is created, or when chests are created. This can be done directly by defining chest_metatable:on_created().
-Another way is to define chest_metatable:on_created() in order to define some events on the sprite of the chest, which would allow that animation to appear.
Remark: using custom entities takes a bit more of work than using the chest metatable, since you would need to define the functions and events of the chest Lua API. On the other hand that solution allows much more customization on chests: for instance, you can make chests that can only be opened by one of the heroes and not by the others, or make chests that can be opened by throwing a pot.
By entity overlap is a good idea Diarandor. I am guessing a specific entity would be best because not one wants any entity to open a chest.
Aha! I did it. I made an on_interaction function. Of course, it will need some tweaking to actually work for the chest, but it allows me to interact with many entities.
function metatable_entity:on_entity_interaction()
local map = self:get_map()
local hero = map:get_hero()
local game = map:get_game()
local dialog_activation_distance = 20
sol.timer.start(2000, function()
local distance_check = hero:get_distance(self)
if distance_check <= dialog_activation_distance then -- dialog_activation_distance
function map:on_key_pressed(key)
if key == "y" then
print("pressed")
end
end
end
return true -- To call the timer again (with the same delay).
end)
end
It can be called in an entity like this:
entity:on_entity_interaction()
I think you are complicating things too much. You should just define custom_entity:on_interaction() for your custom chest. There is no need of checking distances and timers, or using the event on_key_pressed().
I like Diarandor's solution, overwriting a chest to replace it with a custom entity.
For the custom entity script, simple trick is to use add_collision_test to do HUD stuffs and simply add an animation in on_interaction. Thn call hero:start_treasure from there
You need 3 things.
1) the metatable modification
2) a chest entity
3) a chest on a map, where you need to define
- it's spriteset
- it's treasure
- it's variant
- the savegame variable
1) * Keep note that it is from my project so you might need to modify things to fit your needs
And, with this script you can only set a treasure that you can open if you press Action, other chest action cannot be done without more complex modifications
Also to set a direction for your chest (if needed), put the desired direction as the chest name.
local chest_meta = sol.main.get_metatable("chest")
function chest_meta:on_created()
local treasure, variant, savegame = self:get_treasure()
local x, y, layer = self:get_position()
local graphic = self:get_sprite():get_animation_set()
local setup = {
x = x,
y = y,
layer = layer,
model = "chest/chest",
width = 16,
height = 16,
direction = 3,
sprite = graphic
}
local entity = self:get_map():create_custom_entity(setup)
entity:set_treasure(treasure, variant, savegame)
entity:create()
-- You might need to customize this chest.
function self:get_chest()
return entity
end
self:remove()
end
2)
local entity = ...
entity.data = {}
function entity:set_treasure(treasure, variant, savegame)
self.data.treasure = treasure
self.data.variant = variant
self.data.savegame = savegame
end
local game = entity:get_game()
local hero = game:get_hero()
function entity:is_open()
return game:get_value(self.data.savegame)
end
function entity:create()
self:set_drawn_in_y_order(true)
self:set_can_traverse("hero", false)
self:set_traversable_by("hero", false)
self:set_traversable_by("custom_entity", false)
if self:is_open() then
self:get_sprite():set_animation("open")
return
end
-- Hud notification
self:add_collision_test("facing", function(_, other)
if other:get_type() == "hero" then
if not self:is_open() then
self.action_effect = other:get_direction() == self:get_direction() and "open" or "look"
else
self:clear_collision_tests()
end
end
end)
end
function entity:on_interaction()
-- This is where you will play your animation, set the savegame value to true and give the hero the treasure
-- savegame value is stored in entity.data.savegame
if self:is_open() then
return
end
hero:freeze()
game:set_pause_allowed(false)
self:get_sprite():set_animation("opening", function()
self:get_sprite():set_animation("open")
hero:start_treasure(self.data.treasure, self.data.variant, self.data.savegame, function()
-- After the treasure has been obtained
hero:unfreeze()
game:set_pause_allowed(true)
end)
end)
self.action_effect = nil
end
Quote from: Diarandor on May 10, 2017, 09:07:50 PM
I think you are complicating things too much. You should just define custom_entity:on_interaction() for your custom chest. There is no need of checking distances and timers, or using the event on_key_pressed().
I think only custom_entity:on_interaction() works for a hero. It would not work for a player 2 custom entity as far as I know, but I guess I could just make that a second custom chest function.
Ok, if you allow to do that then you are right, I did not think on that case.
I am still debating on it though because first my main goal is to just get a fully function ally AI system working. A custom entity chest for the hero is far easier.
You will need to do something similar for NPCs, and many other types of interactions with other entities (switches, carried entities, etc). That is a lot of work.
The switch I have already basically done, but only for stepping on. I do not plan to make all the entities except for when it is simple or when I need it for animation purposes. I probably will not have a second player feature because it is not something I want with my games, but in some cases simple second player features can be useful. For example, when you want an entity to step on a switch or to move a block that can only be pushed from their side.
Thanks for the time spent. I just needed advice, not a brainstorming. ;)
I would like to use the editor to create the chest normally; maybe it could be disabled and replaced by an entity during the opening and at the end enabled to appear when completely opened. I will try to write a script even I lost my poor level in lua.
I did posted the solution on page 1, it does replace the default chest by a custom entity, you might do some tweaks to make it properly work to your needs though
Thank you MetalZelda, I did not understand where to put those scripts and I did not realize that there was no need to create an entity from the editor.
Even if I managed to make it work, I found some problems.
- If there is no treasure_savegame_variable, then there are these error messages:
Error: In on_created: [string "entities/chest/chest.lua"]:23: bad argument #1 to is_open (string expected, got nil))
Error: In on_interaction: [string "entities/chest/chest.lua"]:44: bad argument #1 to is_open (string expected, got nil))
- If there is a treasure_savegame_variable but no treasure, then there is the following error message
Error: In sprite callback: [string "entities/chest/chest.lua"]:52: bad argument #1 to start_treasure (string expected, got nil))
This one is not a problem.
- If there is no delay for "opening" animation in "delay between frames", then nothing happens: no error message, no treasure, "hero:unfreeze()" does not start.
In order to correct this, I added a value for "delay between frames", for example: 200 ms.
- hero:freeze() and hero:unfreeze() seem not to be necessary.
To make this work you need to create a chest entity, not a custom entity, the script do the rest (delete the chest and create the custom entity).
You need to define the sprite, treasure and savegame variable from there, like this
(http://i.imgur.com/IFrH8Y6.png)
But, it is very basic atm, the entity name could be used to store frame delays or other stuffs