Hi All,
I thought I would contribute to the scripting community.
Below are a number of scripts and features that I have been working on.
This particular has the following features that you will be able to tease out.
Life regen, Projectile shooting, Enemy spawning, Run away at half health, pathfinding.
I'd like to credit wrightmat with the projectile code.
local enemy = ...
-- ranged leader type
local properties = {}
local main_sprite = nil
local towards_hero = false
local away_hero = false
local attacked_hero = false
local towards_enemy = false
local timer, fire_timer
function enemy:set_properties(prop)
properties = prop
if properties.life == nil then
properties.life = 2
end
if properties.damage == nil then
properties.damage = 2
end
if properties.play_hero_seen_sound == nil then
properties.play_hero_seen_sound = false
end
if properties.stopped_speed == nil then
properties.stopped_speed = 0
end
if properties.normal_speed == nil then
properties.normal_speed = 32
end
if properties.faster_speed == nil then
properties.faster_speed = 64
end
if properties.hurt_style == nil then
properties.hurt_style = "normal"
end
if properties.regen == nil then
properties.regen = 0
end
end
function enemy:on_created()
self:set_life(properties.life)
self:set_damage(properties.damage)
self:set_hurt_style(properties.hurt_style)
main_sprite = self:create_sprite(properties.main_sprite)
self:set_size(16, 16)
self:set_origin(8, 13)
self:set_attack_consequence("sword", 1)
self:begin()
end
function enemy:begin()
local get_life = enemy:get_life()
local ehalflife = .5 * properties.life
local hero = self:get_map():get_entity("hero")
local _, _, layer = self:get_position()
local _, _, hero_layer = hero:get_position()
local spawn_line = layer == hero_layer
and self:get_distance(hero) > 200
local sight_line = layer == hero_layer
and self:get_distance(hero) < 100
local life_recharge = enemy:get_life() < properties.life
local life_low = enemy:get_life() < ehalflife
and self:get_distance(hero) < 64
if spawn_line then
self:go_spawn()
elseif not sight_line then
self:go_random()
elseif sight_line and not towards_hero and not away_hero then
self:go_hero()
elseif not sight_line and not towards_hero then
self:go_random()
elseif sight_line and towards_hero then
if not fire_timer then self:fire()
elseif life then
self:go_away()
else
self:go_random()
end
if life_recharge then
self:get_game():add_life(properties.regen)
end
timer = sol.timer.start(self, 1000, function() self:begin()
return true
end)
end
end
function enemy:on_restarted()
timer = sol.timer.start(self, 1000, function() self:begin()
return true
end)
end
function enemy:on_hurt()
if timer ~= nil then
timer:stop()
timer = nil
end
self:begin()
end
function enemy:on_movement_changed(movement)
local direction4 = movement:get_direction4()
main_sprite:set_direction(direction4)
end
function enemy:go_spawn()
local x, y, layer = self:get_position()
local direction = self:get_sprite():get_direction()
if self:get_map():get_entities_count("lizalfos") <= 3 then
if direction == 0 then
x = x + 32
elseif direction == 1 then
y = y - 32
elseif direction == 2 then
x = x - 32
elseif direction == 3 then
y = y + 32
end
local spawn = enemy:create_enemy{
name = "lizalfos",
breed = "lizalfos",
x = x,
y = y,
layer = layer,
direction = direction,
treasure_name = "random"
}
spawn:set_position(x, y, layer)
spawn:set_optimization_distance(0)
end
end
function enemy:go_away()
local x, y = self:get_map():get_entity("hero"):get_position()
local direction = self:get_sprite():get_direction()
if direction == 0 then
x = x + 128
elseif direction == 1 then
y = y - 128
elseif direction == 2 then
x = x - 128
elseif direction == 3 then
y = y + 128
end
local m = sol.movement.create("target")
m:set_speed(properties.faster_speed)
m:set_target(x, y)
m:set_ignore_obstacles(false)
m:start(self)
away_hero = true
towards_hero = false
end
function enemy:go_random()
self:get_sprite():set_animation("walking")
local m = sol.movement.create("random_path")
m:set_speed(properties.normal_speed)
m:start(self)
towards_hero = false
away_hero = false
end
function enemy:go_hero()
local m = sol.movement.create("target")
m:set_speed(properties.normal_speed)
m:start(self)
towards_hero = true
away_hero = false
end
function enemy:go_static()
local m = sol.movement.create("target")
m:set_speed(0)
m:start(self)
towards_hero = false
end
function enemy:fire()
self:get_sprite():set_animation("firing")
fire_timer = sol.timer.start(self, 100, function()
local x, y, layer = self:get_position()
local direction = self:get_sprite():get_direction()
if direction == 0 then
x = x + 16
elseif direction == 1 then
y = y - 16
elseif direction == 2 then
x = x - 16
elseif direction == 3 then
y = y + 16
end
if rock == nil or not rock:exists() then
local rock = enemy:create_enemy{
x = x,
y = y,
layer = layer,
direction = direction,
breed = "projectile"
}
self.created = true
rock:set_position(x, y, layer)
rock:set_optimization_distance(0)
end
end)
sol.timer.start(self, 1000, function()
fire_timer = nil
self:begin()
end)
end
just use the generic format from solarus dx to make enemies like this.
good luck.
Comments and code corrections are welcome.
That all seems like amazing work to be doing! Have you been able to implement them in your own game (or Mystery of Solarus, as you're basing it on)?
I have implemented them but I still have some unresolved issues.
Such as slow response time after running away.
And having enemies spawn outside the map.
Both of these can be scripted but I haven't done that yet.
I don't recall providing any projectile code - is it from my github? If so, it probably came from christopho in one way or another, lol. Glad it was helpful though! I look forward to trying out this code!