Skip to content
This repository has been archived by the owner on Nov 21, 2017. It is now read-only.

Commit

Permalink
Implement base expansion
Browse files Browse the repository at this point in the history
  • Loading branch information
Afforess committed Jun 16, 2016
1 parent d7d71bd commit 92c7877
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 13 deletions.
3 changes: 2 additions & 1 deletion data-updates.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'stdlib/string'

for _, prototype in pairs(data.raw["unit-spawner"]) do
prototype.pollution_absorbtion_absolute = prototype.pollution_absorbtion_absolute / 10
Expand Down Expand Up @@ -41,7 +42,7 @@ for key, prototype_type in pairs(data.raw) do
for name, prototype in pairs(prototype_type) do
if prototype.energy_source then
if prototype.energy_source.emissions and prototype.energy_source.emissions > 0.001 then
if name == 'assembling-machine-2' or name == 'assembling-machine-3' then
if name:contains('assembling-machine') and not name == 'assembling-machine-1' then
prototype.energy_source.emissions = prototype.energy_source.emissions * 8
else
prototype.energy_source.emissions = prototype.energy_source.emissions * 5
Expand Down
2 changes: 1 addition & 1 deletion libs/biter/ai/alert.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

local Alert = {}
local Log = function(str, ...) BiterBase.Logger.log(string.format(str, ...)) end
local Log = function(str, base, ...) BiterBase.Logger.log(string.format("[Alert] - (" .. base.name .. "): " .. str, ...)) end

function Alert.tick(base, data)
if #base:get_entities() < 15 then
Expand Down
2 changes: 1 addition & 1 deletion libs/biter/ai/attacked_recently.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

local AttackedRecently = {}
local Log = function(str, ...) BiterBase.Logger.log(string.format(str, ...)) end
local Log = function(str, base, ...) BiterBase.Logger.log(string.format("[AttackedRecently] - (" .. base.name .. "): " .. str, ...)) end

function AttackedRecently.tick(base, data)
if #base:get_entities() < 30 then
Expand Down
56 changes: 56 additions & 0 deletions libs/biter/ai/build_worm.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

local BuildWorm = {stages = {}}
local Log = function(str, base, ...) BiterBase.Logger.log(string.format("[BuildWorm] - (" .. base.name .. "): " .. str, ...)) end

BuildWorm.stages.clear_trees = function(base, data)
local surface = base.queen.surface
local pos = base.queen.position
table.each(surface.find_entities_filtered({area = Position.expand_to_area(pos, data.search_distance), type = 'tree'}), function(entity)
entity.destroy()
end)
return 'build_worm'
end

BuildWorm.stages.build_worm = function(base, data)
local surface = base.queen.surface
local pos = base.queen.position
local entity_pos = surface.find_non_colliding_position(data.worm_type, pos, data.search_distance, 0.5)
if entity_pos and Position.distance(pos, entity_pos) <= data.search_distance then
local worm = surface.create_entity({name = data.worm_type, position = entity_pos, force = base.queen.force})
table.insert(base.worms, worm)
Log("Successfully spawned a new worm at %s", base, serpent.line(worm.position))
return 'success'
end

data.search_distance = data.search_distance + 1
return 'clear_trees'
end

function BuildWorm.tick(base, data)
if not data.stage then
data.stage = 'clear_trees'
end
local prev_stage = data.stage
data.stage = BuildWorm.stages[data.stage](base, data)
if prev_stage ~= data.stage then
Log("Updating stage from %s to %s", base, prev_stage, data.stage)
end
return true
end

function BuildWorm.is_expired(base, data)
return data.search_distance > 7 or data.stage == 'success'
end

function BuildWorm.initialize(base, data)
data.search_distance = 2
if game.evolution_factor > 0.66 and math.random(100) > 66 then
data.worm_type = 'big-worm-turret'
elseif game.evolution_factor > 0.4 and math.random(100) > 40 then
data.worm_type = 'medium-worm-turret'
else
data.worm_type = 'small-worm-turret'
end
end

return BuildWorm
54 changes: 54 additions & 0 deletions libs/biter/ai/grow_hive.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

local GrowHive = {stages = {}}
local Log = function(str, base, ...) BiterBase.Logger.log(string.format("[GrowHive] - (" .. base.name .. "): " .. str, ...)) end

GrowHive.stages.clear_trees = function(base, data)
local surface = base.queen.surface
local pos = base.queen.position
table.each(surface.find_entities_filtered({area = Position.expand_to_area(pos, data.search_distance), type = 'tree'}), function(entity)
entity.destroy()
end)
return 'build_hive'
end

GrowHive.stages.build_hive = function(base, data)
local surface = base.queen.surface
local pos = base.queen.position
local entity_pos = surface.find_non_colliding_position(data.hive_type, pos, data.search_distance, 0.5)
if entity_pos and Position.distance(pos, entity_pos) <= data.search_distance then
local hive = surface.create_entity({name = data.hive_type, position = entity_pos, force = base.queen.force})
table.insert(base.hives, hive)
Log("Successfully spawned a new hive at %s", base, serpent.line(hive.position))
return 'success'
end

data.search_distance = data.search_distance + 1
return 'clear_trees'
end

function GrowHive.tick(base, data)
if not data.stage then
data.stage = 'clear_trees'
end
local prev_stage = data.stage
data.stage = GrowHive.stages[data.stage](base, data)
if prev_stage ~= data.stage then
Log("Updating stage from %s to %s", base, prev_stage, data.stage)
end
return true
end

function GrowHive.is_expired(base, data)
return data.search_distance > 10 or data.stage == 'success'
end

function GrowHive.initialize(base, data)
data.search_distance = 3
if math.random(100) > 33 then
data.hive_type = 'biter-spawner'
else
data.hive_type = 'spitter-spawner'
end
end

return GrowHive
49 changes: 40 additions & 9 deletions libs/biter/base.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@ function Base.all_hives(self)
return hives
end

function Base.wanted_hive_count(self)
return math.max(0, 1 + (game.evolution_factor / 10) - #self:all_hives())
end

function Base.wanted_worm_count(self)
local alert_count = 0
if self.history['alert'] then
alert_count = alert_count + self.history['alert']
end

return math.max(0, 1 + alert_count - #self.worms)
end

function Base.can_afford(self, plan)
return self.currency >= BiterBase.plans[plan].cost
end

-- Biter Base metatable
local BaseMt = {}
BaseMt.__index = function(tbl, k)
Expand All @@ -59,7 +76,7 @@ function BiterBase.discover(entity)
local surface = entity.surface

-- initialize biter base data structure
local base = { queen = entity, hives = {}, worms = {}, currency = 0, name = RandomName.get_random_name(14), next_tick = game.tick + math.random(300, 1000), valid = true}
local base = { queen = entity, hives = {}, worms = {}, currency = 0, name = RandomName.get_random_name(14), next_tick = game.tick + math.random(300, 1000), history = {}, valid = true}
table.insert(global.bases, base)
Entity.set_data(entity, {base = base})
local chunk_data = Chunk.get_data(surface, Chunk.from_position(pos), {})
Expand Down Expand Up @@ -168,29 +185,38 @@ end

BiterBase.plans = {
idle = { passive = true, cost = 1, update_frequency = 60 * 60 },
identify_targets = { passive = true, cost = 600, update_frequency = 300, class = require 'libs/biter/ai/identify_targets' },
identify_targets = { passive = true, cost = 600, update_frequency = 120, class = require 'libs/biter/ai/identify_targets' },
attack_area = { passive = false, cost = 2000, update_frequency = 300, class = require 'libs/biter/ai/attack_area'},
attacked_recently = { passive = false, cost = 240, update_frequency = 120, class = require 'libs/biter/ai/attacked_recently' },
alert = { passive = false, cost = 120, update_frequency = 180, class = require 'libs/biter/ai/alert' },
grow_hive = { passive = true, cost = 2000, update_frequency = 300, class = require 'libs/biter/ai/grow_hive' },
build_worm = { passive = true, cost = 1000, update_frequency = 300, class = require 'libs/biter/ai/build_worm' },
}

function BiterBase.create_plan(base)
if not base.target and base.currency > BiterBase.plans.identify_targets.cost then
if not base.target and base:can_afford('identify_targets') then
Log("%s has no active targets, and chooses AI plan to identify targets", BiterBase.tostring(base))
BiterBase.set_active_plan(base, 'identify_targets')
return true
end

if base.target and base.target.type == 'player_value' then
if base:wanted_hive_count() > 0 and base:can_afford('grow_hive') then
BiterBase.set_active_plan(base, 'grow_hive')
return true
end

if base:wanted_worm_count() > 0 and base:can_afford('build_worm') and math.random(100) > 70 then
BiterBase.set_active_plan(base, 'build_worm')
return true
end

if base:can_afford('attack_area') and base.target and base.target.type == 'player_value' then
if BiterBase.is_in_active_chunk(base) then
if base.currency > BiterBase.plans.attack_area.cost then
BiterBase.set_active_plan(base, 'attack_area')
return true
end
BiterBase.set_active_plan(base, 'attack_area')
return true
end
end

Log("%s has no active plans, and failed to choose any new plan. Idling.", BiterBase.tostring(base))
BiterBase.set_active_plan(base, 'idle')
return false
end
Expand Down Expand Up @@ -225,6 +251,11 @@ function BiterBase.set_active_plan(base, plan_name, extra_data)
base.plan = { name = plan_name, data = data, valid = true}
base.currency = base.currency - plan_data.cost
base.next_tick = game.tick + plan_data.update_frequency
if base.history[plan_name] then
base.history[plan_name] = base.history[plan_name] + 1
else
base.history[plan_name] = 1
end

if plan_data.class and plan_data.class.initialize then
plan_data.class.initialize(base, data)
Expand Down
12 changes: 11 additions & 1 deletion libs/region/chunk_value.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,19 @@ function World.entity_value(entity)
if entity.type:contains('turret') then
value = -1 * game.entity_prototypes[entity_name].max_health
adj_value = value / 2
Log("Turret %s value is %d", entity.name, value)
elseif BITER_TARGETS[entity_name] then
value = BITER_TARGETS[entity_name].value
elseif entity.type:contains('electric-pole') then
value = game.entity_prototypes[entity_name].max_health
elseif entity.type:contains('roboport') then
value = game.entity_prototypes[entity_name].max_health / 8
elseif entity.type:contains('transport-belt') then
value = game.entity_prototypes[entity_name].max_health / 2
elseif entity.type:contains('container') then
value = game.entity_prototypes[entity_name].max_health / 3
end
if value ~= 0 then
Log("Entity %s value is %d", entity.name, value)
end
return value, adj_value
end
Expand Down

0 comments on commit 92c7877

Please sign in to comment.