local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius local math_random = math.random local vector_multiply = vector.multiply local vector_direction = vector.direction local integer_test = {-1,1} mobs.collision = function(self) local pos = self.object:get_pos() if not self or not self.object or not self.object:get_luaentity() then return end --do collision detection from the base of the mob local collisionbox = self.object:get_properties().collisionbox pos.y = pos.y + collisionbox[2] local collision_boundary = collisionbox[4] local radius = collision_boundary if collisionbox[5] > collision_boundary then radius = collisionbox[5] end local collision_count = 0 local check_for_attack = false if self.attack_type == "punch" and self.hostile and self.attacking then check_for_attack = true end for _,object in ipairs(minetest_get_objects_inside_radius(pos, radius*1.25)) do if object and object ~= self.object and (object:is_player() or (object:get_luaentity() and object:get_luaentity()._cmi_is_mob == true and object:get_luaentity().health > 0)) 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 --mob cramming if collision_count > 30 then self.health = -20 break end 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 --slightly adjust mob position to prevent equal length --corner/wall sticking dir.x = dir.x + ((math_random()/10)*integer_test[math.random(1,2)]) dir.z = dir.z + ((math_random()/10)*integer_test[math.random(1,2)]) end local velocity = dir --0.5 is the max force multiplier local force = 0.5 - (0.5 * distance / (collision_boundary + object_collision_boundary)) local vel1 = vector.multiply(velocity, -1.5) local vel2 = vector.multiply(velocity, 1.5) vel1 = vector.multiply(vel1, force * 10) vel2 = vector.multiply(vel2, force) if object:is_player() then vel2 = vector_multiply(vel2, 2.5) --integrate mob punching into collision detection if check_for_attack and self.punch_timer <= 0 then if object == self.attacking then mobs.punch_attack(self) end end end self.object:add_velocity(vel1) object:add_velocity(vel2) end end end end --this is used for arrow collisions mobs.arrow_hit = function(self, player) player:punch(self.object, 1.0, { full_punch_interval = 1.0, damage_groups = {fleshy = self._damage} }, nil) --knockback local pos1 = self.object:get_pos() pos1.y = 0 local pos2 = player:get_pos() pos2.y = 0 local dir = vector_direction(pos1,pos2) dir = vector_multiply(dir,3) if player:get_velocity().y <= 1 then dir.y = 5 end player:add_velocity(dir) end