You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
13 KiB
365 lines
13 KiB
Weapon = {}
|
|
|
|
-- constants
|
|
Weapon.tesla_base_damage = 25
|
|
Weapon.tesla_ammo_category = "tesla"
|
|
Weapon.cryogun_freeze_time_min = 300
|
|
Weapon.cryogun_freeze_time_max = 1200
|
|
Weapon.cryogun_ice_radius = 1
|
|
Weapon.cryogun_freeze_radius = 4
|
|
Weapon.name_cryogun_ice = mod_prefix.."cryogun-ice"
|
|
Weapon.name_cryogun_ice_spacer = mod_prefix.."cryogun-ice-spacer"
|
|
|
|
--[[
|
|
plague new plan.
|
|
Limit to 1 acive per chunk?
|
|
Have a table of chunks and expiration date?
|
|
|
|
Get all entities, sort by distance, destroy 1 per frame?
|
|
|
|
Get a chunk, get entities, destroy, get neighbors.
|
|
Choose a random chunk nearby to infect, repeat.
|
|
Limit to X active chunks.
|
|
]]
|
|
|
|
function Weapon.on_trigger_created_entity(event)
|
|
if not event.entity and event.entity.valid then return end
|
|
if event.entity.name == mod_prefix.."tesla-gun-trigger" then
|
|
if event.source and event.source.valid then
|
|
local tick_task = new_tick_task("chain-beam")
|
|
tick_task.surface = event.entity.surface
|
|
tick_task.beam = mod_prefix.."tesla-gun-beam"
|
|
tick_task.max_bounces = 10 + math.random() * 20
|
|
tick_task.range = 10
|
|
tick_task.instigator = event.source
|
|
tick_task.instigator_force = event.source.force
|
|
tick_task.initial_vector = util.vector_normalise(util.vectors_delta(event.source.position, event.entity.position))
|
|
local first_hit = util.move_to(event.source.position, event.entity.position, 3, false)
|
|
tick_task.affected_locations = {{position = first_hit}}
|
|
local source = event.source.position
|
|
-- gun graphic offset
|
|
source.y = source.y - 1
|
|
source = util.move_to(source, util.vectors_add(source, tick_task.initial_vector), 0.7, true)
|
|
|
|
tick_task.surface.create_entity{
|
|
name = tick_task.beam,
|
|
position = first_hit,
|
|
target_position = first_hit,
|
|
source_position = source,
|
|
duration = 10,
|
|
}
|
|
end
|
|
elseif event.entity.name == mod_prefix .. "plague-cloud"then
|
|
local surface_index = event.entity.surface.index
|
|
local zone = Zone.from_surface_index(surface_index)
|
|
if zone and Zone.is_solid(zone) and not zone.plague_tick_task then
|
|
if not zone.plague_used then
|
|
zone.plague_used = game.tick
|
|
end
|
|
local surface = event.entity.surface
|
|
local map_gen_settings = surface.map_gen_settings
|
|
zone.controls["enemy-base"] = {frequency = 0, size = -1, richness = -1}
|
|
zone.controls["trees"] = {frequency = 0, size = -1, richness = -1}
|
|
map_gen_settings.autoplace_controls["enemy-base"] = {frequency = 0, size = -1, richness = -1}
|
|
map_gen_settings.autoplace_controls["trees"] = {frequency = 0, size = -1, richness = -1}
|
|
if map_gen_settings.autoplace_controls["se-vitamelange"] then
|
|
zone.controls["se-vitamelange"] = {frequency = 0, size = -1, richness = -1}
|
|
map_gen_settings.autoplace_controls["se-vitamelange"] = {frequency = 0, size = -1, richness = -1}
|
|
Universe.remove_resource_from_zone_surface(zone, "se-vitamelange")
|
|
end
|
|
if zone.primary_resource == "se-vitamelange" then
|
|
zone.primary_resource = "coal"
|
|
zone.fragment_name = Coreminer.resource_to_fragment_name(zone.primary_resource)
|
|
Coreminer.update_zone_fragment_resources(zone)
|
|
end
|
|
surface.map_gen_settings = map_gen_settings
|
|
local tick_task = new_tick_task("plague-tick")
|
|
tick_task.surface_index = surface_index
|
|
tick_task.position = event.entity.position
|
|
tick_task.zone = zone
|
|
if event.entity.force then
|
|
tick_task.force_name = event.entity.force.name
|
|
end
|
|
tick_task.started = game.tick
|
|
zone.plague_tick_task = tick_task
|
|
end
|
|
elseif event.entity.name == mod_prefix.."cryogun-trigger" then
|
|
local pos = event.entity.position
|
|
local surface = event.entity.surface
|
|
local spaceship = Spaceship.from_own_surface_index(surface.index)
|
|
local safe_pos = surface.find_non_colliding_position(Weapon.name_cryogun_ice_spacer, pos, Weapon.cryogun_ice_radius, 0.1, false)
|
|
local ice_entities = {}
|
|
if safe_pos then
|
|
local ice = surface.create_entity{name = Weapon.name_cryogun_ice, position = safe_pos, force = "neutral"}
|
|
table.insert(ice_entities, ice)
|
|
if spaceship then
|
|
SpaceshipObstacles.add_moveable_entity(spaceship, ice, "ice")
|
|
end
|
|
end
|
|
local freeze_entities = surface.find_entities_filtered{
|
|
type = {"unit", "turret", "ammo-turret", "electric-turret", "fluid-turret"},
|
|
position = safe_pos or pos,
|
|
radius = Weapon.cryogun_freeze_radius
|
|
}
|
|
local reactivate_entities = {}
|
|
for _, entity in pairs(freeze_entities) do
|
|
if entity.active then
|
|
entity.active = false
|
|
table.insert(reactivate_entities, entity)
|
|
table.insert(ice_entities, surface.create_entity{name = Weapon.name_cryogun_ice, position = entity.position, force = "neutral"})
|
|
end
|
|
end
|
|
if #ice_entities > 0 or #reactivate_entities > 0 then
|
|
local tick_task = new_tick_task("cryogun-unfreeze")
|
|
tick_task.ice_entities = ice_entities
|
|
tick_task.reactivate_entities = reactivate_entities
|
|
tick_task.freeze_tick = game.tick
|
|
tick_task.unfreeze_tick = game.tick + math.random(Weapon.cryogun_freeze_time_min, Weapon.cryogun_freeze_time_max)
|
|
end
|
|
elseif event.entity.name == mod_prefix.."pheromone-trigger" then
|
|
local units = event.entity.surface.find_entities_filtered{type="unit", position = event.entity.position}
|
|
if event.source and event.source.valid then
|
|
for _, unit in pairs(units) do
|
|
if unit.force ~= event.source.force then
|
|
if string.find(unit.name, "biter", 1, true) or string.find(unit.name, "spitter", 1, true) then
|
|
unit.force = event.source.force
|
|
unit.set_command({type = defines.command.wander})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_trigger_created_entity, Weapon.on_trigger_created_entity)
|
|
|
|
function Weapon.cryogun_unfreeze(tick_task)
|
|
if game.tick >= tick_task.unfreeze_tick then
|
|
tick_task.valid = false
|
|
for _, e in pairs(tick_task.ice_entities) do
|
|
if e.valid then e.destroy() end
|
|
end
|
|
for _, e in pairs(tick_task.reactivate_entities) do
|
|
if e.valid then e.active = true end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Weapon.plague_end(tick_task)
|
|
tick_task.valid = false
|
|
tick_task.zone.plague_tick_task = nil
|
|
local surface = game.surfaces[tick_task.surface_index]
|
|
if surface then
|
|
local enemies = surface.find_entities_filtered{ force = "enemy" }
|
|
for _, entity in pairs(enemies) do
|
|
entity.destroy()
|
|
end
|
|
local plague = surface.find_entities_filtered{ name={
|
|
mod_prefix .. "plague-cloud",
|
|
mod_prefix .. "plague-wave"} }
|
|
for _, entity in pairs(plague) do
|
|
entity.destroy()
|
|
end
|
|
local trees = surface.find_entities_filtered{ type = "tree" }
|
|
for _, entity in pairs(trees) do
|
|
entity.destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
function Weapon.plague_tick(tick_task)
|
|
--game.print((game.tick - (tick_task.started + 10 * 60 * 60)) / 60)
|
|
if game.tick > tick_task.started + settings.global["se-plague-max-runtime-2"].value * 60 * 60 then -- 15 minutes
|
|
Weapon.plague_end(tick_task)
|
|
end
|
|
|
|
if not tick_task.death_range then
|
|
tick_task.death_range = 32
|
|
end
|
|
local surface = game.surfaces[tick_task.surface_index]
|
|
if not surface then Weapon.plague_end(tick_task) end
|
|
if (not tick_task.death_list) or #tick_task.death_list <= (tick_task.death_quota or 0) then
|
|
if tick_task.death_range > tick_task.zone.radius * 4 then
|
|
Weapon.plague_end(tick_task)
|
|
else
|
|
if (tick_task.death_quota or 0) > 1000 then
|
|
tick_task.death_range = tick_task.death_range + 1
|
|
else
|
|
tick_task.death_range = tick_task.death_range + 32
|
|
end
|
|
tick_task.death_list = surface.find_entities_filtered{
|
|
position = tick_task.position or {0,0},
|
|
radius = tick_task.death_range,
|
|
type = {
|
|
"unit",
|
|
"unit-spawner",
|
|
"turret",
|
|
"tree",
|
|
"fish"
|
|
} }
|
|
tick_task.death_quota = math.ceil(#tick_task.death_list*0.1)
|
|
if #tick_task.death_list < 10 then
|
|
tick_task.death_range = tick_task.death_range * 2
|
|
end
|
|
end
|
|
else
|
|
local m = math.min(10, math.ceil(#tick_task.death_list / 100))
|
|
for i = 1, m do
|
|
local entity = table.remove(tick_task.death_list, math.random(#tick_task.death_list))
|
|
if entity and entity.valid then
|
|
if entity.type == "unit-spawner" then
|
|
local enemy = surface.find_nearest_enemy{
|
|
position = entity.position,
|
|
max_distance = 2000,
|
|
force = entity.force}
|
|
if enemy and enemy.valid then
|
|
entity.damage(200, tick_task.force_name, "poison", enemy)
|
|
else
|
|
entity.damage(200, tick_task.force_name, "poison")
|
|
end
|
|
if entity.valid then
|
|
entity.die()
|
|
end
|
|
elseif entity.type == "unit" then
|
|
if #tick_task.death_list % 20 == 0 then
|
|
entity.die()
|
|
end
|
|
else
|
|
entity.die()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function Weapon.chain_beam(tick_task)
|
|
if not (tick_task.surface and tick_task.surface.valid) then
|
|
tick_task.valid = false
|
|
return
|
|
end
|
|
local branch_chance = tick_task.branch_chance or 0.1
|
|
local emanate_from = nil
|
|
if math.random() < branch_chance then
|
|
emanate_from = tick_task.affected_locations[math.random(#tick_task.affected_locations)] -- branching bouncing beam
|
|
else
|
|
emanate_from = tick_task.affected_locations[#tick_task.affected_locations] -- single bouncing beam
|
|
end
|
|
|
|
local entities = tick_task.surface.find_entities_filtered{
|
|
area = util.position_to_area(emanate_from.position, tick_task.range),
|
|
collision_mask = {"object-layer", "player-layer"},
|
|
}
|
|
|
|
local valids = {}
|
|
for _, entity in pairs(entities) do
|
|
if entity.valid and entity.is_entity_with_health and entity.type ~= "cliff" and entity.force ~= tick_task.instigator_force then
|
|
local already_affected = false
|
|
for _, affected in pairs(tick_task.affected_locations) do
|
|
if entity == affected.entity then
|
|
already_affected = true
|
|
end
|
|
end
|
|
if not already_affected then
|
|
table.insert(valids, entity)
|
|
end
|
|
end
|
|
end
|
|
|
|
local desired_pos = util.vectors_add(emanate_from.position, util.vector_multiply(util.vector_normalise(tick_task.initial_vector), 2))
|
|
|
|
local chosen = nil
|
|
|
|
if #valids > 0 then
|
|
|
|
local closest_dist = 10000
|
|
for _, valid in pairs(valids) do
|
|
local dist = (1 + util.vectors_delta_length(desired_pos, valid.position)) * 0.5 + math.random()
|
|
if dist < closest_dist then
|
|
closest_dist = dist
|
|
chosen = valid
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
if chosen then
|
|
table.insert(tick_task.affected_locations, {position = chosen.position, entity = chosen})
|
|
|
|
if chosen.type == "simple-entity" and string.find(chosen.name, "rock") then
|
|
chosen.health = math.max(0.01, chosen.health - chosen.prototype.max_health / 50)
|
|
end
|
|
|
|
local target_position = chosen.position
|
|
|
|
local force = tick_task.instigator_force
|
|
local bonus_damage = Weapon.tesla_base_damage * force.get_ammo_damage_modifier(Weapon.tesla_ammo_category)
|
|
if bonus_damage > 0 then
|
|
chosen.damage(bonus_damage, force, "electric")
|
|
end
|
|
|
|
local target = nil
|
|
if chosen and chosen.valid then
|
|
target = chosen
|
|
end
|
|
|
|
tick_task.surface.create_entity{
|
|
name = tick_task.beam,
|
|
position = emanate_from.position,
|
|
target = target,
|
|
force = force,
|
|
target_position = target_position,
|
|
source_position = emanate_from.position,
|
|
duration = 10,
|
|
}
|
|
else
|
|
-- hit ground
|
|
local ground = {x = desired_pos.x + ((math.random() - 0.5) * 0.25 * tick_task.range),
|
|
y = desired_pos.y + ((math.random() - 0.5) * 0.25 * tick_task.range)}
|
|
|
|
table.insert(tick_task.affected_locations, {position = ground})
|
|
|
|
tick_task.surface.create_entity{
|
|
name = tick_task.beam,
|
|
position = emanate_from.position,
|
|
target_position = ground,
|
|
source_position = emanate_from.position,
|
|
duration = 10,
|
|
}
|
|
end
|
|
|
|
if #tick_task.affected_locations >= (tick_task.max_bounces or 2) then
|
|
tick_task.valid = false
|
|
end
|
|
|
|
end
|
|
|
|
function Weapon.on_entity_died(event)
|
|
if event.entity and event.entity.valid and event.entity.type == "unit"then
|
|
local entity = event.entity
|
|
if entity.stickers then
|
|
for _, sticker in pairs(entity.stickers) do
|
|
if sticker.name == mod_prefix .. "bloater-sticker" then
|
|
local max_health = entity.prototype.max_health
|
|
local remain = max_health
|
|
while remain > 0 do
|
|
local done = false
|
|
for _, e in pairs({10000, 4000, 1000, 400, 100, 40, 10}) do
|
|
done = true
|
|
remain = remain - e
|
|
entity.surface.create_entity{
|
|
name= mod_prefix .. "bloater-burst-"..e,
|
|
position = entity.position,
|
|
force = "player"
|
|
}
|
|
end
|
|
if not done then remain = 0 end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_entity_died, Weapon.on_entity_died)
|
|
|
|
return Weapon
|
|
|