Hi ;D
I create a new item: the pickaxe. It allows the hero to destroy some specifics entities and enemies. I want to know if it is possible to add a new kind of "attack_consequence" (as lign 26).
The principe is to attack a specific enemy class with the pickaxe to destroy their armor and, after, kill them with the sword.
enemy script:
local enemy = ...
local game = enemy:get_game()
local map = enemy:get_map()
local hero = map:get_hero()
local body_sprite
local movement
local shield_remove
-- Properties
local life = 2
local damage = 2
local speed = 24
local speed_faster = speed + speed/2
-----------------------------------------
-- Proprieties of the enemy with shield
local function shield_mode()
body_sprite:set_animation("walking_rock")
enemy:set_push_hero_on_sword(true)
enemy:set_attack_consequence("sword", "protected")
movement = sol.movement.create("target")
movement:set_target(hero)
movement:set_speed(speed)
movement:start(enemy)
enemy:set_attack_consequence("pickaxe","custom")-- ??
end
-----------------------------------------
-- Proprieties of the enemy without shield
local function normal_mode()
shield_remove = true
body_sprite:set_animation("walking")
movement = sol.movement.create("random")
enemy:set_push_hero_on_sword(false)
enemy:set_default_attack_consequences()
movement:set_speed(speed_faster)
movement:start(enemy)
end
-----------------------------------------
-- When the enemy is hit by a pickaxe
function enemy:on_custom_attack_received(attack,sprite)
normal_mode()
end
-----------------------------------------
function enemy:on_created()
body_sprite = enemy:create_sprite("enemies/" .. enemy:get_breed())
enemy:set_life(life)
enemy:set_damage(damage)
shield_remove = false
end
-----------------------------------------
function enemy:on_restarted()
if shield_remove == false then
shield_mode()
else
normal_mode()
end
end
-----------------------------------------
function enemy:on_movement_changed(movement)
local direction4 = movement:get_direction4()
local sprite = enemy:get_sprite()
sprite:set_direction(direction4)
end
You can add your own attacks with scripts. Don't use enemy:set_attack_consequence(), but instead, define your own functions. This is what I do with several items like the hammer, the hookshot, etc.
See for example the hammer script here: https://github.com/solarus-games/zelda-roth-se/blob/dev/data/items/hammer.lua#L114
I create functions enemy:get_hammer_reaction(), enemy:set_hammer_reaction() and enemy:set_hammer_reaction_sprite(). Metatables are used so that all enemies have the new functions.
Okay thanks ;)
I adapt my script with your but I don't really understand how the functions work :-\
When I attack the enemy with the pickaxe, nothing happen.
Item code:
local item = ...
local game = item:get_game()
function item:on_created()
item:set_savegame_variable("possession_pickaxe")
item:set_assignable(true)
item:set_destroy_block(false)
end
function item:on_using()
local map = item:get_map()
local hero = map:get_hero()
hero:freeze()
-- Handle block
item:set_destroy_block(false)
sol.timer.start(map, 200, function()
if item:has_destroy_block() then
sol.audio.play_sound("stone") -- sucessfully destroy rocks
else
sol.audio.play_sound("sword_tapping")
end
item:set_destroy_block(false)
end)
-- Hero coordonates
local x, y, layer = hero:get_position()
local direction = hero:get_direction()
if direction4 == 0 then x = x + 12
elseif direction4 == 1 then y = y - 12
elseif direction4 == 2 then x = x - 12
else y = y + 12
end
-- Create pickaxe and collisions
local pickaxe = map:create_custom_entity{
x = x,
y = y,
layer = layer,
width = 8,
height = 8,
direction = 0,
}
local entities_touched = { }
pickaxe:set_origin(4, 5)
pickaxe:add_collision_test("overlapping", function(pickaxe, entity)
-- Hurt enemies
if entity:get_type() == "enemy" then
local enemy = entity
if entities_touched[enemy] then
-- If protected we don't want to play the sound repeatedly.
return
end
entities_touched[enemy] = true
local reaction = enemy:get_pickaxe_reaction(enemy_sprite)
enemy:receive_attack_consequence("pickaxe", reaction)
end
end)
--## Launch animation
hero:set_animation("pickaxe")
sol.timer.start(600, function()
hero:unfreeze()
end)
end
function item:has_destroy_block()
return item.destroy_block
end
function item:set_destroy_block(destroy_block)
item.destroy_block = destroy_block
end
---------------------------------------------------------------------------------------
-- Initialize the metatable of appropriate entities to work with the pickaxe-----------
local function initialize_meta()
--Add Lua pickaxe properties to enemies
local enemy_meta = sol.main.get_metatable("enemy")
if enemy_meta.get_pickaxe_reaction ~= nil then
return
end
enemy_meta.pickaxe_reaction = 2 -- 2 damages
enemy_meta.pickaxe_reaction_sprite = {}
-----------------------------------------------------------------------
function enemy_meta:get_pickaxe_reaction(sprite)
if sprite ~= nil and self.pickaxe_reaction_sprite[sprite] ~= nil then
return self.pickaxe_reaction_sprite[sprite]
end
return self.pickaxe_reaction
end
----------------------------------------------------------------------
function enemy_meta:set_pickaxe_reaction(reaction, sprite)
self.pickaxe_reaction = reaction
end
----------------------------------------------------------------------
function enemy_meta:set_pickaxe_reaction_sprite(sprite, reaction)
self.pickaxe_reaction_sprite[sprite] = reaction
end
----------------------------------------------------------------------
-- Change the default enemy:set_invincible() to also take into account the pickaxe.
local previous_set_invincible = enemy_meta.set_invincible
function enemy_meta:set_invincible()
previous_set_invincible(self)
self:set_pickaxe_reaction("ignored")
end
local previous_set_invincible_sprite = enemy_meta.set_invincible_sprite
function enemy_meta:set_invincible_sprite(sprite)
previous_set_invincible_sprite(self, sprite)
self:set_pickaxe_reaction_sprite(sprite, "ignored")
end
end
initialize_meta()
Enemy code:
local enemy = ...
local game = enemy:get_game()
local map = enemy:get_map()
local hero = map:get_hero()
local body_sprite
local movement
local shield_remove
-- Properties
local life = 2
local damage = 2
local speed = 24
local speed_faster = speed + speed/2
-----------------------------------------
-- Proprieties of the enemy with shield
local function shield_mode()
body_sprite:set_animation("walking_rock")
enemy:set_push_hero_on_sword(true)
enemy:set_attack_consequence("sword", "protected")
movement = sol.movement.create("target")
movement:set_target(hero)
movement:set_speed(speed)
movement:start(enemy)
end
-----------------------------------------
-- Proprieties of the enemy without shield
local function normal_mode()
shield_remove = true
body_sprite:set_animation("walking")
movement = sol.movement.create("random")
enemy:set_push_hero_on_sword(false)
enemy:set_default_attack_consequences()
movement:set_speed(speed_faster)
movement:start(enemy)
end
-----------------------------------------
-- When the enemy is hit by a pickaxe (TO CHANGE !)
function enemy:on_custom_attack_received(attack,sprite)
normal_mode()
end
-----------------------------------------
function enemy:on_created()
body_sprite = enemy:create_sprite("enemies/" .. enemy:get_breed())
enemy:set_life(life)
enemy:set_damage(damage)
shield_remove = false
enemy:set_pickaxe_reaction_sprite("attack", body_sprite) -- Initialise shield
end
-----------------------------------------
function enemy:on_restarted()
if shield_remove == false then
shield_mode()
else
normal_mode()
end
end
-----------------------------------------
function enemy:on_movement_changed(movement)
local direction4 = movement:get_direction4()
local sprite = enemy:get_sprite()
sprite:set_direction(direction4)
end
I just go back on this problem and I sucess. I just forgot to check the "quest.manager.lua" in which the function "receive_attack_consequence" are.
Thanks to you Christopho (3 years later ;D )