diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 9a32c394d5..6cc81aeb83 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -384,560 +384,7 @@ local do_states = function(self, dtime) local yaw = self.object:get_yaw() or 0 - --[[ - if self.state == "stand" then - - if math_random(1, 4) == 1 then - - local lp = nil - local s = self.object:get_pos() - local objs = minetest_get_objects_inside_radius(s, 3) - - for n = 1, #objs do - - if objs[n]:is_player() then - lp = objs[n]:get_pos() - break - end - end - - -- look at any players nearby, otherwise turn randomly - if lp then - - local vec = { - x = lp.x - s.x, - z = lp.z - s.z - } - - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - - if lp.x > s.x then yaw = yaw + math_pi end - else - yaw = yaw + math_random(-0.5, 0.5) - end - - yaw = set_yaw(self, yaw, 8) - end - - set_velocity(self, 0) - set_animation(self, "stand") - - -- npc's ordered to stand stay standing - if self.type ~= "npc" - or self.order ~= "stand" then - - if self.walk_chance ~= 0 - and self.facing_fence ~= true - and math_random(1, 100) <= self.walk_chance - and is_at_cliff_or_danger(self) == false then - - set_velocity(self, self.walk_velocity) - self.state = "walk" - set_animation(self, "walk") - end - end - - elseif self.state == "walk" then - - local s = self.object:get_pos() - local lp = nil - - -- is there something I need to avoid? - if (self.water_damage > 0 - and self.lava_damage > 0) - or self.breath_max ~= -1 then - - lp = minetest_find_node_near(s, 1, {"group:water", "group:lava"}) - - elseif self.water_damage > 0 then - - lp = minetest_find_node_near(s, 1, {"group:water"}) - - elseif self.lava_damage > 0 then - - lp = minetest_find_node_near(s, 1, {"group:lava"}) - - elseif self.fire_damage > 0 then - - lp = minetest_find_node_near(s, 1, {"group:fire"}) - - end - - local is_in_danger = false - if lp then - -- If mob in or on dangerous block, look for land - if (is_node_dangerous(self, self.standing_in) or - is_node_dangerous(self, self.standing_on)) or (is_node_waterhazard(self, self.standing_in) or is_node_waterhazard(self, self.standing_on)) and (not self.fly) then - is_in_danger = true - - -- If mob in or on dangerous block, look for land - if is_in_danger then - -- Better way to find shore - copied from upstream - lp = minetest_find_nodes_in_area_under_air( - {x = s.x - 5, y = s.y - 0.5, z = s.z - 5}, - {x = s.x + 5, y = s.y + 1, z = s.z + 5}, - {"group:solid"}) - - lp = #lp > 0 and lp[math_random(#lp)] - - -- did we find land? - if lp then - - local vec = { - x = lp.x - s.x, - z = lp.z - s.z - } - - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - - - if lp.x > s.x then yaw = yaw + math_pi end - - -- look towards land and move in that direction - yaw = set_yaw(self, yaw, 6) - set_velocity(self, self.walk_velocity) - - end - end - - -- A danger is near but mob is not inside - else - - -- Randomly turn - if math_random(1, 100) <= 30 then - yaw = yaw + math_random(-0.5, 0.5) - yaw = set_yaw(self, yaw, 8) - end - end - - yaw = set_yaw(self, yaw, 8) - - -- otherwise randomly turn - elseif math_random(1, 100) <= 30 then - - yaw = yaw + math_random(-0.5, 0.5) - yaw = set_yaw(self, yaw, 8) - end - - -- stand for great fall or danger or fence in front - local cliff_or_danger = false - if is_in_danger then - cliff_or_danger = is_at_cliff_or_danger(self) - end - if self.facing_fence == true - or cliff_or_danger - or math_random(1, 100) <= 30 then - - set_velocity(self, 0) - self.state = "stand" - set_animation(self, "stand") - local yaw = self.object:get_yaw() or 0 - yaw = set_yaw(self, yaw + 0.78, 8) - else - - set_velocity(self, self.walk_velocity) - - if flight_check(self) - and self.animation - and self.animation.fly_start - and self.animation.fly_end then - set_animation(self, "fly") - else - set_animation(self, "walk") - end - end - - -- runaway when punched - elseif self.state == "runaway" then - - self.runaway_timer = self.runaway_timer + 1 - - -- stop after 5 seconds or when at cliff - if self.runaway_timer > 5 - or is_at_cliff_or_danger(self) then - self.runaway_timer = 0 - set_velocity(self, 0) - self.state = "stand" - set_animation(self, "stand") - local yaw = self.object:get_yaw() or 0 - yaw = set_yaw(self, yaw + 0.78, 8) - else - set_velocity(self, self.run_velocity) - set_animation(self, "run") - end - - -- attack routines (explode, dogfight, shoot, dogshoot) - elseif self.state == "attack" then - - local s = self.object:get_pos() - local p = self.attack:get_pos() or s - - -- stop attacking if player invisible or out of range - if not self.attack - or not self.attack:get_pos() - or not object_in_range(self, self.attack) - or self.attack:get_hp() <= 0 - or (self.attack:is_player() and mobs.invis[ self.attack:get_player_name() ]) then - - self.state = "stand" - set_velocity(self, 0) - set_animation(self, "stand") - self.attack = nil - self.v_start = false - self.timer = 0 - self.blinktimer = 0 - self.path.way = nil - - return - end - - -- calculate distance from mob and enemy - local dist = vector.distance(p, s) - - if self.attack_type == "explode" then - - local vec = { - x = p.x - s.x, - z = p.z - s.z - } - - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - - if p.x > s.x then yaw = yaw + math_pi end - - yaw = set_yaw(self, yaw, 0, dtime) - - local node_break_radius = self.explosion_radius or 1 - local entity_damage_radius = self.explosion_damage_radius - or (node_break_radius * 2) - - -- start timer when in reach and line of sight - if not self.v_start - and dist <= self.reach - and line_of_sight(self, s, p, 2) then - - self.v_start = true - self.timer = 0 - self.blinktimer = 0 - mob_sound(self, "fuse", nil, false) - - -- stop timer if out of reach or direct line of sight - elseif self.allow_fuse_reset - and self.v_start - and (dist >= self.explosiontimer_reset_radius - or not line_of_sight(self, s, p, 2)) then - self.v_start = false - self.timer = 0 - self.blinktimer = 0 - self.blinkstatus = false - remove_texture_mod(self, "^[brighten") - end - - -- walk right up to player unless the timer is active - if self.v_start and (self.stop_to_explode or dist < self.reach) then - set_velocity(self, 0) - else - set_velocity(self, self.run_velocity) - end - - if self.animation and self.animation.run_start then - set_animation(self, "run") - else - set_animation(self, "walk") - end - - if self.v_start then - - self.timer = self.timer + dtime - self.blinktimer = (self.blinktimer or 0) + dtime - - if self.blinktimer > 0.2 then - - self.blinktimer = 0 - - if self.blinkstatus then - remove_texture_mod(self, "^[brighten") - else - add_texture_mod(self, "^[brighten") - end - - self.blinkstatus = not self.blinkstatus - end - - if self.timer > self.explosion_timer then - - local pos = self.object:get_pos() - - if mod_explosions then - if mobs_griefing and not minetest_is_protected(pos, "") then - mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object) - else - minetest_sound_play(self.sounds.explode, { - pos = pos, - gain = 1.0, - max_hear_distance = self.sounds.distance or 32 - }, true) - - entity_physics(pos, entity_damage_radius) - effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0) - end - end - mcl_burning.extinguish(self.object) - self.object:remove() - - return true - end - end - - elseif self.attack_type == "dogfight" - or (self.attack_type == "dogshoot" and dogswitch(self, dtime) == 2) - or (self.attack_type == "dogshoot" and dist <= self.reach and dogswitch(self) == 0) then - - if self.fly - and dist > self.reach then - - local p1 = s - local me_y = math_floor(p1.y) - local p2 = p - local p_y = math_floor(p2.y + 1) - local v = self.object:get_velocity() - - if flight_check(self, s) then - - if me_y < p_y then - - self.object:set_velocity({ - x = v.x, - y = 1 * self.walk_velocity, - z = v.z - }) - - elseif me_y > p_y then - - self.object:set_velocity({ - x = v.x, - y = -1 * self.walk_velocity, - z = v.z - }) - end - else - if me_y < p_y then - - self.object:set_velocity({ - x = v.x, - y = 0.01, - z = v.z - }) - - elseif me_y > p_y then - - self.object:set_velocity({ - x = v.x, - y = -0.01, - z = v.z - }) - end - end - - end - - -- rnd: new movement direction - if self.path.following - and self.path.way - and self.attack_type ~= "dogshoot" then - - -- no paths longer than 50 - if #self.path.way > 50 - or dist < self.reach then - self.path.following = false - return - end - - local p1 = self.path.way[1] - - if not p1 then - self.path.following = false - return - end - - if math_abs(p1.x-s.x) + math_abs(p1.z - s.z) < 0.6 then - -- reached waypoint, remove it from queue - table.remove(self.path.way, 1) - end - - -- set new temporary target - p = {x = p1.x, y = p1.y, z = p1.z} - end - - local vec = { - x = p.x - s.x, - z = p.z - s.z - } - - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - - if p.x > s.x then yaw = yaw + math_pi end - - yaw = set_yaw(self, yaw, 0, dtime) - - -- move towards enemy if beyond mob reach - if dist > self.reach then - - -- path finding by rnd - if self.pathfinding -- only if mob has pathfinding enabled - and enable_pathfinding then - - smart_mobs(self, s, p, dist, dtime) - end - - if is_at_cliff_or_danger(self) then - - set_velocity(self, 0) - set_animation(self, "stand") - local yaw = self.object:get_yaw() or 0 - yaw = set_yaw(self, yaw + 0.78, 8) - else - - if self.path.stuck then - set_velocity(self, self.walk_velocity) - else - set_velocity(self, self.run_velocity) - end - - if self.animation and self.animation.run_start then - set_animation(self, "run") - else - set_animation(self, "walk") - end - end - - else -- rnd: if inside reach range - - self.path.stuck = false - self.path.stuck_timer = 0 - self.path.following = false -- not stuck anymore - - set_velocity(self, 0) - - if not self.custom_attack then - - if self.timer > 1 then - - self.timer = 0 - - if self.double_melee_attack - and math_random(1, 2) == 1 then - set_animation(self, "punch2") - else - set_animation(self, "punch") - end - - local p2 = p - local s2 = s - - p2.y = p2.y + .5 - s2.y = s2.y + .5 - - if line_of_sight(self, p2, s2) == true then - - -- play attack sound - mob_sound(self, "attack") - - -- punch player (or what player is attached to) - local attached = self.attack:get_attach() - if attached then - self.attack = attached - end - self.attack:punch(self.object, 1.0, { - full_punch_interval = 1.0, - damage_groups = {fleshy = self.damage} - }, nil) - end - end - else -- call custom attack every second - if self.custom_attack - and self.timer > 1 then - - self.timer = 0 - - self.custom_attack(self, p) - end - end - end - - elseif self.attack_type == "shoot" - or (self.attack_type == "dogshoot" and dogswitch(self, dtime) == 1) - or (self.attack_type == "dogshoot" and dist > self.reach and dogswitch(self) == 0) then - - p.y = p.y - .5 - s.y = s.y + .5 - - local dist = vector.distance(p, s) - local vec = { - x = p.x - s.x, - y = p.y - s.y, - z = p.z - s.z - } - - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - - if p.x > s.x then yaw = yaw + math_pi end - - yaw = set_yaw(self, yaw, 0, dtime) - - set_velocity(self, 0) - - local p = self.object:get_pos() - p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2 - - if self.shoot_interval - and self.timer > self.shoot_interval - and not minetest_raycast(p, self.attack:get_pos(), false, false):next() - and math_random(1, 100) <= 60 then - - self.timer = 0 - set_animation(self, "shoot") - - -- play shoot attack sound - mob_sound(self, "shoot_attack") - - -- Shoot arrow - if minetest_registered_entities[self.arrow] then - - local arrow, ent - local v = 1 - if not self.shoot_arrow then - self.firing = true - minetest_after(1, function() - self.firing = false - end) - arrow = minetest_add_entity(p, self.arrow) - ent = arrow:get_luaentity() - if ent.velocity then - v = ent.velocity - end - ent.switch = 1 - ent.owner_id = tostring(self.object) -- add unique owner id to arrow - end - - local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5 - -- offset makes shoot aim accurate - vec.y = vec.y + self.shoot_offset - vec.x = vec.x * (v / amount) - vec.y = vec.y * (v / amount) - vec.z = vec.z * (v / amount) - if self.shoot_arrow then - vec = vector.normalize(vec) - self:shoot_arrow(p, vec) - else - arrow:set_velocity(vec) - end - end - end - end - end - ]]-- end diff --git a/mods/ENTITIES/mcl_mobs/backup_code_api.lua b/mods/ENTITIES/mcl_mobs/backup_code_api.lua index 85cf0db5f0..88b6eb0414 100644 --- a/mods/ENTITIES/mcl_mobs/backup_code_api.lua +++ b/mods/ENTITIES/mcl_mobs/backup_code_api.lua @@ -2593,4 +2593,559 @@ local mob_detach_child = function(self, child) self.driver = nil end -end \ No newline at end of file +end + + --[[ + + if self.state == "stand" then + + if math_random(1, 4) == 1 then + + local lp = nil + local s = self.object:get_pos() + local objs = minetest_get_objects_inside_radius(s, 3) + + for n = 1, #objs do + + if objs[n]:is_player() then + lp = objs[n]:get_pos() + break + end + end + + -- look at any players nearby, otherwise turn randomly + if lp then + + local vec = { + x = lp.x - s.x, + z = lp.z - s.z + } + + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + + if lp.x > s.x then yaw = yaw + math_pi end + else + yaw = yaw + math_random(-0.5, 0.5) + end + + yaw = set_yaw(self, yaw, 8) + end + + set_velocity(self, 0) + set_animation(self, "stand") + + -- npc's ordered to stand stay standing + if self.type ~= "npc" + or self.order ~= "stand" then + + if self.walk_chance ~= 0 + and self.facing_fence ~= true + and math_random(1, 100) <= self.walk_chance + and is_at_cliff_or_danger(self) == false then + + set_velocity(self, self.walk_velocity) + self.state = "walk" + set_animation(self, "walk") + end + end + + elseif self.state == "walk" then + + local s = self.object:get_pos() + local lp = nil + + -- is there something I need to avoid? + if (self.water_damage > 0 + and self.lava_damage > 0) + or self.breath_max ~= -1 then + + lp = minetest_find_node_near(s, 1, {"group:water", "group:lava"}) + + elseif self.water_damage > 0 then + + lp = minetest_find_node_near(s, 1, {"group:water"}) + + elseif self.lava_damage > 0 then + + lp = minetest_find_node_near(s, 1, {"group:lava"}) + + elseif self.fire_damage > 0 then + + lp = minetest_find_node_near(s, 1, {"group:fire"}) + + end + + local is_in_danger = false + if lp then + -- If mob in or on dangerous block, look for land + if (is_node_dangerous(self, self.standing_in) or + is_node_dangerous(self, self.standing_on)) or (is_node_waterhazard(self, self.standing_in) or is_node_waterhazard(self, self.standing_on)) and (not self.fly) then + is_in_danger = true + + -- If mob in or on dangerous block, look for land + if is_in_danger then + -- Better way to find shore - copied from upstream + lp = minetest_find_nodes_in_area_under_air( + {x = s.x - 5, y = s.y - 0.5, z = s.z - 5}, + {x = s.x + 5, y = s.y + 1, z = s.z + 5}, + {"group:solid"}) + + lp = #lp > 0 and lp[math_random(#lp)] + + -- did we find land? + if lp then + + local vec = { + x = lp.x - s.x, + z = lp.z - s.z + } + + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + + + if lp.x > s.x then yaw = yaw + math_pi end + + -- look towards land and move in that direction + yaw = set_yaw(self, yaw, 6) + set_velocity(self, self.walk_velocity) + + end + end + + -- A danger is near but mob is not inside + else + + -- Randomly turn + if math_random(1, 100) <= 30 then + yaw = yaw + math_random(-0.5, 0.5) + yaw = set_yaw(self, yaw, 8) + end + end + + yaw = set_yaw(self, yaw, 8) + + -- otherwise randomly turn + elseif math_random(1, 100) <= 30 then + + yaw = yaw + math_random(-0.5, 0.5) + yaw = set_yaw(self, yaw, 8) + end + + -- stand for great fall or danger or fence in front + local cliff_or_danger = false + if is_in_danger then + cliff_or_danger = is_at_cliff_or_danger(self) + end + if self.facing_fence == true + or cliff_or_danger + or math_random(1, 100) <= 30 then + + set_velocity(self, 0) + self.state = "stand" + set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) + else + + set_velocity(self, self.walk_velocity) + + if flight_check(self) + and self.animation + and self.animation.fly_start + and self.animation.fly_end then + set_animation(self, "fly") + else + set_animation(self, "walk") + end + end + + -- runaway when punched + elseif self.state == "runaway" then + + self.runaway_timer = self.runaway_timer + 1 + + -- stop after 5 seconds or when at cliff + if self.runaway_timer > 5 + or is_at_cliff_or_danger(self) then + self.runaway_timer = 0 + set_velocity(self, 0) + self.state = "stand" + set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) + else + set_velocity(self, self.run_velocity) + set_animation(self, "run") + end + + -- attack routines (explode, dogfight, shoot, dogshoot) + elseif self.state == "attack" then + + local s = self.object:get_pos() + local p = self.attack:get_pos() or s + + -- stop attacking if player invisible or out of range + if not self.attack + or not self.attack:get_pos() + or not object_in_range(self, self.attack) + or self.attack:get_hp() <= 0 + or (self.attack:is_player() and mobs.invis[ self.attack:get_player_name() ]) then + + self.state = "stand" + set_velocity(self, 0) + set_animation(self, "stand") + self.attack = nil + self.v_start = false + self.timer = 0 + self.blinktimer = 0 + self.path.way = nil + + return + end + + -- calculate distance from mob and enemy + local dist = vector.distance(p, s) + + if self.attack_type == "explode" then + + local vec = { + x = p.x - s.x, + z = p.z - s.z + } + + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + + if p.x > s.x then yaw = yaw + math_pi end + + yaw = set_yaw(self, yaw, 0, dtime) + + local node_break_radius = self.explosion_radius or 1 + local entity_damage_radius = self.explosion_damage_radius + or (node_break_radius * 2) + + -- start timer when in reach and line of sight + if not self.v_start + and dist <= self.reach + and line_of_sight(self, s, p, 2) then + + self.v_start = true + self.timer = 0 + self.blinktimer = 0 + mob_sound(self, "fuse", nil, false) + + -- stop timer if out of reach or direct line of sight + elseif self.allow_fuse_reset + and self.v_start + and (dist >= self.explosiontimer_reset_radius + or not line_of_sight(self, s, p, 2)) then + self.v_start = false + self.timer = 0 + self.blinktimer = 0 + self.blinkstatus = false + remove_texture_mod(self, "^[brighten") + end + + -- walk right up to player unless the timer is active + if self.v_start and (self.stop_to_explode or dist < self.reach) then + set_velocity(self, 0) + else + set_velocity(self, self.run_velocity) + end + + if self.animation and self.animation.run_start then + set_animation(self, "run") + else + set_animation(self, "walk") + end + + if self.v_start then + + self.timer = self.timer + dtime + self.blinktimer = (self.blinktimer or 0) + dtime + + if self.blinktimer > 0.2 then + + self.blinktimer = 0 + + if self.blinkstatus then + remove_texture_mod(self, "^[brighten") + else + add_texture_mod(self, "^[brighten") + end + + self.blinkstatus = not self.blinkstatus + end + + if self.timer > self.explosion_timer then + + local pos = self.object:get_pos() + + if mod_explosions then + if mobs_griefing and not minetest_is_protected(pos, "") then + mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object) + else + minetest_sound_play(self.sounds.explode, { + pos = pos, + gain = 1.0, + max_hear_distance = self.sounds.distance or 32 + }, true) + + entity_physics(pos, entity_damage_radius) + effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0) + end + end + mcl_burning.extinguish(self.object) + self.object:remove() + + return true + end + end + + elseif self.attack_type == "dogfight" + or (self.attack_type == "dogshoot" and dogswitch(self, dtime) == 2) + or (self.attack_type == "dogshoot" and dist <= self.reach and dogswitch(self) == 0) then + + if self.fly + and dist > self.reach then + + local p1 = s + local me_y = math_floor(p1.y) + local p2 = p + local p_y = math_floor(p2.y + 1) + local v = self.object:get_velocity() + + if flight_check(self, s) then + + if me_y < p_y then + + self.object:set_velocity({ + x = v.x, + y = 1 * self.walk_velocity, + z = v.z + }) + + elseif me_y > p_y then + + self.object:set_velocity({ + x = v.x, + y = -1 * self.walk_velocity, + z = v.z + }) + end + else + if me_y < p_y then + + self.object:set_velocity({ + x = v.x, + y = 0.01, + z = v.z + }) + + elseif me_y > p_y then + + self.object:set_velocity({ + x = v.x, + y = -0.01, + z = v.z + }) + end + end + + end + + -- rnd: new movement direction + if self.path.following + and self.path.way + and self.attack_type ~= "dogshoot" then + + -- no paths longer than 50 + if #self.path.way > 50 + or dist < self.reach then + self.path.following = false + return + end + + local p1 = self.path.way[1] + + if not p1 then + self.path.following = false + return + end + + if math_abs(p1.x-s.x) + math_abs(p1.z - s.z) < 0.6 then + -- reached waypoint, remove it from queue + table.remove(self.path.way, 1) + end + + -- set new temporary target + p = {x = p1.x, y = p1.y, z = p1.z} + end + + local vec = { + x = p.x - s.x, + z = p.z - s.z + } + + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + + if p.x > s.x then yaw = yaw + math_pi end + + yaw = set_yaw(self, yaw, 0, dtime) + + -- move towards enemy if beyond mob reach + if dist > self.reach then + + -- path finding by rnd + if self.pathfinding -- only if mob has pathfinding enabled + and enable_pathfinding then + + smart_mobs(self, s, p, dist, dtime) + end + + if is_at_cliff_or_danger(self) then + + set_velocity(self, 0) + set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) + else + + if self.path.stuck then + set_velocity(self, self.walk_velocity) + else + set_velocity(self, self.run_velocity) + end + + if self.animation and self.animation.run_start then + set_animation(self, "run") + else + set_animation(self, "walk") + end + end + + else -- rnd: if inside reach range + + self.path.stuck = false + self.path.stuck_timer = 0 + self.path.following = false -- not stuck anymore + + set_velocity(self, 0) + + if not self.custom_attack then + + if self.timer > 1 then + + self.timer = 0 + + if self.double_melee_attack + and math_random(1, 2) == 1 then + set_animation(self, "punch2") + else + set_animation(self, "punch") + end + + local p2 = p + local s2 = s + + p2.y = p2.y + .5 + s2.y = s2.y + .5 + + if line_of_sight(self, p2, s2) == true then + + -- play attack sound + mob_sound(self, "attack") + + -- punch player (or what player is attached to) + local attached = self.attack:get_attach() + if attached then + self.attack = attached + end + self.attack:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = self.damage} + }, nil) + end + end + else -- call custom attack every second + if self.custom_attack + and self.timer > 1 then + + self.timer = 0 + + self.custom_attack(self, p) + end + end + end + + elseif self.attack_type == "shoot" + or (self.attack_type == "dogshoot" and dogswitch(self, dtime) == 1) + or (self.attack_type == "dogshoot" and dist > self.reach and dogswitch(self) == 0) then + + p.y = p.y - .5 + s.y = s.y + .5 + + local dist = vector.distance(p, s) + local vec = { + x = p.x - s.x, + y = p.y - s.y, + z = p.z - s.z + } + + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + + if p.x > s.x then yaw = yaw + math_pi end + + yaw = set_yaw(self, yaw, 0, dtime) + + set_velocity(self, 0) + + local p = self.object:get_pos() + p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2 + + if self.shoot_interval + and self.timer > self.shoot_interval + and not minetest_raycast(p, self.attack:get_pos(), false, false):next() + and math_random(1, 100) <= 60 then + + self.timer = 0 + set_animation(self, "shoot") + + -- play shoot attack sound + mob_sound(self, "shoot_attack") + + -- Shoot arrow + if minetest_registered_entities[self.arrow] then + + local arrow, ent + local v = 1 + if not self.shoot_arrow then + self.firing = true + minetest_after(1, function() + self.firing = false + end) + arrow = minetest_add_entity(p, self.arrow) + ent = arrow:get_luaentity() + if ent.velocity then + v = ent.velocity + end + ent.switch = 1 + ent.owner_id = tostring(self.object) -- add unique owner id to arrow + end + + local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5 + -- offset makes shoot aim accurate + vec.y = vec.y + self.shoot_offset + vec.x = vec.x * (v / amount) + vec.y = vec.y * (v / amount) + vec.z = vec.z * (v / amount) + if self.shoot_arrow then + vec = vector.normalize(vec) + self:shoot_arrow(p, vec) + else + arrow:set_velocity(vec) + end + end + end + end + end + ]]-- \ No newline at end of file