--local textures_b = { -- "amogus_entity.png", -- "amogus_entity_b.png", -- "amogus_entity_g.png", -- "amogus_entity_br.png" --} local entity = { physical = true, collisionbox = {-0.75, 0, -0.75, 0.75, 1.5, 0.75}, visual = "mesh", visual_size = {x=15, y=15, z=15}, mesh = "sussy_imposter_entity.obj", textures = {"sussy_imposter_entity.png"}, on_rightclick = function(self, clicker) minetest.chat_send_player(clicker:get_player_name(), "YOU MET THE MOST SUS THING IN THE WORLD!") amogus_general.play_random_sound( "sus_sound", self.object:get_pos(), 1.0, -- gain 40, -- max_hear_distance 1.0 -- pitch ) end, -- impostor config -- walk_acceleration_speed = 0.08, -- acceleration speed when no panic, no stress run_acceleration_speed = 0.15, -- acceleration speed when chasing player rotation_acceleration_speed = 0.5, -- self explainatory gravity = 9.81, -- m/s^2 jump_force = 8, -- self explainatory friction = 0.6, -- friction (0.0 - no friction like perfectly smooth ice | 1.0 - full friction and can't even move) rotation_friction = 0.8, -- the same but for rotation largest_distance_to_find_player = 12, -- largest distance to find player smallest_distance_to_lost_player = 16, -- smallest distance to lost player largest_distance_to_hurt_player = 1.5, -- largest distance to hurt player -------------------------- block_lastly_in_front = false, rotation_velocity = 0, rotation_direction = nil, sound_pitch = nil, sound_propability = nil, -- player detection variables player = nil, player_pos = nil, entity_pos = nil, entity_player_vector = nil, distance = nil, current_distance = nil, current_entity_player_vector = nil, nearest_player_index = nil, mode = 0, -- | 0 - stand still | 1 - walk | 2 - chase on_activate = function(self, staticdata) self.object:set_yaw(math.random() * 2 * math.pi) self.rotation_direction = math.random(-1, 1) end, on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir) amogus_general.play_random_sound( "sus_sound", self.object:get_pos(), 1.0, -- gain 40, -- max_hear_distance 1.5 -- pitch ) end, on_step = function(self, dtime) -- play sus sound randomly with different pitch depending on situation if self.mode == 0 or self.mode == 1 then -- stand still or walk self.sound_pitch = 0.8 self.sound_propability = 100 else -- chase (2) self.sound_pitch = 1.2 self.sound_propability = 50 end if math.random(self.sound_propability) == 1 then amogus_general.play_random_sound( "sus_sound", self.object:get_pos(), 1.0, -- gain 40, -- max_hear_distance self.sound_pitch -- pitch ) end -- if on singpleplayer mode or only one player is connected, calculate distance between player and mini crewmate if minetest.is_singleplayer() or #minetest.get_connected_players() == 1 then -- get first player self.player = minetest.get_connected_players()[1] self.player_pos = self.player:get_pos() self.entity_pos = self.object:get_pos() self.entity_player_vector = vector.subtract(self.player_pos, self.entity_pos) self.distance = vector.length(self.entity_player_vector) -- if on multiplayer mode, calculate distance between nearest player and mini crewmate else self.player = minetest.get_connected_players() self.distance = nil self.entity_player_vector = nil self.nearest_player_index = nil self.entity_pos = self.object:get_pos() -- iterate over all players for i = 1, #self.player do self.player_pos = self.player[i]:get_pos() --self.entity_player_vector = vector.subtract(self.player_pos, self.entity_pos) self.current_entity_player_vector = vector.subtract(self.player_pos, self.entity_pos) self.current_distance = vector.length(self.current_entity_player_vector) -- if distance is nil or current_distance is smaller than distance, set distance to current_distance if self.distance == nil or self.current_distance < self.distance then self.distance = self.current_distance self.entity_player_vector = self.current_entity_player_vector self.nearest_player_index = i end end -- get nearest player self.player = self.player[self.nearest_player_index] end -- if mode is 0 or 1 (stand still or walk) and distance is smaller or equal to largest_distance_to_find_player, set mode to 2 (chase) if (self.mode == 0 or self.mode == 1) and self.distance <= self.largest_distance_to_find_player then self.mode = 2 -- elseif mode is 2 (chase) elseif self.mode == 2 then -- if distance is greater or equal to smallest_distance_to_lost_player, set mode to 0 (stand still) if self.distance >= self.smallest_distance_to_lost_player then self.mode = 0 -- else if distance is smaller or equal to largest_distance_to_hurt_player, hurt player elseif self.distance <= self.largest_distance_to_hurt_player then if math.random(10) == 1 then self.player:punch(self.object, 1.0, { full_punch_interval = 1.0, damage_groups = {fleshy = 5}, }, nil) end end end -- if if not performing an action related to the player if self.mode ~= 2 then -- make mini crewmate sometimes stand still and sometimes walk if math.random(100) == 1 then if self.mode == 0 then self.mode = 1 else self.mode = 0 end end -- some chance of chaning rotation_direction to random value if math.random(10) == 1 then --self.rotation_direction = math.random(-1, 1) local rand = math.random() if rand < 0.2 then self.rotation_direction = 1 elseif rand < 0.4 then self.rotation_direction = -1 else self.rotation_direction = 0 end end -- update rotation_velocity self.rotation_velocity = self.rotation_velocity + self.rotation_direction * self.rotation_acceleration_speed * dtime -- update rotation self.object:set_yaw(self.object:get_yaw() + self.rotation_velocity * dtime) -- apply rotation_friction self.rotation_velocity = self.rotation_velocity * (1 - self.rotation_friction * dtime) else -- else performing an action related to the player self.rotation_velocity = 0; -- set rotation so entity is facing at the player self.object:set_yaw(math.atan2(self.entity_player_vector.z, self.entity_player_vector.x)) end -- perform calculations on direction local dir = self.object:get_yaw() local dir_cos = math.cos(dir) local dir_sin = math.sin(dir) -- if not standing still if self.mode ~= 0 then -- make mini crewmate walk or run local vel = self.object:get_velocity() -- if walking if self.mode == 1 then vel.x = vel.x + dir_cos * self.walk_acceleration_speed vel.z = vel.z + dir_sin * self.walk_acceleration_speed else -- chasing (2) vel.x = vel.x + dir_cos * self.run_acceleration_speed vel.z = vel.z + dir_sin * self.run_acceleration_speed end self.object:set_velocity(vel) end -- Make it also jump when some block is in front of it local pos = self.object:get_pos() pos.x = pos.x + dir_cos pos.z = pos.z + dir_sin local bnode = minetest.get_node(pos) --if bnode.name == "air" or bnode.name == "amogus_blocks:water_source" or bnode.name == "amogus_blocks:water_flowing" then -- if node is not solid OR is a liquid if minetest.registered_nodes[bnode.name].walkable == false or minetest.registered_nodes[bnode.name].liquidtype ~= "none" then self.block_lastly_in_front = false -- if node next to the entity is a solid block else if self.block_lastly_in_front == false then self.block_lastly_in_front = true local vel = self.object:get_velocity() vel.y = vel.y + self.jump_force self.object:set_velocity(vel) -- randomly jump in the next iteration even if theres still a block in front elseif math.random(10) == 1 then self.block_lastly_in_front = false end end local vel = self.object:get_velocity() -- change velocity by gravity vel.y = vel.y - self.gravity * dtime * 2 -- change velocity by friction vel.x = vel.x * (1 - self.friction * dtime) vel.z = vel.z * (1 - self.friction * dtime) self.object:set_velocity(vel) end } minetest.register_entity("amogus_entities:sussy_imposter", entity) -- register spawn egg minetest.register_craftitem("amogus_entities:sussy_imposter_spawn_egg", { description = "Sussy Imposter Spawn Egg", inventory_image = "imposta_egg.png", on_place = function(itemstack, placer, pointed_thing) if pointed_thing.type ~= "node" then return end local pos = pointed_thing.above local node = minetest.get_node(pos) local def = minetest.registered_nodes[node.name] if not def or not def.buildable_to then return end minetest.add_entity(pos, "amogus_entities:sussy_imposter") itemstack:take_item() return itemstack end, })