Leaves drop sticks, sticks craft to wood planks, leaves craft to sticks, find stone and steel axes and picks in villages

master
Brandon 2015-08-29 14:41:29 -05:00
parent 23617c6d82
commit d864bea27a
6 changed files with 483 additions and 425 deletions

View File

@ -7,6 +7,18 @@ minetest.register_craft({
}
})
minetest.register_craft({
output = "default:stick",
type = "shapeless",
recipe = { "default:leaves","default:leaves","default:leaves","default:leaves" },
})
minetest.register_craft({
output = "default:wood",
type = "shapeless",
recipe = { "default:stick","default:stick","default:stick","default:stick" },
})
minetest.register_craft({
output = 'default:junglewood 4',
recipe = {

View File

@ -398,6 +398,10 @@ minetest.register_node("default:leaves", {
items = {'default:sapling'},
rarity = 20,
},
{
items = {'default:stick'},
rarity = 40,
},
{
-- player will get leaves only if he get no saplings,
-- this is because max_items is 1
@ -578,7 +582,7 @@ minetest.register_node("default:water_source", {
-- New-style water source material (mostly unused)
{
name="default_water_source_animated.png",
animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0},
animation={type="vertical_frames", aspect_w=128, aspect_h=128, length=2.0},
backface_culling = false,
}
},

View File

@ -132,7 +132,7 @@ minetest.register_on_generated( function (minp, maxp, blockseed)
end
end
vm:set_data(data)
vm:calc_lighting()
vm:calc_lighting(emin,emax)
vm:write_to_map(data)
for _,v in ipairs(spawn) do
mobs:spawn_mob(v.pos,v.mob)

View File

@ -17,4 +17,9 @@ minetest.after(5,function()
ADD_RCC2({"experience:6_exp", 60, 2, 1, chest_storage=1, chest_private=1, shelf=1})
ADD_RCC2({"experience:9_exp", 40, 1, 1, chest_storage=1, chest_private=1, shelf=1})
ADD_RCC2({"experience:12_exp", 30, 1, 1, chest_storage=1, chest_private=1, shelf=1})
ADD_RCC2({"default:axe_stone", 20, 1, 0, chest_storage=1, chest_private=1, shelf=1})
ADD_RCC2({"default:axe_steel", 5, 1, 0, chest_storage=1, chest_private=1, shelf=1})
ADD_RCC2({"default:pick_stone", 20, 1, 0, chest_storage=1, chest_private=1, shelf=1})
ADD_RCC2({"default:pick_steel", 5, 1, 0, chest_storage=1, chest_private=1, shelf=1})
end)

View File

@ -48,7 +48,7 @@ mg_villages.villages_at_point = function(minp, noise1)
local height = pr:next(1, 5)
-- villages of a size >= 40 are always placed at a height of 1
if( size >= 40 ) then
height = 1;
height = 5;
-- slightly smaller but still relatively large villages have a deterministic height now as well
elseif( size >= 30 ) then
height = 40-height;
@ -813,7 +813,7 @@ mg_villages.house_in_one_mapchunk = function( minp, mapchunk_size, vnoise )
if( mg_villages.all_villages and mg_villages.all_villages[ village_id ] and mg_villages.all_villages[ village_id ].optimal_height) then
village.optimal_height = mg_villages.all_villages[ village_id ].optimal_height;
village.vh = mg_villages.all_villages[ village_id ].optimal_height;
--village.vh = mg_villages.all_villages[ village_id ].optimal_height;
village.artificial_snow = mg_villages.all_villages[ village_id ].artificial_snow;
end

View File

@ -1,5 +1,9 @@
mobs = {}
mobs.mob_list = { npc={}, barbarian={}, monster={}, animal={}}
mobs.api_throttle = 5 -- limits the amount of intense operations that can happen per second
mobs.api_icount = 0
mobs.api_timer = 0
function mobs:register_mob(name, def)
table.insert(mobs.mob_list[def.type],name)
minetest.register_entity(name, {
@ -34,7 +38,7 @@ function mobs:register_mob(name, def)
shoot_interval = def.shoot_interval,
sounds = def.sounds,
animation = def.animation,
follow = def.follow,
follow = def.follow or nil,
jump = def.jump,
exp_min = def.exp_min or 0,
exp_max = def.exp_max or 0,
@ -248,419 +252,7 @@ function mobs:register_mob(name, def)
end
end,
on_step = function(self, dtime)
if self.type == "monster" and minetest.setting_getbool("only_peaceful_mobs") then
self.object:remove()
end
if self.lifetimer ~= false then
self.lifetimer = self.lifetimer - dtime
if self.lifetimer <= 0 and not self.tamed and self.type ~= "npc" then
local player_count = 0
for _,obj in ipairs(minetest.get_objects_inside_radius(self.object:getpos(), 10)) do
if obj:is_player() then
player_count = player_count+1
end
end
if player_count == 0 and self.state ~= "attack" then
minetest.log("action","lifetimer expired, removed mob "..self.name)
self.object:remove()
return
end
end
end
if self.object:getvelocity().y > 0.1 then
local yaw = self.object:getyaw()
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
local x = math.sin(yaw) * -2
local z = math.cos(yaw) * 2
self.object:setacceleration({x=x, y=-10, z=z})
else
self.object:setacceleration({x=0, y=-10, z=0})
end
if self.disable_fall_damage and self.object:getvelocity().y == 0 then
if not self.old_y then
self.old_y = self.object:getpos().y
else
local d = self.old_y - self.object:getpos().y
if d > 5 then
local damage = d-5
self.object:set_hp(self.object:get_hp()-damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
self.old_y = self.object:getpos().y
end
end
-- if pause state then this is where the loop ends
-- pause is only set after a monster is hit
if self.pause_timer > 0 then
self.pause_timer = self.pause_timer - dtime
if self.pause_timer <= 0 then
self.pause_timer = 0
end
return
end
self.timer = self.timer+dtime
if self.state ~= "attack" then
if self.timer < 1 then
return
end
self.timer = 0
end
if self.sounds and self.sounds.random and math.random(1, 100) <= 1 then
minetest.sound_play(self.sounds.random, {object = self.object})
end
local do_env_damage = function(self)
local pos = self.object:getpos()
local n = minetest.get_node(pos)
if self.light_damage and self.light_damage ~= 0
and pos.y>0
and minetest.get_node_light(pos)
and minetest.get_node_light(pos) > 4
and minetest.get_timeofday() > 0.2
and minetest.get_timeofday() < 0.8
then
self.object:set_hp(self.object:get_hp()-self.light_damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
if self.water_damage and self.water_damage ~= 0 and
minetest.get_item_group(n.name, "water") ~= 0
then
self.object:set_hp(self.object:get_hp()-self.water_damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
if self.lava_damage and self.lava_damage ~= 0 and
minetest.get_item_group(n.name, "lava") ~= 0
then
self.object:set_hp(self.object:get_hp()-self.lava_damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
end
self.env_damage_timer = self.env_damage_timer + dtime
if self.state == "attack" and self.env_damage_timer > 1 then
self.env_damage_timer = 0
do_env_damage(self)
elseif self.state ~= "attack" then
do_env_damage(self)
end
-- FIND SOMEONE TO ATTACK
if ( self.type == "monster" or self.type == "barbarian" ) and minetest.setting_getbool("enable_damage") and self.state ~= "attack" then
local s = self.object:getpos()
local inradius = minetest.get_objects_inside_radius(s,self.view_range)
local player = nil
local type = nil
for _,oir in ipairs(inradius) do
if oir:is_player() then
player = oir
type = "player"
else
local obj = oir:get_luaentity()
if obj then
player = obj.object
type = obj.type
end
end
if type == "player" or type == "npc" then
local s = self.object:getpos()
local p = player:getpos()
local sp = s
p.y = p.y + 1
sp.y = sp.y + 1 -- aim higher to make looking up hills more realistic
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
--print("Dist "..tostring(dist) .. " < " .. tostring(self.view_range) .. " in_fov " .. tostring(self.in_fov(self,p)))
if dist < self.view_range and self.in_fov(self,p) then
if minetest.line_of_sight(sp,p,2) == true then
self.do_attack(self,player,dist)
break
else
--print("no line of site")
end
end
end
end
end
-- NPC FIND A MONSTER TO ATTACK
if self.type == "npc" and self.attacks_monsters and self.state ~= "attack" then
local s = self.object:getpos()
local inradius = minetest.get_objects_inside_radius(s,self.view_range)
for _, oir in pairs(inradius) do
local obj = oir:get_luaentity()
if obj then
if obj.type == "monster" or obj.type == "barbarian" then
-- attack monster
local p = obj.object:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
self.do_attack(self,obj.object,dist)
break
end
end
end
end
if self.follow ~= "" and not self.following then
for _,player in pairs(minetest.get_connected_players()) do
local s = self.object:getpos()
local p = player:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if self.view_range and dist < self.view_range then
self.following = player
break
end
end
end
if self.following and self.following:is_player() then
if self.following:get_wielded_item():get_name() ~= self.follow then
self.following = nil
else
local s = self.object:getpos()
local p = self.following:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if dist > self.view_range then
self.following = nil
self.v_start = false
else
local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
local yaw = math.atan(vec.z/vec.x)+math.pi/2
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
if p.x > s.x then
yaw = yaw+math.pi
end
self.object:setyaw(yaw)
if dist > 2 then
if not self.v_start then
self.v_start = true
self.set_velocity(self, self.walk_velocity)
else
if self.jump == true and self.get_velocity(self) <= 1.5 and self.object:getvelocity().y == 0 then
local v = self.object:getvelocity()
v.y = 6
self.object:setvelocity(v)
end
self.set_velocity(self, self.walk_velocity)
end
self:set_animation("walk")
else
self.v_start = false
self.set_velocity(self, 0)
self:set_animation("stand")
end
return
end
end
end
if self.state == "stand" then
-- randomly turn
math.randomseed(os.clock())
if math.random(1, 100) < self.activity_level then
-- if there is a player nearby look at them
local lp = nil
local s = self.object:getpos()
if self.type == "npc" then
local o = minetest.get_objects_inside_radius(self.object:getpos(), 3)
local yaw = 0
for _,o in ipairs(o) do
if o:is_player() then
lp = o:getpos()
break
end
end
end
if lp ~= nil then
mobs:face_pos(self,lp)
else
local yaw = self.object:getyaw()+((math.random(0,360)-270)/180*math.pi)
self.object:setyaw(yaw)
end
end
self.set_velocity(self, 0)
self.set_animation(self, "stand")
if math.random(1, 100) <= self.activity_level and self.stationary == false then
self.set_velocity(self, self.walk_velocity)
self.state = "walk"
self.set_animation(self, "walk")
end
elseif self.state == "walk" or self.state == "path" then
if ( math.random(1, 100) <= 30 or ( self.get_velocity(self) < self.walk_velocity ) ) and self.state ~= "path" then
self.object:setyaw(self.object:getyaw()+((math.random(0,360)-270)/180*math.pi))
end
if self.jump == true and self.get_velocity(self) <= 0.5 and self.object:getvelocity().y == 0 then
local v = self.object:getvelocity()
v.y = 5
self.object:setvelocity(v)
end
self:set_animation("walk")
self.set_velocity(self, self.walk_velocity)
if math.random(1, 100) <= 30 and self.state ~= "path" then
self.set_velocity(self, 0)
self.state = "stand"
self:set_animation("stand")
end
if self.state == "path" then
self.leg_timer = self.leg_timer + dtime
self.check_path(self)
end
elseif self.state == "attack" and self.attack_type == "dogfight" then
if not self.attack.player or not self.attack.player:getpos() then
self.state = "stand"
self:set_animation("stand")
return
end
local s = self.object:getpos()
local p = self.attack.player:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if dist > self.view_range or self.attack.player:get_hp() <= 0 then
self.state = "stand"
self.v_start = false
self.set_velocity(self, 0)
self.attack = {player=nil, dist=nil}
self:set_animation("stand")
return
else
self.attack.dist = dist
end
local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
local yaw = math.atan(vec.z/vec.x)+math.pi/2
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
if p.x > s.x then
yaw = yaw+math.pi
end
self.object:setyaw(yaw)
if self.attack.dist > self.attack_range then
if not self.v_start then
self.v_start = true
self.set_velocity(self, self.run_velocity)
else
if self.jump == true and self.get_velocity(self) <= 0.5 and self.object:getvelocity().y == 0 then
local v = self.object:getvelocity()
v.y = 5
self.object:setvelocity(v)
end
self.set_velocity(self, self.run_velocity)
end
self:set_animation("run")
else
self.set_velocity(self, 0)
self:set_animation("punch")
self.v_start = false
if self.timer > 1 then
self.timer = 0
local p2 = p
local s2 = s
p2.y = p2.y + 1.5
s2.y = s2.y + 1.5
if minetest.line_of_sight(p2,s2) == true then
if self.sounds and self.sounds.attack then
minetest.sound_play(self.sounds.attack, {object = self.object})
end
if self.attack_function ~= nil then
self.attack_function(self,self.attack.player)
else
self.attack.player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups = {fleshy=self.damage}
}, vec)
end
if self.attack.player:get_hp() <= 0 then
self.state = "stand"
self:set_animation("stand")
end
end
end
end
elseif self.state == "attack" and self.attack_type == "shoot" then
if not self.attack.player or not self.attack.player:is_player() then
self.state = "stand"
self:set_animation("stand")
return
end
local s = self.object:getpos()
local p = self.attack.player:getpos()
p.y = p.y - .5
s.y = s.y + .5
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if dist > self.view_range or self.attack.player:get_hp() <= 0 then
self.state = "stand"
self.v_start = false
self.set_velocity(self, 0)
if self.type ~= "npc" then
self.attack = {player=nil, dist=nil}
end
self:set_animation("stand")
return
else
self.attack.dist = dist
end
local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
local yaw = math.atan(vec.z/vec.x)+math.pi/2
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
if p.x > s.x then
yaw = yaw+math.pi
end
self.object:setyaw(yaw)
self.set_velocity(self, 0)
if self.timer > self.shoot_interval and math.random(1, 100) <= 60 then
self.timer = 0
self:set_animation("punch")
if self.sounds and self.sounds.attack then
minetest.sound_play(self.sounds.attack, {object = self.object})
end
local p = self.object:getpos()
p.y = p.y + self.arrow_offset
local obj = minetest.add_entity(p, self.arrow)
local amount = (vec.x^2+vec.y^2+vec.z^2)^0.5
local v = obj:get_luaentity().velocity
vec.y = vec.y
vec.x = vec.x*v/amount
vec.y = vec.y*v/amount
vec.z = vec.z*v/amount
obj:setvelocity(vec)
if obj:get_luaentity().drop_rate ~= nil then
obj:setacceleration({x=vec.x, y=obj:get_luaentity().drop_rate, z=vec.z})
end
end
end
end,
on_step = mobs.on_step,
on_activate = function(self, staticdata, dtime_s)
-- reset HP
@ -780,8 +372,8 @@ function mobs:register_mob(name, def)
r = r * ( tflp / tool_capabilities.full_punch_interval )
end
else
kb = kb * ( tflp / 1 )
r = r * ( tflp / 1 )
kb = kb * ( tflp / 1 )
r = r * ( tflp / 1 )
end
local ykb=2
@ -824,6 +416,7 @@ function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_o
interval = 30,
chance = chance,
action = function(pos, node, _, active_object_count_wider)
local bstart = os.clock()
if active_object_count_wider > active_object_count then
return
end
@ -840,6 +433,10 @@ function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_o
return
end]]
if pos.y > max_height then
return
end
pos.y = pos.y+1
if not minetest.get_node_light(pos) then
return
@ -850,10 +447,7 @@ function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_o
if minetest.get_node_light(pos) < min_light then
return
end
if pos.y > max_height then
return
end
if min_dist == nil then
min_dist = {x=-1,z=-1}
end
@ -883,6 +477,7 @@ end
function mobs:spawn_mob(pos,name)
-- make sure the nodes above are walkable
minetest.log("action","Attempting to spawn "..name)
local nodename = minetest.get_node(pos).name
if minetest.registered_nodes[nodename] ~= nil then
@ -896,8 +491,8 @@ function mobs:spawn_mob(pos,name)
end
pos.y = pos.y - 1
end
local mob = minetest.add_entity(pos, name)
-- setup the hp, armor, drops, etc... for this specific mob
local distance_rating = ( ( get_distance({x=0,y=0,z=0},pos) ) / 15000 )
if mob ~= nil then
@ -992,6 +587,432 @@ function mobs:face_pos(self,pos)
return yaw
end
function mobs.on_step(self,dtime)
if self.type == "monster" and minetest.setting_getbool("only_peaceful_mobs") then
self.object:remove()
return
end
if self.lifetimer ~= false then
self.lifetimer = self.lifetimer - dtime
if self.lifetimer <= 0 and not self.tamed and self.type ~= "npc" then
local player_count = 0
for _,obj in ipairs(minetest.get_objects_inside_radius(self.object:getpos(), 10)) do
if obj:is_player() then
player_count = player_count+1
end
end
if player_count == 0 and self.state ~= "attack" then
minetest.log("action","lifetimer expired, removed mob "..self.name)
self.object:remove()
return
end
end
end
if self.object:getvelocity().y > 0.1 then
local yaw = self.object:getyaw()
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
local x = math.sin(yaw) * -2
local z = math.cos(yaw) * 2
self.object:setacceleration({x=x, y=-10, z=z})
else
self.object:setacceleration({x=0, y=-10, z=0})
end
if self.disable_fall_damage and self.object:getvelocity().y == 0 then
if not self.old_y then
self.old_y = self.object:getpos().y
else
local d = self.old_y - self.object:getpos().y
if d > 5 then
local damage = d-5
self.object:set_hp(self.object:get_hp()-damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
self.old_y = self.object:getpos().y
end
end
-- if pause state then this is where the loop ends
-- pause is only set after a monster is hit
if self.pause_timer > 0 then
self.pause_timer = self.pause_timer - dtime
if self.pause_timer <= 0 then
self.pause_timer = 0
end
return
end
self.timer = self.timer+dtime
if self.state ~= "attack" then
if self.timer < 1 then
return
end
self.timer = 0
end
if self.sounds and self.sounds.random and math.random(1, 100) <= 1 then
minetest.sound_play(self.sounds.random, {object = self.object})
end
local do_env_damage = function(self)
local pos = self.object:getpos()
local n = minetest.get_node(pos)
if self.light_damage and self.light_damage ~= 0
and pos.y>0
and minetest.get_node_light(pos)
and minetest.get_node_light(pos) > 4
and minetest.get_timeofday() > 0.2
and minetest.get_timeofday() < 0.8
then
self.object:set_hp(self.object:get_hp()-self.light_damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
if self.water_damage and self.water_damage ~= 0 and
minetest.get_item_group(n.name, "water") ~= 0
then
self.object:set_hp(self.object:get_hp()-self.water_damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
if self.lava_damage and self.lava_damage ~= 0 and
minetest.get_item_group(n.name, "lava") ~= 0
then
self.object:set_hp(self.object:get_hp()-self.lava_damage)
if self.object:get_hp() == 0 then
self.object:remove()
end
end
end
self.env_damage_timer = self.env_damage_timer + dtime
if self.state == "attack" and self.env_damage_timer > 1 then
self.env_damage_timer = 0
do_env_damage(self)
elseif self.state ~= "attack" then
do_env_damage(self)
end
-- if they are attacking that should take priority over everything else so move it up here
if self.state == "attack" and self.attack_type == "dogfight" then
if not self.attack.player or not self.attack.player:getpos() then
self.state = "stand"
self:set_animation("stand")
return
end
local s = self.object:getpos()
local p = self.attack.player:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if dist > self.view_range or self.attack.player:get_hp() <= 0 then
self.state = "stand"
self.v_start = false
self.set_velocity(self, 0)
self.attack = {player=nil, dist=nil}
self:set_animation("stand")
return
else
self.attack.dist = dist
end
local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
local yaw = math.atan(vec.z/vec.x)+math.pi/2
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
if p.x > s.x then
yaw = yaw+math.pi
end
self.object:setyaw(yaw)
if self.attack.dist > self.attack_range then
if not self.v_start then
self.v_start = true
self.set_velocity(self, self.run_velocity)
else
if self.jump == true and self.get_velocity(self) <= 0.5 and self.object:getvelocity().y == 0 then
local v = self.object:getvelocity()
v.y = 5
self.object:setvelocity(v)
end
self.set_velocity(self, self.run_velocity)
end
self:set_animation("run")
else
self.set_velocity(self, 0)
self:set_animation("punch")
self.v_start = false
if self.timer > 1 then
self.timer = 0
local p2 = p
local s2 = s
p2.y = p2.y + 1.5
s2.y = s2.y + 1.5
if minetest.line_of_sight(p2,s2) == true then
if self.sounds and self.sounds.attack then
minetest.sound_play(self.sounds.attack, {object = self.object})
end
if self.attack_function ~= nil then
self.attack_function(self,self.attack.player)
else
self.attack.player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups = {fleshy=self.damage}
}, vec)
end
if self.attack.player:get_hp() <= 0 then
self.state = "stand"
self.v_start = false
self.set_velocity(self, 0)
self.attack = {player=nil, dist=nil}
self:set_animation("stand")
end
end
end
end
return
elseif self.state == "attack" and self.attack_type == "shoot" then
if not self.attack.player or not self.attack.player:is_player() then
self.state = "stand"
self:set_animation("stand")
return
end
local s = self.object:getpos()
local p = self.attack.player:getpos()
p.y = p.y - .5
s.y = s.y + .5
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if dist > self.view_range or self.attack.player:get_hp() <= 0 then
self.state = "stand"
self.v_start = false
self.set_velocity(self, 0)
if self.type ~= "npc" then
self.attack = {player=nil, dist=nil}
end
self:set_animation("stand")
return
else
self.attack.dist = dist
end
local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
local yaw = math.atan(vec.z/vec.x)+math.pi/2
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
if p.x > s.x then
yaw = yaw+math.pi
end
self.object:setyaw(yaw)
self.set_velocity(self, 0)
if self.timer > self.shoot_interval and math.random(1, 100) <= 60 then
self.timer = 0
self:set_animation("punch")
if self.sounds and self.sounds.attack then
minetest.sound_play(self.sounds.attack, {object = self.object})
end
local p = self.object:getpos()
p.y = p.y + self.arrow_offset
local obj = minetest.add_entity(p, self.arrow)
local amount = (vec.x^2+vec.y^2+vec.z^2)^0.5
local v = obj:get_luaentity().velocity
vec.y = vec.y
vec.x = vec.x*v/amount
vec.y = vec.y*v/amount
vec.z = vec.z*v/amount
obj:setvelocity(vec)
if obj:get_luaentity().drop_rate ~= nil then
obj:setacceleration({x=vec.x, y=obj:get_luaentity().drop_rate, z=vec.z})
end
end
return
end
-- FIND SOMEONE TO ATTACK
if ( self.type == "monster" or self.type == "barbarian" ) and minetest.setting_getbool("enable_damage") and self.state ~= "attack" then
if mobs.api_throttling(self) then return end
local s = self.object:getpos()
local inradius = minetest.get_objects_inside_radius(s,self.view_range)
local player = nil
local type = nil
for _,oir in ipairs(inradius) do
if oir:is_player() then
player = oir
type = "player"
else
local obj = oir:get_luaentity()
if obj then
player = obj.object
type = obj.type
end
end
if type == "player" or type == "npc" then
local s = self.object:getpos()
local p = player:getpos()
local sp = s
p.y = p.y + 1
sp.y = sp.y + 1 -- aim higher to make looking up hills more realistic
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
--print("Dist "..tostring(dist) .. " < " .. tostring(self.view_range) .. " in_fov " .. tostring(self.in_fov(self,p)))
if dist < self.view_range and self.in_fov(self,p) then
if minetest.line_of_sight(sp,p,2) == true then
self.do_attack(self,player,dist)
break
else
--print("no line of site")
end
end
end
end
end
-- NPC FIND A MONSTER TO ATTACK
if self.type == "npc" and self.attacks_monsters and self.state ~= "attack" then
if mobs.api_throttling(self) then return end
local s = self.object:getpos()
local inradius = minetest.get_objects_inside_radius(s,self.view_range)
for _, oir in pairs(inradius) do
local obj = oir:get_luaentity()
if obj then
if obj.type == "monster" or obj.type == "barbarian" then
-- attack monster
local p = obj.object:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
self.do_attack(self,obj.object,dist)
break
end
end
end
end
if self.follow ~= nil and not self.following then
if mobs.api_throttling(self) then return end
for _,player in pairs(minetest.get_connected_players()) do
local s = self.object:getpos()
local p = player:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if self.view_range and dist < self.view_range then
self.following = player
break
end
end
end
if self.following and self.following:is_player() then
if self.following:get_wielded_item():get_name() ~= self.follow then
self.following = nil
else
local s = self.object:getpos()
local p = self.following:getpos()
local dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
if dist > self.view_range then
self.following = nil
self.v_start = false
else
local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
local yaw = math.atan(vec.z/vec.x)+math.pi/2
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
if p.x > s.x then
yaw = yaw+math.pi
end
self.object:setyaw(yaw)
if dist > 2 then
if not self.v_start then
self.v_start = true
self.set_velocity(self, self.walk_velocity)
else
if self.jump == true and self.get_velocity(self) <= 1.5 and self.object:getvelocity().y == 0 then
local v = self.object:getvelocity()
v.y = 6
self.object:setvelocity(v)
end
self.set_velocity(self, self.walk_velocity)
end
self:set_animation("walk")
else
self.v_start = false
self.set_velocity(self, 0)
self:set_animation("stand")
end
return
end
end
end
if self.state == "stand" then
-- randomly turn
math.randomseed(os.clock())
if math.random(1, 100) < self.activity_level then
if mobs.api_throttling(self) then return end
-- if there is a player nearby look at them
local lp = nil
local s = self.object:getpos()
if self.type == "npc" then
local o = minetest.get_objects_inside_radius(self.object:getpos(), 3)
local yaw = 0
for _,o in ipairs(o) do
if o:is_player() then
lp = o:getpos()
break
end
end
end
if lp ~= nil then
mobs:face_pos(self,lp)
else
local yaw = self.object:getyaw()+((math.random(0,360)-270)/180*math.pi)
self.object:setyaw(yaw)
end
end
self.set_velocity(self, 0)
self.set_animation(self, "stand")
if math.random(1, 100) <= self.activity_level and self.stationary == false then
self.set_velocity(self, self.walk_velocity)
self.state = "walk"
self.set_animation(self, "walk")
end
elseif self.state == "walk" or self.state == "path" then
if ( math.random(1, 100) <= 30 or ( self.get_velocity(self) < self.walk_velocity ) ) and self.state ~= "path" then
self.object:setyaw(self.object:getyaw()+((math.random(0,360)-270)/180*math.pi))
end
if self.jump == true and self.get_velocity(self) <= 0.5 and self.object:getvelocity().y == 0 then
local v = self.object:getvelocity()
v.y = 5
self.object:setvelocity(v)
end
self:set_animation("walk")
self.set_velocity(self, self.walk_velocity)
if math.random(1, 100) <= 30 and self.state ~= "path" then
self.set_velocity(self, 0)
self.state = "stand"
self:set_animation("stand")
end
if self.state == "path" then
self.leg_timer = self.leg_timer + dtime
self.check_path(self)
end
end
end
function get_distance(pos1,pos2)
if ( pos1 ~= nil and pos2 ~= nil ) then
@ -1046,3 +1067,19 @@ local weapon = player:get_wielded_item()
end
end
function mobs.global_step(dtime)
mobs.api_timer = mobs.api_timer + dtime
if mobs.api_timer >= 1 then
mobs.api_icount = 0
mobs.api_timer = 0
end
end
function mobs.api_throttling(self)
if mobs.api_icount > mobs.api_throttle then
return true
end
mobs.api_icount = mobs.api_icount + 1
self.timer = -2
return false
end