mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-01-08 00:39:30 +02:00
b6201765df
Changes: - When player from lobby spectates a crew that is at sea, it no longer crashes (in debug mode) and shows boat destination instead of marooned island - When player from lobby spectates a crew that is at sea, and waiting for island to load, it now shows boat surface instead of island that is being loaded
1038 lines
39 KiB
Lua
1038 lines
39 KiB
Lua
-- This file is part of thesixthroc's Pirate Ship softmod, licensed under GPLv3 and stored at https://github.com/danielmartin0/ComfyFactorio-Pirates.
|
|
|
|
|
|
local Balance = require 'maps.pirates.balance'
|
|
local _inspect = require 'utils.inspect'.inspect
|
|
local Memory = require 'maps.pirates.memory'
|
|
local Math = require 'maps.pirates.math'
|
|
local Common = require 'maps.pirates.common'
|
|
-- local Parrot = require 'maps.pirates.parrot'
|
|
local CoreData = require 'maps.pirates.coredata'
|
|
local Server = require 'utils.server'
|
|
local Utils = require 'maps.pirates.utils_local'
|
|
local Surfaces = require 'maps.pirates.surfaces.surfaces'
|
|
-- local Structures = require 'maps.pirates.structures.structures'
|
|
local Boats = require 'maps.pirates.structures.boats.boats'
|
|
local Crowsnest = require 'maps.pirates.surfaces.crowsnest'
|
|
local Hold = require 'maps.pirates.surfaces.hold'
|
|
local Lobby = require 'maps.pirates.surfaces.lobby'
|
|
local Cabin = require 'maps.pirates.surfaces.cabin'
|
|
local Roles = require 'maps.pirates.roles.roles'
|
|
local Classes = require 'maps.pirates.roles.classes'
|
|
local Token = require 'utils.token'
|
|
local Task = require 'utils.task'
|
|
local SurfacesCommon = require 'maps.pirates.surfaces.common'
|
|
|
|
local Public = {}
|
|
local enum = {
|
|
ADVENTURING = 'adventuring',
|
|
LEAVING_INITIAL_DOCK = 'leavinginitialdock'
|
|
}
|
|
Public.enum = enum
|
|
|
|
|
|
function Public.difficulty_vote(player_index, difficulty_id)
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
|
|
if not (memory.difficulty_votes) then memory.difficulty_votes = {} end
|
|
local player = game.players[player_index]
|
|
if not (player and player.valid) then return end
|
|
|
|
|
|
if memory.difficulty_votes[player_index] and memory.difficulty_votes[player_index] == difficulty_id then
|
|
return nil
|
|
else
|
|
log(_inspect(CoreData.difficulty_options))
|
|
local option = CoreData.difficulty_options[difficulty_id]
|
|
if not option then return end
|
|
|
|
local color = option.associated_color
|
|
Common.notify_force(memory.force, {'pirates.notify_difficulty_vote',player.name, color.r, color.g, color.b, option.text})
|
|
|
|
memory.difficulty_votes[player_index] = difficulty_id
|
|
|
|
Public.update_difficulty()
|
|
end
|
|
end
|
|
|
|
|
|
function Public.update_difficulty()
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
local vote_counts = {}
|
|
for _, difficulty_id in pairs(memory.difficulty_votes) do
|
|
if not vote_counts[difficulty_id] then
|
|
vote_counts[difficulty_id] = 1
|
|
else
|
|
vote_counts[difficulty_id] = vote_counts[difficulty_id] + 1
|
|
end
|
|
end
|
|
|
|
local modal_id = 1
|
|
local modal_count = 0
|
|
for difficulty_id, votes in pairs(vote_counts) do
|
|
if votes > modal_count or (votes == modal_count and difficulty_id < modal_id) then
|
|
modal_count = votes
|
|
modal_id = difficulty_id
|
|
end
|
|
end
|
|
|
|
if modal_id ~= memory.difficulty_option then
|
|
local color = CoreData.difficulty_options[modal_id].associated_color
|
|
|
|
local message1 = {'pirates.notify_difficulty_change', color.r, color.g, color.b, CoreData.difficulty_options[modal_id].text}
|
|
|
|
Common.notify_force(memory.force, message1)
|
|
|
|
-- local message2 = 'Difficulty changed to ' .. CoreData.difficulty_options[modal_id].text .. '.'
|
|
Server.to_discord_embed_raw({'', CoreData.comfy_emojis.kewl .. '[' .. memory.name .. '] ', message1}, true)
|
|
|
|
memory.difficulty_option = modal_id
|
|
memory.difficulty = CoreData.difficulty_options[modal_id].value
|
|
end
|
|
end
|
|
|
|
|
|
function Public.try_add_extra_time_at_sea(ticks)
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
if not memory.extra_time_at_sea then memory.extra_time_at_sea = 0 end
|
|
|
|
if memory.extra_time_at_sea >= CoreData.max_extra_seconds_at_sea * 60 then return false end
|
|
|
|
-- if memory.boat and memory.boat.state and memory.boat.state == Boats.enum_state.ATSEA_LOADING_MAP then return false end
|
|
|
|
memory.extra_time_at_sea = memory.extra_time_at_sea + ticks
|
|
return true
|
|
end
|
|
|
|
function Public.get_crewmembers_printable_string()
|
|
local crewmembers_string = ''
|
|
for _, player in pairs(Common.crew_get_crew_members()) do
|
|
if player.valid then
|
|
if crewmembers_string ~= '' then crewmembers_string = crewmembers_string .. ', ' end
|
|
crewmembers_string = crewmembers_string .. player.name
|
|
end
|
|
end
|
|
if crewmembers_string ~= '' then crewmembers_string = crewmembers_string .. '.' end
|
|
|
|
return crewmembers_string
|
|
end
|
|
|
|
function Public.try_lose(loss_reason)
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
if (not memory.game_lost) then
|
|
-- if (not memory.game_lost) and (not memory.game_won) then
|
|
memory.game_lost = true
|
|
memory.crew_disband_tick = game.tick + 360
|
|
|
|
local playtimetext = Utils.time_longform((memory.age or 0)/60)
|
|
|
|
local message = {'',loss_reason,' ',{'pirates.loss_rest_of_message_long', playtimetext, Public.get_crewmembers_printable_string()}}
|
|
|
|
Server.to_discord_embed_raw({'',CoreData.comfy_emojis.trashbin .. '[' .. memory.name .. '] ', message}, true)
|
|
|
|
local message2 = {'',loss_reason,' ',{'pirates.loss_rest_of_message_short', '[font=default-large-semibold]' .. playtimetext .. '[/font]'}}
|
|
|
|
Common.notify_game({'', '[' .. memory.name .. '] ',message2}, CoreData.colors.notify_gameover)
|
|
|
|
local force = memory.force
|
|
if not (force and force.valid) then return end
|
|
|
|
force.play_sound{path='utility/game_lost', volume_modifier=0.75} --playing to the whole game might scare ppl
|
|
end
|
|
end
|
|
|
|
function Public.try_win()
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
if (not (memory.game_lost or memory.game_won)) then
|
|
-- if (not memory.game_lost) and (not memory.game_won) then
|
|
memory.completion_time = Math.floor((memory.age or 0)/60)
|
|
|
|
local speedrun_time = (memory.age or 0)/60
|
|
local speedrun_time_str = Utils.time_longform(speedrun_time)
|
|
memory.game_won = true
|
|
-- memory.crew_disband_tick = game.tick + 1200
|
|
|
|
Server.to_discord_embed_raw({'', CoreData.comfy_emojis.goldenobese .. '[' .. memory.name .. '] Victory, on v' .. CoreData.version_string .. ', ', CoreData.difficulty_options[memory.difficulty_option].text, ', capacity ' .. CoreData.capacity_options[memory.capacity_option].text3 .. '. Playtime: ' .. speedrun_time_str .. ' since 1st island. Crewmembers: ' .. Public.get_crewmembers_printable_string()}, true)
|
|
|
|
Common.notify_game({'','[' .. memory.name .. '] ',{'pirates.victory',CoreData.version_string, CoreData.difficulty_options[memory.difficulty_option].text, CoreData.capacity_options[memory.capacity_option].text3, speedrun_time_str, Public.get_crewmembers_printable_string()}}, CoreData.colors.notify_victory)
|
|
|
|
game.play_sound{path='utility/game_won', volume_modifier=0.9}
|
|
|
|
memory.victory_pause_until_tick = game.tick + 60*18
|
|
memory.victory_continue_message = true
|
|
end
|
|
end
|
|
|
|
|
|
function Public.choose_crew_members()
|
|
-- local global_memory = Memory.get_global_memory()
|
|
local memory = Memory.get_crew_memory()
|
|
local capacity = memory.capacity
|
|
local boat = memory.boat
|
|
|
|
-- if the boat is over capacity, should prefer original endorsers over everyone else:
|
|
local crew_members = {}
|
|
local crew_members_count = 0
|
|
for _, player in pairs(game.connected_players) do
|
|
if crew_members_count < capacity and player.surface.name == CoreData.lobby_surface_name and Boats.on_boat(boat, player.position) then
|
|
-- check if they were an endorser
|
|
local endorser = false
|
|
for _, index in pairs(memory.original_proposal.endorserindices) do
|
|
if player.index == index then endorser = true end
|
|
end
|
|
if endorser then
|
|
crew_members[player.index] = player
|
|
crew_members_count = crew_members_count + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
if crew_members_count < capacity then
|
|
for _, player in pairs(game.connected_players) do
|
|
if crew_members_count < capacity and (not crew_members[player.index]) and player.surface.name == CoreData.lobby_surface_name and Boats.on_boat(boat, player.position) then
|
|
crew_members[player.index] = player
|
|
crew_members_count = crew_members_count + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, player in pairs(crew_members) do
|
|
player.force = memory.force
|
|
memory.crewplayerindices[#memory.crewplayerindices + 1] = player.index
|
|
end
|
|
|
|
return crew_members
|
|
end
|
|
|
|
|
|
function Public.join_spectators(player, crewid)
|
|
if not (crewid > 0) then return end
|
|
|
|
Memory.set_working_id(crewid)
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
local force = memory.force
|
|
if not (force and force.valid and Common.validate_player(player)) then return end
|
|
|
|
local surface = game.surfaces[CoreData.lobby_surface_name]
|
|
|
|
local adventuring = false
|
|
local spectating = false
|
|
if memory.crewstatus and memory.crewstatus == enum.ADVENTURING then
|
|
for _, playerindex in pairs(memory.crewplayerindices) do
|
|
if player.index == playerindex then adventuring = true end
|
|
end
|
|
for _, playerindex in pairs(memory.spectatorplayerindices) do
|
|
if player.index == playerindex then spectating = true end
|
|
end
|
|
end
|
|
|
|
if spectating then return end
|
|
|
|
if adventuring then
|
|
local char = player.character
|
|
|
|
if char and char.valid then
|
|
local p = char.position
|
|
-- local surface_name = char.surface.name
|
|
if p then
|
|
Common.notify_force(force, {'pirates.crew_to_spectator', player.name})
|
|
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
|
|
end
|
|
-- if p then
|
|
-- Common.notify_force(force, message .. ' to become a spectator.' .. ' [gps=' .. Math.ceil(p.x) .. ',' .. Math.ceil(p.y) .. ',' .. surface_name ..']')
|
|
-- -- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
|
|
-- end
|
|
|
|
Common.send_important_items_from_player_to_crew(player, true)
|
|
char.die(memory.force_name)
|
|
|
|
player.set_controller{type = defines.controllers.spectator}
|
|
else
|
|
Common.notify_force(force, {'pirates.crew_to_spectator', player.name})
|
|
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
|
|
player.set_controller{type = defines.controllers.spectator}
|
|
end
|
|
|
|
local c = surface.create_entity{name = 'character', position = surface.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint, force = 'player'}
|
|
|
|
player.associate_character(c)
|
|
|
|
player.set_controller{type = defines.controllers.spectator}
|
|
|
|
memory.crewplayerindices = Utils.ordered_table_with_values_removed(memory.crewplayerindices, player.index)
|
|
|
|
Roles.player_left_so_redestribute_roles(player)
|
|
else
|
|
Public.player_abandon_endorsements(player)
|
|
local c = player.character
|
|
player.set_controller{type = defines.controllers.spectator}
|
|
player.teleport(memory.spawnpoint, game.surfaces[memory.boat.surface_name])
|
|
player.force = force
|
|
player.associate_character(c)
|
|
|
|
Common.notify_force(force, {'pirates.lobby_to_spectator', player.name})
|
|
Common.notify_lobby({'pirates.lobby_to_spectator_2', player.name, memory.name})
|
|
end
|
|
memory.spectatorplayerindices[#memory.spectatorplayerindices + 1] = player.index
|
|
memory.tempbanned_from_joining_data[player.index] = game.tick
|
|
-- if #Common.crew_get_crew_members() == 0 then
|
|
-- memory.crew_disband_tick = game.tick + 30
|
|
-- -- memory.crew_disband_tick = game.tick + 60*60*2 --give players time to log back in after a crash or save
|
|
-- end
|
|
if not (memory.difficulty_votes) then memory.difficulty_votes = {} end
|
|
memory.difficulty_votes[player.index] = nil
|
|
end
|
|
|
|
|
|
function Public.leave_spectators(player, quiet)
|
|
quiet = quiet or false
|
|
local memory = Memory.get_crew_memory()
|
|
local surface = game.surfaces[CoreData.lobby_surface_name]
|
|
|
|
if not Common.validate_player(player) then return end
|
|
|
|
if not quiet then
|
|
Common.notify_force(player.force, {'pirates.spectator_to_lobby', player.name})
|
|
end
|
|
|
|
local chars = player.get_associated_characters()
|
|
if #chars > 0 then
|
|
player.teleport(chars[1].position, surface)
|
|
player.set_controller{type = defines.controllers.character, character = chars[1]}
|
|
else
|
|
player.set_controller{type = defines.controllers.god}
|
|
player.teleport(surface.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint, surface)
|
|
player.create_character()
|
|
end
|
|
|
|
memory.spectatorplayerindices = Utils.ordered_table_with_values_removed(memory.spectatorplayerindices, player.index)
|
|
|
|
if #Common.crew_get_crew_members() == 0 then
|
|
if Common.autodisband_ticks then
|
|
memory.crew_disband_tick = game.tick + Common.autodisband_ticks
|
|
end
|
|
if _DEBUG then memory.crew_disband_tick = game.tick + 30*60*60 end
|
|
end
|
|
|
|
player.force = 'player'
|
|
end
|
|
|
|
|
|
function Public.join_crew(player, crewid, rejoin)
|
|
if not crewid then return end
|
|
|
|
Memory.set_working_id(crewid)
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
if not Common.validate_player(player) then return end
|
|
|
|
-- local startsurface = game.surfaces[CoreData.lobby_surface_name]
|
|
|
|
local boat = memory.boat
|
|
local surface
|
|
if boat and boat.surface_name and game.surfaces[boat.surface_name] and game.surfaces[boat.surface_name].valid then
|
|
surface = game.surfaces[boat.surface_name]
|
|
else
|
|
surface = game.surfaces[Common.current_destination().surface_name]
|
|
end
|
|
|
|
-- local adventuring = false
|
|
local spectating = false
|
|
if memory.crewstatus and memory.crewstatus == enum.ADVENTURING then
|
|
-- for _, playerindex in pairs(memory.crewplayerindices) do
|
|
-- if player.index == playerindex then adventuring = true end
|
|
-- end
|
|
for _, playerindex in pairs(memory.spectatorplayerindices) do
|
|
if player.index == playerindex then spectating = true end
|
|
end
|
|
end
|
|
|
|
if spectating then
|
|
local chars = player.get_associated_characters()
|
|
for _, char in pairs(chars) do
|
|
char.destroy()
|
|
end
|
|
|
|
player.teleport(surface.find_non_colliding_position('character', memory.spawnpoint, 32, 0.5) or memory.spawnpoint, surface)
|
|
|
|
player.set_controller{type = defines.controllers.god}
|
|
player.create_character()
|
|
|
|
memory.spectatorplayerindices = Utils.ordered_table_with_values_removed(memory.spectatorplayerindices, player.index)
|
|
else
|
|
Public.player_abandon_endorsements(player)
|
|
player.force = memory.force
|
|
player.teleport(surface.find_non_colliding_position('character', memory.spawnpoint, 32, 0.5) or memory.spawnpoint, surface)
|
|
|
|
Common.notify_lobby({'pirates.lobby_to_crew_2', player.name, memory.name})
|
|
end
|
|
|
|
Common.notify_force(player.force, {'pirates.lobby_to_crew', player.name})
|
|
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.yum1 .. '[' .. memory.name .. '] ' .. message)
|
|
|
|
memory.crewplayerindices[#memory.crewplayerindices + 1] = player.index
|
|
|
|
-- don't give them items if they've been in the crew recently:
|
|
if not (memory.tempbanned_from_joining_data and memory.tempbanned_from_joining_data[player.index]) and (not rejoin) then --just using tempbanned_from_joining_data as a quick proxy for whether the player has ever been in this run before
|
|
for item, amount in pairs(Balance.starting_items_player_late) do
|
|
player.insert({name = item, count = amount})
|
|
end
|
|
end
|
|
|
|
Roles.confirm_captain_exists(player)
|
|
|
|
if #Common.crew_get_crew_members() == 1 and memory.crew_disband_tick then
|
|
memory.crew_disband_tick = nil --to prevent disbanding the crew after saving the game (booting everyone) and loading it again (joining the crew as the only member)
|
|
end
|
|
|
|
if memory.overworldx > 0 then
|
|
local color = CoreData.difficulty_options[memory.difficulty_option].associated_color
|
|
|
|
Common.notify_player_announce(player, {'pirates.personal_join_string_1', memory.name, CoreData.capacity_options[memory.capacity_option].text3, color.r, color.g, color.b, CoreData.difficulty_options[memory.difficulty_option].text})
|
|
else
|
|
Common.notify_player_announce(player, {'pirates.personal_join_string_1', memory.name, CoreData.capacity_options[memory.capacity_option].text3})
|
|
end
|
|
end
|
|
|
|
function Public.leave_crew(player, to_lobby, quiet)
|
|
quiet = quiet or false
|
|
local memory = Memory.get_crew_memory()
|
|
local surface = game.surfaces[CoreData.lobby_surface_name]
|
|
|
|
if not Common.validate_player(player) then return end
|
|
|
|
local char = player.character
|
|
if char and char.valid then
|
|
-- local p = char.position
|
|
-- local surface_name = char.surface.name
|
|
if not quiet then
|
|
Common.notify_force(player.force, {'pirates.crew_leave', player.name})
|
|
-- else
|
|
-- message = player.name .. ' left.'
|
|
end
|
|
-- if p then
|
|
-- Common.notify_force(player.force, message .. ' [gps=' .. Math.ceil(p.x) .. ',' .. Math.ceil(p.y) .. ',' .. surface_name ..']')
|
|
-- -- Server.to_discord_embed_raw(CoreData.comfy_emojis.feel .. '[' .. memory.name .. '] ' .. message)
|
|
-- end
|
|
|
|
if to_lobby then
|
|
Common.send_important_items_from_player_to_crew(player, true)
|
|
char.die(memory.force_name)
|
|
else
|
|
Common.send_important_items_from_player_to_crew(player)
|
|
memory.temporarily_logged_off_characters[player.index] = game.tick
|
|
end
|
|
-- else
|
|
-- if not quiet then
|
|
-- -- local message = player.name .. ' left the crew.'
|
|
-- -- Common.notify_force(player.force, message)
|
|
-- end
|
|
end
|
|
|
|
if to_lobby then
|
|
player.set_controller{type = defines.controllers.god}
|
|
|
|
player.teleport(surface.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint, surface)
|
|
player.force = 'player'
|
|
player.create_character()
|
|
end
|
|
|
|
memory.crewplayerindices = Utils.ordered_table_with_values_removed(memory.crewplayerindices, player.index)
|
|
|
|
-- setting it to this won't ban them from rejoining, it just affects the loot they spawn in with:
|
|
memory.tempbanned_from_joining_data[player.index] = game.tick - Common.ban_from_rejoining_crew_ticks
|
|
|
|
if not (memory.difficulty_votes) then memory.difficulty_votes = {} end
|
|
memory.difficulty_votes[player.index] = nil
|
|
|
|
if #Common.crew_get_crew_members() == 0 then
|
|
if Common.autodisband_ticks then
|
|
memory.crew_disband_tick = game.tick + Common.autodisband_ticks
|
|
end
|
|
-- memory.crew_disband_tick = game.tick + 60*60*2 --give players time to log back in after a crash or save
|
|
if _DEBUG then memory.crew_disband_tick = game.tick + 30*60*60 end
|
|
else
|
|
Roles.player_left_so_redestribute_roles(player)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function Public.get_unaffiliated_players()
|
|
local global_memory = Memory.get_global_memory()
|
|
|
|
local playerlist = {}
|
|
for _, player in pairs(game.connected_players) do
|
|
local found = false
|
|
for _, id in pairs(global_memory.crew_active_ids) do
|
|
Memory.set_working_id(id)
|
|
for _, player2 in pairs(Common.crew_get_crew_members_and_spectators()) do
|
|
if player == player2 then found = true end
|
|
end
|
|
end
|
|
if not found then playerlist[#playerlist + 1] = player end
|
|
end
|
|
return playerlist
|
|
end
|
|
|
|
|
|
function Public.plank(captain, player)
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
if Utils.contains(Common.crew_get_crew_members(), player) then
|
|
if (not (captain.index == player.index)) then
|
|
Server.to_discord_embed_raw(CoreData.comfy_emojis.monkas .. string.format("%s planked %s!", captain.name, player.name))
|
|
|
|
Common.notify_force(player.force, {'pirates.plank', captain.name, player.name})
|
|
|
|
Public.join_spectators(player, memory.id)
|
|
memory.tempbanned_from_joining_data[player.index] = game.tick + 60 * 120
|
|
return true
|
|
else
|
|
Common.notify_player_error(player, {'pirates.plank_error_self'})
|
|
return false
|
|
end
|
|
else
|
|
Common.notify_player_error(player, {'pirates.plank_error_invalid_player'})
|
|
return false
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function Public.disband_crew(donotprint)
|
|
local global_memory = Memory.get_global_memory()
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
if not memory.name then return end
|
|
|
|
local id = memory.id
|
|
local players = Common.crew_get_crew_members_and_spectators()
|
|
|
|
for _,player in pairs(players) do
|
|
if player.controller_type == defines.controllers.editor then player.toggle_map_editor() end
|
|
player.force = 'player'
|
|
end
|
|
|
|
if (not donotprint) then
|
|
|
|
local message = {'pirates.crew_disband', memory.name, Utils.time_longform((memory.real_age or 0)/60)}
|
|
Common.notify_game(message)
|
|
Server.to_discord_embed_raw({'', CoreData.comfy_emojis.monkas, message}, true)
|
|
|
|
-- if memory.game_won then
|
|
-- game.print({'chronosphere.message_game_won_restart'}, {r=0.98, g=0.66, b=0.22})
|
|
-- end
|
|
end
|
|
|
|
|
|
Public.reset_crew_and_enemy_force(id)
|
|
|
|
local lobby = game.surfaces[CoreData.lobby_surface_name]
|
|
for _, player in pairs(players) do
|
|
|
|
if player.character then
|
|
player.character.destroy()
|
|
player.character = nil
|
|
end
|
|
|
|
player.set_controller({type=defines.controllers.god})
|
|
|
|
if player.get_associated_characters() and #player.get_associated_characters() == 1 then
|
|
local char = player.get_associated_characters()[1]
|
|
player.teleport(char.position, char.surface)
|
|
|
|
player.set_controller({type=defines.controllers.character, character=char})
|
|
else
|
|
local pos = lobby.find_non_colliding_position('character', Common.lobby_spawnpoint, 32, 0.5) or Common.lobby_spawnpoint
|
|
player.teleport(pos, lobby)
|
|
player.create_character()
|
|
end
|
|
end
|
|
|
|
if memory.sea_name then
|
|
local seasurface = game.surfaces[memory.sea_name]
|
|
if seasurface then game.delete_surface(seasurface) end
|
|
end
|
|
|
|
for i = 1, memory.hold_surface_count do
|
|
local holdname = Hold.get_hold_surface_name(i)
|
|
if game.surfaces[holdname] then
|
|
game.delete_surface(game.surfaces[holdname])
|
|
end
|
|
end
|
|
|
|
local cabinname = Cabin.get_cabin_surface_name()
|
|
if game.surfaces[cabinname] then
|
|
game.delete_surface(game.surfaces[cabinname])
|
|
end
|
|
|
|
local s = Hold.get_hold_surface(1)
|
|
if s and s.valid then
|
|
log('hold failed to delete')
|
|
end
|
|
|
|
s = Cabin.get_cabin_surface()
|
|
if s and s.valid then
|
|
log(_inspect(cabinname))
|
|
log('cabin failed to delete')
|
|
end
|
|
|
|
local crowsnestname = SurfacesCommon.encode_surface_name(memory.id, 0, Surfaces.enum.CROWSNEST, nil)
|
|
if game.surfaces[crowsnestname] then game.delete_surface(game.surfaces[crowsnestname]) end
|
|
|
|
for _, destination in pairs(memory.destinations) do
|
|
if game.surfaces[destination.surface_name] then game.delete_surface(game.surfaces[destination.surface_name]) end
|
|
end
|
|
|
|
global_memory.crew_memories[id] = nil
|
|
for k, idd in pairs(global_memory.crew_active_ids) do
|
|
if idd == id then table.remove(global_memory.crew_active_ids, k) end
|
|
end
|
|
|
|
Lobby.place_starting_dock_showboat(id)
|
|
end
|
|
|
|
|
|
function Public.generate_new_crew_id()
|
|
local global_memory = Memory.get_global_memory()
|
|
|
|
if not global_memory.crew_memories[1] then return 1
|
|
elseif not global_memory.crew_memories[2] then return 2
|
|
elseif not global_memory.crew_memories[3] then return 3
|
|
else return end
|
|
end
|
|
|
|
|
|
function Public.player_abandon_proposal(player)
|
|
local global_memory = Memory.get_global_memory()
|
|
|
|
for k, proposal in pairs(global_memory.crewproposals) do
|
|
if proposal.endorserindices and proposal.endorserindices[1] and proposal.endorserindices[1] == player.index then
|
|
proposal.endorserindices[k] = nil
|
|
Common.notify_lobby({'pirates.proposal_retracted', proposal.name})
|
|
-- Server.to_discord_embed(message)
|
|
global_memory.crewproposals[k] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function Public.player_abandon_endorsements(player)
|
|
local global_memory = Memory.get_global_memory()
|
|
|
|
for k, proposal in pairs(global_memory.crewproposals) do
|
|
for k2, i in pairs(proposal.endorserindices) do
|
|
if i == player.index then
|
|
proposal.endorserindices[k2] = nil
|
|
if #proposal.endorserindices == 0 then
|
|
Common.notify_lobby({'pirates.proposal_abandoned', proposal.name})
|
|
-- Server.to_discord_embed(message)
|
|
global_memory.crewproposals[k] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local crowsnest_delayed = Token.register(
|
|
function(data)
|
|
Memory.set_working_id(data.crew_id)
|
|
Crowsnest.crowsnest_surface_delayed_init()
|
|
end
|
|
)
|
|
function Public.initialise_crowsnest()
|
|
local memory = Memory.get_crew_memory()
|
|
Crowsnest.create_crowsnest_surface()
|
|
Task.set_timeout_in_ticks(5, crowsnest_delayed, {crew_id = memory.id})
|
|
end
|
|
|
|
function Public.initialise_crowsnest_1()
|
|
Crowsnest.create_crowsnest_surface()
|
|
end
|
|
function Public.initialise_crowsnest_2()
|
|
Crowsnest.crowsnest_surface_delayed_init()
|
|
end
|
|
|
|
function Public.initialise_crew(accepted_proposal)
|
|
local global_memory = Memory.get_global_memory()
|
|
|
|
local new_id = Public.generate_new_crew_id()
|
|
|
|
global_memory.crew_active_ids[#global_memory.crew_active_ids + 1] = new_id
|
|
|
|
Memory.initialise_crew_memory(new_id)
|
|
Memory.set_working_id(new_id)
|
|
|
|
game.reset_time_played() -- affects the multiplayer lobby view
|
|
|
|
local memory = Memory.get_crew_memory()
|
|
|
|
local secs = Server.get_current_time()
|
|
if not secs then secs = 0 end
|
|
memory.secs_id = secs
|
|
|
|
memory.id = new_id
|
|
|
|
memory.force_name = Common.get_crew_force_name(new_id)
|
|
memory.enemy_force_name = Common.get_enemy_force_name(new_id)
|
|
memory.ancient_enemy_force_name = Common.get_ancient_hostile_force_name(new_id)
|
|
memory.ancient_friendly_force_name = Common.get_ancient_friendly_force_name(new_id)
|
|
|
|
memory.force = game.forces[memory.force_name]
|
|
memory.enemy_force = game.forces[memory.enemy_force_name]
|
|
memory.ancient_enemy_force = game.forces[memory.ancient_enemy_force_name]
|
|
memory.ancient_friendly_force = game.forces[memory.ancient_friendly_force_name]
|
|
|
|
memory.evolution_factor = 0
|
|
|
|
memory.delayed_tasks = {}
|
|
memory.buffered_tasks = {}
|
|
memory.crewplayerindices = {}
|
|
memory.spectatorplayerindices = {}
|
|
memory.tempbanned_from_joining_data = {}
|
|
memory.destinations = {}
|
|
memory.temporarily_logged_off_characters = {}
|
|
memory.class_renderings = {}
|
|
memory.class_auxiliary_data = {}
|
|
|
|
memory.hold_surface_count = 1
|
|
|
|
memory.speed_boost_characters = {}
|
|
|
|
memory.original_proposal = accepted_proposal
|
|
memory.name = accepted_proposal.name
|
|
memory.difficulty_option = accepted_proposal.difficulty_option
|
|
memory.capacity_option = accepted_proposal.capacity_option
|
|
-- memory.mode_option = accepted_proposal.mode_option
|
|
memory.difficulty = CoreData.difficulty_options[accepted_proposal.difficulty_option].value
|
|
memory.capacity = CoreData.capacity_options[accepted_proposal.capacity_option].value
|
|
-- memory.mode = CoreData.mode_options[accepted_proposal.mode_option].value
|
|
|
|
memory.destinationsvisited_indices = {}
|
|
memory.stored_fuel = Balance.starting_fuel
|
|
memory.available_classes_pool = Classes.initial_class_pool()
|
|
memory.playtesting_stats = {
|
|
coins_gained_by_biters = 0,
|
|
coins_gained_by_nests_and_worms = 0,
|
|
coins_gained_by_trees_and_rocks = 0,
|
|
coins_gained_by_ore = 0,
|
|
coins_gained_by_rocket_launches = 0,
|
|
coins_gained_by_markets = 0,
|
|
coins_gained_by_krakens = 0,
|
|
}
|
|
|
|
memory.captain_accrued_time_data = {}
|
|
memory.max_players_recorded = 0
|
|
|
|
memory.classes_table = {}
|
|
memory.officers_table = {}
|
|
memory.spare_classes = {}
|
|
memory.unlocked_classes = {}
|
|
|
|
memory.healthbars = {}
|
|
memory.overworld_krakens = {}
|
|
memory.kraken_stream_registrations = {}
|
|
|
|
memory.overworldx = 0
|
|
memory.overworldy = 0
|
|
|
|
memory.hold_surface_destroyable_wooden_chests = {}
|
|
|
|
memory.seaname = SurfacesCommon.encode_surface_name(memory.id, 0, SurfacesCommon.enum.SEA, enum.DEFAULT)
|
|
|
|
local surface = game.surfaces[CoreData.lobby_surface_name]
|
|
memory.spawnpoint = Common.lobby_spawnpoint
|
|
|
|
memory.force.set_spawn_position(memory.spawnpoint, surface)
|
|
|
|
local message = {'pirates.crew_launch', accepted_proposal.name}
|
|
Common.notify_game(message)
|
|
-- Server.to_discord_embed_raw(CoreData.comfy_emojis.pogkot .. message .. ' Difficulty: ' .. CoreData.difficulty_options[memory.difficulty_option].text .. ', Capacity: ' .. CoreData.capacity_options[memory.capacity_option].text3 .. '.')
|
|
Server.to_discord_embed_raw({'',CoreData.comfy_emojis.pogkot,message,' Capacity: ',CoreData.capacity_options[memory.capacity_option].text3,'.'}, true)
|
|
game.surfaces[CoreData.lobby_surface_name].play_sound{path='utility/new_objective', volume_modifier=0.75}
|
|
|
|
memory.boat = global_memory.lobby_boats[new_id]
|
|
local boat = memory.boat
|
|
|
|
for _, e in pairs(memory.boat.cannons_temporary_reference or {}) do
|
|
Common.new_healthbar(true, e, Balance.cannon_starting_hp, nil, e.health, 0.3, -0.1, memory.boat)
|
|
end
|
|
|
|
boat.dockedposition = boat.position
|
|
boat.speed = 0
|
|
boat.cannonscount = 2
|
|
end
|
|
|
|
|
|
function Public.summon_crew()
|
|
local memory = Memory.get_crew_memory()
|
|
local boat = memory.boat
|
|
|
|
local print = false
|
|
for _, player in pairs(game.connected_players) do
|
|
if player.surface and player.surface.valid and boat.surface_name and player.surface.name == boat.surface_name and (not Boats.on_boat(boat, player.position)) then
|
|
local p = player.surface.find_non_colliding_position('character', memory.spawnpoint, 5, 0.1)
|
|
if p then
|
|
player.teleport(p)
|
|
else
|
|
player.teleport(memory.spawnpoint)
|
|
end
|
|
print = true
|
|
end
|
|
end
|
|
if print then
|
|
Common.notify_force(memory.force, {'pirates.crew_summon'})
|
|
end
|
|
end
|
|
|
|
|
|
function Public.reset_crew_and_enemy_force(id)
|
|
local crew_force = game.forces[Common.get_crew_force_name(id)]
|
|
local enemy_force = game.forces[Common.get_enemy_force_name(id)]
|
|
local ancient_friendly_force = game.forces[Common.get_ancient_friendly_force_name(id)]
|
|
local ancient_enemy_force = game.forces[Common.get_ancient_hostile_force_name(id)]
|
|
|
|
crew_force.reset()
|
|
enemy_force.reset()
|
|
ancient_friendly_force.reset()
|
|
ancient_enemy_force.reset()
|
|
|
|
ancient_enemy_force.set_turret_attack_modifier('gun-turret', 0.2)
|
|
|
|
enemy_force.reset_evolution()
|
|
for _, tech in pairs(crew_force.technologies) do
|
|
crew_force.set_saved_technology_progress(tech, 0)
|
|
end
|
|
local lobby = game.surfaces[CoreData.lobby_surface_name]
|
|
crew_force.set_spawn_position(Common.lobby_spawnpoint, lobby)
|
|
|
|
enemy_force.ai_controllable = true
|
|
|
|
|
|
|
|
crew_force.set_friend('player', true)
|
|
game.forces['player'].set_friend(crew_force, true)
|
|
crew_force.set_friend(ancient_friendly_force, true)
|
|
ancient_friendly_force.set_friend(crew_force, true)
|
|
enemy_force.set_friend(ancient_friendly_force, true)
|
|
ancient_friendly_force.set_friend(enemy_force, true)
|
|
enemy_force.set_friend(ancient_enemy_force, true)
|
|
ancient_enemy_force.set_friend(enemy_force, true)
|
|
|
|
-- enemy_force.set_friend(environment_force, true)
|
|
-- environment_force.set_friend(enemy_force, true)
|
|
|
|
-- environment_force.set_friend(ancient_enemy_force, true)
|
|
-- ancient_enemy_force.set_friend(environment_force, true)
|
|
|
|
-- environment_force.set_friend(ancient_friendly_force, true)
|
|
-- ancient_friendly_force.set_friend(environment_force, true)
|
|
|
|
-- maybe make these dependent on map... it could be slower to mine on poor maps, so that players jump more often rather than getting every last drop
|
|
crew_force.mining_drill_productivity_bonus = 1
|
|
-- crew_force.mining_drill_productivity_bonus = 1.25
|
|
crew_force.manual_mining_speed_modifier = 3
|
|
crew_force.character_inventory_slots_bonus = 0
|
|
-- crew_force.character_inventory_slots_bonus = 10
|
|
-- crew_force.character_running_speed_modifier = Balance.base_extra_character_speed
|
|
crew_force.laboratory_productivity_bonus = 0
|
|
crew_force.ghost_time_to_live = 12 * 60 * 60
|
|
|
|
for k, v in pairs(Balance.player_ammo_damage_modifiers()) do
|
|
crew_force.set_ammo_damage_modifier(k, v)
|
|
end
|
|
for k, v in pairs(Balance.player_gun_speed_modifiers()) do
|
|
crew_force.set_gun_speed_modifier(k, v)
|
|
end
|
|
for k, v in pairs(Balance.player_turret_attack_modifiers()) do
|
|
crew_force.set_turret_attack_modifier(k, v)
|
|
end
|
|
|
|
crew_force.technologies['circuit-network'].researched = true
|
|
crew_force.technologies['uranium-processing'].researched = true
|
|
crew_force.technologies['kovarex-enrichment-process'].researched = true
|
|
crew_force.technologies['gun-turret'].researched = true
|
|
crew_force.technologies['electric-energy-distribution-1'].researched = true
|
|
crew_force.technologies['electric-energy-distribution-2'].researched = true
|
|
crew_force.technologies['advanced-material-processing'].researched = true
|
|
crew_force.technologies['advanced-material-processing-2'].researched = true
|
|
crew_force.technologies['solar-energy'].researched = true
|
|
crew_force.technologies['inserter-capacity-bonus-1'].researched = true --needed to make stack inserters different to fast inserters
|
|
-- crew_force.technologies['inserter-capacity-bonus-2'].researched = true
|
|
|
|
--as prerequisites for uranium ammo and automation 3:
|
|
crew_force.technologies['speed-module'].researched = true
|
|
crew_force.technologies['tank'].researched = true
|
|
crew_force.recipes['speed-module'].enabled = false
|
|
crew_force.recipes['tank'].enabled = false
|
|
crew_force.recipes['cannon-shell'].enabled = false
|
|
crew_force.recipes['explosive-cannon-shell'].enabled = false
|
|
|
|
|
|
|
|
--@TRYING this out:
|
|
crew_force.technologies['coal-liquefaction'].enabled = true
|
|
crew_force.technologies['coal-liquefaction'].researched = true
|
|
|
|
crew_force.technologies['automobilism'].enabled = false
|
|
|
|
crew_force.technologies['toolbelt'].enabled = false --trying this. we don't actually want players to carry too many things manually, and in fact in a resource-tight scenario that's problematic
|
|
|
|
-- note: many of these recipes are overwritten after tech researched!!!!!!! like pistol. check elsewhere in code
|
|
|
|
crew_force.recipes['pistol'].enabled = false
|
|
|
|
-- these are redundant I think...?:
|
|
crew_force.recipes['centrifuge'].enabled = false
|
|
crew_force.recipes['flamethrower-turret'].enabled = false
|
|
|
|
crew_force.technologies['railway'].researched = true --needed for purple sci
|
|
crew_force.recipes['rail'].enabled = true --needed for purple sci
|
|
crew_force.recipes['locomotive'].enabled = false
|
|
crew_force.recipes['car'].enabled = false
|
|
crew_force.recipes['cargo-wagon'].enabled = false
|
|
|
|
crew_force.recipes['nuclear-fuel'].enabled = false -- reduce clutter
|
|
|
|
-- crew_force.recipes['underground-belt'].enabled = false
|
|
-- crew_force.recipes['fast-underground-belt'].enabled = false
|
|
-- crew_force.recipes['express-underground-belt'].enabled = false
|
|
|
|
crew_force.technologies['land-mine'].enabled = false
|
|
crew_force.technologies['landfill'].enabled = false
|
|
crew_force.technologies['cliff-explosives'].enabled = false
|
|
|
|
crew_force.technologies['rail-signals'].enabled = false
|
|
|
|
crew_force.technologies['logistic-system'].enabled = false
|
|
|
|
|
|
crew_force.technologies['tank'].enabled = false
|
|
crew_force.technologies['rocketry'].enabled = false
|
|
crew_force.technologies['artillery'].enabled = false
|
|
crew_force.technologies['destroyer'].enabled = false
|
|
crew_force.technologies['spidertron'].enabled = false
|
|
crew_force.technologies['atomic-bomb'].enabled = false
|
|
crew_force.technologies['explosive-rocketry'].enabled = false
|
|
|
|
crew_force.technologies['research-speed-1'].enabled = false
|
|
crew_force.technologies['research-speed-2'].enabled = false
|
|
crew_force.technologies['research-speed-3'].enabled = false
|
|
crew_force.technologies['research-speed-4'].enabled = false
|
|
crew_force.technologies['research-speed-5'].enabled = false
|
|
crew_force.technologies['research-speed-6'].enabled = false
|
|
-- crew_force.technologies['follower-robot-count-1'].enabled = false
|
|
-- crew_force.technologies['follower-robot-count-2'].enabled = false
|
|
-- crew_force.technologies['follower-robot-count-3'].enabled = false
|
|
-- crew_force.technologies['follower-robot-count-4'].enabled = false
|
|
|
|
-- crew_force.technologies['inserter-capacity-bonus-3'].enabled = false
|
|
-- crew_force.technologies['inserter-capacity-bonus-4'].enabled = false
|
|
-- crew_force.technologies['inserter-capacity-bonus-5'].enabled = false
|
|
-- crew_force.technologies['inserter-capacity-bonus-6'].enabled = false
|
|
-- crew_force.technologies['refined-flammables-3'].enabled = false
|
|
-- crew_force.technologies['refined-flammables-4'].enabled = false
|
|
-- crew_force.technologies['refined-flammables-5'].enabled = false
|
|
|
|
-- for lategame balance:
|
|
-- crew_force.technologies['worker-robots-storage-1'].enabled = false
|
|
crew_force.technologies['worker-robots-storage-2'].enabled = false
|
|
crew_force.technologies['worker-robots-storage-3'].enabled = false
|
|
crew_force.technologies['worker-robots-speed-5'].enabled = false
|
|
crew_force.technologies['worker-robots-speed-6'].enabled = false
|
|
crew_force.technologies['follower-robot-count-5'].enabled = false
|
|
crew_force.technologies['follower-robot-count-6'].enabled = false
|
|
crew_force.technologies['follower-robot-count-7'].enabled = false
|
|
crew_force.technologies['inserter-capacity-bonus-6'].enabled = false
|
|
crew_force.technologies['inserter-capacity-bonus-7'].enabled = false
|
|
|
|
crew_force.technologies['weapon-shooting-speed-6'].enabled = false
|
|
crew_force.technologies['laser-shooting-speed-6'].enabled = false
|
|
crew_force.technologies['laser-shooting-speed-7'].enabled = false
|
|
crew_force.technologies['refined-flammables-5'].enabled = false
|
|
crew_force.technologies['refined-flammables-6'].enabled = false
|
|
crew_force.technologies['refined-flammables-7'].enabled = false
|
|
crew_force.technologies['energy-weapons-damage-5'].enabled = false --5 makes krakens too easy
|
|
crew_force.technologies['energy-weapons-damage-6'].enabled = false
|
|
crew_force.technologies['energy-weapons-damage-7'].enabled = false
|
|
crew_force.technologies['physical-projectile-damage-5'].enabled = false
|
|
crew_force.technologies['physical-projectile-damage-6'].enabled = false
|
|
crew_force.technologies['physical-projectile-damage-7'].enabled = false
|
|
crew_force.technologies['stronger-explosives-5'].enabled = false
|
|
crew_force.technologies['stronger-explosives-6'].enabled = false
|
|
crew_force.technologies['stronger-explosives-7'].enabled = false
|
|
-- these require 2000 white sci each:
|
|
crew_force.technologies['artillery-shell-range-1'].enabled = false --infinite techs
|
|
crew_force.technologies['artillery-shell-speed-1'].enabled = false --infinite techs
|
|
|
|
crew_force.technologies['steel-axe'].enabled = false
|
|
|
|
crew_force.technologies['concrete'].enabled = false
|
|
crew_force.technologies['nuclear-power'].enabled = false
|
|
|
|
crew_force.technologies['effect-transmission'].enabled = true
|
|
|
|
-- exploit?:
|
|
crew_force.technologies['gate'].enabled = true
|
|
|
|
crew_force.technologies['productivity-module-2'].enabled = true
|
|
crew_force.technologies['productivity-module-3'].enabled = false
|
|
crew_force.technologies['speed-module'].enabled = true
|
|
crew_force.technologies['speed-module-2'].enabled = false
|
|
crew_force.technologies['speed-module-3'].enabled = false
|
|
crew_force.technologies['effectivity-module'].enabled = false
|
|
crew_force.technologies['effectivity-module-2'].enabled = false
|
|
crew_force.technologies['effectivity-module-3'].enabled = false
|
|
crew_force.technologies['automation-3'].enabled = true
|
|
crew_force.technologies['rocket-control-unit'].enabled = false
|
|
crew_force.technologies['rocket-silo'].enabled = false
|
|
crew_force.technologies['space-science-pack'].enabled = false
|
|
crew_force.technologies['mining-productivity-4'].enabled = false
|
|
crew_force.technologies['logistics-3'].enabled = true
|
|
crew_force.technologies['nuclear-fuel-reprocessing'].enabled = false
|
|
|
|
-- crew_force.technologies['railway'].enabled = false
|
|
crew_force.technologies['automated-rail-transportation'].enabled = false
|
|
crew_force.technologies['braking-force-1'].enabled = false
|
|
crew_force.technologies['braking-force-2'].enabled = false
|
|
crew_force.technologies['braking-force-3'].enabled = false
|
|
crew_force.technologies['braking-force-4'].enabled = false
|
|
crew_force.technologies['braking-force-5'].enabled = false
|
|
crew_force.technologies['braking-force-6'].enabled = false
|
|
crew_force.technologies['braking-force-7'].enabled = false
|
|
crew_force.technologies['fluid-wagon'].enabled = false
|
|
|
|
crew_force.technologies['production-science-pack'].enabled = true
|
|
crew_force.technologies['utility-science-pack'].enabled = true
|
|
|
|
crew_force.technologies['modular-armor'].enabled = false
|
|
crew_force.technologies['power-armor'].enabled = false
|
|
crew_force.technologies['solar-panel-equipment'].enabled = false
|
|
crew_force.technologies['personal-roboport-equipment'].enabled = false
|
|
crew_force.technologies['personal-laser-defense-equipment'].enabled = false
|
|
crew_force.technologies['night-vision-equipment'].enabled = false
|
|
crew_force.technologies['energy-shield-equipment'].enabled = false
|
|
crew_force.technologies['belt-immunity-equipment'].enabled = false
|
|
crew_force.technologies['exoskeleton-equipment'].enabled = false
|
|
crew_force.technologies['battery-equipment'].enabled = false
|
|
crew_force.technologies['fusion-reactor-equipment'].enabled = false
|
|
crew_force.technologies['power-armor-mk2'].enabled = false
|
|
crew_force.technologies['energy-shield-mk2-equipment'].enabled = false
|
|
crew_force.technologies['personal-roboport-mk2-equipment'].enabled = false
|
|
crew_force.technologies['battery-mk2-equipment'].enabled = false
|
|
crew_force.technologies['discharge-defense-equipment'].enabled = false
|
|
|
|
crew_force.technologies['distractor'].enabled = false
|
|
crew_force.technologies['military-4'].enabled = true
|
|
crew_force.technologies['uranium-ammo'].enabled = true
|
|
end
|
|
|
|
|
|
return Public |