|
local production_score = require("production-score") |
|
local config = require("rocket-rush-config") |
|
|
|
local script_data = |
|
{ |
|
game_state = nil, |
|
prices = nil |
|
} |
|
|
|
local game_state = |
|
{ |
|
preparing = 0, |
|
in_progress = 1 |
|
} |
|
|
|
local sort_groups = function(groups) |
|
local new = {} |
|
for name, group in pairs (groups) do |
|
local order = group.order |
|
local put = false |
|
for k, other in pairs (new) do |
|
if order <= other.order then |
|
table.insert(new, k, group) |
|
put = true |
|
break |
|
end |
|
end |
|
if not put then |
|
table.insert(new, group) |
|
end |
|
end |
|
return new |
|
end |
|
|
|
local get_all_groups = function(items) |
|
local groups = {} |
|
local subgroups = {} |
|
for name, item in pairs (items) do |
|
if not item.has_flag("hidden") then |
|
if not groups[item.group.name] then |
|
|
|
groups[item.group.name] = item.group |
|
end |
|
if not subgroups[item.subgroup.name] then |
|
subgroups[item.subgroup.name] = {} |
|
end |
|
local subgroup = subgroups[item.subgroup.name] |
|
local order = item.order |
|
local put = false |
|
for k, other in pairs (subgroup) do |
|
if order <= other.order then |
|
table.insert(subgroup, k, item) |
|
put = true |
|
break |
|
end |
|
end |
|
if not put then |
|
table.insert(subgroup, item) |
|
end |
|
end |
|
end |
|
return sort_groups(groups), subgroups |
|
end |
|
|
|
local make_markets = function(surface) |
|
|
|
local subgroup_filter = |
|
{ |
|
|
|
["raw-resource"] = true, |
|
["armor"] = true, |
|
["equipment"] = true |
|
} |
|
|
|
local name_filter = |
|
{ |
|
|
|
} |
|
|
|
local prices = script_data.prices |
|
|
|
local is_valid_item = function(item) |
|
local name = item.name |
|
if not (prices[name] and (prices[name] <= config.starting_money) and prices[name] >= 1) then |
|
return false |
|
end |
|
|
|
if name_filter[name] or subgroup_filter[item.subgroup.name] then |
|
return false |
|
end |
|
|
|
if item.has_flag("hidden") then |
|
return false |
|
end |
|
|
|
return true |
|
|
|
end |
|
|
|
local items = {} |
|
for k, item in pairs (game.item_prototypes) do |
|
if is_valid_item(item) then |
|
items[k] = item |
|
end |
|
|
|
end |
|
|
|
local groups, subgroups = get_all_groups(items) |
|
|
|
local market_width = 5 |
|
local width = math.min(market_width * #groups, 40) |
|
market_width = width / #groups |
|
local offset = {2, -5} |
|
local icon_offset = {0, 0} |
|
local icon_scale = 0.5 |
|
|
|
for k, group in pairs (groups) do |
|
local market = surface.create_entity |
|
{ |
|
name = "market", |
|
position = {((k - 1) * market_width) - (width / 2) + offset[1], offset[2]}, |
|
force = "player" |
|
} |
|
market.destructible = false |
|
|
|
rendering.draw_sprite |
|
{ |
|
sprite = "utility/entity_info_dark_background", |
|
surface = surface, |
|
target = market, |
|
target_offset = icon_offset, |
|
x_scale = icon_scale * 4, |
|
y_scale = icon_scale * 4, |
|
only_in_alt_mode = true |
|
} |
|
|
|
rendering.draw_sprite |
|
{ |
|
sprite = "item-group/"..group.name, |
|
surface = surface, |
|
target = market, |
|
target_offset = icon_offset, |
|
x_scale = icon_scale, |
|
y_scale = icon_scale, |
|
only_in_alt_mode = true |
|
} |
|
|
|
for k, subgroup in pairs (group.subgroups) do |
|
local items = subgroups[subgroup.name] |
|
if items then |
|
for k, item in pairs (items) do |
|
local price = prices[item.name] |
|
local count = 1 |
|
if price < 40 then |
|
count = math.floor(40 / price) |
|
price = price * count |
|
end |
|
market.add_market_item |
|
{ |
|
price = {{"coin", price}}, offer = {type = "give-item", item = item.name, count = count} |
|
} |
|
end |
|
end |
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
local make_money_bags = function(surface) |
|
|
|
local offsets = |
|
{ |
|
{-4, 4}, |
|
{3, 4}, |
|
{-4, 3}, |
|
{3, 3} |
|
} |
|
|
|
local money_per_chest = config.starting_money / #offsets |
|
|
|
for k, offset in pairs (offsets) do |
|
local chest = surface.create_entity{name = "steel-chest", force = "player", position = offset} |
|
chest.insert{name = "coin", count = money_per_chest} |
|
chest.minable = false |
|
chest.destructible = false |
|
end |
|
|
|
end |
|
|
|
local get_lobby = function() |
|
local lobby = game.surfaces.lobby |
|
if (lobby and lobby.valid) then |
|
return lobby |
|
end |
|
|
|
lobby = game.create_surface("lobby", {width = 1, height = 1}) |
|
|
|
lobby.solar_power_multiplier = 0 |
|
|
|
for x = -1, 1 do |
|
for y = -1, 1 do |
|
lobby.set_chunk_generated_status({x, y}, defines.chunk_generated_status.entities) |
|
end |
|
end |
|
|
|
local tiles = {} |
|
|
|
for x = -20, 19 do |
|
for y = -10, 9 do |
|
local name = "refined-concrete" |
|
if x == -20 or x == 19 or y == -10 or y == 9 then |
|
name = "tutorial-grid" |
|
end |
|
table.insert(tiles, {name = name, position = {x, y}}) |
|
end |
|
end |
|
|
|
for x = -3, 2 do |
|
for y = 9, 9 + 29 do |
|
local name = "refined-concrete" |
|
if x == -3 or x == 2 or y == 9 + 29 then |
|
name = "tutorial-grid" |
|
end |
|
table.insert(tiles, {name = name, position = {x, y}}) |
|
end |
|
end |
|
|
|
for x = -6, 5 do |
|
for y = 31, 41 do |
|
local name = "hazard-concrete-left" |
|
if x == -6 or x == 5 or y == 41 then |
|
name = "tutorial-grid" |
|
end |
|
table.insert(tiles, {name = name, position = {x, y}}) |
|
end |
|
end |
|
|
|
table.insert(tiles, {name = "tutorial-grid", position = {-5, 30}}) |
|
table.insert(tiles, {name = "tutorial-grid", position = {-6, 30}}) |
|
table.insert(tiles, {name = "tutorial-grid", position = {-4, 30}}) |
|
table.insert(tiles, {name = "tutorial-grid", position = {3, 30}}) |
|
table.insert(tiles, {name = "tutorial-grid", position = {4, 30}}) |
|
table.insert(tiles, {name = "tutorial-grid", position = {5, 30}}) |
|
|
|
lobby.set_tiles(tiles) |
|
|
|
lobby.always_day = true |
|
lobby.daytime = 0 |
|
|
|
make_markets(lobby) |
|
make_money_bags(lobby) |
|
|
|
return lobby |
|
|
|
end |
|
|
|
local give_respawn_equipment = function(player) |
|
local equipment = config.starting_equipment |
|
local items = game.item_prototypes |
|
local list = {items = {}, armor = false, equipment = {}} |
|
for name, count in pairs (equipment) do |
|
local item = items[name] |
|
if item then |
|
if item.type == "armor" then |
|
local count = count |
|
if not list.armor then |
|
list.armor = item |
|
end |
|
count = count - 1 |
|
if count > 0 then |
|
list.items[item] = (list.items[item] or 0) + count |
|
end |
|
elseif item.place_as_equipment_result then |
|
list.equipment[item] = (list.equipment[item] or 0) + count |
|
else |
|
list.items[item] = (list.items[item] or 0) + count |
|
end |
|
else |
|
equipment[name] = nil |
|
end |
|
end |
|
local put_equipment = false |
|
if list.armor then |
|
local stack = player.get_inventory(defines.inventory.character_armor)[1] |
|
stack.set_stack{name = list.armor.name} |
|
local grid = stack.grid |
|
if grid then |
|
put_equipment = true |
|
for prototype, count in pairs (list.equipment) do |
|
local equipment = prototype.place_as_equipment_result |
|
for k = 1, count do |
|
local equipment = grid.put{name = equipment.name} |
|
if equipment then |
|
equipment.energy = equipment.max_energy |
|
else |
|
player.insert{name = prototype.name} |
|
end |
|
end |
|
end |
|
end |
|
end |
|
|
|
if not put_equipment then |
|
for prototype, count in pairs (list.equipment) do |
|
player.insert{name = prototype.name, count = count} |
|
end |
|
end |
|
|
|
for prototype, count in pairs (list.items) do |
|
player.insert{name = prototype.name, count = count} |
|
end |
|
end |
|
|
|
local launchpad_area = {{x = -5, y = 31}, {x = 5, y = 41}} |
|
local teleport_shift = {x = 0, y = -36} |
|
|
|
local start_round = function() |
|
script_data.game_state = game_state.in_progress |
|
|
|
local surface = game.surfaces.nauvis |
|
surface.request_to_generate_chunks({0,0}, 5) |
|
surface.force_generate_chunk_requests() |
|
|
|
local spawn_position = surface.find_non_colliding_position("rocket-silo", {0,0}, 100, 2, false) or {0,0} |
|
|
|
game.forces.player.set_spawn_position(spawn_position, surface) |
|
|
|
local tiles = {} |
|
for x = -5, 4 do |
|
for y = -5, 4 do |
|
local name = "refined-hazard-concrete-left" |
|
table.insert(tiles, {name = name, position = {x + spawn_position.x, y + spawn_position.y}}) |
|
end |
|
end |
|
|
|
surface.set_tiles(tiles) |
|
|
|
local remove_param = {name = "coin", count = config.starting_money} |
|
|
|
local get_position = function(position, entity) |
|
return surface.find_non_colliding_position(entity, {(position.x + teleport_shift.x) + spawn_position.x, (position.y + teleport_shift.y) + spawn_position.y}, 100, 0.25, false) |
|
end |
|
|
|
for k, player in pairs (game.players) do |
|
if player.surface ~= surface then |
|
if player.vehicle then |
|
if player.vehicle.train then |
|
player.driving = false |
|
player.teleport(get_position(player.position, player.character and player.character.name or "character"), surface) |
|
else |
|
player.vehicle.remove_item(remove_param) |
|
player.vehicle.teleport(get_position(player.vehicle.position, player.vehicle.name), surface) |
|
end |
|
else |
|
player.teleport(get_position(player.position, "character"), surface) |
|
end |
|
end |
|
|
|
player.remove_item(remove_param) |
|
|
|
if player.character then |
|
player.get_inventory(defines.inventory.character_trash).remove(remove_param) |
|
end |
|
|
|
end |
|
|
|
local lobby = get_lobby() |
|
local entities = lobby.find_entities_filtered{area = launchpad_area} |
|
for k, entity in pairs (entities) do |
|
entity.remove_item(remove_param) |
|
if not entity.valid then |
|
entities[k] = nil |
|
end |
|
end |
|
lobby.clone_entities{entities = entities, destination_offset = {teleport_shift.x + spawn_position.x, teleport_shift.y + spawn_position.y} , destination_surface = surface} |
|
|
|
surface.play_sound{path = "utility/achievement_unlocked"} |
|
|
|
game.forces.enemy.evolution_factor = config.starting_evolution_factor |
|
game.forces.enemy.ai_controllable = true |
|
|
|
game.delete_surface(lobby) |
|
game.reset_time_played() |
|
|
|
game.forces.player.manual_crafting_speed_modifier = 0 |
|
|
|
|
|
script_data.prices = nil |
|
|
|
end |
|
|
|
local notify_ready = function() |
|
|
|
if not script_data.start_tick then |
|
script_data.start_tick = game.tick + (59 * 15) |
|
script_data.tick_of_autosave = game.tick + (59 * 10) |
|
game.print({"all-players-ready"}) |
|
return |
|
end |
|
|
|
if game.tick == script_data.tick_of_autosave then |
|
game.auto_save("rocket-rush-prelaunch") |
|
end |
|
|
|
if game.tick >= script_data.start_tick then |
|
start_round() |
|
end |
|
|
|
end |
|
|
|
local notify_not_ready = function() |
|
if not script_data.start_tick then return end |
|
game.print({"not-all-players-ready"}) |
|
script_data.start_tick = nil |
|
script_data.tick_of_autosave = nil |
|
end |
|
|
|
local is_in_launchpad = function(position) |
|
|
|
local left_top = launchpad_area[1] |
|
if position.x < left_top.x or position.y < left_top.y then |
|
return |
|
end |
|
|
|
local right_bottom = launchpad_area[2] |
|
if position.x > right_bottom.x or position.y > right_bottom.y then |
|
return |
|
end |
|
|
|
return true |
|
end |
|
|
|
local check_launchpad = function() |
|
|
|
if script_data.game_state == game_state.in_progress then return end |
|
|
|
local player_count = #game.connected_players |
|
if player_count == 0 then |
|
notify_not_ready() |
|
return |
|
end |
|
|
|
for k, player in pairs (game.connected_players) do |
|
if not (is_in_launchpad(player.position)) then |
|
notify_not_ready() |
|
return |
|
end |
|
end |
|
|
|
notify_ready() |
|
|
|
end |
|
|
|
local on_player_created = function(event) |
|
|
|
check_launchpad() |
|
|
|
local player = game.get_player(event.player_index) |
|
|
|
player.game_view_settings.show_entity_info = true |
|
|
|
give_respawn_equipment(player) |
|
|
|
if script_data.game_state == game_state.in_progress then |
|
if game.is_multiplayer() then |
|
player.print({"msg-intro"}) |
|
else |
|
game.show_message_dialog{text = {"msg-intro"}} |
|
end |
|
return |
|
end |
|
|
|
if script_data.game_state == game_state.preparing then |
|
local surface = get_lobby() |
|
local position = surface.find_non_colliding_position("character", {0,0}, 100, 0.25, false) |
|
player.teleport(position, surface) |
|
|
|
if game.is_multiplayer() then |
|
player.print({"msg-intro"}) |
|
player.print({"msg-buy-equipment"}) |
|
player.print({"msg-refund-hint"}) |
|
else |
|
game.show_message_dialog{text = {"msg-intro"}} |
|
game.show_message_dialog{text = {"msg-buy-equipment"}} |
|
game.show_message_dialog{text = {"msg-refund-hint"}} |
|
end |
|
|
|
return |
|
end |
|
|
|
end |
|
|
|
local on_pre_player_died = function(event) |
|
if script_data.game_state == game_state.in_progress then |
|
return |
|
end |
|
|
|
local player = game.get_player(event.player_index) |
|
|
|
local character = player.character |
|
if character then |
|
character.health = 1 |
|
end |
|
|
|
end |
|
|
|
local anti_cheese = |
|
{ |
|
["refined-concrete"] = true, |
|
["hazard-concrete"] = true |
|
} |
|
|
|
local check_trash_refund = function() |
|
if script_data.game_state == game_state.in_progress then |
|
return |
|
end |
|
|
|
|
|
|
|
local prices = script_data.prices |
|
local equipment = config.starting_equipment |
|
|
|
for k, player in pairs (game.connected_players) do |
|
if player.character then |
|
local inventory = player.get_inventory(defines.inventory.character_trash) |
|
if inventory then |
|
local contents = inventory.get_contents() |
|
for name, count in pairs (contents) do |
|
if prices[name] and not (equipment[name] or anti_cheese[name]) then |
|
local removed_count = inventory.remove({name = name, count = count}) |
|
if removed_count > 0 then |
|
player.insert{name = "coin", count = removed_count * prices[name]} |
|
end |
|
end |
|
end |
|
end |
|
end |
|
end |
|
|
|
end |
|
|
|
local lib = {} |
|
|
|
lib.events = |
|
{ |
|
[defines.events.on_player_created] = on_player_created, |
|
[defines.events.on_pre_player_died] = on_pre_player_died, |
|
|
|
} |
|
|
|
lib.on_nth_tick = |
|
{ |
|
[59] = check_launchpad, |
|
[127] = check_trash_refund |
|
} |
|
|
|
lib.on_init = function() |
|
global.rocket_rush = global.rocket_rush or script_data |
|
|
|
script_data.prices = production_score.generate_price_list(config.prices_param) |
|
script_data.game_state = game_state.preparing |
|
|
|
game.forces.player.research_all_technologies() |
|
game.forces.player.manual_crafting_speed_modifier = -1 |
|
|
|
|
|
game.forces.enemy.evolution_factor = config.starting_evolution_factor |
|
game.forces.enemy.ai_controllable = false |
|
|
|
end |
|
|
|
lib.on_load = function() |
|
script_data = global.rocket_rush or script_data |
|
end |
|
|
|
lib.on_configuration_changed = function() |
|
|
|
end |
|
|
|
return lib |
|
|