forked from theFox6/working_villages
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathasync_actions.lua
213 lines (202 loc) · 7.05 KB
/
async_actions.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
function smart_villages.villager:go_to(pos)
self.destination=vector.round(pos)
if smart_villages.func.walkable_pos(self.destination) then
self.destination=smart_villages.pathfinder.get_ground_level(vector.round(self.destination))
end
local val_pos = smart_villages.func.validate_pos(self.object:getpos())
self.path = smart_villages.pathfinder.get_reachable(val_pos,self.destination,self)
self:set_timer("go_to:find_path",0) -- find path interval
self:set_timer("go_to:change_dir",0)
self:set_timer("go_to:give_up",0)
if self.path == nil then
--TODO: actually no path shouldn't be accepted
--we'd have to check whether we can find a shorter path in the right direction
self.path = {self.destination}
end
--print("the first waypiont on his path:" .. minetest.pos_to_string(self.path[1]))
self:change_direction(self.path[1])
self:set_animation(smart_villages.animation_frames.WALK)
while #self.path ~= 0 do
self:count_timer("go_to:find_path")
self:count_timer("go_to:change_dir")
if self:timer_exceeded("go_to:find_path",100) then
val_pos = smart_villages.func.validate_pos(self.object:getpos())
local path = smart_villages.pathfinder.get_reachable(val_pos,self.destination,self)
if path == nil then
self:count_timer("go_to:give_up")
if self:timer_exceeded("go_to:give_up",3) then
self.destination=vector.round(self.destination)
if smart_villages.func.walkable_pos(self.destination) then
self.destination=smart_villages.pathfinder.get_ground_level(vector.round(self.destination))
end
print("villager can't find path")
--FIXME: we ought to give up at this point
end
else
self.path = path
end
end
if self:timer_exceeded("go_to:change_dir",30) then
self:change_direction(self.path[1])
end
-- follow path
if self:is_near({x=self.path[1].x,y=self.object:getpos().y,z=self.path[1].z}, 1) then
table.remove(self.path, 1)
if #self.path == 0 then -- end of path
break
else -- else next step, follow next path.
self:set_timer("go_to:find_path",0)
self:change_direction(self.path[1])
end
end
-- if vilager is stopped by obstacles, the villager must jump.
self:handle_obstacles()
-- end step
coroutine.yield()
end
self.object:setvelocity{x = 0, y = 0, z = 0}
self.path = nil
self:set_animation(smart_villages.animation_frames.STAND)
end
function smart_villages.villager:dig(pos)
self.object:setvelocity{x = 0, y = 0, z = 0}
self:set_animation(smart_villages.animation_frames.MINE)
self:set_yaw_by_direction(vector.subtract(pos, self.object:getpos()))
for _=0,30 do coroutine.yield() end --wait 30 steps
local destnode = minetest.get_node(pos)
minetest.remove_node(pos)
local stacks = minetest.get_node_drops(destnode.name)
for _, stack in ipairs(stacks) do
local leftover = self:add_item_to_main(stack)
minetest.add_item(pos, leftover)
end
local sounds = minetest.registered_nodes[destnode.name].sounds
if sounds then
local sound = sounds.dug
if sound then
minetest.sound_play(sound,{object=self.object, max_hear_distance = 10})
end
end
self:set_animation(smart_villages.animation_frames.STAND)
end
function smart_villages.villager:place(item,pos)
if type(pos)~="table" then
error("no target position given")
end
local pred
if type(item)=="string" then
pred = function (name) return name == item end
elseif type(item)=="function" then
pred = item
else
error("no item to place given")
end
local wield_stack = self:get_wield_item_stack()
--move item to wield
if pred(wield_stack:get_name()) or self:move_main_to_wield(pred) then
--set animation
if self.object:getvelocity().x==0 and self.object:getvelocity().z==0 then
self:set_animation(smart_villages.animation_frames.MINE)
else
self:set_animation(smart_villages.animation_frames.WALK_MINE)
end
--turn to target
self:set_yaw_by_direction(vector.subtract(pos, self.object:getpos()))
--wait 15 steps
for _=0,15 do coroutine.yield() end
--get wielded item
local stack = self:get_wield_item_stack()
--create pointed_thing
local pointed_thing = {
type = "node",
above = pos,
under = vector.add(pos, {x = 0, y = -1, z = 0}),
}
local itemname = stack:get_name()
--place item
--minetest.item_place(stack, minetest.get_player_by_name(self.owner_name), pointed_thing)
minetest.set_node(pointed_thing.above, {name = itemname})
--take item
stack:take_item(1)
self:set_wield_item_stack(stack)
--handle sounds
local sounds = minetest.registered_nodes[itemname].sounds
if sounds then
local sound = sounds.place
if sound then
minetest.sound_play(sound,{object=self.object, max_hear_distance = 10})
end
end
--reset animation
if self.object:getvelocity().x==0 and self.object:getvelocity().z==0 then
self:set_animation(smart_villages.animation_frames.STAND)
else
self:set_animation(smart_villages.animation_frames.WALK)
end
else
minetest.chat_send_player(self.owner_name,"villager couldn't place item")
end
end
function smart_villages.villager.wait_until_dawn()
local daytime = minetest.get_timeofday()
while (daytime < 0.2 or daytime > 0.76) do
coroutine.yield()
daytime = minetest.get_timeofday()
end
--print("wake up:"..daytime)
end
function smart_villages.villager:sleep()
minetest.log("action","a villager is laying down")
self.object:setvelocity{x = 0, y = 0, z = 0}
local bed_pos=self:get_home():get_bed()
local bed_top = smart_villages.func.find_adjacent_pos(bed_pos,
function(p) return string.find(minetest.get_node(p).name,"_top") end)
local bed_bottom = smart_villages.func.find_adjacent_pos(bed_pos,
function(p) return string.find(minetest.get_node(p).name,"_bottom") end)
if bed_top and bed_bottom then
self:set_yaw_by_direction(vector.subtract(bed_bottom, bed_top))
else
minetest.log("info","no bed found")
end
self:set_animation(smart_villages.animation_frames.LAY)
self.object:setpos(bed_pos)
self.pause="sleeping"
self:update_infotext()
self.wait_until_dawn()
local pos=self.object:getpos()
self.object:setpos({x=pos.x,y=pos.y+0.5,z=pos.z})
minetest.log("action","a villager gets up")
self:set_animation(smart_villages.animation_frames.STAND)
self.pause="active"
self:update_infotext()
end
function smart_villages.villager:goto_bed()
if smart_villages.debug_logging then
minetest.log("action",self.inventory_name.." is going home")
end
if not self:has_home() then
self:set_animation(smart_villages.animation_frames.SIT)
self.pause="sleeping"
self:update_infotext()
self.wait_until_dawn()
self:set_animation(smart_villages.animation_frames.STAND)
self.pause="active"
self:update_infotext()
else
local bed_pos = self:get_home():get_bed()
if not bed_pos then
minetest.log("warning","villager couldn't find his bed")
--perhaps go home
self:set_animation(smart_villages.animation_frames.SIT)
self.wait_until_dawn()
else
if smart_villages.debug_logging then
minetest.log("info","his bed is at:" .. bed_pos.x .. ",".. bed_pos.y .. ",".. bed_pos.z)
end
self:go_to(bed_pos)
self:sleep()
--TODO: perhaps go back to the position we were at before going home
self:go_to(self:get_home():get_door())
end
end
end