local Chrono_table = require 'maps.chronosphere.table' local Balance = require 'maps.chronosphere.balance' local Difficulty = require 'modules.difficulty_vote' local Chrono = require 'maps.chronosphere.chrono' local Upgrades = require 'maps.chronosphere.upgrades' local Public = {} local tick_tack_trap = require 'utils.functions.tick_tack_trap' local unearthing_worm = require 'utils.functions.unearthing_worm' local unearthing_biters = require 'utils.functions.unearthing_biters' local FT = require 'utils.functions.flying_texts' local math_random = math.random local math_floor = math.floor local math_ceil = math.ceil local function get_ore_amount(scrap) local objective = Chrono_table.get_table() local scaling = (game.forces.player.mining_drill_productivity_bonus - 1) / 2 local amount = Balance.Base_ore_loot_yield(objective.chronojumps, scrap) * (1 + scaling) if not scrap then amount = amount * objective.world.ores.factor end if amount > 500 then amount = 500 end amount = math_random(math_floor(amount * 0.7), math_floor(amount * 1.3)) if amount < 1 then amount = 1 end return amount end local function reward_ores(amount, mined_loot, surface, player, entity) local a = 0 if player then a = player.insert { name = mined_loot, count = amount } end amount = amount - a if amount > 0 then if amount >= 50 then for i = 1, math_floor(amount / 50), 1 do local e = surface.create_entity { name = 'item-on-ground', position = entity.position, stack = { name = mined_loot, count = 50 } } if e and e.valid then e.to_be_looted = true end amount = amount - 50 end end if amount > 0 then if amount < 5 then surface.spill_item_stack({position = entity.position, stack = { name = mined_loot, count = amount }, enable_looted = true}) else local e = surface.create_entity { name = 'item-on-ground', position = entity.position, stack = { name = mined_loot, count = amount } } if e and e.valid then e.to_be_looted = true end end end end end function Public.biters_chew_rocks_faster(event) if not event.cause then return end if not event.cause.valid then return end if event.cause.force.index ~= 2 then return end --Enemy Force event.entity.health = event.entity.health - event.final_damage_amount * 5 end function Public.isprotected(entity) if entity.surface.name == 'cargo_wagon' then return true end local objective = Chrono_table.get_table() local protected = { objective.locomotive, objective.locomotive_cargo[1], objective.locomotive_cargo[2], objective.locomotive_cargo[3] } for i = 1, #protected do if protected[i] == entity then return true end end for _, chest in pairs(objective.comfychests) do if chest == entity then return true end end return false end function Public.trap(entity, trap) if trap then tick_tack_trap(entity.surface, entity.position) tick_tack_trap(entity.surface, { x = entity.position.x + math_random(-2, 2), y = entity.position.y + math_random(-2, 2) }) return end if math_random(1, 256) == 1 then tick_tack_trap(entity.surface, entity.position) return end if math_random(1, 128) == 1 then unearthing_worm(entity.surface, entity.surface.find_non_colliding_position('big-worm-turret', entity.position, 5, 1)) end if math_random(1, 64) == 1 then unearthing_biters(entity.surface, entity.position, math_random(4, 8)) end end function Public.lava_planet(event) local playertable = Chrono_table.get_player_table() local player = game.get_player(event.player_index) if not player or not player.character then return end if player.character.driving then return end local surface = player.surface if surface.name == 'cargo_wagon' then return end local safe = { 'stone-path', 'concrete', 'hazard-concrete-left', 'hazard-concrete-right', 'refined-concrete', 'refined-hazard-concrete-left', 'refined-hazard-concrete-right' } local pavement = surface.get_tile(player.position.x, player.position.y) for i = 1, 7, 1 do if pavement.name == safe[i] then return end end if not playertable.flame_boots[player.index].steps then playertable.flame_boots[player.index].steps = {} end local steps = playertable.flame_boots[player.index].steps local elements = #steps steps[elements + 1] = { x = player.position.x, y = player.position.y } if elements > 10 then surface.create_entity({ name = 'fire-flame', position = steps[elements - 1] }) for i = 1, elements, 1 do steps[i] = steps[i + 1] end steps[elements + 1] = nil end end function Public.shred_simple_entities(entity) if game.forces.enemy.get_evolution_factor(entity.surface) < 0.25 then return end local simple_entities = entity.surface.find_entities_filtered({ type = { 'simple-entity', 'tree' }, area = { { entity.position.x - 3, entity.position.y - 3 }, { entity.position.x + 3, entity.position.y + 3 } } }) for _, simple_entity in pairs(simple_entities) do if simple_entity.valid then simple_entity.destroy() end end end function Public.spawner_loot(surface, position) if math_random(1, 18) == 1 then local objective = Chrono_table.get_table() local count = math_random(1, 1 + objective.chronojumps) objective.research_tokens.weapons = objective.research_tokens.weapons + count FT.flying_text(nil, surface, position, { 'chronosphere.token_weapons_add', count }, { r = 0.8, g = 0.8, b = 0.8 }) script.raise_event(Chrono_table.events['update_upgrades_gui'], {}) end end function Public.research_loot(event) local objective = Chrono_table.get_table() local bonus = 1 if #event.research.research_unit_ingredients >= 6 then bonus = 2 end objective.research_tokens.tech = objective.research_tokens.tech + 5 * #event.research.research_unit_ingredients * bonus script.raise_event(Chrono_table.events['update_upgrades_gui'], {}) end function Public.tree_loot() local objective = Chrono_table.get_table() objective.research_tokens.ecology = objective.research_tokens.ecology + 1 script.raise_event(Chrono_table.events['update_upgrades_gui'], {}) end function Public.choppy_loot(event) local entity = event.entity local choppy_entity_yield = { ['tree-01'] = { 'iron-ore' }, ['tree-02-red'] = { 'copper-ore' }, ['tree-04'] = { 'coal' }, ['tree-08-brown'] = { 'stone' } } if choppy_entity_yield[entity.name] then if event.buffer then event.buffer.clear() end if not event.player_index then return end local amount = math_ceil(get_ore_amount(false) / 2) local second_item_amount = math_random(1, 3) local second_item = 'wood' local main_item = choppy_entity_yield[entity.name][math_random(1, #choppy_entity_yield[entity.name])] local text = '+' .. amount .. ' [item=' .. main_item .. '] +' .. second_item_amount .. ' [item=' .. second_item .. ']' local player = game.get_player(event.player_index) FT.flying_text(player, entity.surface, entity.position, text, { r = 0.8, g = 0.8, b = 0.8 }) reward_ores(amount, main_item, entity.surface, player, player) reward_ores(second_item_amount, second_item, entity.surface, player, player) end end function Public.rocky_loot(event) local player = game.get_player(event.player_index) if not player or not player.valid then return end local amount = math_ceil(get_ore_amount(false)) local rock_mining = { 'iron-ore', 'iron-ore', 'iron-ore', 'iron-ore', 'copper-ore', 'copper-ore', 'copper-ore', 'stone', 'stone', 'coal', 'coal' } local mined_loot = rock_mining[math_random(1, #rock_mining)] local text = '+' .. amount .. ' [item=' .. mined_loot .. ']' FT.flying_text(player, player.surface, player.position, text, { r = 0.98, g = 0.66, b = 0.22 }) reward_ores(amount, mined_loot, player.surface, player, player) reward_ores(math_random(1, 3), 'raw-fish', player.surface, player, player) end function Public.scrap_loot(event) local objective = Chrono_table.get_table() local scrap_table = Balance.scrap() local scrap = scrap_table.main[math_random(1, #scrap_table.main)] local scrap2 = scrap_table.second[math_random(1, #scrap_table.second)] local amount = math_ceil(get_ore_amount(true) * scrap.amount) local amount2 = math_ceil(get_ore_amount(true) * scrap2.amount) local player = game.get_player(event.player_index) if not player or not player.valid then return end local text = '+' .. amount .. ' [item=' .. scrap.name .. '] + ' .. amount2 .. ' [item=' .. scrap2.name .. ']' FT.flying_text(player, player.surface, player.position, text, { r = 0.98, g = 0.66, b = 0.22 }) reward_ores(amount, scrap.name, player.surface, player, player) reward_ores(amount2, scrap2.name, player.surface, player, player) if math_random(1, 50) == 1 then objective.research_tokens.tech = objective.research_tokens.tech + 1 FT.flying_text(player, player.surface, { x = player.position.x, y = player.position.y - 0.5 }, { 'chronosphere.token_tech_add', 1 }, { r = 0.8, g = 0.8, b = 0.8 }) end end local biter_yield = { ['behemoth-biter'] = 5, ['behemoth-spitter'] = 5, ['behemoth-worm-turret'] = 6, ['big-biter'] = 3, ['big-spitter'] = 3, ['big-worm-turret'] = 4, ['biter-spawner'] = 10, ['medium-biter'] = 2, ['medium-spitter'] = 2, ['medium-worm-turret'] = 3, ['small-biter'] = 1, ['small-spitter'] = 1, ['small-worm-turret'] = 2, ['spitter-spawner'] = 10 } function Public.swamp_loot(event) local objective = Chrono_table.get_table() local surface = game.surfaces[objective.active_surface_index] local amount = math_floor(get_ore_amount(false) / 10) if biter_yield[event.entity.name] then amount = math_floor((get_ore_amount(false) * biter_yield[event.entity.name]) / 10) end if amount > 50 then amount = 50 end local rock_mining = { 'iron-ore', 'iron-ore', 'coal' } local mined_loot = rock_mining[math_random(1, #rock_mining)] reward_ores(amount, mined_loot, surface, nil, event.entity) local text = '+' .. amount .. ' [img=item/' .. mined_loot .. ']' FT.flying_text(nil, surface, event.entity.position, text, { r = 0.7, g = 0.8, b = 0.4 }) end function Public.biter_loot(event) local objective = Chrono_table.get_table() if biter_yield[event.entity.name] then objective.research_tokens.biters = objective.research_tokens.biters + biter_yield[event.entity.name] end end function Public.danger_silo(entity) local objective = Chrono_table.get_table() if objective.world.id == 2 and objective.world.variant.id == 2 then if objective.dangers and #objective.dangers >= 1 then for i = 1, #objective.dangers, 1 do if entity == objective.dangers[i].silo then game.print({ 'chronosphere.message_silo', Balance.nukes_looted_per_silo(Difficulty.get().difficulty_vote_value) }, { color = { r = 0.98, g = 0.66, b = 0.22 }}) objective.dangers[i].destroyed = true objective.dangers[i].silo = nil objective.dangers[i].speaker.destroy() objective.dangers[i].combinator.destroy() objective.dangers[i].solar.destroy() objective.dangers[i].acu.destroy() objective.dangers[i].pole.destroy() objective.dangers[i].text.destroy() objective.dangers[i].timer.destroy() objective.dangers[i].text = -1 objective.dangers[i].timer = -1 end end end end end function Public.biter_immunities(event) local objective = Chrono_table.get_table() local id = objective.world.id if event.damage_type.name == 'fire' then if id == 1 and objective.world.variant.id == 11 then --lava planet event.entity.health = event.entity.health + event.final_damage_amount local fire = event.entity.stickers if fire and #fire > 0 then for i = 1, #fire, 1 do if fire[i].sticked_to == event.entity and fire[i].name == 'fire-sticker' then fire[i].destroy() break end end end -- else -- other planets -- event.entity.health = math_floor(event.entity.health + event.final_damage_amount - (event.final_damage_amount / (1 + 0.02 * Difficulty.get().difficulty_vote_value * objective.chronojumps))) end elseif event.damage_type.name == 'poison' then if id == 8 then --swamp planet event.entity.health = event.entity.health + event.final_damage_amount else if objective.upgrades[25] > 0 then event.entity.health = event.entity.health - event.final_damage_amount * (0.25 * objective.upgrades[25]) end end end end function Public.flamer_nerfs() local objective = Chrono_table.get_table() local difficulty = Difficulty.get().difficulty_vote_value local flame_researches = { [1] = { name = 'refined-flammables-1', bonus = 0.2 }, [2] = { name = 'refined-flammables-2', bonus = 0.2 }, [3] = { name = 'refined-flammables-3', bonus = 0.2 }, [4] = { name = 'refined-flammables-4', bonus = 0.3 }, [5] = { name = 'refined-flammables-5', bonus = 0.3 }, [6] = { name = 'refined-flammables-6', bonus = 0.4 }, [7] = { name = 'refined-flammables-7', bonus = 0.2 } } local flamer_power = 0 for i = 1, 6, 1 do if game.forces.player.technologies[flame_researches[i].name].researched then flamer_power = flamer_power + flame_researches[i].bonus end end flamer_power = flamer_power + (game.forces.player.technologies[flame_researches[7].name].level - 7) * 0.2 game.forces.player.set_ammo_damage_modifier('flamethrower', flamer_power - Balance.flamers_nerfs_size(objective.chronojumps, difficulty)) game.forces.player.set_turret_attack_modifier('flamethrower-turret', flamer_power - Balance.flamers_nerfs_size(objective.chronojumps, difficulty)) end local mining_researches = { -- these already give .1 productivity so we're only adding .1 to get to 20% ['mining-productivity-1'] = { bonus_productivity = .1, bonus_mining_speed = .2, bonus_inventory = 10 }, ['mining-productivity-2'] = { bonus_productivity = .1, bonus_mining_speed = .2, bonus_inventory = 10 }, ['mining-productivity-3'] = { bonus_productivity = .1, bonus_mining_speed = .2, bonus_inventory = 10 }, ['mining-productivity-4'] = { bonus_productivity = .1, bonus_mining_speed = .2, bonus_inventory = 10, infinite = true, infinite_level = 4 } } function Public.mining_buffs(event) local force = game.forces.player if event == nil then -- initialization/reset call force.mining_drill_productivity_bonus = force.mining_drill_productivity_bonus + 1 force.manual_mining_speed_modifier = force.manual_mining_speed_modifier + 1 return end if mining_researches[event.research.name] == nil then return end local tech = mining_researches[event.research.name] if tech.bonus_productivity then force.mining_drill_productivity_bonus = force.mining_drill_productivity_bonus + tech.bonus_productivity end if tech.bonus_mining_speed then force.manual_mining_speed_modifier = force.manual_mining_speed_modifier + tech.bonus_mining_speed end if tech.bonus_inventory then force.character_inventory_slots_bonus = force.character_inventory_slots_bonus + tech.bonus_inventory end end function Public.jump_timers(event) local objective = Chrono_table.get_table() if event.research and event.research.name == 'logistic-science-pack' then objective.warmup = false objective.chronocharges = objective.chronochargesneeded / 2 end end function Public.on_technology_effects_reset(event) local objective = Chrono_table.get_table() if event.force.name == 'player' then local force = game.forces.player force.character_inventory_slots_bonus = force.character_inventory_slots_bonus + objective.upgrades[5] * 10 force.character_loot_pickup_distance_bonus = force.character_loot_pickup_distance_bonus + objective.upgrades[4] local fake_event = {} Public.mining_buffs(nil) for name, bonuses in pairs(mining_researches) do local technology = force.technologies[name] if technology.researched == true or bonuses.infinite == true then fake_event.research = technology if bonuses.infinite and bonuses.infinite_level and technology.level > bonuses.infinite_level then for _ = bonuses.infinite_level, technology.level - 1 do Public.mining_buffs(fake_event) end else Public.mining_buffs(fake_event) end end end end end function Public.check_if_overstayed() local objective = Chrono_table.get_table() if objective.passivetimer * objective.passive_chronocharge_rate > (objective.chronochargesneeded * 0.75) and objective.chronojumps >= Balance.jumps_until_overstay_is_on(Difficulty.get().difficulty_vote_value) then objective.overstaycount = objective.overstaycount + 1 end end function Public.initiate_jump_countdown() local objective = Chrono_table.get_table() objective.jump_countdown_start_time = objective.passivetimer game.print({ 'chronosphere.message_jump180' }, { color = { r = 0.98, g = 0.66, b = 0.22 }}) end function Public.render_train_hp() local objective = Chrono_table.get_table() local surface = game.surfaces[objective.active_surface_index] objective.health_text = rendering.draw_text { text = { 'chronosphere.train_HP', objective.health, objective.max_health }, surface = surface, target = { entity = objective.locomotive, offset = { 0, -2.5 }, position = objective.locomotive.position }, color = objective.locomotive.color, scale = 1.40, font = 'default-game', alignment = 'center', scale_with_zoom = false } objective.caption = rendering.draw_text { text = { 'chronosphere.train_name' }, surface = surface, target = { entity = objective.locomotive, offset = { 0, -4.25 }, position = objective.locomotive.position }, color = objective.locomotive.color, scale = 1.80, font = 'default-game', alignment = 'center', scale_with_zoom = false } end function Public.set_objective_health(final_damage_amount) if final_damage_amount == 0 then return end local objective = Chrono_table.get_table() objective.health = math_floor(objective.health - final_damage_amount) if objective.health > objective.max_health then objective.health = objective.max_health end if objective.health <= 0 then Chrono.objective_died() end if objective.health < objective.max_health / 2 and final_damage_amount > 0 then Upgrades.trigger_poison() end objective.health_text.text = { 'chronosphere.train_HP', objective.health, objective.max_health } end function Public.nuclear_artillery(entity, cause) local objective = Chrono_table.get_table() if objective.upgrades[23] ~= 1 then return end if objective.upgrades[24] > 0 and objective.last_artillery_event ~= game.tick then entity.surface.create_entity({ name = 'atomic-rocket', position = entity.position, force = 'player', speed = 1, max_range = 100, target = entity, source = cause }) objective.upgrades[24] = objective.upgrades[24] - 1 objective.last_artillery_event = game.tick end end return Public