Crafter/mods/mob/api/interaction.lua
2020-05-15 13:59:47 -04:00

321 lines
9.6 KiB
Lua

--
mobs.create_interaction_functions = function(def,mob_register)
--the sword wear mechanic
mob_register.add_sword_wear = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
if puncher:is_player() then
local itemstack = puncher:get_wielded_item()
local 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
mob_register.collision_detection = function(self)
local pos = self.object:get_pos()
--do collision detection from the base of the mob
pos.y = pos.y - self.object:get_properties().collisionbox[2]
for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.collision_boundary)) do
if object:is_player() or object:get_luaentity().mob == true then
local pos2 = object:get_pos()
local 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
local velocity = vector.multiply(dir,1.1)
local vel1 = vector.multiply(velocity, -1)
local vel2 = velocity
self.object:add_velocity(vel1)
if object:is_player() then
object:add_player_velocity(vel2)
else
object:add_velocity(vel2)
end
end
end
end
if def.takes_fall_damage == nil or def.takes_fall_damage == true then
mob_register.fall_damage = function(self)
local vel = self.object:get_velocity()
if vel and self.oldvel then
if self.oldvel.y < -7 and vel.y == 0 then
local 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
--this controls what happens when the mob gets punched
mob_register.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
local hp = self.hp
local vel = self.object:get_velocity()
local hurt = tool_capabilities.damage_groups.damage
if not hurt then
hurt = 1
end
local critical = false
--criticals
local pos = self.object:get_pos()
if puncher:is_player() then
local puncher_vel = puncher:get_player_velocity().y
if puncher_vel < 0 then
hurt = hurt * 1.5
critical = true
end
end
local hp = hp-hurt
if (self.punched_timer <= 0 and hp > 1) and not self.dead then
self.object:set_texture_mod("^[colorize:red:130")
self.hurt_color_timer = 0.25
if puncher ~= self.object then
self.punched_timer = 0.8
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
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
minetest.sound_play(self.hurt_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(100,140)/100})
self.hp = hp
self.direction = vector.multiply(dir,-1)
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:red:130")
self.hurt_color_timer = 0.25
if puncher ~= self.object then
self.punched_timer = 0.8
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
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
minetest.sound_play(self.die_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(80,100)/100})
self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir)
end
end
--this is what happens when a mob dies
mob_register.on_death = function(self, killer)
local pos = self.object:get_pos()
--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
--detect if multiple items are going to be added
if self.item_max then
local data_item_amount = math.random(self.item_minimum, self.item_max)
for i = 1 ,data_item_amount do
minetest.throw_item(pos,self.item_drop)
end
else
minetest.throw_item(pos,self.item_drop)
end
end
global_mob_amount = global_mob_amount - 1
print("Mobs Died. Current Mobs: "..global_mob_amount)
self.object:remove()
end
--the pig will look for and at players
mob_register.look_around = function(self,dtime)
local pos = self.object:get_pos()
if self.die_in_light and self.die_in_light_level and self.die_in_light == true then
local light_level = minetest.get_node_light(pos)
if light_level then
if (self.die_in_light == true and light_level > self.die_in_light_level) then
local damage = self.hp
self.object:punch(self.object, 2,
{
full_punch_interval=1.5,
damage_groups = {damage=damage},
})
end
end
end
--STARE O_O
--and follow!
self.following = false
local 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
local 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
local distance = vector.distance(pos,pos2)
--punch the player
if self.attack_type == "punch" then
if distance < 2.5 and self.punch_timer <= 0 and object:get_hp() > 0 then
local line_of_sight = minetest.line_of_sight(pos, pos2)
if line_of_sight == true then
self.punch_timer = 1
object:punch(self.object, 2,
{
full_punch_interval=1.5,
damage_groups = {fleshy=2},
},vector.direction(pos,pos2))
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
local obj = minetest.add_entity(pos, self.projectile_type)
if obj then
local dir = vector.multiply(vector.direction(pos,pos2), 50)
obj:set_velocity(dir)
obj:get_luaentity().timer = 2
end
end
end
self.direction = vector.direction(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z))
self.speed = self.max_speed
self.following = true
end
--only look at one player
break
end
end
--stare straight if not found
if player_found == false then
self.move_head(self,nil,dtime)
if self.manage_hostile_timer then
self.manage_hostile_timer(self,dtime)
end
end
end
return(mob_register)
end