2015-07-12 21:12:53 +01:00

210 lines
6.1 KiB
Lua

local FREE_ROAMING = true
local WALKING_SPEED = 1
local RUNNING_SPEED = 2
local FOLLOW_RADIUS_MIN = 5
local FOLLOW_RADIUS_MAX = 30
local AVOIDED_NODES = {
"ignore",
"default:water_source",
"default:water_flowing",
"default:lava_source",
"default:lava_flowing",
}
local ANIMATION = {
["Stand"] = {id=1, state=NPCF_ANIM_STAND},
["Sit"] = {id=2, state=NPCF_ANIM_SIT},
["Lay"] = {id=3, state=NPCF_ANIM_LAY},
["Mine"] = {id=4, state=NPCF_ANIM_MINE},
}
local function get_target_player(self)
local target_player = nil
local min_dist = FOLLOW_RADIUS_MAX
for _,player in ipairs(minetest.get_connected_players()) do
if player then
local pos = player:getpos()
if pos then
local dist = vector.distance(pos, pos)
if dist < min_dist then
target_player = player
min_dist = dist
end
end
end
end
return target_player
end
npcf:register_npc("npcf_deco:npc" ,{
description = "Decorative NPC",
mesh = "npcf_deco.x",
textures = {"npcf_deco_skin.png"},
animation_speed = 12,
animation = {
stand_START = 0,
stand_END = 79,
sit_START = 81,
sit_END = 160,
lay_START = 162,
lay_END = 166,
walk_START = 168,
walk_END = 187,
mine_START = 189,
mine_END = 198,
run_START = 221,
run_END = 240,
},
metadata = {
free_roaming = "false",
follow_players = "false",
anim_stop = "Stand",
},
var = {
speed = 1,
avoid_dir = 1,
last_pos = {x=0,y=0,z=0},
target = nil,
},
stepheight = 1.1,
inventory_image = "npcf_deco_inv.png",
on_construct = function(self)
self.object:setvelocity({x=0, y=0, z=0})
self.object:setacceleration({x=0, y=-10, z=0})
npcf:set_animation(self, ANIMATION[self.metadata.anim_stop].state)
end,
on_activate = function(self)
if self.metadata.follow_players == "true" then
self.var.target = get_target_player(self)
end
end,
on_rightclick = function(self, clicker)
local player_name = clicker:get_player_name()
local message = "Hello"
if self.metadata.message then
message = minetest.formspec_escape(self.metadata.message)
end
local formspec
if player_name == self.owner then
local selected_id = ANIMATION[self.metadata.anim_stop].id or ""
formspec = "size[8,4.0]"
.."field[0.5,1.0;7.5,0.5;message;Message;"..message.."]"
.."label[0.5,1.8;Stationary Animation\\:]"
.."dropdown[4.0,1.8;3.5;anim_stop;Stand,Sit,Lay,Mine;"..selected_id.."]"
.."checkbox[0.5,2.7;follow_players;Follow Players;"..self.metadata.follow_players.."]"
.."button_exit[7.0,3.5;1.0,0.5;;Ok]"
if FREE_ROAMING == true then
formspec = formspec.."checkbox[3.5,2.7;free_roaming;Wander Map;"..self.metadata.free_roaming.."]"
end
else
formspec = "size[8,4]".."label[0,0;"..message.."]"
end
self.var.speed = 0
npcf:show_formspec(player_name, self.npc_id, formspec)
end,
on_step = function(self, dtime)
if self.timer > 1 then
self.timer = 0
local speed = 0
local pos = self.object:getpos()
local yaw = self.object:getyaw()
local turn = pos.x == self.var.last_pos.x and pos.z == self.var.last_pos.z
local acceleration = {x=0, y=-10, z=0}
local velocity = self.object:getvelocity()
local roaming = FREE_ROAMING == true and self.metadata.free_roaming == "true"
if roaming == true or self.metadata.follow_players == "true" then
speed = self.var.speed
if math.random(10) == 1 then
if speed == 0 or speed == RUNNING_SPEED then
speed = WALKING_SPEED
elseif math.random(5) == 1 then
speed = RUNNING_SPEED
elseif math.random(5) == 1 then
speed = 0
end
elseif math.random(30) == 1 then
self.var.avoid_dir = self.var.avoid_dir * -1
end
if self.metadata.follow_players == "true" then
local valid_target = false
if self.var.target then
local target = self.var.target:getpos()
if target then
valid_target = true
yaw = npcf:get_face_direction(pos, target)
if vector.distance(pos, target) < FOLLOW_RADIUS_MIN then
speed = 0
end
end
end
if math.random(10) == 1 or valid_target == false then
self.var.target = get_target_player(self)
end
end
if speed ~= 0 then
local node_pos = vector.add(npcf:get_walk_velocity(5, 0, yaw), pos)
node_pos = vector.round(node_pos)
local air_content = 0
for i = 1, 5 do
local test_pos = {x=node_pos.x, y=node_pos.y-i, z=node_pos.z}
local node = minetest.get_node(test_pos)
if node.name == "air" then
air_content = air_content + 1
end
for _, v in ipairs(AVOIDED_NODES) do
if node.name == v then
turn = true
break
end
end
end
if turn == false then
local objects = minetest.get_objects_inside_radius(node_pos, 2)
if #objects > 0 then
turn = true
end
end
if turn == true or air_content == 5 then
yaw = yaw + math.pi * 0.5 * self.var.avoid_dir
speed = WALKING_SPEED
elseif pos.x == self.var.last_pos.x or pos.z == self.var.last_pos.z then
yaw = yaw + math.pi * 0.25 * self.var.avoid_dir
end
if roaming == true then
if math.random(4) == 1 then
yaw = yaw + (math.random(3) - 2) * 0.25
end
elseif self.var.target == nil then
speed = 0
end
end
self.var.speed = speed
self.object:setyaw(yaw)
end
self.var.last_pos = pos
if speed == 0 then
npcf:set_animation(self, ANIMATION[self.metadata.anim_stop].state)
elseif speed == RUNNING_SPEED then
self.object:set_animation({x=self.animation.run_START, y=self.animation.run_END}, 20)
self.state = 0
else
npcf:set_animation(self, NPCF_ANIM_WALK)
end
local node = minetest.get_node(pos)
if string.find(node.name, "^default:water") then
acceleration = {x=0, y=-4, z=0}
velocity = {x=0, y=3, z=0}
elseif minetest.find_node_near(pos, 2, {"group:water"}) then
acceleration = {x=0, y=-1, z=0}
end
self.object:setvelocity(npcf:get_walk_velocity(speed, velocity.y, yaw))
self.object:setacceleration(acceleration)
end
end,
on_receive_fields = function(self, fields, sender)
if fields.free_roaming or fields.follow_players then
self.var.speed = WALKING_SPEED
end
end,
})