123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- local context={}
- minetest.register_on_joinplayer(
- function(player)
- context[player:get_player_name()]={}
- end
- )
- minetest.register_on_leaveplayer(
- function(player)
- context[player:get_player_name()]=nil
- end
- )
- local function round(num)
- local dec=(10*num)%10
- if dec>=5 then
- return math.ceil(num)
- else
- return math.floor(num)
- end
- end
- local function findPath(npc,ps1,ps2)
- return minetest.find_path(ps1,ps2,15,npc.stepheight,npc.fear_height-1,"Dijkstra")
- end
- local function turnTo(npc,pos)
- local currentPos=npc.object:get_pos();
- local ve={x=pos.x-currentPos.x,y=pos.y-currentPos.y,z=pos.z-currentPos.z}
- local px=math.abs(ve.x)
- local pz=math.abs(ve.z)
- local yaw
- --atan(opposite/adjacent)
- if px<pz then
- yaw=math.atan(px,pz)
- if ve.x<0 then
- if ve.z<0 then
- yaw=math.rad(180)-yaw
- end
- elseif ve.x>0 then
- if ve.z<0 then
- yaw=math.rad(180)+yaw
- elseif ve.z>0 then
- yaw=math.rad(360)-yaw
- end
- end
- elseif px>pz then
- yaw=math.atan(pz,px)
- if ve.x<0 then
- if ve.z<0 then
- yaw=math.rad(90)+yaw
- elseif ve.z>0 then
- yaw=math.rad(90)-yaw
- end
- elseif ve.x>0 then
- if ve.z<0 then
- yaw=math.rad(270)-yaw
- elseif ve.z>0 then
- yaw=math.rad(270)+yaw
- end
- end
- end
- npc:set_yaw(yaw)
- end
- local function moveTo(npc,pos)
- local ps=npc.object:get_pos()
- ps.x=round(ps.x)
- ps.z=round(ps.z)
- if ps.x==pos.x and ps.z==pos.z then
- return true
- else
- turnTo(npc,pos)
- npc:set_velocity(npc.walk_velocity)
- return false
- end
- end
- local function followPath(npc,path)
- if path and #path>0 then
- if moveTo(npc,path[1]) then
- if #path==1 then
- npc.state="stand"
- npc:set_animation("stand")
- npc.object:set_velocity({x=0,y=0,z=0})
- npc.h2=npc.h1
- npc.h1=path[1]
- end
- table.remove(path,1)
- end
- end
- end
- local function spiral(cursor,r,fu)
- cursor.x=round(cursor.x)
- cursor.y=round(cursor.y)
- cursor.z=round(cursor.z)
- fu(cursor)
- cursor.z=cursor.z+1
- fu(cursor)
- for j=1,2*r+1,2 do
- for i=0,j-1,1 do
- cursor.x=cursor.x+1
- fu(cursor)
- end
- for i=0,j,1 do
- cursor.z=cursor.z-1
- fu(cursor)
- end
- for i=0,j,1 do
- cursor.x=cursor.x-1
- fu(cursor)
- end
- for i=0,j+1,1 do
- if i+1<=2*r+2
- then
- cursor.z=cursor.z+1
- fu(cursor)
- end
- end
- end
- end
- local function findPatrolPoint(npc,pos)
- local nodes={}
- local function add(ps)
- if minetest.get_node(ps).name=="mobs_dungeon:patrol_point" then
- nodes[#nodes+1]={x=ps.x,y=ps.y,z=ps.z}
- end
- end
- spiral({x=pos.x,y=pos.y-1,z=pos.z},5,add)
- if nodes then
- for fi=1,#nodes,1 do
- if not npc.h2 or (not (nodes[fi].x==npc.h2.x
- and nodes[fi].y==npc.h2.y and nodes[fi].z==npc.h2.z)
- and not (nodes[fi].x==npc.h1.x
- and nodes[fi].y==npc.h1.y and nodes[fi].z==npc.h1.z))
- then
- return nodes[fi]
- end
- end
- end
- return nil
- end
- mobs:register_mob(
- "mobs_dungeon:npc",
- {
- type="npc",
- hp_min=50,
- hp_max=100,
- armor=50,
- passive=false,
- walk_velocity=2,
- run_velocity=3,
- stand_chance=0,
- walk_chance=0,
- jump=false,
- stay_near={},
- pushable=false,
- view_range=15,
- damage=4,
- fear_height=3,
- suffocation=true,
- follow={},
- attacks_monsters=true,
- attack_npcs=false,
- attack_type="dogfight",
- runaway_from={},
- pathfinding=true,
- makes_footstep_sound=true,
- drops={},
- sounds={
- random="mobs_dungeon_npc_random",
- death="mobs_dungeon_npc_death",
- damage="mobs_dungeon_npc_damage"
- },
- visual="mesh",
- collisionbox={-0.35,-1.0,-0.35, 0.35,0.8,0.35},
- textures={{"character.png"}},
- child_texture={{"character.png"}},
- mesh="mobs_character.b3d",
- animation={
- speed_normal=30,
- speed_run=30,
- stand_start=0,
- stand_end=79,
- walk_start=168,
- walk_end=187,
- run_start=168,
- run_end=187,
- punch_start=200,
- punch_end=219,
- },
- owner="",
- order="patrol",
- on_spawn=function(self)
- self.object:set_properties(
- {
- textures={
- "character.png^mobs_dungeon_npc_overlay_"
- ..Random:next(1,9)..".png"
- }
- }
- )
- end,
- on_rightclick=function(self, clicker)
- local item=clicker:get_wielded_item()
- local name=clicker:get_player_name()
- local form={
- "size[2,2]",
- "real_coordinates[true]",
- "position[0,0]",
- "anchor[0,0]",
- }
- if self.owner and self.owner == name then
- if self.order == "follow" then
- form[#form+1]="dropdown[0,0;1;order;follow,stand,patrol;1]"
- elseif self.order == "stand" then
- form[#form+1]="dropdown[0,0;1;order;follow,stand,patrol;2]"
- else
- form[#form+1]="dropdown[0,0;1;order;follow,stand,patrol;3]"
- end
- end
- context[name].npc=self
- minetest.show_formspec(name,"mobs_dungeon:menu",table.concat(form,""))
- end,
- do_custom=function(self,dtime)
- if self.state=="attack" or self.state=="runaway" then
- self.mdPath={}
- return
- end
- if self.mdPath and #self.mdPath>0 then
- followPath(self,self.mdPath)
- elseif self.order=="patrol" then
- local target=findPatrolPoint(self,self.object:get_pos())
- if target then
- local path=findPath(self,self.object:get_pos(),target)
- if path then
- self.mdPath=path
- self.state=""
- self:set_animation("walk")
- followPath(self,path)
- end
- end
- end
- end
- }
- )
- local orders={
- follow=function(npc)
- npc.order="follow"
- npc.state="walk"
- npc.mdPath=nil
- end,
- stand=function(npc)
- npc.order="stand"
- npc.state="stand"
- npc.mdPath=nil
- npc:set_animation("stand")
- npc:set_velocity({x=0,y=0,z=0})
- end,
- patrol=function(npc)
- npc.order="patrol"
- end
- }
- minetest.register_on_player_receive_fields(
- function(player,formname,fields)
- if formname~="mobs_dungeon:menu" then
- return
- end
- if fields.order then
- local npc=context[player:get_player_name()].npc
- npc.order=fields.order
- orders[fields.order](npc)
- end
- end
- )
- mobs:spawn(
- {
- name="mobs_dungeon:npc",
- nodes={"mobs_dungeon:patrol_point"},
- min_light=8,
- chance=5000,
- active_object_count=1,
- max_height=0,
- }
- )
- mobs:register_egg("mobs_dungeon:npc", "NPC", "mobs_dungeon_npc_inventory.png", 0)
|