mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
155 lines
5.1 KiB
Lua
155 lines
5.1 KiB
Lua
function get_any_stack_size(name)
|
|
local item = prototypes.item[name]
|
|
if item ~= nil then
|
|
return item.stack_size
|
|
end
|
|
item = prototypes.equipment[name]
|
|
if item ~= nil then
|
|
return item.stack_size
|
|
end
|
|
-- failsafe
|
|
return 1
|
|
end
|
|
|
|
-- from https://stackoverflow.com/a/40180465
|
|
-- split("a,b,c", ",") => {"a", "b", "c"}
|
|
function split(s, sep)
|
|
local fields = {}
|
|
|
|
sep = sep or " "
|
|
local pattern = string.format("([^%s]+)", sep)
|
|
string.gsub(s, pattern, function(c) fields[#fields + 1] = c end)
|
|
|
|
return fields
|
|
end
|
|
|
|
function random_offset_position(position, offset)
|
|
return {x=position.x+math.random(-offset, offset), y=position.y+math.random(-offset, offset)}
|
|
end
|
|
|
|
function fire_entity_at_players(entity_name, speed)
|
|
local entities = {}
|
|
for _, player in ipairs(game.forces["player"].players) do
|
|
if player.character ~= nil then
|
|
table.insert(entities, player.character)
|
|
end
|
|
end
|
|
return fire_entity_at_entities(entity_name, entities, speed)
|
|
end
|
|
|
|
function fire_entity_at_entities(entity_name, entities, speed)
|
|
for _, current_entity in ipairs(entities) do
|
|
local target = current_entity
|
|
if target.health == nil then
|
|
target = target.position
|
|
end
|
|
current_entity.surface.create_entity{name=entity_name,
|
|
position=random_offset_position(current_entity.position, 128),
|
|
target=target, speed=speed}
|
|
end
|
|
end
|
|
|
|
local teleport_requests = {}
|
|
local teleport_attempts = {}
|
|
local max_attempts = 100
|
|
|
|
function attempt_teleport_player(player, attempt)
|
|
-- global attempt storage as metadata can't be stored
|
|
if attempt == nil then
|
|
attempt = teleport_attempts[player.index]
|
|
else
|
|
teleport_attempts[player.index] = attempt
|
|
end
|
|
|
|
if attempt > max_attempts then
|
|
player.print("Teleport failed: No valid position found after " .. max_attempts .. " attempts!")
|
|
teleport_attempts[player.index] = 0
|
|
return
|
|
end
|
|
|
|
local surface = player.character.surface
|
|
local prototype_name = player.character.prototype.name
|
|
local original_position = player.character.position
|
|
local candidate_position = random_offset_position(original_position, 1024)
|
|
|
|
local non_colliding_position = surface.find_non_colliding_position(
|
|
prototype_name, candidate_position, 0, 1
|
|
)
|
|
|
|
if non_colliding_position then
|
|
-- Request pathfinding asynchronously
|
|
local path_id = surface.request_path{
|
|
bounding_box = player.character.prototype.collision_box,
|
|
collision_mask = { layers = { ["player"] = true } },
|
|
start = original_position,
|
|
goal = non_colliding_position,
|
|
force = player.force.name,
|
|
radius = 1,
|
|
pathfind_flags = {cache = true, low_priority = true, allow_paths_through_own_entities = true},
|
|
}
|
|
|
|
-- Store the request with the player index as the key
|
|
teleport_requests[player.index] = path_id
|
|
else
|
|
attempt_teleport_player(player, attempt + 1)
|
|
end
|
|
end
|
|
|
|
function handle_teleport_attempt(event)
|
|
for player_index, path_id in pairs(teleport_requests) do
|
|
-- Check if the event matches the stored path_id
|
|
if path_id == event.id then
|
|
local player = game.players[player_index]
|
|
|
|
if event.path then
|
|
if player.character then
|
|
player.character.teleport(event.path[#event.path].position) -- Teleport to the last point in the path
|
|
-- Clear the attempts for this player
|
|
teleport_attempts[player_index] = 0
|
|
return
|
|
end
|
|
return
|
|
end
|
|
|
|
attempt_teleport_player(player, nil)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
function spill_character_inventory(character)
|
|
if not (character and character.valid) then
|
|
return false
|
|
end
|
|
|
|
-- grab attrs once pre-loop
|
|
local position = character.position
|
|
local surface = character.surface
|
|
|
|
local inventories_to_spill = {
|
|
defines.inventory.character_main, -- Main inventory
|
|
defines.inventory.character_trash, -- Logistic trash slots
|
|
}
|
|
|
|
for _, inventory_type in pairs(inventories_to_spill) do
|
|
local inventory = character.get_inventory(inventory_type)
|
|
if inventory and inventory.valid then
|
|
-- Spill each item stack onto the ground
|
|
for i = 1, #inventory do
|
|
local stack = inventory[i]
|
|
if stack and stack.valid_for_read then
|
|
local spilled_items = surface.spill_item_stack{
|
|
position = position,
|
|
stack = stack,
|
|
enable_looted = false, -- do not mark for auto-pickup
|
|
force = nil, -- do not mark for auto-deconstruction
|
|
allow_belts = true, -- do mark for putting it onto belts
|
|
}
|
|
if #spilled_items > 0 then
|
|
stack.clear() -- only delete if spilled successfully
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|