--luacheck: ignore local Token = require 'utils.token' local Task = require 'utils.task' local Event = require 'utils.event' local Global = require 'utils.global' local Alert = require 'utils.alert' local WPT = require 'maps.amap.table' local WD = require 'modules.wave_defense.table' local math2d = require 'math2d' local Commands = require 'commands.misc' local RPG = require 'modules.rpg.table' local this = { power_sources = {index = 1}, refill_turrets = {index = 1}, magic_crafters = {index = 1}, magic_fluid_crafters = {index = 1}, art_table = {index = 1}, surface_cleared = false } local starting_items = {['pistol'] = 1, ['firearm-magazine'] = 16, ['wood'] = 16} Global.register( this, function(t) this = t end ) local Public = {} local random = math.random local floor = math.floor local remove = table.remove local sqrt = math.sqrt local magic_crafters_per_tick = 3 local magic_fluid_crafters_per_tick = 8 local tile_damage = 50 local artillery_target_entities = { 'character', 'tank', 'car', 'radar', 'lab', 'furnace', 'locomotive', 'cargo-wagon', 'fluid-wagon', 'artillery-wagon', 'artillery-turret', 'laser-turret', 'gun-turret', 'flamethrower-turret', 'silo', 'spidertron' } function Public.get_player_data(player, remove_user_data) local players = WPT.get('players') if remove_user_data then if players[player.index] then players[player.index] = nil end end if not players[player.index] then players[player.index] = {} end return players[player.index] end local get_player_data = Public.get_player_data local function debug_str(msg) local debug = WPT.get('debug') if not debug then return end print('Mtn: ' .. msg) end local function show_text(msg, pos, color, surface) if color == nil then surface.create_entity({name = 'flying-text', position = pos, text = msg}) else surface.create_entity({name = 'flying-text', position = pos, text = msg, color = color}) end end local function fast_remove(tbl, index) local count = #tbl if index > count then return elseif index < count then tbl[index] = tbl[count] end tbl[count] = nil end local function do_refill_turrets() local refill_turrets = this.refill_turrets local index = refill_turrets.index if index > #refill_turrets then refill_turrets.index = 1 return end local turret_data = refill_turrets[index] local turret = turret_data.turret if not turret.valid then fast_remove(refill_turrets, index) return end refill_turrets.index = index + 1 local data = turret_data.data if data.liquid then turret.fluidbox[1] = data elseif data then turret.insert(data) end end local function do_turret_energy() local power_sources = this.power_sources for index = 1, #power_sources do local ps_data = power_sources[index] if not (ps_data and ps_data.valid) then fast_remove(power_sources, index) return end ps_data.energy = 0xfffff end end local function do_magic_crafters() local magic_crafters = this.magic_crafters local limit = #magic_crafters if limit == 0 then return end local index = magic_crafters.index for i = 1, magic_crafters_per_tick do if index > limit then index = 1 end local data = magic_crafters[index] local entity = data.entity if not entity.valid then fast_remove(magic_crafters, index) limit = limit - 1 if limit == 0 then return end else index = index + 1 local tick = game.tick local last_tick = data.last_tick local rate = data.rate local count = (tick - last_tick) * rate local fcount = floor(count) if fcount > 1 then fcount = 1 end if fcount > 0 then entity.get_output_inventory().insert {name = data.item, count = fcount} data.last_tick = tick - (count - fcount) / rate end end end magic_crafters.index = index end local function do_magic_fluid_crafters() local magic_fluid_crafters = this.magic_fluid_crafters local limit = #magic_fluid_crafters if limit == 0 then return end local index = magic_fluid_crafters.index for i = 1, magic_fluid_crafters_per_tick do if index > limit then index = 1 end local data = magic_fluid_crafters[index] local entity = data.entity if not entity.valid then fast_remove(magic_fluid_crafters, index) limit = limit - 1 if limit == 0 then return end else index = index + 1 local tick = game.tick local last_tick = data.last_tick local rate = data.rate local count = (tick - last_tick) * rate local fcount = floor(count) if fcount > 0 then local fluidbox_index = data.fluidbox_index local fb = entity.fluidbox local fb_data = fb[fluidbox_index] or {name = data.item, amount = 0} fb_data.amount = fb_data.amount + fcount fb[fluidbox_index] = fb_data data.last_tick = tick - (count - fcount) / rate end end end magic_fluid_crafters.index = index end local function tick() do_magic_crafters() do_magic_fluid_crafters() end Public.deactivate_callback = Token.register( function(entity) if entity and entity.valid then entity.active = false entity.operable = false entity.destructible = false end end ) Public.neutral_force = Token.register( function(entity) if entity and entity.valid then entity.force = 'neutral' end end ) Public.enemy_force = Token.register( function(entity) if entity and entity.valid then entity.force = 'enemy' end end ) Public.active_not_destructible_callback = Token.register( function(entity) if entity and entity.valid then entity.active = true entity.operable = false entity.destructible = false end end ) Public.disable_minable_callback = Token.register( function(entity) if entity and entity.valid then entity.minable = false end end ) Public.disable_minable_and_ICW_callback = Token.register( function(entity) if entity and entity.valid then entity.minable = false ICW.register_wagon(entity, true) end end ) Public.disable_destructible_callback = Token.register( function(entity) if entity and entity.valid then entity.destructible = false entity.minable = false end end ) Public.disable_active_callback = Token.register( function(entity) if entity and entity.valid then entity.active = false end end ) local disable_active_callback = Public.disable_active_callback Public.power_source_callback = Token.register( function(turret) local power_sources = this.power_sources power_sources[#power_sources + 1] = turret end ) Public.magic_item_crafting_callback = Token.register( function(entity, data) local callback_data = data.callback_data if not (entity and entity.valid) then return end entity.minable = false entity.destructible = false entity.operable = false local force = game.forces.player local tech = callback_data.tech if tech then if not force.technologies[tech].researched then entity.destroy() return end end local recipe = callback_data.recipe if recipe then entity.set_recipe(recipe) else local furance_item = callback_data.furance_item if furance_item then local inv = entity.get_inventory(defines.inventory.furnace_result) inv.insert(furance_item) end end local p = entity.position local x, y = p.x, p.y local distance = sqrt(x * x + y * y) local output = callback_data.output if #output == 0 then add_magic_crafter_output(entity, output, distance) else for i = 1, #output do local o = output[i] add_magic_crafter_output(entity, o, distance) end end if not callback_data.keep_active then Task.set_timeout_in_ticks(2, disable_active_callback, entity) -- causes problems with refineries. end end ) Public.magic_item_crafting_callback_weighted = Token.register( function(entity, data) local callback_data = data.callback_data if not (entity and entity.valid) then return end entity.minable = false entity.destructible = false entity.operable = false local weights = callback_data.weights local loot = callback_data.loot local p = entity.position local i = random() * weights.total local index = table.binary_search(weights, i) if (index < 0) then index = bit32.bnot(index) end local stack = loot[index].stack if not stack then return end local force = game.forces.player local tech = stack.tech if tech then if force.technologies[tech] then if not force.technologies[tech].researched then entity.destroy() return end end end local recipe = stack.recipe if recipe then entity.set_recipe(recipe) else local furance_item = stack.furance_item if furance_item then local inv = entity.get_inventory(defines.inventory.furnace_result) inv.insert(furance_item) end end local x, y = p.x, p.y local distance = sqrt(x * x + y * y) local output = stack.output if #output == 0 then add_magic_crafter_output(entity, output, distance) else for o_i = 1, #output do local o = output[o_i] add_magic_crafter_output(entity, o, distance) end end if not callback_data.keep_active then Task.set_timeout_in_ticks(2, disable_active_callback, entity) -- causes problems with refineries. end end ) function Public.prepare_weighted_loot(loot) local total = 0 local weights = {} for i = 1, #loot do local v = loot[i] total = total + v.weight weights[#weights + 1] = total end weights.total = total return weights end function Public.do_random_loot(entity, weights, loot) if not entity.valid then return end entity.operable = false --entity.destructible = false local i = random() * weights.total local index = table.binary_search(weights, i) if (index < 0) then index = bit32.bnot(index) end local stack = loot[index].stack if not stack then return end local df = stack.distance_factor local count if df then local p = entity.position local x, y = p.x, p.y local d = sqrt(x * x + y * y) count = stack.count + d * df else count = stack.count end entity.insert {name = stack.name, count = count} end function Public.remove_offline_players() local offline_players_enabled = WPT.get('offline_players_enabled') if not offline_players_enabled then return end local offline_players = WPT.get('offline_players') local active_surface_index = WPT.get('active_surface_index') local surface = game.surfaces[active_surface_index] local player_inv = {} local items = {} if #offline_players > 0 then local later = {} for i = 1, #offline_players, 1 do if offline_players[i] and game.players[offline_players[i].index] and game.players[offline_players[i].index].connected then offline_players[i] = nil else if offline_players[i] and game.players[offline_players[i].index] and offline_players[i].tick < game.tick - 54000 then local name = offline_players[i].name player_inv[1] = game.players[offline_players[i].index].get_inventory(defines.inventory.character_main) player_inv[2] = game.players[offline_players[i].index].get_inventory(defines.inventory.character_armor) player_inv[3] = game.players[offline_players[i].index].get_inventory(defines.inventory.character_guns) player_inv[4] = game.players[offline_players[i].index].get_inventory(defines.inventory.character_ammo) player_inv[5] = game.players[offline_players[i].index].get_inventory(defines.inventory.character_trash) local pos = game.forces.player.get_spawn_position(surface) local e = surface.create_entity( { name = 'character', position = pos, force = 'neutral' } ) local inv = e.get_inventory(defines.inventory.character_main) e.character_inventory_slots_bonus = #player_inv[1] for ii = 1, 5, 1 do if player_inv[ii].valid then for iii = 1, #player_inv[ii], 1 do if player_inv[ii][iii].valid then items[#items + 1] = player_inv[ii][iii] end end end end if #items > 0 then for item = 1, #items, 1 do if items[item].valid then inv.insert(items[item]) end end local message = ({'main.cleaner', name}) local data = { position = pos } Alert.alert_all_players_location(data, message) e.die('neutral') else e.destroy() end for ii = 1, 5, 1 do if player_inv[ii].valid then player_inv[ii].clear() end end offline_players[i] = nil else later[#later + 1] = offline_players[i] end end end for k, _ in pairs(offline_players) do offline_players[k] = nil end if #later > 0 then for i = 1, #later, 1 do offline_players[#offline_players + 1] = later[i] end end end end local function calc_players() local players = game.connected_players local check_afk_players = WPT.get('check_afk_players') if not check_afk_players then return #players end local total = 0 for i = 1, #players do local player = players[i] if player.afk_time < 36000 then total = total + 1 end end if total <= 0 then total = 1 end return total end function Public.on_player_joined_game(event) local active_surface_index = WPT.get('active_surface_index') local player = game.players[event.player_index] local surface = game.surfaces[active_surface_index] local reward = require 'maps.amap.main'.reward local player_data = get_player_data(player) if not player_data.first_join then for item, amount in pairs(starting_items) do player.insert({name = item, count = amount}) end local rpg_t = RPG.get('rpg_t') local wave_number = WD.get('wave_number') local this = WPT.get() for i = 0, this.science do local point = math.floor(math.random(1, 5)) local money = math.floor(math.random(1, 100)) rpg_t[player.index].points_to_distribute = rpg_t[player.index].points_to_distribute + point player.insert {name = 'coin', count = money} player.print({'amap.science', point, money}, {r = 0.22, g = 0.88, b = 0.22}) end rpg_t[player.index].xp = rpg_t[player.index].xp + wave_number * 10 player_data.first_join = true player.print({'amap.joingame'}) end if player.surface.index ~= active_surface_index then --player.teleport(surface.find_non_colliding_position("character", game.forces.player.get_spawn_position(surface), 20, 1, false) or {x=0,y=0}, surface) player.teleport(surface.find_non_colliding_position('character', game.forces.player.get_spawn_position(surface), 20, 1, false) or {x = 0, y = 0}, surface) else local p = {x = player.position.x, y = player.position.y} local get_tile = surface.get_tile(p) if get_tile.valid and get_tile.name == 'out-of-map' then player.teleport(surface.find_non_colliding_position('character', game.forces.player.get_spawn_position(surface), 20, 1, false) or {x = 0, y = 0}, surface) --player.teleport({x=0,y=0}, surface) end end end function Public.is_creativity_mode_on() local creative_enabled = Commands.get('creative_enabled') if creative_enabled then WD.set('next_wave', 1000) Collapse.start_now(true) Public.set_difficulty() end end local function on_player_mined_entity(event) local name = event.entity.name local entity = event.entity local this = WPT.get() if name == 'flamethrower-turret' then this.flame = this.flame - 1 if this.flame <= 0 then this.flame = 0 end end end function Public.disable_creative() local creative_enabled = Commands.get('creative_enabled') if creative_enabled then Commands.set('creative_enabled', false) end end function Public.on_pre_player_left_game(event) local offline_players_enabled = WPT.get('offline_players_enabled') if not offline_players_enabled then return end local offline_players = WPT.get('offline_players') local player = game.players[event.player_index] local ticker = game.tick if player.character then offline_players[#offline_players + 1] = { index = event.player_index, name = player.name, tick = ticker } end end local on_player_or_robot_built_entity = function(event) --change_pos 改变位置 local name = event.created_entity.name local entity = event.created_entity local this = WPT.get() if name == 'flamethrower-turret' then if this.flame >= 15 then game.print({'amap.too_many'}) entity.destroy() else this.flame = this.flame + 1 game.print({'amap.ok_many', this.flame}) end end if name == 'stone-wall' then local this = WPT.get() if not this.change then local wave_defense_table = WD.get_table() local dx = entity.position.x - this.pos.x local dy = entity.position.y - this.pos.y if dx < 0 then dx = -dx end if dy < 0 then dy = -dy end local d = dx + dy if d < 100 then this.change = true end end --game.print(dx) --game.print(dy) --game.print('差值为') --game.print(d) --game.print('出生地为') --game.print(this.pos) end end function Public.on_player_respawned(event) local player = game.get_player(event.player_index) if not (player and player.valid) then return end local player_data = get_player_data(player) if player_data.died then player_data.died = nil end end function Public.on_player_died(event) local player = game.get_player(event.player_index) if not (player and player.valid) then return end local player_data = get_player_data(player) player_data.died = true end function Public.on_player_changed_position(event) local active_surface_index = WPT.get('active_surface_index') if not active_surface_index then return end local player = game.players[event.player_index] local map_name = 'amap' if string.sub(player.surface.name, 0, #map_name) ~= map_name then return end local position = player.position local surface = game.surfaces[active_surface_index] local p = {x = player.position.x, y = player.position.y} local get_tile = surface.get_tile(p) local config_tile = WPT.get('void_or_tile') if config_tile == 'lab-dark-2' then if get_tile.valid and get_tile.name == 'lab-dark-2' then if random(1, 2) == 1 then if random(1, 2) == 1 then show_text('This path is not for players!', p, {r = 0.98, g = 0.66, b = 0.22}, surface) end player.surface.create_entity({name = 'fire-flame', position = player.position}) player.character.health = player.character.health - tile_damage if player.character.health == 0 then player.character.die() local message = ({'main.death_message_' .. random(1, 7), player.name}) game.print(message, {r = 0.98, g = 0.66, b = 0.22}) end end end end if position.y >= 74 then player.teleport({position.x, position.y - 1}, surface) player.print(({'main.forcefield'}), {r = 0.98, g = 0.66, b = 0.22}) if player.character then player.character.health = player.character.health - 5 player.character.surface.create_entity({name = 'water-splash', position = position}) if player.character.health <= 0 then player.character.die('enemy') end end end end local disable_recipes = function() local force = game.forces.player force.recipes['car'].enabled = false force.recipes['tank'].enabled = false force.recipes['pistol'].enabled = false force.recipes['land-mine'].enabled = false force.recipes['spidertron-remote'].enabled = false -- force.recipes['flamethrower-turret'].enabled = false end function Public.disable_tech() game.forces.player.technologies['landfill'].enabled = false game.forces.player.technologies['spidertron'].enabled = false game.forces.player.technologies['spidertron'].researched = false disable_recipes() end local disable_tech = Public.disable_tech function Public.on_research_finished(event) disable_tech() end local function on_entity_died(event) local name = event.entity.name local entity = event.entity local this = WPT.get() if name == 'flamethrower-turret' then this.flame = this.flame - 1 if this.flame <= 0 then this.flame = 0 end end end Public.firearm_magazine_ammo = {name = 'firearm-magazine', count = 200} Public.piercing_rounds_magazine_ammo = {name = 'piercing-rounds-magazine', count = 200} Public.uranium_rounds_magazine_ammo = {name = 'uranium-rounds-magazine', count = 200} Public.light_oil_ammo = {name = 'light-oil', amount = 100} Public.artillery_shell_ammo = {name = 'artillery-shell', count = 15} Public.laser_turrent_power_source = {buffer_size = 2400000, power_production = 40000} function Public.reset_table() this.power_sources = {index = 1} this.refill_turrets = {index = 1} this.magic_crafters = {index = 1} this.magic_fluid_crafters = {index = 1} end local on_research_finished = Public.on_research_finished local on_player_joined_game = Public.on_player_joined_game local on_player_respawned = Public.on_player_respawned local on_player_died = Public.on_player_died local on_player_changed_position = Public.on_player_changed_position local on_pre_player_left_game = Public.on_pre_player_left_game Event.add(defines.events.on_built_entity, on_player_or_robot_built_entity) Event.add(defines.events.on_robot_built_entity, on_player_or_robot_built_entity) Event.add(defines.events.on_research_finished, on_research_finished) Event.add(defines.events.on_player_joined_game, on_player_joined_game) Event.add(defines.events.on_player_respawned, on_player_respawned) Event.add(defines.events.on_player_died, on_player_died) Event.add(defines.events.on_entity_died, on_entity_died) Event.add(defines.events.on_player_mined_entity, on_player_mined_entity) Event.add(defines.events.on_robot_mined_entity, on_player_mined_entity) --Event.add(defines.events.on_player_changed_position, on_player_changed_position) Event.add(defines.events.on_pre_player_left_game, on_pre_player_left_game) Event.on_nth_tick(10, tick) Event.on_nth_tick(5, do_turret_energy) return Public