add head code and interaction code from crafter

This commit is contained in:
Brandon 2020-07-16 19:56:35 -04:00
parent 0e797e2c3f
commit 796c45d4b3
8 changed files with 2007 additions and 0 deletions

View File

@ -0,0 +1,56 @@
local math,vector = math,vector
local speed
local self_rotation
local currentvel
local goal = vector.new(0,0,0)
local acceleration
--
mobs.create_animation_functions = function(def,mob_register)
if def.movement_type ~= "jump" then
mob_register.set_animation = function(self)
if self.speed == 0 or vector.equals(self.direction,vector.new(0,0,0)) then
self.current_animation = 0
self.object:set_animation(def.standing_frame, 1, 0, true)
else
if self.current_animation ~= 1 then
self.object:set_animation(def.moving_frame, 1, 0, true)
self.current_animation = 1
end
speed = self.object:get_velocity()
speed.y = 0
self.object:set_animation_frame_speed(vector.distance(vector.new(0,0,0),speed)*def.animation_multiplier)
end
end
end
--this makes the mob rotate and then die
mob_register.manage_death_animation = function(self,dtime)
if self.death_animation_timer >= 0 and self.dead == true then
self.death_animation_timer = self.death_animation_timer - dtime
self_rotation = self.object:get_rotation()
if self.death_rotation == "x" then
if self_rotation.x < math.pi/2 then
self_rotation.x = self_rotation.x + (dtime*2)
self.object:set_rotation(self_rotation)
end
elseif self.death_rotation == "z" then
if self_rotation.z < math.pi/2 then
self_rotation.z = self_rotation.z + (dtime*2)
self.object:set_rotation(self_rotation)
end
end
--print(self.death_animation_timer)
currentvel = self.object:get_velocity()
acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
acceleration = vector.multiply(acceleration, 0.05)
self.object:add_velocity(acceleration)
self.object:set_animation(def.standing_frame, 15, 0, true)
end
end
return(mob_register)
end

View File

@ -0,0 +1,250 @@
local minetest = minetest
--class
mobs = {}
local path = minetest.get_modpath(minetest.get_current_modname()).."/api/"
dofile(path.."movement.lua")
dofile(path.."interaction.lua")
dofile(path.."data_handling.lua")
dofile(path.."head_code.lua")
dofile(path.."animation.lua")
dofile(path.."timers.lua")
mobs.register_mob = function(def)
local mob_register = {}
register_mob_spawner(def.mobname,def.textures,def.mesh)
------------------------------------------------
mob_register.initial_properties = {
physical = def.physical,
collide_with_objects = def.collide_with_objects,
collisionbox = def.collisionbox,
visual = def.visual,
visual_size = def.visual_size,
mesh = def.mesh,
textures = def.textures,
is_visible = def.is_visible,
pointable = def.pointable,
automatic_face_movement_dir = def.automatic_face_movement_dir,
automatic_face_movement_max_rotation_per_sec = def.automatic_face_movement_max_rotation_per_sec,
makes_footstep_sound = def.makes_footstep_sound,
static_save = false,
}
mob_register.hp = def.hp
mob_register.max_speed = def.max_speed
mob_register.jump_timer = 0
if def.head_bone then
mob_register.head_bone = def.head_bone
mobs.create_head_functions(def,mob_register)
mob_register.debug_head_pos = def.debug_head_pos
mob_register.head_directional_offset = def.head_directional_offset
mob_register.head_height_offset = def.head_height_offset
mob_register.head_rotation_offset = def.head_rotation_offset
mob_register.head_position_correction = def.head_position_correction
mob_register.head_coord = def.head_coord
mob_register.flip_pitch = def.flip_pitch
else
--print("create some other functions to turn mob " .. def.mobname)
end
mob_register.hurt_inside_timer = 0
mob_register.death_animation_timer = 0
mob_register.dead = false
mob_register.mob = true
mob_register.mobname = def.mobname
mob_register.hostile = def.hostile
if def.friendly_in_daylight == true then
mob_register.friendly_in_daylight = def.friendly_in_daylight
mob_register.friendly_in_daylight_timer = 0
end
mob_register.hostile_cooldown = def.hostile_cooldown
mob_register.hostile_timer = 0
mob_register.timer = 0
mob_register.state = def.state
mob_register.hunger = 200
mob_register.view_distance = def.view_distance
mob_register.punch_timer = 0
mob_register.punched_timer = 0
mob_register.group_attack = def.group_attack
mob_register.death_rotation = def.death_rotation
mob_register.head_mount = def.head_mount
mob_register.rotational_correction = def.rotational_correction or 0
mob_register.hurt_sound = def.hurt_sound
mob_register.die_sound = def.die_sound
mob_register.attack_type = def.attack_type
if def.attack_type == "explode" then
mob_register.tnt_tick_timer = 0
mob_register.explosion_type = def.explosion_type
end
mob_register.explosion_radius = def.explosion_radius
mob_register.explosion_power = def.explosion_power
mob_register.tnt_timer = nil
mob_register.explosion_time = def.explosion_time
mob_register.explosion_blink_color = def.explosion_blink_color or "white"
mob_register.explosion_blink_timer = def.explosion_blink_timer or 0.2
mob_register.custom_function_begin = def.custom_function_begin
mob_register.custom_function = def.custom_function
mob_register.custom_function_end = def.custom_function_end
mob_register.projectile_timer_cooldown = def.projectile_timer_cooldown
mob_register.attacked_hostile = def.attacked_hostile
if not def.hostile and not def.attacked_hostile then
mob_register.scared = false
mob_register.scared_timer = 0
end
mob_register.attack_damage = def.attack_damage
mob_register.projectile_timer = 0
mob_register.projectile_type = def.projectile_type
mob_register.takes_fall_damage = def.takes_fall_damage or true
mob_register.make_jump_noise = def.make_jump_noise
mob_register.jump_animation = def.jump_animation
mob_register.jumping_frame = def.jumping_frame
mob_register.item_drop = def.item_drop
mob_register.item_minimum = def.item_minimum or 1
mob_register.item_max = def.item_max
mob_register.die_in_light = def.die_in_light
mob_register.die_in_light_level = def.die_in_light_level
mob_register.current_animation = 0
mob_register.hurt_color_timer = 0
mob_register.damage_color = def.damage_color or "red"
mob_register.custom_on_death = def.custom_on_death
mob_register.custom_on_activate = def.custom_on_activate
mob_register.custom_on_punch = def.custom_on_punch
mob_register.c_mob_data = def.c_mob_data
mob_register.deactivating = false
mob_register.on_fire = false
mob_register.fire_table = def.fire_table
mob_register.sound_pitch_mod_min = def.sound_pitch_mod_min
mob_register.sound_pitch_mod_max = def.sound_pitch_mod_max
mob_register.sound_pitch_mod_min_die = def.sound_pitch_mod_min_die
mob_register.sound_pitch_mod_max_die = def.sound_pitch_mod_max_die
if def.pathfinds then
--mob_register.path = {}
mob_register.pathfinding_timer = 0
end
if def.custom_timer then
mob_register.c_timer = 0
mob_register.custom_timer = def.custom_timer
mob_register.custom_timer_function = def.custom_timer_function
end
mobs.create_movement_functions(def,mob_register)
mobs.create_interaction_functions(def,mob_register)
mobs.create_data_handling_functions(def,mob_register)
mobs.create_animation_functions(def,mob_register)
mobs.create_timer_functions(def,mob_register)
mob_register.on_step = function(self, dtime,moveresult)
if self.custom_function_begin then
self.custom_function_begin(self,dtime)
end
self.collision_detection(self)
if self.fall_damage then
self.fall_damage(self)
end
if self.dead == false and self.death_animation_timer == 0 then
if self.do_custom_timer then
self.do_custom_timer(self,dtime)
end
if self.custom_function then
self.custom_function(self,dtime,moveresult)
end
self.move(self,dtime,moveresult)
self.flow(self)
--self.debug_nametag(self,dtime)
self.manage_hurt_color_timer(self,dtime)
if self.manage_scared_timer then
self.manage_scared_timer(self,dtime)
end
if self.set_animation then
self.set_animation(self)
end
if self.look_around then
self.look_around(self,dtime)
end
if self.pathfinding then
self.pathfinding(self,dtime)
end
if self.handle_friendly_in_daylight_timer then
self.handle_friendly_in_daylight_timer(self,dtime)
end
self.manage_punch_timer(self,dtime)
else
self.manage_death_animation(self,dtime)
if self.move_head then
self.move_head(self,nil,dtime)
end
end
--fix zombie state again
if self.dead == true and self.death_animation_timer <= 0 then
self.on_death(self)
end
if self.tnt_timer then
self.manage_explode_timer(self,dtime)
end
if self.projectile_timer then
self.manage_projectile_timer(self,dtime)
end
if self.custom_function_end then
self.custom_function_end(self,dtime)
end
end
minetest.register_entity("mob:"..def.mobname, mob_register)
------------------------------------------------
end

View File

@ -0,0 +1,105 @@
local
vector,minetest,math,pairs
=
vector,minetest,math,pairs
--
mobs.create_data_handling_functions = function(def,mob_register)
--mob_register.get_staticdata = function(self)
--[[
return minetest.serialize({
--range = self.range,
hp = self.hp,
hunger = self.hunger,
hostile = self.hostile,
hostile_timer = self.hostile_timer,
death_animation_timer = self.death_animation_timer,
dead = self.dead,
tnt_timer = self.tnt_timer,
tnt_tick_timer = self.tnt_tick_timer,
tnt_mod_state = self.tnt_mod_state,
punch_timer = self.punch_timer,
projectile_timer = self.projectile_timer,
scared = self.scared,
scared_timer = self.scared_timer,
c_mob_data = self.c_mob_data,
on_fire = self.on_fire,
})
]]--
--end
mob_register.on_activate = function(self)--, staticdata, dtime_s)
--[[
if string.sub(staticdata, 1, string.len("return")) == "return" then
local data = minetest.deserialize(staticdata)
if data and type(data) == "table" then
--self.range = data.range
self.hp = data.hp
self.hunger = data.hunger
self.hostile = data.hostile
self.hostile_timer = data.hostile_timer
self.death_animation_timer = data.death_animation_timer
self.dead = data.dead
self.tnt_timer = data.tnt_timer
self.tnt_tick_timer = data.tnt_tick_timer
self.tnt_mod_state = data.tnt_mod_state
self.punch_timer = data.punch_timer
self.projectile_timer = data.projectile_timer
self.scared = data.scared
self.scared_timer = data.scared_timer
self.c_mob_data = data.c_mob_data
self.on_fire = data.on_fire
end
end
]]--
--set up mob
self.object:set_armor_groups({immortal = 1})
--self.object:set_velocity({x = math.random(-5,5), y = 5, z = math.random(-5,5)})
self.object:set_acceleration(def.gravity)
self.object:set_animation(def.standing_frame, 0, 0, true)
self.current_animation = 0
self.object:set_hp(self.hp)
self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
--set the head up
if self.head_bone then
self.object:set_bone_position(self.head_bone, self.head_position_correction, vector.new(0,0,0))
end
self.is_mob = true
self.object:set_armor_groups({immortal = 1})
if self.custom_on_activate then
self.custom_on_activate(self)
end
if self.on_fire == true then
start_fire(self.object)
end
--use this to handle the global mob table
--minetest.after(0,function()
-- self.deactivating = true
--end)
end
--this is the info on the mob
mob_register.debug_nametag = function(self,dtime)
--we're doing this to the child because the nametage breaks the
--animation on the mob's body
--we add in items we want to see in this list
local debug_items = {"hostile","hostile_timer"}
local text = ""
for _,item in pairs(debug_items) do
if self[item] ~= nil then
text = text..item..": "..tostring(self[item]).."\n"
end
end
self.object:set_nametag_attributes({
color = "white",
text = text
})
end
return(mob_register)
end

View File

@ -0,0 +1,287 @@
local
minetest,math,vector
=
minetest,math,vector
--converts the degrees to radians
local degrees_to_radians = function(degrees)
--print(d)
return(degrees/180.0*math.pi)
end
--converts yaw to degrees
local degrees = function(yaw)
return(yaw*180.0/math.pi)
end
--rounds it up to an integer
local degree_round = function(degree)
return(degree + 0.5 - (degree + 0.5) % 1)
end
--turns radians into degrees - not redundant
--doesn't add math.pi
local radians_to_degrees = function(radians)
return(radians*180.0/math.pi)
end
--make sure this is redefined as shown below aka
--don't run mob_rotation_degree_to_radians(rotation)
--run local radians = mob_rotation_degree_to_radians(rotation)
--or the mobs head rotation will become overwritten
local head_rotation_to_radians = function(rotation)
return{
x = 0, --roll should never be changed
y = degrees_to_radians(180 - rotation.y)*-1,
z = degrees_to_radians(90 - rotation.z)
}
end
--
local pos
local body_yaw
local head_yaw
local dir
local head_position
local head_rotation
mcl_mobs.create_head_functions = function(def,mob_register)
--a movement test to move the head
mob_register.move_head = function(self,pos2,dtime)
if self.head_bone then
if self.head_coord == "horizontal" then
--print(self.head_bone)
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
--[[ debug
if rotation then
--print("--------------------------------")
--rotation.x = rotation.x + 1
rotation.z = rotation.z + 1
rotation.y = 0
if rotation.x > 90 then
rotation.x = -90
end
if rotation.z > 90 then
rotation.z = -90
end
--print(rotation.x)
self.object:set_bone_position(self.head_bone, head_position, rotation)
end
]]--
--if passed a direction to look
pos = self.object:get_pos()
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
body_yaw = minetest.dir_to_yaw(dir)
--pos is where the head actually is
pos = vector.add(pos,dir)
pos.y = pos.y + self.head_height_offset
--use this to literally look around
--self.head_pos = pos
--if self.debug_head_pos == true then
-- minetest.add_particle({
-- pos = pos,
-- velocity = {x=0, y=0, z=0},
-- acceleration = {x=0, y=0, z=0},
-- expirationtime = 0.2,
-- size = 1,
-- texture = "dirt.png",
-- })
--end
--if the function was given a pos
if pos2 then
--compare the head yaw to the body
--we must do a bunch of calculations to correct
--strange function returns
--for some reason get_yaw is offset 90 degrees
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
head_yaw = degrees(head_yaw)-degrees(body_yaw)
if head_yaw < -180 then
head_yaw = head_yaw + 360
elseif head_yaw > 180 then
head_yaw = head_yaw - 360
end
--if within range then do calculations
if head_yaw >= -90 and head_yaw <= 90 then
---begin pitch calculation
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
if self.flip_pitch then
head_rotation.x = head_rotation.x * -1
end
head_rotation.z = head_yaw
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
return(true)
--nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
--if nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
elseif self.head_coord == "vertical" then
--print(self.head_bone)
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
--[[ debug
if rotation then
--print("--------------------------------")
--rotation.x = rotation.x + 1
rotation.z = rotation.z + 1
rotation.y = 0
if rotation.x > 90 then
rotation.x = -90
end
if rotation.z > 90 then
rotation.z = -90
end
--print(rotation.x)
self.object:set_bone_position(self.head_bone, head_position, rotation)
end
]]--
--print(self.head_rotation.y)
--if passed a direction to look
pos = self.object:get_pos()
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
body_yaw = minetest.dir_to_yaw(dir)
--pos is where the head actually is
pos = vector.add(pos,dir)
pos.y = pos.y + self.head_height_offset
--use this to literally look around
--self.head_pos = pos
--if self.debug_head_pos == true then
-- minetest.add_particle({
-- pos = pos,
-- velocity = {x=0, y=0, z=0},
-- acceleration = {x=0, y=0, z=0},
-- expirationtime = 0.2,
-- size = 1,
-- texture = "dirt.png",
-- })
--end
--if the function was given a pos
if pos2 then
--compare the head yaw to the body
--we must do a bunch of calculations to correct
--strange function returns
--for some reason get_yaw is offset 90 degrees
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
head_yaw = degrees(head_yaw)-degrees(body_yaw)
if head_yaw < -180 then
head_yaw = head_yaw + 360
elseif head_yaw > 180 then
head_yaw = head_yaw - 360
end
--if within range then do calculations
if head_yaw >= -90 and head_yaw <= 90 then
---begin pitch calculation
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
if self.flip_pitch then
head_rotation.x = head_rotation.x * -1
end
head_rotation.y = -head_yaw
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
return(true)
--nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
--if nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
end
end
end
--this sets the mob to move it's head back to pointing forwards
mob_register.return_head_to_origin = function(self,dtime)
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
if self.head_coord == "horizontal" then
--make the head yaw move back
if head_rotation.x > 0 then
head_rotation.x = head_rotation.x - (dtime*100)
elseif head_rotation.x < 0 then
head_rotation.x = head_rotation.x + (dtime*100)
end
if math.abs(head_rotation.x) < (dtime*100) then
head_rotation.x = 0
end
--move up down (pitch) back to center
if head_rotation.z > 0 then
head_rotation.z = head_rotation.z - (dtime*100)
elseif head_rotation.z < 0 then
head_rotation.z = head_rotation.z + (dtime*100)
end
if math.abs(head_rotation.z) < (dtime*100) then
head_rotation.z = 0
end
elseif self.head_coord == "vertical" then
--make the head yaw move back
if head_rotation.x > 0 then
head_rotation.x = head_rotation.x - (dtime*100)
elseif head_rotation.x < 0 then
head_rotation.x = head_rotation.x + (dtime*100)
end
if math.abs(head_rotation.x) < (dtime*100) then
head_rotation.x = 0
end
--move up down (pitch) back to center
if head_rotation.y > 0 then
head_rotation.y = head_rotation.y - (dtime*100)
elseif head_rotation.y < 0 then
head_rotation.y = head_rotation.y + (dtime*100)
end
if math.abs(head_rotation.y) < (dtime*100) then
head_rotation.y = 0
end
end
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
end
return(mob_register)
end

View File

@ -0,0 +1,287 @@
local
minetest,math,vector
=
minetest,math,vector
--converts the degrees to radians
local degrees_to_radians = function(degrees)
--print(d)
return(degrees/180.0*math.pi)
end
--converts yaw to degrees
local degrees = function(yaw)
return(yaw*180.0/math.pi)
end
--rounds it up to an integer
local degree_round = function(degree)
return(degree + 0.5 - (degree + 0.5) % 1)
end
--turns radians into degrees - not redundant
--doesn't add math.pi
local radians_to_degrees = function(radians)
return(radians*180.0/math.pi)
end
--make sure this is redefined as shown below aka
--don't run mob_rotation_degree_to_radians(rotation)
--run local radians = mob_rotation_degree_to_radians(rotation)
--or the mobs head rotation will become overwritten
local head_rotation_to_radians = function(rotation)
return{
x = 0, --roll should never be changed
y = degrees_to_radians(180 - rotation.y)*-1,
z = degrees_to_radians(90 - rotation.z)
}
end
--
local pos
local body_yaw
local head_yaw
local dir
local head_position
local head_rotation
mobs.create_head_functions = function(def,mob_register)
--a movement test to move the head
mob_register.move_head = function(self,pos2,dtime)
if self.head_bone then
if self.head_coord == "horizontal" then
--print(self.head_bone)
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
--[[ debug
if rotation then
--print("--------------------------------")
--rotation.x = rotation.x + 1
rotation.z = rotation.z + 1
rotation.y = 0
if rotation.x > 90 then
rotation.x = -90
end
if rotation.z > 90 then
rotation.z = -90
end
--print(rotation.x)
self.object:set_bone_position(self.head_bone, head_position, rotation)
end
]]--
--if passed a direction to look
pos = self.object:get_pos()
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
body_yaw = minetest.dir_to_yaw(dir)
--pos is where the head actually is
pos = vector.add(pos,dir)
pos.y = pos.y + self.head_height_offset
--use this to literally look around
--self.head_pos = pos
--if self.debug_head_pos == true then
-- minetest.add_particle({
-- pos = pos,
-- velocity = {x=0, y=0, z=0},
-- acceleration = {x=0, y=0, z=0},
-- expirationtime = 0.2,
-- size = 1,
-- texture = "dirt.png",
-- })
--end
--if the function was given a pos
if pos2 then
--compare the head yaw to the body
--we must do a bunch of calculations to correct
--strange function returns
--for some reason get_yaw is offset 90 degrees
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
head_yaw = degrees(head_yaw)-degrees(body_yaw)
if head_yaw < -180 then
head_yaw = head_yaw + 360
elseif head_yaw > 180 then
head_yaw = head_yaw - 360
end
--if within range then do calculations
if head_yaw >= -90 and head_yaw <= 90 then
---begin pitch calculation
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
if self.flip_pitch then
head_rotation.x = head_rotation.x * -1
end
head_rotation.z = head_yaw
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
return(true)
--nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
--if nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
elseif self.head_coord == "vertical" then
--print(self.head_bone)
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
--[[ debug
if rotation then
--print("--------------------------------")
--rotation.x = rotation.x + 1
rotation.z = rotation.z + 1
rotation.y = 0
if rotation.x > 90 then
rotation.x = -90
end
if rotation.z > 90 then
rotation.z = -90
end
--print(rotation.x)
self.object:set_bone_position(self.head_bone, head_position, rotation)
end
]]--
--print(self.head_rotation.y)
--if passed a direction to look
pos = self.object:get_pos()
body_yaw = self.object:get_yaw()-math.pi/2+self.rotational_correction
dir = vector.multiply(minetest.yaw_to_dir(body_yaw),self.head_directional_offset)
body_yaw = minetest.dir_to_yaw(dir)
--pos is where the head actually is
pos = vector.add(pos,dir)
pos.y = pos.y + self.head_height_offset
--use this to literally look around
--self.head_pos = pos
--if self.debug_head_pos == true then
-- minetest.add_particle({
-- pos = pos,
-- velocity = {x=0, y=0, z=0},
-- acceleration = {x=0, y=0, z=0},
-- expirationtime = 0.2,
-- size = 1,
-- texture = "dirt.png",
-- })
--end
--if the function was given a pos
if pos2 then
--compare the head yaw to the body
--we must do a bunch of calculations to correct
--strange function returns
--for some reason get_yaw is offset 90 degrees
head_yaw = minetest.dir_to_yaw(vector.direction(pos,pos2))
head_yaw = minetest.dir_to_yaw(minetest.yaw_to_dir(head_yaw))
head_yaw = degrees(head_yaw)-degrees(body_yaw)
if head_yaw < -180 then
head_yaw = head_yaw + 360
elseif head_yaw > 180 then
head_yaw = head_yaw - 360
end
--if within range then do calculations
if head_yaw >= -90 and head_yaw <= 90 then
---begin pitch calculation
--feed a 2D coordinate flipped into dir to yaw to calculate pitch
head_rotation.x = degrees(minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)),0,pos.y-pos2.y))+(math.pi/2))
if self.flip_pitch then
head_rotation.x = head_rotation.x * -1
end
head_rotation.y = -head_yaw
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
return(true)
--nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
--if nothing to look at
else
self.return_head_to_origin(self,dtime)
return(false)
end
end
end
end
--this sets the mob to move it's head back to pointing forwards
mob_register.return_head_to_origin = function(self,dtime)
head_position,head_rotation = self.object:get_bone_position(self.head_bone)
if self.head_coord == "horizontal" then
--make the head yaw move back
if head_rotation.x > 0 then
head_rotation.x = head_rotation.x - (dtime*100)
elseif head_rotation.x < 0 then
head_rotation.x = head_rotation.x + (dtime*100)
end
if math.abs(head_rotation.x) < (dtime*100) then
head_rotation.x = 0
end
--move up down (pitch) back to center
if head_rotation.z > 0 then
head_rotation.z = head_rotation.z - (dtime*100)
elseif head_rotation.z < 0 then
head_rotation.z = head_rotation.z + (dtime*100)
end
if math.abs(head_rotation.z) < (dtime*100) then
head_rotation.z = 0
end
elseif self.head_coord == "vertical" then
--make the head yaw move back
if head_rotation.x > 0 then
head_rotation.x = head_rotation.x - (dtime*100)
elseif head_rotation.x < 0 then
head_rotation.x = head_rotation.x + (dtime*100)
end
if math.abs(head_rotation.x) < (dtime*100) then
head_rotation.x = 0
end
--move up down (pitch) back to center
if head_rotation.y > 0 then
head_rotation.y = head_rotation.y - (dtime*100)
elseif head_rotation.y < 0 then
head_rotation.y = head_rotation.y + (dtime*100)
end
if math.abs(head_rotation.y) < (dtime*100) then
head_rotation.y = 0
end
end
self.object:set_bone_position(self.head_bone, head_position, head_rotation)
end
return(mob_register)
end

View File

@ -0,0 +1,506 @@
local
minetest,math,vector,ipairs
=
minetest,math,vector,ipairs
--
--for add sword wear
local itemstack
local wear
--for collision detection
local pos
local collision_count
local collisionbox
local collision_boundary
local radius
local pos2
local object_collisionbox
local object_collision_boundary
local y_base_diff
local y_top_diff
local distance
local dir
local velocity
local vel1
local vel2
--for fall damage
local vel
local damage
--for on_punch
local hp
local hurt
local critical
local puncher_vel
--for item drop
local item
local data_item_amount
--for look around
local light_level
local player_found
local player_punch_timer
local line_of_sight
local obj
local sound_max
local sound_min
local head_pos
local light
local fire_it_up
mobs.create_interaction_functions = function(def,mob_register)
mob_register.flow = function(self)
local flow_dir = flow(self.object:get_pos())
if flow_dir then
flow_dir = vector.multiply(flow_dir,10)
local vel = self.object:get_velocity()
local acceleration = vector.new(flow_dir.x-vel.x,flow_dir.y-vel.y,flow_dir.z-vel.z)
acceleration = vector.multiply(acceleration, 0.01)
self.object:add_velocity(acceleration)
end
end
--the pig will look for and at players
mob_register.look_around = function(self,dtime)
pos = self.object:get_pos()
if self.die_in_light then
fire_it_up = false
if minetest.get_item_group(minetest.get_node(pos).name, "extinguish") > 0 then
fire_it_up = false
else
head_pos = table.copy(pos)
head_pos.y = head_pos.y + self.object:get_properties().collisionbox[5]
light = minetest.get_node_light(head_pos)
if light and light == 15 then
if weather_type == 2 then
fire_it_up = false
else
fire_it_up = true
end
end
end
if fire_it_up then
start_fire(self.object)
end
end
if self.on_fire then
if minetest.get_item_group(minetest.get_node(pos).name, "extinguish") > 0 then
put_fire_out(self.object)
else
head_pos = table.copy(pos)
head_pos.y = head_pos.y + self.object:get_properties().collisionbox[5]
light = minetest.get_node_light(head_pos, 0.5)
if light and light == 15 then
if weather_type == 2 then
put_fire_out(self.object)
end
end
end
end
--STARE O_O
--and follow!
self.following = false
player_found = false
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.view_distance)) do
if object:is_player() and player_found == false and object:get_hp() > 0 then
--look at player's camera
pos2 = object:get_pos()
pos2.y = pos2.y + 1.625
player_found = true
if self.head_bone then
self.move_head(self,pos2,dtime)
end
--print(self.hostile)
if self.hostile == true then
distance = vector.distance(pos,pos2)
self.following_pos = vector.new(pos2.x,pos2.y-1.625,pos2.z)
--punch the player
if self.attack_type == "punch" then
if distance < 2.5 and self.punch_timer <= 0 and object:get_hp() > 0 then
if player_can_be_punched(object) then
line_of_sight = minetest.line_of_sight(pos, pos2)
if line_of_sight == true then
self.punch_timer = 0.5
object:punch(self.object, 2,
{
full_punch_interval=1.5,
damage_groups = {damage=self.attack_damage},
},vector.direction(pos,pos2))
--light the player on fire
if self.on_fire then
start_fire(object)
end
if is_player_on_fire(object) then
start_fire(self.object)
end
end
end
end
elseif self.attack_type == "explode" then
--mob will not explode if it cannot see you
if distance < self.explosion_radius and minetest.line_of_sight(vector.new(pos.x,pos.y+self.object:get_properties().collisionbox[5],pos.z), pos2) then
if not self.tnt_timer then
minetest.sound_play("tnt_ignite", {object = self.object, gain = 1.0,})
self.tnt_timer = self.explosion_time
self.tnt_tick_timer = 0.2
self.tnt_mod_state = 1
self.object:set_texture_mod("^[colorize:white:130")
end
end
elseif self.attack_type == "projectile" then
if not self.projectile_timer then
self.projectile_timer = self.projectile_timer_cooldown
end
if self.projectile_timer <= 0 then
self.projectile_timer = self.projectile_timer_cooldown
obj = minetest.add_entity(vector.new(pos.x,pos.y+self.object:get_properties().collisionbox[5],pos.z), self.projectile_type)
if obj then
dir = vector.multiply(vector.direction(pos,vector.new(pos2.x,pos2.y-3,pos2.z)), 50)
obj:set_velocity(dir)
obj:get_luaentity().timer = 2
obj:get_luaentity().owner = self.object
end
end
end
--smart
if self.path_data and table.getn(self.path_data) > 0 then
self.direction = vector.direction(vector.new(pos.x,0,pos.z), vector.new(self.path_data[1].x,0,self.path_data[1].z))
--dumb
else
self.direction = vector.direction(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z))
end
self.speed = self.max_speed
self.following = true
elseif self.scared == true then
self.speed = self.max_speed
self.direction = vector.direction(vector.new(pos2.x,0,pos2.z),vector.new(pos.x,0,pos.z))
self.scared_timer = 10
end
--only look at one player
break
end
end
--stare straight if not found
if player_found == false then
if self.move_head then
self.move_head(self,nil,dtime)
end
if self.following_pos then
self.following_pos = nil
end
if self.manage_hostile_timer then
self.manage_hostile_timer(self,dtime)
end
end
end
--this is what happens when a mob dies
mob_register.on_death = function(self, killer)
pos = self.object:get_pos()
if def.hp then
minetest.throw_experience(pos,math.ceil(def.hp/5)+math.random(0,1))
end
--pos.y = pos.y + 0.4
minetest.sound_play("mob_die", {pos = pos, gain = 1.0})
minetest.add_particlespawner({
amount = 40,
time = 0.001,
minpos = pos,
maxpos = pos,
minvel = vector.new(-5,-5,-5),
maxvel = vector.new(5,5,5),
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1.1,
maxexptime = 1.5,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "smoke.png",
})
--only throw items if registered
if self.item_drop then
if type(self.item_drop) == "string" then
item = self.item_drop
elseif type(self.item_drop) == "table" then
item = self.item_drop[math.random(1,table.getn(self.item_drop))]
end
--detect if multiple items are going to be added
if self.item_max then
data_item_amount = math.random(self.item_minimum, self.item_max)
for i = 1 ,data_item_amount do
minetest.throw_item(vector.new(pos.x,pos.y+0.1,pos.z),item)
end
else
minetest.throw_item(vector.new(pos.x,pos.y+0.1,pos.z),item)
end
end
if self.custom_on_death then
self.custom_on_death(self)
end
self.object:remove()
end
--this controls what happens when the mob gets punched
mob_register.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
hp = self.hp
vel = self.object:get_velocity()
hurt = tool_capabilities.damage_groups.damage
if not hurt then
hurt = 1
end
critical = false
--criticals
pos = self.object:get_pos()
if puncher:is_player() then
puncher_vel = puncher:get_player_velocity().y
if puncher_vel < 0 then
hurt = hurt * 1.5
critical = true
end
end
hp = hp-hurt
if (self.punched_timer <= 0 and hp > 1) and not self.dead then
self.object:set_texture_mod("^[colorize:"..self.damage_color..":130")
self.hurt_color_timer = 0.25
if puncher ~= self.object then
self.punched_timer = 0.25
if self.attacked_hostile then
self.hostile = true
self.hostile_timer = 20
if self.group_attack == true then
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.view_distance)) do
if not object:is_player() and object:get_luaentity() and object:get_luaentity().mobname == self.mobname then
object:get_luaentity().hostile = true
object:get_luaentity().hostile_timer = 20
end
end
end
else
self.scared = true
self.scared_timer = 10
end
if self.custom_on_punch then
self.custom_on_punch(self)
end
end
--critical effect
if critical == true then
self.do_critical_particles(pos)
minetest.sound_play("critical", {object=self.object, gain = 0.1, max_hear_distance = 10,pitch = math.random(80,100)/100})
end
sound_min = self.sound_pitch_mod_min or 100
sound_max = self.sound_pitch_mod_max or 140
minetest.sound_play(self.hurt_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(sound_min,sound_max)/100})
self.hp = hp
dir = vector.multiply(dir,10)
if vel.y <= 0 then
dir.y = 4
else
dir.y = 0
end
self.object:add_velocity(dir)
self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir)
elseif (self.punched_timer <= 0 and self.death_animation_timer == 0) then
self.object:set_texture_mod("^[colorize:"..self.damage_color..":130")
self.hurt_color_timer = 0.25
if puncher ~= self.object then
self.punched_timer = 0.25
if self.attacked_hostile then
self.hostile = true
self.hostile_timer = 20
if self.group_attack == true then
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.view_distance)) do
if not object:is_player() and object:get_luaentity() and object:get_luaentity().mobname == self.mobname then
object:get_luaentity().hostile = true
object:get_luaentity().hostile_timer = 20
end
end
end
end
if self.custom_on_punch then
self.custom_on_punch(self)
end
end
self.death_animation_timer = 1
self.dead = true
--critical effect
if critical == true then
self.do_critical_particles(pos)
minetest.sound_play("critical", {object=self.object, gain = 0.1, max_hear_distance = 10,pitch = math.random(80,100)/100})
end
sound_min = self.sound_pitch_mod_min_die or 80
sound_max = self.sound_pitch_mod_max_die or 100
minetest.sound_play(self.die_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(sound_min,sound_max)/100})
self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir)
end
end
mob_register.collision_detection = function(self)
pos = self.object:get_pos()
--do collision detection from the base of the mob
collisionbox = self.object:get_properties().collisionbox
pos.y = pos.y + collisionbox[2]
collision_boundary = collisionbox[4]
radius = collision_boundary
if collisionbox[5] > collision_boundary then
radius = collisionbox[5]
end
collision_count = 0
for _,object in ipairs(minetest.get_objects_inside_radius(pos, radius*1.25)) do
if object ~= self.object and (object:is_player() or object:get_luaentity().mob == true) and
--don't collide with rider, rider don't collide with thing
(not object:get_attach() or (object:get_attach() and object:get_attach() ~= self.object)) and
(not self.object:get_attach() or (self.object:get_attach() and self.object:get_attach() ~= object)) then
--stop infinite loop
collision_count = collision_count + 1
if collision_count > 100 then
break
end
pos2 = object:get_pos()
object_collisionbox = object:get_properties().collisionbox
pos2.y = pos2.y + object_collisionbox[2]
object_collision_boundary = object_collisionbox[4]
--this is checking the difference of the object collided with's possision
--if positive top of other object is inside (y axis) of current object
y_base_diff = (pos2.y + object_collisionbox[5]) - pos.y
y_top_diff = (pos.y + collisionbox[5]) - pos2.y
distance = vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z))
if distance <= collision_boundary + object_collision_boundary and y_base_diff >= 0 and y_top_diff >= 0 then
dir = vector.direction(pos,pos2)
dir.y = 0
--eliminate mob being stuck in corners
if dir.x == 0 and dir.z == 0 then
dir = vector.new(math.random(-1,1)*math.random(),0,math.random(-1,1)*math.random())
end
velocity = vector.multiply(dir,1.1)
vel1 = vector.multiply(velocity, -1)
vel2 = velocity
self.object:add_velocity(vel1)
if object:is_player() then
object:add_player_velocity(vel2)
if self.on_fire then
start_fire(object)
end
if is_player_on_fire(object) then
start_fire(self.object)
end
else
object:add_velocity(vel2)
if self.on_fire then
start_fire(object)
end
if object:get_luaentity().on_fire then
start_fire(self.object)
end
end
end
end
end
end
--the sword wear mechanic
mob_register.add_sword_wear = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
if puncher:is_player() then
itemstack = puncher:get_wielded_item()
wear = itemstack:get_definition().mob_hit_wear
if wear then
itemstack:add_wear(wear)
if itemstack:get_name() == "" then
minetest.sound_play("tool_break",{to_player = puncher:get_player_name(),gain=0.4})
end
puncher:set_wielded_item(itemstack)
end
end
end
--critical effect particles
mob_register.do_critical_particles = function(pos)
minetest.add_particlespawner({
amount = 40,
time = 0.001,
minpos = pos,
maxpos = pos,
minvel = vector.new(-2,-2,-2),
maxvel = vector.new(2,8,2),
minacc = {x=0, y=4, z=0},
maxacc = {x=0, y=12, z=0},
minexptime = 1.1,
maxexptime = 1.5,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "critical.png",
})
end
if def.takes_fall_damage == nil or def.takes_fall_damage == true then
mob_register.fall_damage = function(self)
vel = self.object:get_velocity()
if vel and self.oldvel then
if self.oldvel.y < -7 and vel.y == 0 then
damage = math.abs(self.oldvel.y + 7)
damage = math.floor(damage/1.5)
self.object:punch(self.object, 2,
{
full_punch_interval=1.5,
damage_groups = {damage=damage},
})
end
end
self.oldvel = vel
end
end
return(mob_register)
end

View File

@ -0,0 +1,400 @@
local
minetest,math,vector,pairs,table
=
minetest,math,vector,pairs,table
local pos
local node
local vel
local goal
local acceleration
local hurt
local fire
local currentvel
local goal
local y
local modifier
local pos2
local ray
local pointed_thing
local acute_pos
local height_diff
local acute_following_pos
local min
local max
local index_table
local path
local number
local pos1
local pos3
local can_cut
local _
--index all mods
local all_walkable_nodes = {}
minetest.register_on_mods_loaded(function()
for name in pairs(minetest.registered_nodes) do
if name ~= "air" and name ~= "ignore" then
if minetest.get_nodedef(name,"walkable") then
table.insert(all_walkable_nodes,name)
end
end
end
end)
mobs.create_movement_functions = function(def,mob_register)
--makes the mob swim
mob_register.swim = function(self,dtime)
pos = self.object:get_pos()
pos.y = pos.y + 0.3
node = minetest.get_node(pos).name
self.swimming = false
if node == "main:water" or node =="main:waterflow" then
vel = self.object:get_velocity()
goal = 3
acceleration = vector.new(0,goal-vel.y,0)
--jump out of the water
if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
self.object:set_velocity(vector.new(vel.x,5,vel.z))
--else swim
else
self.object:add_velocity(acceleration)
end
self.swimming = true
end
end
mob_register.hurt_inside = function(self,dtime)
if self.hp > 0 and self.hurt_inside_timer <= 0 then
pos = self.object:get_pos()
node = minetest.get_node(pos).name
hurt = minetest.get_item_group(node, "hurt_inside")
if hurt > 0 then
self.object:punch(self.object, 2,
{
full_punch_interval=1.5,
damage_groups = {damage=hurt},
})
end
fire = minetest.get_item_group(node, "fire")
if not self.on_fire and fire > 0 then
start_fire(self.object)
end
self.hurt_inside_timer = 0.25
else
self.hurt_inside_timer = self.hurt_inside_timer - dtime
end
end
--This makes the mob walk at a certain speed and jump
if def.movement_type == "walk" then
mob_register.move = function(self,dtime,moveresult)
self.manage_jump_timer(self,dtime)
self.timer = self.timer - dtime
--jump
self.jump(self,moveresult)
--swim
self.swim(self,dtime)
--print(self.timer)
--direction state change
if self.timer <= 0 and not self.following == true then
--print("changing direction")
self.timer = math.random(2,7)
self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
--local yaw = self.object:get_yaw() + dtime
self.speed = math.random(0,self.max_speed)
--self.object:set_yaw(yaw)
end
self.hurt_inside(self,dtime)
currentvel = self.object:get_velocity()
goal = vector.multiply(self.direction,self.speed)
acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
if self.whip_turn then
self.whip_turn = self.whip_turn - dtime
if self.whip_turn <= 0 then
self.whip_turn = nil
end
else
acceleration = vector.multiply(acceleration, 0.05)
end
self.object:add_velocity(acceleration)
end
mob_register.jump = function(self,moveresult)
if moveresult and moveresult.touching_ground and self.direction then
pos = self.object:get_pos()
pos.y = pos.y+0.1
if self.path_data and table.getn(self.path_data) > 0 then
--smart jump
y = math.floor(pos.y+0.5)
vel = self.object:get_velocity()
if y < self.path_data[1].y then
self.object:set_velocity(vector.new(vel.x,5,vel.z))
elseif self.path_data[2] and y < self.path_data[2].y then
self.object:set_velocity(vector.new(vel.x,5,vel.z))
elseif self.path_data[3] and y < self.path_data[3].y then
self.object:set_velocity(vector.new(vel.x,5,vel.z))
elseif ((vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0)) then
self.object:set_velocity(vector.new(vel.x,5,vel.z))
end
else
--assume collisionbox is even x and z
modifier = self.object:get_properties().collisionbox[4]*3
pos2 = vector.add(vector.multiply(self.direction,modifier),pos)
ray = minetest.raycast(pos, pos2, false, false)
pointed_thing = nil
if ray then
pointed_thing = ray:next()
end
if pointed_thing then
if minetest.get_nodedef(minetest.get_node(pointed_thing.under).name, "walkable") then
--print("jump")
vel = self.object:get_velocity()
--self.jump_timer = 1+math.random()
self.object:set_velocity(vector.new(vel.x,5,vel.z))
else
--print("velocity check")
vel = self.object:get_velocity()
if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
self.object:set_velocity(vector.new(vel.x,5,vel.z))
end
end
else
--print("velcheck 2")
vel = self.object:get_velocity()
if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
self.object:set_velocity(vector.new(vel.x,5,vel.z))
end
end
end
end
end
elseif def.movement_type == "jump" then
mob_register.move = function(self,dtime,moveresult)
self.manage_jump_timer(self,dtime)
self.timer = self.timer - dtime
--jump
self.jump(self,moveresult)
--swim
self.swim(self,dtime)
--direction state change
if self.timer <= 0 and not self.following == true then
--print("changing direction")
self.timer = math.random(2,7)
self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
--local yaw = self.object:get_yaw() + dtime
self.speed = math.random(0,self.max_speed)
--self.object:set_yaw(yaw)
end
self.hurt_inside(self,dtime)
currentvel = self.object:get_velocity()
if currentvel.y ~= 0 then
goal = vector.multiply(self.direction,self.speed)
acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
acceleration = vector.multiply(acceleration, 0.05)
self.object:add_velocity(acceleration)
end
end
mob_register.jump = function(self,moveresult)
if moveresult and moveresult.touching_ground and self.direction then
if self.jump_timer <= 0 then
if self.make_jump_noise then
minetest.sound_play("slime_splat", {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(80,100)/100})
end
vel = self.object:get_velocity()
self.object:set_velocity(vector.new(vel.x,5,vel.z))
if self.following == true then
self.jump_timer = 0.5
else
self.jump_timer = 1+math.random()
end
else
self.object:set_velocity(vector.new(0,0,0))
end
end
end
end
if def.pathfinds then
mob_register.pathfinding = function(self,dtime)
acute_pos = vector.floor(vector.add(self.object:get_pos(),0.5))
if self.following and self.following_pos then
self.pathfinding_timer = self.pathfinding_timer + dtime
height_diff = nil
if self.object:get_pos().y > self.following_pos.y then
height_diff = math.abs(self.object:get_pos().y-self.following_pos.y)
elseif self.object:get_pos().y <= self.following_pos.y then
height_diff = math.abs(self.following_pos.y-self.object:get_pos().y)
end
--delete path if height too far
if self.path_data and height_diff > self.view_distance/2 then
self.path_data = nil
self.old_path_pos = nil
self.old_acute_following_pos = nil
return
end
if self.pathfinding_timer >= 0.5 and height_diff <= self.view_distance/2 then
acute_following_pos = vector.floor(vector.add(self.following_pos,0.5))
if (not self.old_path_pos or (self.old_path_pos and not vector.equals(acute_pos,self.old_path_pos))) and
(not self.old_acute_following_pos or (self.old_acute_following_pos and vector.distance(self.old_acute_following_pos,acute_following_pos) > 2)) then
--if a player tries to hide in a node
if minetest.get_nodedef(minetest.get_node(acute_following_pos).name, "walkable") then
acute_following_pos.y = acute_following_pos.y + 1
end
--if a player tries to stand off the side of a node
if not minetest.get_nodedef(minetest.get_node(vector.new(acute_following_pos.x,acute_following_pos.y-1,acute_following_pos.z)).name, "walkable") then
min = vector.subtract(acute_following_pos,1)
max = vector.add(acute_following_pos,1)
index_table = minetest.find_nodes_in_area_under_air(min, max, all_walkable_nodes)
--optimize this as much as possible
for _,i_pos in pairs(index_table) do
if minetest.get_nodedef(minetest.get_node(i_pos).name, "walkable") then
acute_following_pos = vector.new(i_pos.x,i_pos.y+1,i_pos.z)
break
end
end
end
path = minetest.find_path(acute_pos,acute_following_pos,self.view_distance,1,1,"A*_noprefetch")
--if the path fails then raycast down to scare player or accidentally find new path
--disabled for extreme cpu usage
--[[
if not path then
local ray = minetest.raycast(acute_following_pos, vector.new(acute_following_pos.x,acute_following_pos.y-self.view_distance,acute_following_pos.z), false, false)
for pointed_thing in ray do
if pointed_thing.above then
path = minetest.find_path(self.object:get_pos(),pointed_thing.above,self.view_distance,1,5,"A*_noprefetch")
break
end
end
end
]]--
if path then
self.whip_turn = 0.025
self.path_data = path
--remove the first element of the list
--shift whole list down
for i = 2,table.getn(self.path_data) do
self.path_data[i-1] = self.path_data[i]
end
self.path_data[table.getn(self.path_data)] = nil
--cut corners (go diagonal)
if self.path_data and table.getn(self.path_data) >= 3 then
number = 3
for i = 3,table.getn(self.path_data) do
pos1 = self.path_data[number-2]
pos2 = self.path_data[number]
--print(number)
--check if diagonal and has direct line of sight
if pos1 and pos2 and pos1.x ~= pos2.x and pos1.z ~= pos2.z and pos1.y == pos2.y then
pos3 = vector.divide(vector.add(pos1,pos2),2)
pos3.y = pos3.y - 1
can_cut,_ = minetest.line_of_sight(pos1, pos2)
if can_cut then
if minetest.get_nodedef(minetest.get_node(pos3).name, "walkable") == true then
--shift whole list down
--print("removing"..number-1)
for z = number-1,table.getn(self.path_data) do
self.path_data[z-1] = self.path_data[z]
end
self.path_data[table.getn(self.path_data)] = nil
number = number + 2
else
number = number + 1
end
else
number = number + 1
end
if number > table.getn(self.path_data) then
break
end
else
number = number + 1
end
end
--if self.path_data and table.getn(self.path_data) <= 2 then
-- self.path_data = nil
--end
end
end
self.old_path_pos = acute_pos
self.old_acute_following_pos = acute_following_pos
end
end
elseif (not self.following and self.path_data) or (self.path_data and height_diff > self.view_distance/2) then
self.path_data = nil
self.old_path_pos = nil
self.old_acute_following_pos = nil
end
--[[
if self.path_data then
for index,pos_data in pairs(self.path_data) do
--print(dump(pos_data))
minetest.add_particle({
pos = pos_data,
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
expirationtime = 0.01,
size = 1,
texture = "dirt.png",
})
end
end
]]--
--this is the real time path deletion as it goes along it
if self.swimming == true then
self.path_data = nil
end
if self.path_data and table.getn(self.path_data) > 0 then
if vector.distance(acute_pos,self.path_data[1]) <= 1 then
--shift whole list down
for i = 2,table.getn(self.path_data) do
self.path_data[i-1] = self.path_data[i]
end
self.path_data[table.getn(self.path_data)] = nil
self.whip_turn = 0.01
--if table.getn(self.path_data) == 0 then
-- self.path_data = nil
--end
end
end
--charge at the player
if self.path_data and table.getn(self.path_data) < 2 then
self.path_data = nil
end
end
end
return(mob_register)
end

View File

@ -0,0 +1,116 @@
local
minetest,math
=
minetest,math
local pos
local light
mobs.create_timer_functions = function(def,mob_register)
--this controls how fast the mob punches
mob_register.manage_punch_timer = function(self,dtime)
if self.punch_timer > 0 then
self.punch_timer = self.punch_timer - dtime
end
--this controls how fast you can punch the mob (punched timer reset)
if self.punched_timer > 0 then
--print(self.punched_timer)
self.punched_timer = self.punched_timer - dtime
end
end
--this controls the hostile state
if def.hostile == true or def.attacked_hostile == true then
if def.hostile_cooldown == true then
mob_register.manage_hostile_timer = function(self,dtime)
if self.hostile_timer > 0 then
self.hostile_timer = self.hostile_timer - dtime
end
if self.hostile_timer <= 0 then
self.hostile = false
end
end
end
else
mob_register.manage_scared_timer = function(self,dtime)
if self.scared_timer > 0 then
self.scared_timer = self.scared_timer - dtime
end
if self.scared_timer <= 0 then
self.scared = false
end
end
end
mob_register.manage_hurt_color_timer = function(self,dtime)
if self.hurt_color_timer > 0 then
self.hurt_color_timer = self.hurt_color_timer - dtime
if self.hurt_color_timer <= 0 then
self.hurt_color_timer = 0
self.object:set_texture_mod("")
end
end
end
mob_register.manage_explode_timer = function(self,dtime)
self.tnt_timer = self.tnt_timer - dtime
self.tnt_tick_timer = self.tnt_tick_timer - dtime
if self.tnt_tick_timer <= 0 and not self.dead then
self.tnt_tick_timer = self.explosion_blink_timer
self.tnt_mod_state = math.abs(self.tnt_mod_state-1)
if self.tnt_mod_state == 0 then
self.object:set_texture_mod("")
else
self.object:set_texture_mod("^[colorize:"..self.explosion_blink_color..":130")
end
--print(self.object:get_texture_mod())
--self.object:set_texture_mod("^[colorize:red:130")
end
if self.tnt_timer <= 0 and not self.dead then
self.object:set_texture_mod("^[colorize:red:130")
pos = self.object:get_pos()
self.object:remove()
tnt(pos,self.explosion_power,self.explosion_type)
end
end
if def.custom_timer then
mob_register.do_custom_timer = function(self,dtime)
self.c_timer = self.c_timer + dtime
if self.c_timer >= self.custom_timer then
self.c_timer = 0
self.custom_timer_function(self,dtime)
end
end
end
mob_register.manage_projectile_timer = function(self,dtime)
self.projectile_timer = self.projectile_timer - dtime
end
if def.friendly_in_daylight then
mob_register.handle_friendly_in_daylight_timer = function(self,dtime)
self.friendly_in_daylight_timer = self.friendly_in_daylight_timer + dtime
if self.friendly_in_daylight_timer >= 2 then
self.friendly_in_daylight_timer = 0
pos = self.object:get_pos()
light = minetest.get_node_light(pos)
if pos and light and light >= 13 then --1 greater than torch light
if self.following == false then
self.hostile = false
end
else
self.hostile = true
end
end
end
end
--this stops the pig from flying into the air
mob_register.manage_jump_timer = function(self,dtime)
if self.jump_timer > 0 then
self.jump_timer = self.jump_timer - dtime
end
end
return(mob_register)
end