Hoping for a little help on one of my bosses. For some reason he keeps disappearing when that's not what I'm intending with my script, so I must be missing something. It seems to happen primarily as he's finishing the "opening" phase.
Enemy script:
local enemy = ...
-- Gohma: Boss who has to be shot in the eye with an arrow to be hurt
function enemy:on_created()
self:set_life(9)
self:set_damage(2)
self:create_sprite("enemies/gohma")
self:set_hurt_style("boss")
self:set_size(64, 32)
self:set_origin(32, 29)
self:set_attack_consequence("sword", "protected")
self:get_sprite():set_animation("walking")
end
function enemy:check_action()
local action = math.random(10)
if self:get_life() > 6 then
-- first phase: if less than three hits then mostly just move around (slowly), and create tektites
local son_name = self:get_name().."_son"
self:create_enemy{
name = son_name,
breed = "tektite_green",
treasure_name = "heart"
}
if action >= 1 and action <= 7 then self:go(96) else self:blink() end
elseif self:get_life() > 3 and self:get_life() <= 6 then
-- second phase: if more than 3 but less than 6 hits then blink a lot more, and create tektites
if action >= 1 and action <= 7 then self:blink() else self:go(96) end
local son_name = self:get_name().."_son"
self:create_enemy{
name = son_name,
breed = "tektite_green"
}
elseif self:get_life() < 3 and self:get_life() > 0 then
-- final phase: if more than 6 hits then move a lot faster, and create tektites!
if action >= 1 and action <= 6 then self:blink() else self:go(128) end
local son_name = self:get_name().."_son"
self:create_enemy{
name = son_name,
breed = "tektite_green"
}
end
sol.timer.start(self, 100, function() self:open() end)
end
function enemy:go(speed)
self:get_sprite():set_animation("walking")
self:set_attack_consequence("arrow", 1)
local m = sol.movement.create("random")
m:set_speed(speed)
m:set_max_distance(24)
m:start(self)
end
function enemy:blink()
self:set_attack_consequence("arrow", "protected")
self:get_sprite():set_animation("blinking")
end
function enemy:open()
self:set_attack_consequence("arrow", 1)
self:get_sprite():set_animation("opening")
end
function enemy:on_restarted()
self:get_sprite():set_animation("walking")
self:check_action()
end
function enemy:on_obstacle_reached()
self:check_action()
end
function enemy:on_animation_finished(sprite, animation)
self:set_attack_consequence("arrow", "protected")
if animation == "blinking" then
self:get_sprite():set_animation("closed")
sol.timer.start(self, random(6)*1000, function() self:open() end)
self:go(64)
elseif animation == "opening" then
self:get_sprite():set_animation("walking")
sol.timer.start(self, 1000, function() self:check_action() end)
end
end
Sprite file:
animation{
name = "walking",
src_image = "enemies/gohma.png",
frame_delay = 200,
frame_to_loop_on = 0,
directions = {
{ x = 0, y = 128, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 0, y = 64, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 0, y = 96, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 0, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
},
}
animation{
name = "shaking",
src_image = "enemies/gohma.png",
frame_delay = 100,
frame_to_loop_on = 0,
directions = {
{ x = 64, y = 128, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
{ x = 64, y = 64, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
{ x = 64, y = 96, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
{ x = 64, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
},
}
animation{
name = "hurt",
src_image = "enemies/gohma.png",
frame_delay = 100,
frame_to_loop_on = 0,
directions = {
{ x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 256, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
},
}
animation{
name = "closed",
src_image = "enemies/gohma.png",
frame_delay = 200,
frame_to_loop_on = 0,
directions = {
{ x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
{ x = 256, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 4 },
},
}
animation{
name = "blinking",
src_image = "enemies/gohma.png",
frame_delay = 150,
directions = {
{ x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
{ x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
{ x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
{ x = 0, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 3 },
},
}
animation{
name = "opening",
src_image = "enemies/gohma.png",
frame_delay = 150,
directions = {
{ x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
{ x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
{ x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
{ x = 128, y = 0, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29, num_frames = 2 },
},
}
animation{
name = "immobilized",
src_image = "enemies/gohma.png",
directions = {
{ x = 0, y = 128, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
{ x = 0, y = 64, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
{ x = 0, y = 96, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
{ x = 0, y = 32, frame_width = 64, frame_height = 32, origin_x = 32, origin_y = 29 },
},
}
I don't see anything strange in your script... Think to print a lot when you are debugging to know exactly what is wrong. Can you show us the image for the sprite ? It may be a problem with the sprite declaration of the walking animation, but I suppose you double checked it...
Not related, but in you check action, you don't need to repeat the opposite if in you elseif statement... Like "if self:get_life() > 6 then ... elseif self:get_life() > 3 then ... else ...". It's just coding style, and if you think it's easier to read after it's ok but it's not useful in a programming way (in my opinion). In the same way, the creation of the sons in the check_action seems to be always true, so maybe not repeat this code ? I'm not sure to have read it correctly but that's how I understand the check action :)
Nice boss by the way ^^
Try to add self:set_optimization_distance(0) in on_created. The default optimization distance is often the source of problems with bosses and I will try to remove it in 1.3.
See http://www.solarus-games.org/doc/1.2/lua_api_entity.html#lua_api_entity_set_optimization_distance
Christopho- no luck on the optimization distance trick, thanks though.
Renkineko- I did double check the sprite, but I always could have missed something!
https://github.com/wrightmat/zbom/blob/master/data/sprites/enemies/gohma.png
Ok so I cloned your repository because I did not understand where the problem was, and I did a lot of printing everywhere. With this, I saw that you never enter in the function enemy:on_animation_finished. So after checking on the documentation, this event does not exist, you have to do the "on_animation_finished" on the sprite and not on the enemy :) so the good method should be something like :
function enemy:blink()
self:set_attack_consequence("arrow", "protected")
local sprite = self:get_sprite()
sprite:set_animation("blinking")
function sprite:on_animation_finished(animation)
enemy:set_attack_consequence("arrow", "protected")
sprite:set_animation("closed")
sol.timer.start(enemy, random(6)*1000, function() enemy:open() end)
enemy:go(64)
end
end
function enemy:open()
self:set_attack_consequence("arrow", 1)
local sprite = self:get_sprite()
sprite:set_animation("opening")
function sprite:on_animation_finished(animation)
enemy:set_attack_consequence("arrow", "protected")
sprite:set_animation("walking")
sol.timer.start(enemy, 1000, function() enemy:check_action() end)
end
end
With this code, your enemy exists and is hell in a cell :p As I said : doing a lot of print everywhere can help to resolve the problem. For information, here is the file I had before knowing where the problem was :
local enemy = ...
-- Gohma: Boss who has to be shot in the eye with an arrow to be hurt
function enemy:on_created()
self:set_life(9)
self:set_damage(2)
self:create_sprite("enemies/gohma")
self:set_hurt_style("boss")
self:set_size(64, 32)
self:set_origin(32, 29)
self:set_attack_consequence("sword", "protected")
self:get_sprite():set_animation("walking")
self:set_optimization_distance(0)
end
function enemy:check_action()
local action = math.random(10)
print('action : ', action)
if self:get_life() > 6 then
print('first phase, creating son')
-- first phase: if less than three hits then mostly just move around (slowly), and create tektites
local son_name = self:get_name().."_son"
self:create_enemy{
name = son_name,
breed = "tektite_green",
treasure_name = "heart"
}
if action >= 1 and action <= 7 then
print('go somewhere')
self:go(96)
else
print('will blink')
self:blink()
end
elseif self:get_life() > 3 and self:get_life() <= 6 then
-- second phase: if more than 3 but less than 6 hits then blink a lot more, and create tektites
if action >= 1 and action <= 7 then self:blink() else self:go(96) end
local son_name = self:get_name().."_son"
self:create_enemy{
name = son_name,
breed = "tektite_green"
}
elseif self:get_life() < 3 and self:get_life() > 0 then
-- final phase: if more than 6 hits then move a lot faster, and create tektites!
if action >= 1 and action <= 6 then self:blink() else self:go(128) end
local son_name = self:get_name().."_son"
self:create_enemy{
name = son_name,
breed = "tektite_green"
}
end
sol.timer.start(self, 100, function()
print('open what, i do not know')
self:open()
end)
end
function enemy:go(speed)
print('enemy go to ',speed)
self:get_sprite():set_animation("walking")
self:set_attack_consequence("arrow", 1)
local m = sol.movement.create("random")
m:set_speed(speed)
m:set_max_distance(24)
m:start(self)
end
function enemy:blink()
print('enemy is blinking')
self:set_attack_consequence("arrow", "protected")
self:get_sprite():set_animation("blinking")
end
function enemy:open()
print ('enemy is opening')
self:set_attack_consequence("arrow", 1)
self:get_sprite():set_animation("opening")
end
function enemy:on_restarted()
print('enemy:restarting')
self:get_sprite():set_animation("walking")
self:check_action()
end
function enemy:on_obstacle_reached()
print('oh, an obstacle...')
self:check_action()
end
function enemy:on_animation_finished(sprite, animation)
print('animation finished : ', sprite, animation)
self:set_attack_consequence("arrow", "protected")
if animation == "blinking" then
print('animation was blinking, we will close')
self:get_sprite():set_animation("closed")
sol.timer.start(self, random(6)*1000, function() self:open() end)
self:go(64)
elseif animation == "opening" then
print('animation was opening, we will walk')
self:get_sprite():set_animation("walking")
sol.timer.start(self, 1000, function() self:check_action() end)
end
end
And the game was pretty chatty, so it can be useful :] Good luck for the boss settings.
Wow, thanks so much Renkineko!
If you were referring to the difficulty of the boss - now that the script works, I've fine-tuned the boss's difficulty level :-)
You're welcome :) and yep I was referring the difficulty of the boss, but I knew you will update it when the script works properly, you can't modify an enemy if you can't test it first :p good luck o/