X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=mods%2Fmob%2Fapi%2Finteraction.lua;h=5d257c01c265dbc27d2a5c68c3d8f69605cb2702;hb=7a724644067aed7843a334ac31fd0afbba7bf4e0;hp=dd567e6e410b5154b84d23729788eed96d64a8af;hpb=419873cf89577037ec5759756525b76073b8597d;p=Crafter.git diff --git a/mods/mob/api/interaction.lua b/mods/mob/api/interaction.lua index dd567e6..5d257c0 100644 --- a/mods/mob/api/interaction.lua +++ b/mods/mob/api/interaction.lua @@ -1,304 +1,382 @@ -- 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 + --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) - - vel1 = vector.multiply(velocity, -1) - 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 - - 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 + --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 + + local collisionbox = self.object:get_properties().collisionbox - --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) then - if puncher ~= self.object then - self.hostile = true - end - self.hostile_timer = 20 - self.punched_timer = 0.8 - - --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.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.object:set_texture_mod("^[colorize:red:130") - if self.child then - self.child:set_texture_mod("^[colorize:red:130") - end - self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir) - end - end + pos.y = pos.y + collisionbox[2] + + local collision_boundary = collisionbox[4] - --this is what happens when a mob dies - mob_register.on_death = function(self, killer) - local pos = self.object:getpos() - --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_amount and self.item_minumum then - local data_item_amount = math.random(self.item_minimum, self.item_amount) - for i = self.item_minimum,data_item_amount do - minetest.throw_item(pos,self.item_drop) - end - else - minetest.throw_item(pos,self.item_drop) - end - end - - - self.object:remove() - - if self.child then - self.child:get_luaentity().parent = nil - end - 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.child then - self.move_head(self,pos2,dtime) - end - - if self.hostile == true then - - self.direction = vector.direction(pos,pos2) - local distance = vector.distance(pos,pos2)-2 - if distance < 0 then - distance = 0 - end - - --punch the player - if self.attack_type == "punch" then - if distance < 1 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 - if distance < self.explosion_radius 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.object:set_texture_mod("^[colorize:white:130") - if self.child then - self.child:set_texture_mod("^[colorize:white:130") - end - 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.speed = distance * 4 - if self.speed > self.max_speed then - self.speed = self.max_speed - end - self.following = true - end - --only look at one player - break - end - end - --stare straight if not found - if player_found == false then - if self.child then - self.move_head(self,nil,dtime) - end - if self.manage_hostile_timer then - self.manage_hostile_timer(self,dtime) - end - end - end - - return(mob_register) -end + local radius = collision_boundary + + if collisionbox[5] > collision_boundary then + radius = collisionbox[5] + end + + 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 + + local pos2 = object:get_pos() + + local object_collisionbox = object:get_properties().collisionbox + + pos2.y = pos2.y + object_collisionbox[2] + + local 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 + local y_base_diff = (pos2.y + object_collisionbox[5]) - pos.y + + local y_top_diff = (pos.y + collisionbox[5]) - pos2.y + + + local 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 + + 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 + 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:"..self.damage_color..":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:"..self.damage_color..":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() + 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 + local item + 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 + local 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 + + global_mob_amount = global_mob_amount - 1 + --print("Mobs Died. Current Mobs: "..global_mob_amount) + + if self.custom_on_death then + self.custom_on_death(self) + end + + 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) + 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 + 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 = {damage=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(vector.new(pos.x,pos.y+self.object:get_properties().collisionbox[5],pos.z), self.projectile_type) + if obj then + local 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 + 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 + + return(mob_register) +end \ No newline at end of file