util = require("util") colors = require("colors") require("utils") require "cameras" require "particles" require "stdlib/area/chunk" require "stdlib/area/area" function ReadRunTimeSettings(event) global.chances = global.chances or {} -- in priority order of danger global.chances.volcano = {min_evo=settings.global["bm-volcano-min_evo"].value ,chance=settings.global["bm-volcano-chance"].value, max_evo=settings.global["bm-volcano-max_evo"].value} global.chances.spidertron = {min_evo=settings.global["bm-spidertron-min_evo"].value , chance=settings.global["bm-spidertron-chance"].value} global.chances.biterzilla = {min_evo=settings.global["bm-biterzilla-min_evo"].value , chance=settings.global["bm-biterzilla-chance"].value} global.chances.worms = {min_evo=settings.global["bm-worms-min_evo"].value ,chance=settings.global["bm-worms-chance"].value} global.chances.brutals = {min_evo=settings.global["bm-brutals-min_evo"].value , chance=settings.global["bm-brutals-chance"].value} global.chances.soldiers = {min_evo=settings.global["bm-soldiers-min_evo"].value ,chance=settings.global["bm-soldiers-chance"].value} global.chances.invasion = {min_evo=settings.global["bm-invasion-min_evo"].value , chance=settings.global["bm-invasion-chance"].value} global.chances.swarm = {min_evo=0, chance=settings.global["bm-swarm-chance"].value, max_evo=settings.global["bm-swarm-max_evo"].value} global.enable_silo_attack = settings.global["bm-enable-silo-attack"].value global.show_cameras = settings.global["bm-show-cameras"].value global.show_alerts = settings.global["bm-show-alerts"].value global.play_sound_alert = settings.global["bm-play-sound-alert"].value global.days = settings.global["bm-event-days"].value global.allow_nuker = settings.global["bm-allow-nuker"].value global.difficulty_level = settings.global["bm-difficulty-level"].value global.spidertron_nuke = settings.global["bm-spidertron-nuke"].value global.tree_events_chance = settings.global["bm-tree-events-chance"].value/100 global.spawn_near_nests = settings.global["bm-spawn_near_nests"].value if event and event.setting_type=='runtime-per-user' then local player = game.players[event.player_index] if event.setting=='bm_draggable_camera' then global.enable_drag_camera[player.name] = settings.get_player_settings(player)["ic_draggable_camera"].value elseif event.setting=='bm_camera_size' then global.camera_size[player.name] = settings.get_player_settings(player)["ic_camera_size"].value end end end script.on_event(defines.events.on_runtime_mod_setting_changed, ReadRunTimeSettings) function setup_mod_vars() global.player_forces = global.player_forces or {'player'} global.surfaces = global.surfaces or {'nauvis'} global.bm_volcano = global.bm_volcano or {} global.biterzillas = global.biterzillas or {} global.invasions = global.invasions or {} global.rocket_silos = global.rocket_silos or {} global.other_enemies = global.other_enemies or {} global.next_wave = global.next_wave or {} ReadRunTimeSettings() global.next_event = global.next_event or (game.tick + (global.days * 7 * 60 * 60)) global.next_silo_event = global.next_silo_event or (game.tick + (global.days * 4 * 60 * 60)) end function on_init() cam_on_init() setup_mod_vars() RegisterModEvents() end script.on_init(on_init) function on_configuration_changed() cam_on_init() setup_mod_vars() end script.on_configuration_changed(on_configuration_changed) function on_load() RegisterModEvents() end script.on_load(on_load) -- camera events local function on_gui_click(event) cam_on_gui_click(event) end script.on_event(defines.events.on_gui_click, on_gui_click) ------------------------------------------------------------------------------------------ function pick_event(excludes) local the_event local evo = game.forces.enemy.evolution_factor if not excludes then excludes={} end for event, chances in pairs (global.chances) do if not in_list(excludes,event) then if evo >= chances.min_evo and math.random(100) <= chances.chance then if (not chances.max_evo) or (chances.max_evo>=evo) then the_event = event break end end end end return the_event end function Play_sound_alert(force,id) if global.play_sound_alert then local sound if id==1 then if game.active_mods['mferrari-mod-sounds'] then sound = 'mferrari_tense_music_1m' else sound='tc_sound_alarm_1' end elseif id==2 then if game.active_mods['mferrari-mod-sounds'] then sound = 'mferrari_tense_music_2m' else sound='tc_sound_alarm_2' end elseif id==3 then if game.active_mods['mferrari-mod-sounds'] then sound = 'mferrari_tense_music_3m' else sound='tc_sound_siren' end end if game.active_mods['mferrari-mod-sounds'] then force.play_sound{path=sound,override_sound_type='ambient' } else force.play_sound{path=sound} end end end --the_event = biterzilla,soldiers,worms,volcano,invasion,swarm function CreateNewEvent(the_event,surfacename, forcename) local sufaces_tab = table.deepcopy(global.surfaces) if surfacename then add_list(sufaces_tab, surfacename) end local next_waves={} for s=1,#sufaces_tab do local surface = game.surfaces[sufaces_tab[s]] if not the_event then the_event=pick_event() end for p=1,#global.player_forces do local pforce = game.forces[global.player_forces[p]] if surface and the_event and pforce and (not surfacename or surface.name==surfacename) and (not forcename or pforce.name==forcename) then --DRD if surface.peaceful_mode then break end --DRD local player_spawn = pforce.get_spawn_position(surface) local pcount = #pforce.connected_players if pcount>0 then local target if the_event=='swarm' then local last_building = FindTeamAttackCorner(surface, pforce, player_spawn,1) local attack = {surface=surface,target=last_building} --(at.surface,at.target,at.limit,at.multiplier) table.insert (next_waves,attack) --CallFrenzyAttack(surface,last_building) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-swarm"},colors.lightred) end Play_sound_alert(pforce,1) elseif the_event=='invasion' then local last_building, player_chunks = FindTeamAttackCorner(surface, pforce, player_spawn,1) local rchunk = player_chunks[math.random(#player_chunks)] local target = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} create_invasion(surface,target,pcount) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-invasion"},colors.lightred) end Play_sound_alert(pforce,1) if global.show_cameras then CreateCameraForForce(pforce,target,surface,nil,nil,120,0.15) end elseif the_event=='volcano' then local last_building, player_chunks = FindTeamAttackCorner(surface, pforce, player_spawn,1) local rchunk = player_chunks[math.random(#player_chunks)] local target = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} local volcano = create_volcano(surface, target, pcount) if volcano then if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-volcano"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,volcano,surface,nil,nil,120,0.15) end end elseif the_event=='worms' then local last_building, player_chunks = FindTeamAttackCorner(surface, pforce, player_spawn,1) local rchunk = player_chunks[math.random(#player_chunks)] local target = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} local bigworm = create_bigworm(surface,target,pcount) if bigworm then if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-worm"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,bigworm,surface,nil,nil,120,0.15) end end elseif the_event=='soldiers' then local attack1, player_chunks, spawn = FindTeamAttackCorner(surface, pforce, player_spawn,4) local rchunk = player_chunks[math.random(#player_chunks)] local attack2 = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} if spawn then if global.spawn_near_nests then spawn = get_pos_near_enemy_nest(surface,spawn,pforce) end local group, humie = create_soldiers_group(surface,spawn,pcount,attack1, attack2, player_spawn) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-human_soldiers"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,humie,surface,nil,nil,120,0.15) end end elseif the_event=='brutals' then local attack1, player_chunks, spawn = FindTeamAttackCorner(surface, pforce, player_spawn,4) local rchunk = player_chunks[math.random(#player_chunks)] local attack2 = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} if spawn then if global.spawn_near_nests then spawn = get_pos_near_enemy_nest(surface,spawn,pforce) end local group, brutal = create_brutals_group(surface,spawn,pcount,attack1, attack2, player_spawn) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-brutals"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,brutal,surface,nil,nil,120,0.15) end end elseif the_event=='biterzilla' then local attack1, player_chunks, spawn = FindTeamAttackCorner(surface, pforce, player_spawn,4) local rchunk = player_chunks[math.random(#player_chunks)] local attack2 = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} if spawn then if global.spawn_near_nests then spawn = get_pos_near_enemy_nest(surface,spawn,pforce) end local group, zilla = create_biterzilla(surface,spawn,pcount,attack1, attack2, player_spawn) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-biterzilla"},colors.lightred) end Play_sound_alert(pforce,3) if global.show_cameras then CreateCameraForForce(pforce,zilla,surface,nil,nil,120,0.15) end end elseif the_event=='spidertron' then local attack1, player_chunks, spawn = FindTeamAttackCorner(surface, pforce, player_spawn,4) local rchunk = player_chunks[math.random(#player_chunks)] local attack2 = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} if spawn then if global.spawn_near_nests then spawn = get_pos_near_enemy_nest(surface,spawn,pforce) end local spider = create_spidertron(surface,spawn,pcount) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-biterzilla"},colors.lightred) end Play_sound_alert(pforce,3) if global.show_cameras then CreateCameraForForce(pforce,spider,surface,nil,nil,120,0.15) end end elseif the_event=='ultimate_boss' then local attack1, player_chunks, spawn = FindTeamAttackCorner(surface, pforce, player_spawn,10) local rchunk = player_chunks[math.random(#player_chunks)] local attack2 = {x= rchunk.x*32+math.random(31), y= rchunk.y*32+math.random(31)} if spawn then if global.spawn_near_nests then spawn = get_pos_near_enemy_nest(surface,spawn,pforce) end local group, zilla = create_biterzilla(surface,spawn,pcount,attack1, attack2, player_spawn,'tc_fake_human_ultimate_boss_cannon_20') if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-biterzilla"},colors.lightred) end Play_sound_alert(pforce,3) if global.show_cameras then CreateCameraForForce(pforce,zilla,surface,nil,nil,120,0.15) end end end end --pcount>0 end --the_event end -- p end if #next_waves>0 then local waves = 2 + math.ceil(global.difficulty_level) + math.floor (game.forces.enemy.evolution_factor * 6) for w=1,waves do local tick = game.tick + ((w-1)*60*40 ) local new_wave = {tick=tick, event_name=the_event, attacks=next_waves} table.insert(global.next_wave,new_wave) end end end function get_pos_near_enemy_nest(surface,spawn,pforce) local enemy = surface.find_nearest_enemy{position=spawn, max_distance=500, force=pforce} if enemy then local f = enemy.force local nests = surface.find_entities_filtered{type='unit-spawner', position=enemy.position, radius=300, force=f, limit=5} if #nests>0 then spawn = get_random_pos_near(nests[math.random(#nests)].position,30) spawn = surface.find_non_colliding_position('assembling-machine-1', spawn, 0, 1) end end return spawn end function Create_Position_Event(the_event, surface, position, pforce) --DRD if surface.peaceful_mode then return end --DRD local pcount = #pforce.connected_players if the_event=='swarm' then CallFrenzyAttack(surface,position) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-swarm"},colors.lightred) end elseif the_event=='invasion' then local target = get_random_pos_near(position,150) target = surface.find_non_colliding_position('rocket-silo', target, 60, 1) if target then create_invasion(surface,target,pcount) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-invasion"},colors.lightred) end Play_sound_alert(pforce,1) if global.show_cameras then CreateCameraForForce(pforce,target,surface,nil,nil,120,0.15) end end elseif the_event=='volcano' then local target = get_random_pos_near(position,150) target = surface.find_non_colliding_position('rocket-silo', target, 50, 1) if target then local volcano = create_volcano(surface, target, pcount) if volcano then if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-volcano"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,volcano,surface,nil,nil,120,0.15) end end end elseif the_event=='worms' then local target = get_random_pos_near(position,150) target = surface.find_non_colliding_position('rocket-silo', target, 50, 1) if target then local bigworm = create_bigworm(surface,target,pcount) if bigworm then if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-worm"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,bigworm,surface,nil,nil,120,0.15) end end end elseif the_event=='soldiers' then local spawn = surface.find_nearest_enemy{position=position, max_distance=500, force=pforce} if spawn then spawn = get_random_pos_near(spawn.position,30) local group, humie = create_soldiers_group(surface,spawn,pcount,position) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-human_soldiers"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,humie,surface,nil,nil,120,0.15) end end elseif the_event=='brutals' then local spawn = surface.find_nearest_enemy{position=position, max_distance=500, force=pforce} if spawn then spawn = get_random_pos_near(spawn.position,30) local group, brutal = create_brutals_group(surface,spawn,pcount,position) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-brutals"},colors.lightred) end Play_sound_alert(pforce,2) if global.show_cameras then CreateCameraForForce(pforce,brutal,surface,nil,nil,120,0.15) end end elseif the_event=='biterzilla' then local spawn = surface.find_nearest_enemy{position=position, max_distance=500, force=pforce} if spawn then spawn = get_random_pos_near(spawn.position,30) local group, zilla = create_biterzilla(surface,spawn,pcount,position) if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-biterzilla"},colors.lightred) end Play_sound_alert(pforce,3) if global.show_cameras then CreateCameraForForce(pforce,zilla,surface,nil,nil,120,0.15) end end end end function Create_Silo_Attack(the_event) if not the_event then the_event=pick_event() end if the_event then for s=#global.rocket_silos,1,-1 do local silo=global.rocket_silos[s] if not (silo and silo.valid) then table.remove(global.rocket_silos,s) else local pforce = silo.force local pcount = #pforce.connected_players local surface = silo.surface if pcount>0 then Create_Position_Event(the_event, surface, silo.position, pforce) end end end end end script.on_nth_tick(60*60, function (event) if global.days>0 then if global.next_event 2000) or (math.abs(chunkPos.y) > 2000)) then break elseif (surface.is_chunk_generated(chunkPos)) then local area = Chunk.to_area(chunkPos) local builds = surface.find_entities_filtered{force=force,area=area,limit=1} if #builds>0 then last_building = table.deepcopy(chunkPos) table.insert (player_chunks,table.deepcopy(chunkPos)) else nothing = nothing + 1 if nothing >= chunk_distance then enemy_spawn = chunkPos end end -- Found an ungenerated area else break end end last_building = {x= last_building.x*32+math.random(31), y= last_building.y*32+math.random(31)} if enemy_spawn then enemy_spawn = {x= enemy_spawn.x*32+math.random(31), y= enemy_spawn.y*32+math.random(31)} enemy_spawn = surface.find_non_colliding_position('rocket-silo', enemy_spawn, 100, 1) end return last_building, player_chunks, enemy_spawn end function group_set_command(group,position_1,position_2, position_3) local def = defines local compound = def.command.compound local structure = def.compound_command.return_last local go_to = def.command.attack_area if not position_2 then position_2=position_1 end if not position_3 then position_3=position_2 end group.set_command( { type = compound, structure_type = structure, commands = { {type = go_to, destination = position_1, distraction = defines.distraction.by_anything, radius=50}, {type = go_to, destination = position_2, distraction = defines.distraction.by_enemy, radius=30}, {type = go_to, destination = position_3, distraction = defines.distraction.by_enemy, radius=30}, {type = defines.command.wander, distraction = defines.distraction.by_enemy, radius=30}, } }) --group.start_moving() end -------------------------------------------------------------------------------------- function create_soldiers_group(surface,spawn,pcount, attack1, attack2,attack3) local qt = math.min(10, math.max(2,math.ceil(game.forces.enemy.evolution_factor * 10 + math.random(math.ceil(pcount/2))))) + (global.difficulty_level-1) * 12 local group local one_humie for x=1, qt do local humie = get_random_human_soldier() local position = surface.find_non_colliding_position(humie, spawn, 100, 1) if position then if not group then group = surface.create_unit_group{position = position, force = game.forces.enemy} end one_humie = surface.create_entity{name=humie, position= position, force= game.forces.enemy} if one_humie and one_humie.valid then group.add_member(one_humie) table.insert (global.other_enemies,one_humie ) end end end if game.forces.enemy.evolution_factor>0.91 and math.random(2)==1 then local humie = get_random_boss_human_soldier(0) local position = surface.find_non_colliding_position(humie, spawn, 100, 1) if not group then group = surface.create_unit_group{position = position, force = game.forces.enemy} end one_humie = surface.create_entity{name=humie, position=position, force = game.forces.enemy} if one_humie and one_humie.valid then group.add_member(one_humie) table.insert(global.other_enemies,one_humie) end end group_set_command(group,attack1,attack2,attack3) return group, one_humie end function create_invasion(surface,position,pcount) local qt = math.min(25, math.max(1,math.ceil(game.forces.enemy.evolution_factor * 20 + math.random(math.ceil(pcount/2))))) + global.difficulty_level - 1 table.insert (global.invasions, {name="bm-spawner", surface=surface, position=position, quant=qt}) if game.forces.enemy.evolution_factor>0.8 then if math.random(1,2)==1 then CallWormAttack(surface,position,math.ceil((qt+ global.difficulty_level )/2),0,25) end end end function get_random_human_soldier(evolution) if not evolution then evolution = game.forces.enemy.evolution_factor end local list = { 'tc_fake_human_machine_gunner', 'tc_fake_human_laser', 'tc_fake_human_electric'} if evolution>0.17 then table.insert(list,'tc_fake_human_sniper') else table.insert(list,'tc_fake_human_melee') table.insert(list,'tc_fake_human_pistol_gunner') end if evolution>0.3 then table.insert(list,'tc_fake_human_grenade') end if evolution>0.60 then table.insert(list,'tc_fake_human_rocket') table.insert(list,'tc_fake_human_cannon') end if evolution>0.75 then table.insert(list,'tc_fake_human_erocket') table.insert(list,'tc_fake_human_cluster_grenade') table.insert(list,'tc_fake_human_cannon_explosive') end if global.allow_nuker and evolution>0.96 then table.insert(list,'tc_fake_human_nuke_rocket') end local n=math.min(10, math.max(math.ceil(evolution*10),1)) return list[math.random(#list)] ..'_'..n end function get_random_boss_human_soldier(evolution) if not evolution then evolution = game.forces.enemy.evolution_factor end local list = { 'tc_fake_human_boss_machine_gunner', 'tc_fake_human_boss_laser', 'tc_fake_human_boss_electric'} if evolution>0.94 then table.insert(list,'tc_fake_human_boss_sniper') end if evolution>0.96 then table.insert(list,'tc_fake_human_boss_rocket') table.insert(list,'tc_fake_human_boss_grenade') end if evolution>0.98 then table.insert(list,'tc_fake_human_boss_erocket') table.insert(list,'tc_fake_human_boss_cluster_grenade') table.insert(list,'tc_fake_human_boss_cannon_explosive') end local n=math.min(10, math.max(math.ceil((evolution - 0.9) *100),1)) return list[math.random(#list)] ..'_'..n end function get_brutals_for_evolution(evolution,extra_evo) local brutals = {} local biters = get_units_for_evolution(evolution,extra_evo) for b=1,#biters do local brut = 'brutal-'..biters[b] if game.entity_prototypes[brut] then table.insert(brutals,brut) end end return brutals end function create_brutals_group(surface,spawn,pcount, attack1, attack2,attack3) local qt = math.min(10, math.max(2,math.ceil(game.forces.enemy.evolution_factor * 10 + math.random(math.ceil(pcount/2))))) + (global.difficulty_level-1) * 10 local group local one_brutal local brutals = get_brutals_for_evolution(nil,0.1) for x=1, qt do local brutal = brutals[math.random(#brutals)] local position = surface.find_non_colliding_position(brutal, spawn, 200, 1) if position then if not group then group = surface.create_unit_group{position = position, force = game.forces.enemy} surface.create_entity{name="bm-large-tunnel", position=position, force = game.forces.neutral} create_remnants_particles (surface, math.random(30,50) , position) end one_brutal = surface.create_entity{name=brutal, position= position, force= game.forces.enemy} create_tatoo_for_unit(one_brutal) group.add_member(one_brutal) table.insert (global.other_enemies,one_brutal ) end end group_set_command(group,attack1,attack2,attack3) return group, one_brutal end function get_random_lesser_boss(evolution,surface) if not evolution then evolution = game.forces.enemy.evolution_factor end local list = {'maf-boss-biter-','maf-boss-acid-spitter-'} if game.active_mods['ArmouredBiters'] then table.insert(list,'maf-boss-armoured-biter-') end if game.active_mods['Cold_biters'] then if (not surface) or #surface.find_entities_filtered{name='cb-cold-spawner',limit=1}>0 then table.insert(list,'maf-boss-frost-biter-') table.insert(list,'maf-boss-frost-spitter-') end end if game.active_mods['Explosive_biters'] then if (not surface) or #surface.find_entities_filtered{name='explosive-biter-spawner',limit=1}>0 then table.insert(list,'maf-boss-explosive-biter-') table.insert(list,'maf-boss-explosive-spitter-') end end if game.active_mods['Toxic_biters'] then if (not surface) or #surface.find_entities_filtered{name='toxic-biter-spawner',limit=1}>0 then table.insert(list,'maf-boss-toxic-biter-') table.insert(list,'maf-boss-toxic-spitter-') end end if game.active_mods['Arachnids_enemy'] then if (not surface) or #surface.find_entities_filtered{name='arachnid-spawner-unitspawner',limit=1}>0 then table.insert(list,'maf-boss-arachnid-biter-') end end local n=math.min(10, math.max(math.ceil(evolution*10),1)) return list[math.random(#list)] ..n end function Call_next_wave(event) local event_name = event.event_name if event_name == 'swarm' then local attacks = event.attacks for a=1,#attacks do local at = attacks[a] CallFrenzyAttack(at.surface,at.target,at.limit,at.multiplier) end end end function CallFrenzyAttack(surface,target,limit,multiplier) if not (surface and surface.valid) then return end if surface.map_gen_settings.autoplace_controls and surface.map_gen_settings.autoplace_controls["enemy-base"] and surface.map_gen_settings.autoplace_controls["enemy-base"].size>0 then local position if target.type and target.valid then position=target.position else position = target end local Min = global.difficulty_level * 10 local Max = 270 + global.difficulty_level * 30 local Dist = 1500 local spawn = surface.find_entities_filtered({type = "unit-spawner",limit=1,position=position,radius=Dist}) if #spawn>0 then local force = spawn[1].force local aliens = Max * force.evolution_factor if aliens < Min then aliens=Min end if limit and aliens>limit then aliens=limit end if multiplier then aliens=math.floor(aliens * multiplier) end if target.type and target.valid then local sent = surface.set_multi_command({ command = {type=defines.command.attack, target=target, distraction = defines.distraction.by_anything }, unit_count = aliens, force = force, unit_search_distance = Dist, }) else local sent = surface.set_multi_command({ command = {type=defines.command.attack_area, destination=position, radius=50, distraction = defines.distraction.by_anything }, unit_count = aliens, force = force, unit_search_distance = Dist, }) end end end end function CallWormAttack(surface,position,how_many,min_distance,max_distance,force) local worms = get_worms_for_evolution(nil,nil,surface,position) for w=1,how_many do local worm = worms[math.random(#worms)] for t=1,10 do local x = position.x + math.random(min_distance,max_distance)* RandomNegPos() local y = position.y + math.random(min_distance,max_distance)* RandomNegPos() local pos = surface.find_non_colliding_position(worm, {x=x,y=y}, 6, 2) if pos then create_remnants_particles (surface, math.random(20,40) , pos) local wo = surface.create_entity{name=worm,force=force,position=pos} table.insert (global.other_enemies,wo ) break end end end end -------------------------------------------------------- function create_biterzilla(surface,spawn,pcount, attack1, attack2, attack3,specific_zilla) local zilla, name, group local evo = game.forces.enemy.evolution_factor if evo<0.9 and (not specific_event) then name = get_random_lesser_boss(evo,surface) else local list = {"biterzilla1","biterzilla2","biterzilla3","maf-giant-acid-spitter","maf-giant-fire-spitter","bm-motherbiterzilla"} if global.chances.soldiers.chance>0 then table.insert(list,"big_human") end name = list[math.random(#list)] if name=="big_human" then name=get_random_boss_human_soldier() elseif string.find(name, "zilla") or string.find(name, "maf") then local N=1 if evo>0.98 then N=5 elseif evo>0.96 then N=4 elseif evo>0.94 then N=3 elseif evo>0.92 then N=2 end name=name..N end end if specific_zilla then name=specific_zilla end local position = surface.find_non_colliding_position(name, spawn, 0, 1) if position then group = surface.create_unit_group{position = position, force = game.forces.enemy} create_remnants_particles (surface, math.random(60,100) , position) zilla = surface.create_entity{name=name, position=position, force = game.forces.enemy} zilla.ai_settings.allow_destroy_when_commands_fail=false surface.create_entity{name="bm-large-tunnel", position=position, force = game.forces.neutral} group.add_member(zilla) local effect if specific_zilla then effect='all_buff' elseif (string.find(name, "human") and evo>0.6 and math.random (3)==1) then effect='defender_capsules' elseif (string.find(name, "human") and evo>0.85 and math.random (3)==1) then effect='grenade_launcher' end table.insert (global.biterzillas, {entity=zilla, effect = effect}) if evo>=0.9 then local hpe = (pcount*zilla.health/10) * game.forces.enemy.evolution_factor if game.forces.enemy.evolution_factor>0.95 then hpe = hpe*1.5 end zilla.health = (zilla.health/5) + hpe end if pcount>1 and game.forces.enemy.evolution_factor>0.95 then if math.random(1,2)==1 then CallFrenzyAttack(surface,attack1) else if global.chances.invasion.chance>=math.random(100) then create_invasion(surface,attack1,pcount) end end end end group_set_command(group,attack1,attack2, attack3) return group, zilla end function create_spidertron(surface,spawn,pcount) local spider local evo = game.forces.enemy.evolution_factor local N=1 if evo>0.98 then N=5 elseif evo>0.96 then N=4 elseif evo>0.94 then N=3 elseif evo>0.92 then N=2 end local name='bm-spidertron_' .. N local position = surface.find_non_colliding_position(name, spawn, 0, 1) if position then create_remnants_particles (surface, math.random(60,100) , position) spider = surface.create_entity{name=name, position=position, force = game.forces.enemy} surface.create_entity{name="bm-large-tunnel", position=position, force = game.forces.neutral} local effect if evo>0.6 and math.random (3)==1 then effect='defender_capsules' end if evo>0.85 and math.random (3)==1 then effect='grenade_launcher' end table.insert (global.biterzillas, {entity=spider, effect = effect}) if evo>=0.9 then local hpe = (pcount*spider.health/10) * game.forces.enemy.evolution_factor if game.forces.enemy.evolution_factor>0.95 then hpe = hpe*1.5 end spider.health = ((spider.health/5) + hpe) * global.difficulty_level end end return spider end function Spidertron_Moves(spider) if global.spidertron_nuke then spider.insert{name='maf-small-atomic-rocket',count=5} end local FI = spider.get_fuel_inventory() if FI then if FI.get_item_count('solid-fuel')<20 and FI.can_insert{name='solid-fuel', count=20} then spider.insert {name='solid-fuel', count=20} end end if game.forces.enemy.evolution_factor>0.95 then spider.insert{name='explosive-rocket',count=400} else spider.insert{name='rocket',count=400} end local enemy = spider.surface.find_nearest_enemy{position=spider.position, max_distance=1500, force=spider.force} --zilla.force if enemy and enemy.valid then spider.autopilot_destination = get_random_pos_near(enemy.position,40) end end local tick_zillas = 60 script.on_nth_tick(tick_zillas, function (event) cam_on_tick(event) for i=#global.invasions,1,-1 do local inv =global.invasions[i] local surface = inv.surface if inv.quant>0 and surface.valid then local position = inv.surface.find_non_colliding_position(inv.name, inv.position, 200, 4) if position ~= nil then create_remnants_particles (surface, math.random(20,40) , position) local invader = surface.create_entity{name=inv.name, position=position, force = game.forces.enemy} table.insert(global.other_enemies, invader) end inv.quant=inv.quant-1 else inv.quant=0 end if inv.quant<1 then table.remove(global.invasions,i) end end -- ZILLAS for z=#global.biterzillas,1,-1 do local ZI = global.biterzillas[z] local zilla = ZI.entity local effect = ZI.effect if not (zilla and zilla.valid) then table.remove(global.biterzillas,z) else if string.find(zilla.name, "biterzilla1") then if math.random(1,4)==1 then local xx = zilla.position.x + math.random(-5,5) local yy = zilla.position.y + math.random(-5,5) zilla.surface.create_entity{name ="maf-cluster-fire-projectile", target_position={x=xx,y=yy}, position={x=xx,y=yy}, source=zilla, force=zilla.force, speed=1} end elseif string.find(zilla.name, "biterzilla2") then if math.random(3)==1 then zilla.surface.create_entity{name="electric-shock2", position=zilla.position, force=zilla.force} end elseif string.find(zilla.name, "motherbiterzilla") then if math.random(1,4)==1 then Brood(zilla) end elseif string.find(zilla.name, "human") and math.random(1,40)==1 then BroodHumans(zilla) end if string.find(zilla.name, "tc_fake_human_ultimate_boss") then if math.random(1,10)==1 then BroodHumans(zilla, 2) end end if effect and (effect=='defender_capsules' or effect=='all_buff') then local ent = {'destroyer','defender'} if math.random(3)==1 then zilla.surface.create_entity{name=ent[math.random(#ent)], position=zilla.position,target=zilla,force=zilla.force} end end if effect and (effect=='grenade_launcher' or effect=='all_buff') and math.random(5)==1 then local d=35 if effect=='all_buff' then d=60 end local enemy = zilla.surface.find_nearest_enemy{position=zilla.position, max_distance=d, force=zilla.force} --zilla.force if enemy and enemy.valid and enemy.name~='entity-ghost' and enemy.type~='entity-ghost' and enemy.destructible and enemy.health then local weap = {'explosive-rocket','grenade'} if string.find(zilla.name, "ultimate") then table.insert(weap,'bm-small-atomic-rocket') table.insert(weap,'cluster-grenade') end zilla.surface.create_entity{name=weap[math.random(#weap)], target=enemy, position=zilla.position, force=zilla.force, speed=0.4} end end if zilla.valid and zilla.type == 'spider-vehicle' and game.tick % (tick_zillas*18) ==0 then Spidertron_Moves(zilla) end end end end) script.on_nth_tick(60*3, function (event) if #global.next_wave>0 and global.next_wave[1].tick < game.tick then Call_next_wave(global.next_wave[1]) table.remove(global.next_wave,1) end for k=#global.bm_volcano,1,-1 do local V=global.bm_volcano[k] local volcano = V.volcano local tick = V.tiltick if volcano and volcano.valid then local pos = volcano.position volcano.surface.pollute(pos,75) volcano.surface.create_trivial_smoke{name='fire-smoke-on-adding-fuel', position=pos} volcano.surface.create_trivial_smoke{name='turbine-smoke', position=pos} if game.tick > tick then volcano.die() table.remove(global.bm_volcano,k) else -- erupt!!! volcano.surface.create_entity{name="big-artillery-explosion", position=pos, force = game.forces.neutral} local area = 50 local xx = pos.x + math.random(-area,area) local yy = pos.y + math.random(-area,area) volcano.surface.create_entity{name ="maf-cluster-fire-projectile", target_position={x=xx,y=yy}, position={x=xx,y=yy}, source=volcano, force= game.forces.enemy, speed=4} end else table.remove(global.bm_volcano,k) end end end) function create_volcano(surface, target, pcount) local duration = (60 * 60) + ((pcount + global.difficulty_level) * 60 * 20) local volcano local position = surface.find_non_colliding_position("bm-volcano", target, 200, 1) if position ~= nil then surface.create_entity{name="nuke-explosion", position=position, force = game.forces.enemy} --big-artillery-explosion volcano = surface.create_entity{name="bm-volcano", position=position, force = game.forces.enemy} table.insert(global.bm_volcano, {volcano=volcano, tiltick=game.tick + duration}) end return volcano end -------------------------------------------------------------------------- function create_bigworm(surface,target,pcount) local worm = "maf-behemoth-worm-turret" if game.forces.enemy.evolution_factor > 0.80 then worm = "maf-colossal-worm-turret" end if game.forces.enemy.evolution_factor > 0.9 then if math.random(1,2)==1 then worm = "bm-worm-boss-fire-shooter" else worm = "bm-worm-boss-acid-shooter" end end local worm = "maf-behemoth-worm-turret" local qt = math.min(4, 1 + math.floor(pcount/4)) + global.difficulty_level - 1 local the_worm for x=1,qt do local position = surface.find_non_colliding_position(worm, target, 150, 1) if position then create_remnants_particles (surface, math.random(30,60) , position) the_worm = surface.create_entity{name=worm, position= position, force= game.forces.enemy} table.insert (global.other_enemies,the_worm ) end end -- normal worms for reinforced attack if pcount>2 then local qt = math.min(25, math.max(1,math.ceil(game.forces.enemy.evolution_factor * 12 + math.random(math.ceil(pcount/2))))) + global.difficulty_level - 1 CallWormAttack(surface,target,qt,0,20) end return the_worm end function Brood(mother) local x = mother.position.x local y = mother.position.y local r = 10 local Units = mother.surface.find_entities_filtered({force=mother.force, area={{x-r,y-r},{x+r,y+r}}}) if #Units>50 then return end local Min = 2 local Max = 6 local num = math.random(Min,Max) + global.difficulty_level - 1 local group = mother.unit_group local children = get_units_for_evolution() for k=1,num do local name= children[math.random(#children)] local pos = mother.surface.find_non_colliding_position(name, mother.position, 10, 1) if pos then mother.surface.create_entity{name="bm-acid-splash-fire", position=pos, force = mother.force} local child = mother.surface.create_entity{name=name, position=pos, force = mother.force} if group then group.add_member(child) end end end end function BroodHumans(mother, extra) extra=extra or 0 local x = mother.position.x local y = mother.position.y local r = 10 local Units = mother.surface.find_entities_filtered({force= mother.force, area={{x-r,y-r},{x+r,y+r}}}) if #Units>5 + global.difficulty_level + extra*3 then return end local num = math.random(3+ extra) + global.difficulty_level - 1 local group = mother.unit_group for k=1,num do local name= get_random_human_soldier() local pos = mother.surface.find_non_colliding_position(name, mother.position, 15, 1) if pos then local child = mother.surface.create_entity{name=name, position=pos, force = mother.force} if group then group.add_member(child) end end end end -------------------------------------------------------------------------------------- local function create_rocks(entity,quant) local rocks = {'rock-big','rock-huge','sand-rock-big'} entity.surface.create_entity{name='rock-huge', position=entity.position, force = game.forces.neutral} for q=1,quant do local rock = rocks[math.random(#rocks)] local position = entity.surface.find_non_colliding_position(rock, entity.position, 10, 1) if position ~= nil then entity.surface.create_entity{name="big-artillery-explosion", position=position, force = game.forces.neutral} entity.surface.create_entity{name=rock, position=position, force = game.forces.neutral} end end end function On_Remove(event) if event.entity and event.entity.name == "bm-volcano" then create_rocks(event.entity,12) end end local filters = {{filter = "name", name = "bm-volcano"}} script.on_event(defines.events.on_entity_died, On_Remove) function On_Built(event) local entity = event.created_entity or event.entity if entity and entity.valid and entity.type~='entity-ghost' then local surface = entity.surface local name=entity.name table.insert (global.rocket_silos,entity) if global.enable_silo_attack then CallFrenzyAttack(surface,entity,nil,1.5) end end end local filters = {{filter = "name", name = "rsc-silo-stage1"}, {filter = "name", name = "rsc-silo-stage1-serlp"}, {filter = "name", name = "rocket-silo"}} script.on_event(defines.events.on_built_entity, On_Built, filters) script.on_event(defines.events.on_robot_built_entity, On_Built, filters) script.on_event(defines.events.script_raised_built, On_Built, filters) function player_mined_entity(event) local player = game.players[event.player_index] if not player.valid then return end local ent = event.entity if ent.type=='tree' then if math.random()<=global.tree_events_chance then local the_event=pick_event({'biterzilla','volcano'}) if the_event then local pforce = player.force local surface = ent.surface Create_Position_Event(the_event, surface, ent.position, pforce) end end end end local filters = {{filter = "type", type = "tree"}} script.on_event(defines.events.on_player_mined_entity, player_mined_entity, filters) -- warptorio function on_warptorio_warp(event) global.surfaces = {} local newsurface = event.newsurface local planet = event.newplanet if planet and newsurface then local flags = planet.flags if (not flags) or (not in_list(flags,"rest")) then add_list(global.surfaces, newsurface.name) end end end -- player body abduction mod function on_corpse_feasted(event) local corpse=event.corpse local attack=event.attack_target if corpse and corpse.valid and attack and attack.valid then local evo = game.forces.enemy.evolution_factor local surface = corpse.surface ---if corpse.get_item_count("rocket-launcher")>0 then if global.chances.biterzilla.min_evo<=evo and math.random(100) <= global.chances.biterzilla.chance*2 then local pforce if corpse.character_corpse_player_index and game.players[corpse.character_corpse_player_index] and game.players[corpse.character_corpse_player_index].valid then pforce = game.players[corpse.character_corpse_player_index].force end local boss_name=get_random_boss_human_soldier() local position = surface.find_non_colliding_position(boss_name, corpse.position, 30, 1) local boss = surface.create_entity{name=boss_name, position=position, force = game.forces.enemy} boss.ai_settings.allow_destroy_when_commands_fail=false table.insert (global.biterzillas, {entity=boss}) if pforce then if global.show_alerts then pforce.print({"bm-txt-alert"},colors.lightred) pforce.print({"bm-txt-biterzilla"},colors.lightred) end Play_sound_alert(pforce,3) end else local humie = get_random_human_soldier() local position = surface.find_non_colliding_position(humie, corpse.position, 30, 1) surface.create_entity{name=humie, position= position, force= game.forces.enemy} end end end function RegisterModEvents() if remote.interfaces["warptorio2"] then local warp_event = remote.call("warptorio2","get_event", "on_post_warp") script.on_event(warp_event, function(event) on_warptorio_warp(event) end) end if remote.interfaces["PlayerBodyAbduction"] then local pba_event = remote.call("PlayerBodyAbduction", "get_on_corpse_feasted") script.on_event(pba_event, function(event) on_corpse_feasted(event) end) end end -------------------------------------------------------------------------------------- -- INTERFACE -------------------------------------------------------------------------------------- local interface = {} function interface.destroy_all() global.invasions = {} for _, zilla in pairs(global.biterzillas) do if zilla.entity.valid then zilla.entity.destroy() end end global.biterzillas = {} for k=#global.bm_volcano,1,-1 do local V=global.bm_volcano[k] local volcano = V.volcano if volcano and volcano.valid then volcano.destroy() end end global.bm_volcano = {} for _, e in pairs(global.other_enemies) do if e and e.valid then e.destroy() end end global.other_enemies = {} end local event_names = {'biterzilla','brutals','soldiers','worms','volcano','invasion','swarm','spidertron','ultimate_boss'} function interface.create_event(the_event,surfacename,forcename) if (not the_event) or in_list(event_names, the_event) then CreateNewEvent(the_event,surfacename, forcename) end end function interface.create_silo_event(the_event) if (not the_event) or in_list(event_names, the_event) then Create_Silo_Attack(the_event) end end -- exclude / include surfaces for disasters function interface.exclude_surface(surfacename) if surfacename then del_list(global.surfaces, surfacename) end end function interface.add_surface(surfacename) if surfacename then add_list(global.surfaces, surfacename) end end -- exclude / include player forces to be targeted function interface.exclude_player_force(forcename) if forcename then del_list(global.player_forces, forcename) end end function interface.add_player_force(forcename) if forcename then add_list(global.player_forces, forcename) end end remote.add_interface( "bigmonster", interface ) --[[ Usage for creating events: create_event(eventname,surfacename,forcename) Use these event names 'biterzilla','soldiers','worms','volcano','invasion','swarm' nil will create a random event Examples: Call specific events for all surfaces and all player forces /c remote.call( "bigmonster", "create_event", "biterzilla") /c remote.call( "bigmonster", "create_event", "soldiers") /c remote.call( "bigmonster", "create_event", "worms") /c remote.call( "bigmonster", "create_event", "volcano") /c remote.call( "bigmonster", "create_event", "invasion") /c remote.call( "bigmonster", "create_event", "swarm") /c remote.call( "bigmonster", "create_event", "spidertron") /c remote.call( "bigmonster", "create_event", "ultimate_boss") Call specific event for nauvis surface only, to all player forces /c remote.call( "bigmonster", "create_event", "biterzilla", "nauvis") Call specific event for all registered surfaces, to specific player force /c remote.call( "bigmonster", "create_event", "volcano", nil, "player") Call random event for all registered surfaces, to specific player force /c remote.call( "bigmonster", "create_event", nil, nil, "player") Call an event for attacking All Silos - eventname = all above /c remote.call( "bigmonster", "create_silo_event", eventname) include surfaces for disasters /c remote.call( "bigmonster", "add_surface", surfacename) exclude surfaces for disasters /c remote.call( "bigmonster", "exclude_surface", surfacename) include player force to be targeted /c remote.call( "bigmonster","add_player_force",forcename) exclude player force to be targeted /c remote.call( "bigmonster","exclude_player_force",forcename) destroy all mod enemies /c remote.call( "bigmonster","destroy_all") ]]