Compare commits
6 Commits
ebd3858aef
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00615c7c35 | ||
|
|
194925ab04 | ||
|
|
e25abd87ab | ||
|
|
d7dcc0d873 | ||
|
|
eb0e5b7d5a | ||
|
|
3bcc133674 |
@@ -5,6 +5,10 @@ from aoe.types import *
|
||||
class Costs():
|
||||
|
||||
|
||||
def compute_cost(self, purchase):
|
||||
return self.costs[purchase]
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.costs = {
|
||||
Ages.DARK: (0, 0, 0, 0),
|
||||
|
||||
@@ -1,9 +1,77 @@
|
||||
from aoe.types import *
|
||||
from aoe.exceptions import *
|
||||
|
||||
|
||||
|
||||
class BuildingDependencies():
|
||||
class Dependencies():
|
||||
|
||||
|
||||
def check_dependencies(self, world, thing):
|
||||
if type(thing) == Ages:
|
||||
self._check_age_dependencies(world, thing)
|
||||
else:
|
||||
self._check_non_age_dependencies(world, thing)
|
||||
|
||||
|
||||
def _check_non_age_dependencies(self, world, thing):
|
||||
for dep in self.dependencies[thing]:
|
||||
if dep not in world.buildings and \
|
||||
dep not in world.research and \
|
||||
not self._is_sufficient_age(world, dep):
|
||||
raise MissingDependencyException
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _is_sufficient_age(world, age):
|
||||
if type(age) == Ages and world.age >= age:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _check_age_dependencies(self, world, age):
|
||||
total_buildings = 0
|
||||
for building in self.age_dependencies[age].keys():
|
||||
if world.has_building(building):
|
||||
total_buildings += self.age_dependencies[age][building]
|
||||
if total_buildings < self.age_dependencies_counts[age]:
|
||||
raise MissingDependencyException
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.age_dependencies = {
|
||||
Ages.FEUDAL: {
|
||||
Buildings.BARRACKS: 1,
|
||||
Buildings.MILL: 1,
|
||||
Buildings.LUMBERCAMP: 1,
|
||||
Buildings.MININGCAMP: 1,
|
||||
Buildings.DOCK: 1,
|
||||
#Buildings.MULECART: 1,
|
||||
#Buildings.FOLWARK: 1,
|
||||
#Buildings.SETTLEMENT: 2,
|
||||
},
|
||||
Ages.CASTLE: {
|
||||
Buildings.ARCHERYRANGE: 1,
|
||||
Buildings.STABLE: 1,
|
||||
Buildings.MARKET: 1,
|
||||
Buildings.BLACKSMITH: 1,
|
||||
Buildings.SIEGEWORKSHOP: 1,
|
||||
},
|
||||
Ages.IMPERIAL: {
|
||||
Buildings.MONASTERY: 1,
|
||||
#Buildings.FORTIFIEDCHURCH: 1,
|
||||
Buildings.UNIVERSITY: 1,
|
||||
Buildings.SIEGEWORKSHOP: 1,
|
||||
Buildings.CASTLE: 2,
|
||||
Buildings.KREPOST: 2,
|
||||
},
|
||||
}
|
||||
|
||||
self.age_dependencies_counts = {
|
||||
Ages.FEUDAL: 2,
|
||||
Ages.CASTLE: 2,
|
||||
Ages.IMPERIAL: 2,
|
||||
}
|
||||
|
||||
self.dependencies = {
|
||||
Buildings.HOUSE: [Ages.DARK],
|
||||
Buildings.LUMBERCAMP: [Ages.DARK],
|
||||
@@ -33,56 +101,12 @@ class BuildingDependencies():
|
||||
Buildings.MONASTERY: [Ages.CASTLE],
|
||||
#Buildings.FORTIFIEDCHURCH: [Ages.CASTLE],
|
||||
Buildings.CASTLE: [Ages.CASTLE],
|
||||
#Buildings.KREPOST: [Ages.CASTLE],
|
||||
Buildings.KREPOST: [Ages.CASTLE],
|
||||
#Buildings.DONJON: [Ages.DARK],
|
||||
#Buildings.HARBOR: [Ages.CASTLE, Research.THALASSOCRACY],
|
||||
#Buildings.FEITORIA: [Ages.IMPERIAL],
|
||||
Buildings.BOMBARDTOWER: [Ages.IMPERIAL, Research.BOMBARDTOWER],
|
||||
Buildings.WONDER: [Ages.IMPERIAL],
|
||||
}
|
||||
|
||||
|
||||
|
||||
class AgeDependencies():
|
||||
def __init__(self):
|
||||
self.dependencies = {
|
||||
Ages.FEUDAL: {
|
||||
Buildings.BARRACKS: 1,
|
||||
Buildings.MILL: 1,
|
||||
Buildings.LUMBERCAMP: 1,
|
||||
Buildings.MININGCAMP: 1,
|
||||
Buildings.DOCK: 1,
|
||||
#Buildings.MULECART: 1,
|
||||
#Buildings.FOLWARK: 1,
|
||||
#Buildings.SETTLEMENT: 2,
|
||||
},
|
||||
Ages.CASTLE: {
|
||||
Buildings.ARCHERYRANGE: 1,
|
||||
Buildings.STABLE: 1,
|
||||
Buildings.MARKET: 1,
|
||||
Buildings.BLACKSMITH: 1,
|
||||
#Buildings.SIEGEWORKSHOP: 1,
|
||||
},
|
||||
Ages.IMPERIAL: {
|
||||
#Buildings.MONASTERY: 1,
|
||||
#Buildings.FORTIFIEDCHURCH: 1,
|
||||
#Buildings.UNIVERSITY: 1,
|
||||
#Buildings.SIEGEWORKSHOP: 1,
|
||||
#Buildings.CASTLE: 2,
|
||||
#Buildings.KREPOST: 2,
|
||||
},
|
||||
}
|
||||
self.dependencies_counts = {
|
||||
Ages.FEUDAL: 2,
|
||||
Ages.CASTLE: 2,
|
||||
Ages.IMPERIAL: 2,
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ResearchDependencies():
|
||||
def __init__(self):
|
||||
self.dependencies = {
|
||||
Research.TOWNWATCH: [Ages.FEUDAL,
|
||||
Buildings.TOWNCENTER],
|
||||
Research.TOWNPATROL: [Ages.CASTLE,
|
||||
@@ -237,13 +261,6 @@ class ResearchDependencies():
|
||||
Research.BOMBARDTOWER: [Ages.IMPERIAL,
|
||||
Buildings.UNIVERSITY,
|
||||
Research.CHEMISTRY],
|
||||
}
|
||||
|
||||
|
||||
|
||||
class UnitDependencies():
|
||||
def __init__(self):
|
||||
self.dependencies = {
|
||||
Units.VILLAGER: [Buildings.TOWNCENTER],
|
||||
Units.TRADECART: [Buildings.MARKET],
|
||||
Units.SPEARMAN: [Ages.FEUDAL, Buildings.BARRACKS],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import copy
|
||||
|
||||
from aoe.types import *
|
||||
from aoe.exceptions import *
|
||||
|
||||
|
||||
|
||||
@@ -136,6 +137,76 @@ class Gather():
|
||||
BIG_NUMBER = 1e6
|
||||
|
||||
|
||||
def check_gather(self, world, task, count=1):
|
||||
if task in [Tasks.IDLE, Tasks.BUILD]:
|
||||
return
|
||||
|
||||
required = self.required_gather_buildings[task]
|
||||
have = set(world.buildings)
|
||||
|
||||
match = any(map(have.issuperset, required))
|
||||
|
||||
if not match:
|
||||
raise GatherBuildingNotAvailableException
|
||||
|
||||
if task == task.FARM:
|
||||
if world.villager_tasks[task] + count > len(world.unused_farms):
|
||||
raise GatherBuildingNotAvailableException
|
||||
|
||||
|
||||
def permanently_modify_gather_rate(self, task, rate_multiplier):
|
||||
self.gather_rates[task] *= rate_multiplier
|
||||
self.original_gather_rates[task] *= rate_multiplier
|
||||
|
||||
|
||||
def decrease_gather_rate_by_overuse(self, task):
|
||||
# assumes rate decrease should trigger; does not check
|
||||
new_rate = self.gather_decrease_rates[task]*self.gather_rates[task]
|
||||
self.gather_rates[task] = new_rate
|
||||
|
||||
return new_rate
|
||||
|
||||
|
||||
def improve_gather_rate_by_building(self, building, tasks):
|
||||
if building == Buildings.FARM:
|
||||
raise ValueError('Do not call this routine with a farm')
|
||||
|
||||
if building not in self.buildings_gather_increase.keys():
|
||||
return []
|
||||
|
||||
if not tasks:
|
||||
tasks = self.buildings_gather_increase[building].keys()
|
||||
elif type(tasks) == Tasks:
|
||||
tasks = [tasks]
|
||||
|
||||
for task in tasks:
|
||||
amount = self.buildings_gather_increase[building][task]
|
||||
if self.gather_rates[task] < self.original_gather_rates[task]:
|
||||
self.gather_rates[task] = self.original_gather_rates[task]
|
||||
self.gatherable_amounts[task] = amount
|
||||
else:
|
||||
self.gatherable_amounts[task] += amount
|
||||
|
||||
return tasks
|
||||
|
||||
|
||||
def permanently_modify_consumable_capacity(self, building, task, increase):
|
||||
current_initial_capacity = self.buildings_gather_increase[building]
|
||||
self.buildings_gather_increase[building] += increase
|
||||
|
||||
return increase/current_initial_farm
|
||||
|
||||
|
||||
def compute_gathered_resources_for_duration(self, villager_tasks, duration):
|
||||
all_gathered = [0, 0, 0, 0]
|
||||
for task, count in villager_tasks.items():
|
||||
rate = self.gather_rates[task]
|
||||
gathered = self.gathered_resources[task]
|
||||
for resource, mult in gathered.items():
|
||||
all_gathered[resource] += count*rate*mult*duration
|
||||
return all_gathered
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.gather_rates = {
|
||||
Tasks.BERRIES: 18.6/60,
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from aoe.types import *
|
||||
from aoe.exceptions import *
|
||||
|
||||
|
||||
|
||||
class Housing():
|
||||
|
||||
|
||||
def check_housing(self, world, thing):
|
||||
required = self.required[thing]
|
||||
|
||||
if required > 0:
|
||||
pop_space = world.get_population_space()
|
||||
if world.get_effective_population() > pop_space + required:
|
||||
raise YallGotHousedException
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.space = defaultdict(int, {
|
||||
Buildings.HOUSE: 5,
|
||||
Buildings.TOWNCENTER: 5,
|
||||
})
|
||||
|
||||
self.required = defaultdict(int, {u: 1 for u in Units})
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from aoe.types import *
|
||||
from aoe.exceptions import *
|
||||
|
||||
|
||||
|
||||
class Production():
|
||||
|
||||
|
||||
def check_production(self, world, thing):
|
||||
building = self.building[thing]
|
||||
if world.production_available[building] < 1:
|
||||
raise ProductionBuildingNotAvailableException
|
||||
|
||||
|
||||
# assumes for now each unit can be built in only one type of building
|
||||
def __init__(self):
|
||||
self.building = {
|
||||
self.building = defaultdict(None, {
|
||||
Units.VILLAGER: Buildings.TOWNCENTER,
|
||||
Units.TRADECART: Buildings.MARKET,
|
||||
Units.SPEARMAN: Buildings.BARRACKS,
|
||||
@@ -93,4 +102,4 @@ class Production():
|
||||
Research.LOOM: Buildings.TOWNCENTER,
|
||||
Research.SAPPERS: Buildings.CASTLE,
|
||||
Research.BOMBARDTOWER: Buildings.UNIVERSITY,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -43,28 +43,28 @@ class ResearchEffects():
|
||||
case Research.HANDCART:
|
||||
cls._modify_rates_with_wheelbarrow_line(world, 1.1, 1.11)
|
||||
case Research.DOUBLEBITAXE:
|
||||
world._permanently_modify_gather_rate(Tasks.WOOD, 1.2)
|
||||
world.permanently_modify_gather_rate(Tasks.WOOD, 1.2)
|
||||
case Research.BOWSAW:
|
||||
world._permanently_modify_gather_rate(Tasks.WOOD, 1.2)
|
||||
world.permanently_modify_gather_rate(Tasks.WOOD, 1.2)
|
||||
case Research.TWOMANSAW:
|
||||
world._permanently_modify_gather_rate(Tasks.WOOD, 1.1)
|
||||
world.permanently_modify_gather_rate(Tasks.WOOD, 1.1)
|
||||
case Research.HORSECOLLAR:
|
||||
world._permanently_modify_farm_capacity(75)
|
||||
world.permanently_modify_farm_capacity(75)
|
||||
case Research.HEAVYPLOW:
|
||||
world._permanently_modify_farm_capacity(125)
|
||||
world.permanently_modify_farm_capacity(125)
|
||||
case Research.CROPROTATION:
|
||||
world._permanently_modify_farm_capacity(175)
|
||||
world.permanently_modify_farm_capacity(175)
|
||||
case Research.GOLDMINING:
|
||||
world._permanently_modify_gather_rate(Tasks.GOLD, 1.15)
|
||||
world.permanently_modify_gather_rate(Tasks.GOLD, 1.15)
|
||||
case Research.GOLDSHAFTMINING:
|
||||
world._permanently_modify_gather_rate(Tasks.GOLD, 1.15)
|
||||
world.permanently_modify_gather_rate(Tasks.GOLD, 1.15)
|
||||
case Research.STONEMINING:
|
||||
world._permanently_modify_gather_rate(Tasks.STONE, 1.15)
|
||||
world.permanently_modify_gather_rate(Tasks.STONE, 1.15)
|
||||
case Research.STONESHAFTMINING:
|
||||
world._permanently_modify_gather_rate(Tasks.STONE, 1.15)
|
||||
world.permanently_modify_gather_rate(Tasks.STONE, 1.15)
|
||||
case Research.CARAVAN:
|
||||
world._permanently_modify_gather_rate(Tasks.TRADECART, 1.20)
|
||||
world._permanently_modify_gather_rate(Tasks.TRADECOG, 1.20)
|
||||
world.permanently_modify_gather_rate(Tasks.TRADECART, 1.20)
|
||||
world.permanently_modify_gather_rate(Tasks.TRADECOG, 1.20)
|
||||
#case Research.FISHINGLINES:
|
||||
# probably looks like wheelbarrow
|
||||
#case Research.GILLNETS:
|
||||
@@ -90,6 +90,6 @@ class ResearchEffects():
|
||||
Tasks.GOLD,
|
||||
Tasks.STONE]
|
||||
for task in affected:
|
||||
world._permanently_modify_gather_rate(task, non_farm_rate)
|
||||
world.permanently_modify_gather_rate(task, non_farm_rate)
|
||||
|
||||
world._permanently_modify_gather_rate(Tasks.FARM, farm_rate)
|
||||
world.permanently_modify_gather_rate(Tasks.FARM, farm_rate)
|
||||
|
||||
11
aoe/times.py
11
aoe/times.py
@@ -5,6 +5,12 @@ from aoe.types import *
|
||||
class Times():
|
||||
|
||||
|
||||
def compute_build_time(self, building, num_builders):
|
||||
solo_build_time = self.build_times[building]
|
||||
build_time = 3*solo_build_time/(num_builders + 2)
|
||||
return build_time
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.build_times = {
|
||||
Ages.FEUDAL: 130,
|
||||
@@ -130,8 +136,3 @@ class Times():
|
||||
Units.SKIRMISHER: 22,
|
||||
Units.ARCHER: 35,
|
||||
}
|
||||
|
||||
self.exist_duration = {
|
||||
Buildings.FARM: 0,
|
||||
Buildings.FISHTRAP: 0,
|
||||
}
|
||||
|
||||
353
aoe/world.py
353
aoe/world.py
@@ -54,60 +54,37 @@ class World():
|
||||
# possibly other things
|
||||
# TODO gathering boars and hunting
|
||||
# spend villager time in exchange for adding gatherable resource
|
||||
# TODO food spoilage
|
||||
# TODO use market for buy/sell
|
||||
|
||||
|
||||
MAX_WORLD_TIME = 3*60*60 # 3 hours
|
||||
|
||||
|
||||
def _pay_cost(self, purchase):
|
||||
def add_resources(self, gathered):
|
||||
for i in range(len(self.resources)):
|
||||
if self.resources[i] < self.costs.costs[purchase][i]:
|
||||
self.resources[i] += gathered[i]
|
||||
|
||||
|
||||
def pay_cost(self, thing):
|
||||
spent = self.costs.compute_cost(thing)
|
||||
|
||||
for i in range(len(self.resources)):
|
||||
if self.resources[i] < spent[i]:
|
||||
raise NotEnoughResourcesException
|
||||
|
||||
for i in range(len(self.resources)):
|
||||
self.resources[i] -= self.costs.costs[purchase][i]
|
||||
self.resources[i] -= spent[i]
|
||||
|
||||
|
||||
def _check_research_dependencies(self, research):
|
||||
self._check_dependencies(self.research_deps.dependencies[research])
|
||||
def _remove_event_at_time(self, removed_event, scheduled_time):
|
||||
if not scheduled_time:
|
||||
return
|
||||
|
||||
|
||||
def _check_building_dependencies(self, building):
|
||||
self._check_dependencies(self.building_deps.dependencies[building])
|
||||
|
||||
|
||||
def _check_unit_dependencies(self, unit):
|
||||
self._check_dependencies(self.unit_deps.dependencies[unit])
|
||||
|
||||
|
||||
def _check_dependencies(self, dependencies):
|
||||
for dep in dependencies:
|
||||
if dep not in self.buildings and \
|
||||
dep not in self.research and \
|
||||
not self._is_sufficient_age(dep):
|
||||
raise MissingDependencyException
|
||||
|
||||
|
||||
def _is_sufficient_age(self, age):
|
||||
if type(age) == Ages and self.age >= age:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _check_age_dependencies(self, age):
|
||||
total_buildings = 0
|
||||
for building in self.age_deps.dependencies[age].keys():
|
||||
if self.has_building(building):
|
||||
total_buildings += self.age_deps.dependencies[age][building]
|
||||
if total_buildings < self.age_deps.dependencies_counts[age]:
|
||||
raise MissingDependencyException
|
||||
|
||||
|
||||
def queue_research(self, research):
|
||||
self._check_research_dependencies(research)
|
||||
self._pay_cost(research)
|
||||
|
||||
self._start_research(research)
|
||||
for i, event in enumerate(self.events[scheduled_time]):
|
||||
if event[0] == removed_event:
|
||||
del self.events[scheduled_time][i]
|
||||
break
|
||||
|
||||
|
||||
def _schedule_next_gather_rate_decrease(self, task):
|
||||
@@ -115,14 +92,8 @@ class World():
|
||||
return
|
||||
|
||||
# remove old decrease
|
||||
scheduled_decrease = self.rate_decrease_event_times[task]
|
||||
if scheduled_decrease is not None:
|
||||
decrease_index = None
|
||||
for i, event in enumerate(self.events[scheduled_decrease]):
|
||||
if event[0] == self._decrease_gather_rate:
|
||||
decrease_index = i
|
||||
break
|
||||
del self.events[scheduled_decrease][i]
|
||||
self._remove_event_at_time(self._decrease_gather_rate_by_overuse,
|
||||
self.rate_decrease_event_times[task])
|
||||
|
||||
rate = self.gather.gather_rates[task]
|
||||
|
||||
@@ -148,53 +119,51 @@ class World():
|
||||
if task == Tasks.FARM:
|
||||
self.events[next_decrease].append((self._remove_farm, ()))
|
||||
else:
|
||||
self.events[next_decrease].append((self._decrease_gather_rate,
|
||||
self.events[next_decrease].append((self._decrease_gather_rate_by_overuse,
|
||||
(task,)))
|
||||
|
||||
|
||||
def _decrease_gather_rate(self, task):
|
||||
# assumes rate decrease should trigger; does not check
|
||||
new_rate = self.gather_decrease_rates[task]*self.gather_rates[task]
|
||||
self.gather_rates[task] = new_rate
|
||||
def _decrease_gather_rate_by_overuse(self, task):
|
||||
new_rate = self.gather.decrease_gather_rate_by_overuse(task)
|
||||
|
||||
if new_rate > 0:
|
||||
self._schedule_next_gather_rate_decrease(task)
|
||||
else:
|
||||
self.assign_villager(task, task.IDLE, self.villager_tasks[task])
|
||||
self.assign_villager(task, Tasks.IDLE, self.villager_tasks[task])
|
||||
|
||||
|
||||
def _improve_gather_rate(self, building, tasks):
|
||||
if building == Buildings.FARM:
|
||||
raise ValueError('Do not call this routine with a farm')
|
||||
|
||||
if tasks is None:
|
||||
tasks = self.gather.buildings_gather_increase[building].keys()
|
||||
|
||||
for task in tasks:
|
||||
amount = self.gather.buildings_gather_increase[building][task]
|
||||
if self.gather.gather_rates[task] < self.gather.original_gather_rates[task]:
|
||||
self.gather.gather_rates[task] = self.gather.original_gather_rates[task]
|
||||
self.gather.gatherable_amounts[task] = amount
|
||||
else:
|
||||
self.gather.gatherable_amounts[task] += amount
|
||||
def _improve_gather_rate_by_building(self, building, tasks):
|
||||
tasks_improved = self.gather.improve_gather_rate_by_building(building,
|
||||
tasks)
|
||||
for task in tasks_improved:
|
||||
self._schedule_next_gather_rate_decrease(task)
|
||||
|
||||
|
||||
def _permanently_modify_farm_capacity(self, increase):
|
||||
current_initial_farm = self.gather.buildings_gather_increase[Buildings.FARM]
|
||||
for i in range(len(farms)):
|
||||
farms[i] += (farms[i]/current_initial_farm)*increase
|
||||
for i in range(len(unused_farms)):
|
||||
unused_farms[i] += (unused_farms[i]/current_initial_farm)*increase
|
||||
|
||||
self.gather.buildings_gather_increase[Buildings.FARM] += increase
|
||||
|
||||
self._schedule_next_gather_rate_decrease(Task.FARM)
|
||||
def permanently_modify_gather_rate(self, task, multiplier):
|
||||
self.gather.permanently_modify_gather_rate(task, multiplier)
|
||||
self._schedule_next_gather_rate_decrease(task)
|
||||
|
||||
|
||||
def _permanently_modify_gather_rate(self, task, rate_multiplier):
|
||||
self.gather.gather_rates[tasks] *= rate_multiplier
|
||||
self.gather.original_gather_rates[tasks] *= rate_multiplier
|
||||
def permanently_modify_farm_capacity(self, increase):
|
||||
self._permanently_modify_consumable_capacity(Buildings.FARM,
|
||||
Tasks.FARM,
|
||||
increase)
|
||||
|
||||
|
||||
def _permanently_modify_consumable_capacity(self, building, task, increase):
|
||||
multiplier = self.gather.permanently_modify_consumable_capacity(building,
|
||||
task,
|
||||
increase)
|
||||
|
||||
if building == Buildings.FARM:
|
||||
used = self.farms
|
||||
unused = self.unused_farms
|
||||
|
||||
for i in range(len(used)):
|
||||
used[i] += used[i]*multiplier
|
||||
for i in range(len(unused)):
|
||||
unused[i] += unused[i]*multiplier
|
||||
|
||||
self._schedule_next_gather_rate_decrease(task)
|
||||
|
||||
|
||||
@@ -207,7 +176,7 @@ class World():
|
||||
raise IllegalVillagerMoveException
|
||||
|
||||
if new_task:
|
||||
self._check_gather(new_task, count)
|
||||
self.gather.check_gather(self, new_task, count)
|
||||
self.villager_tasks[new_task] += count
|
||||
else:
|
||||
self.villagers -= 1
|
||||
@@ -254,16 +223,16 @@ class World():
|
||||
villagers_from_count = Counter(villagers_from)
|
||||
|
||||
self._check_villager_move(villagers_from_count)
|
||||
self._check_building_dependencies(building)
|
||||
|
||||
self._pay_cost(building)
|
||||
self.dependencies.check_dependencies(self, building)
|
||||
|
||||
self.pay_cost(building)
|
||||
self._move_villagers_to_build(villagers_from_count)
|
||||
|
||||
villagers_to_count = Counter(villagers_to)
|
||||
|
||||
num_villagers_building = len(villagers_from)
|
||||
solo_build_time = self.build_times.build_times[building]
|
||||
build_time = 3*solo_build_time/(num_villagers_building + 2)
|
||||
num_builders = len(villagers_from)
|
||||
build_time = self.build_times.compute_build_time(building, num_builders)
|
||||
update_time = self.current_time + build_time
|
||||
|
||||
self.events[update_time].append((self._add_building,
|
||||
@@ -281,8 +250,8 @@ class World():
|
||||
|
||||
if building == Buildings.FARM:
|
||||
self._add_farm()
|
||||
elif building in self.gather.buildings_gather_increase.keys():
|
||||
self._improve_gather_rate(building, tasks_improved)
|
||||
else:
|
||||
self._improve_gather_rate_by_building(building, tasks_improved)
|
||||
|
||||
for task, count in villagers_to.items():
|
||||
self.assign_villager(Tasks.BUILD, task, count)
|
||||
@@ -320,7 +289,12 @@ class World():
|
||||
|
||||
|
||||
def _run_clock_without_events(self, end_time):
|
||||
self._gather_resources_for_duration(end_time - self.current_time)
|
||||
duration = end_time - self.current_time
|
||||
|
||||
gathered = self.gather.compute_gathered_resources_for_duration(self.villager_tasks,
|
||||
duration)
|
||||
self.add_resources(gathered)
|
||||
|
||||
self.current_time = end_time
|
||||
|
||||
|
||||
@@ -331,135 +305,72 @@ class World():
|
||||
self._handle_events()
|
||||
|
||||
|
||||
def _get_population_space(self):
|
||||
def get_population_space(self):
|
||||
space = sum([self.housing.space[building] for building in self.buildings])
|
||||
return min(space, 200)
|
||||
|
||||
|
||||
def _get_effective_population(self):
|
||||
def get_effective_population(self):
|
||||
return self.population + self.units_being_built
|
||||
|
||||
|
||||
def _free_housing(self):
|
||||
pop_space = self._get_population_space()
|
||||
original_queue_len = len(self.production_queue)
|
||||
pop_space = self.get_population_space()
|
||||
|
||||
# Assumes each unit costs 1 pop
|
||||
new_builds = []
|
||||
i = 0
|
||||
while (self._get_effective_population() < pop_space and
|
||||
i < original_queue_len):
|
||||
|
||||
unit = self.production_queue[i]
|
||||
if self._check_production(unit):
|
||||
if unit in Units:
|
||||
self._build_unit(unit)
|
||||
elif unit in Research:
|
||||
self._start_research(unit)
|
||||
new_builds.append(i)
|
||||
while (self.get_effective_population() < pop_space and
|
||||
i < len(self.production_queue)):
|
||||
|
||||
thing = self.production_queue[i]
|
||||
if self.housing.check_housing(self, thing) and \
|
||||
self.production.check_production(self, thing):
|
||||
self._start_producing(thing)
|
||||
del self.production_queue[i]
|
||||
else:
|
||||
i += 1
|
||||
|
||||
self.production_queue = [self.production_queue[i]
|
||||
for i in range(original_queue_len)
|
||||
if i not in new_builds]
|
||||
|
||||
|
||||
def _free_production_building_of_unit(self, unit):
|
||||
building = self.production.building[unit]
|
||||
def _free_production_building_of_thing(self, thing):
|
||||
building = self.production.building[thing]
|
||||
self._free_production_building(building)
|
||||
|
||||
|
||||
def _free_production_building(self, building):
|
||||
# This will not respect the order of a queue in a particular building.
|
||||
# For example, if there is a TC with the queue [villager, loom] and
|
||||
# there is no available housing, the TC will research loom. In the
|
||||
# actual game, the villager would block the researching of loom.
|
||||
# There is no easy way around this as long as we are treating the
|
||||
# production queue as a shared pool, and I don't really care.
|
||||
self.production_available[building] += 1
|
||||
|
||||
# Start the next queued unit if one exists
|
||||
ready_index = None
|
||||
ready_unit = None
|
||||
for i in range(len(self.production_queue)):
|
||||
unit = self.production_queue[i]
|
||||
if self.production.building[unit] == building:
|
||||
ready_index = i
|
||||
ready_unit = unit
|
||||
i = 0
|
||||
while i < len(self.production_queue):
|
||||
thing = self.production_queue[i]
|
||||
if self.production.building[thing] == building and \
|
||||
self.housing.check_housing(self, thing):
|
||||
self._start_producing(thing)
|
||||
del self.production_queue[i]
|
||||
break
|
||||
|
||||
if ready_index:
|
||||
self.production_queue.remove(i)
|
||||
if unit in Units:
|
||||
self._build_unit(unit)
|
||||
elif unit in Research:
|
||||
self._start_research(unit)
|
||||
i += 1
|
||||
|
||||
|
||||
def _check_housing(self, unit):
|
||||
# assumes for now that all units cost 1 pop
|
||||
pop_space = sum([self.housing.space[building] for building in self.buildings])
|
||||
if self._get_effective_population() >= pop_space:
|
||||
raise YallGotHousedException
|
||||
def _use_housing_and_production(self, thing):
|
||||
self.housing.check_housing(self, thing)
|
||||
self.production.check_production(self, thing)
|
||||
|
||||
|
||||
def _check_gather(self, task, count=1):
|
||||
if task in [Tasks.IDLE, Tasks.BUILD]:
|
||||
return
|
||||
|
||||
required = self.gather.required_gather_buildings[task]
|
||||
have = set(self.buildings)
|
||||
|
||||
match = any(map(have.issuperset, required))
|
||||
|
||||
if not match:
|
||||
raise GatherBuildingNotAvailableException
|
||||
|
||||
if task == task.FARM:
|
||||
if self.villager_tasks[task] + count > len(self.unused_farms):
|
||||
raise GatherBuildingNotAvailableException
|
||||
|
||||
|
||||
def _check_production(self, unit):
|
||||
building = self.production.building[unit]
|
||||
if self.production_available[building] < 1:
|
||||
raise ProductionBuildingNotAvailableException
|
||||
|
||||
|
||||
def _use_production_for_research(self, research):
|
||||
self._check_production(research)
|
||||
|
||||
building = self.production.building[research]
|
||||
building = self.production.building[thing]
|
||||
if building is not None:
|
||||
self.production_available[building] -= 1
|
||||
|
||||
|
||||
def _add_research(self, research):
|
||||
self.research.append(research)
|
||||
ResearchEffects.complete_research(self, research)
|
||||
self._free_production_building_of_unit(research)
|
||||
|
||||
|
||||
def _start_research(self, research):
|
||||
try:
|
||||
self._use_production_for_research(research)
|
||||
except ProductionBuildingNotAvailableException:
|
||||
self.production_queue.append(research)
|
||||
else:
|
||||
update_time = self.current_time + self.build_times.build_times[research]
|
||||
self.events[update_time].append((self._add_research, (research,)))
|
||||
|
||||
|
||||
def _use_housing_and_production(self, unit):
|
||||
self._check_housing(unit)
|
||||
self._check_production(unit)
|
||||
|
||||
building = self.production.building[unit]
|
||||
|
||||
self.production_available[building] -= 1
|
||||
self.units_being_built += 1
|
||||
self.units_being_built += self.housing.required[thing]
|
||||
|
||||
|
||||
def _kill_unit(self, unit, task=None):
|
||||
if unit == Units.VILLAGER and not task:
|
||||
raise IllegalVillagerMoveException
|
||||
|
||||
# assumes population of 1 for every unit
|
||||
self.population -= 1
|
||||
self.population -= self.housing.required(unit)
|
||||
|
||||
if unit == Units.VILLAGER:
|
||||
self.assign_villager(task, None)
|
||||
@@ -467,47 +378,50 @@ class World():
|
||||
self._free_housing()
|
||||
|
||||
|
||||
def _add_unit(self, unit, initial_task):
|
||||
# assumes population of 1 for every unit
|
||||
self.units_being_built -= 1
|
||||
self.population += 1
|
||||
self._free_production_building_of_unit(unit)
|
||||
def _add_thing(self, thing, initial_task):
|
||||
self.units_being_built -= self.housing.required[thing]
|
||||
self.population += self.housing.required[thing]
|
||||
|
||||
if unit == Units.VILLAGER:
|
||||
if thing in Research:
|
||||
self.research.append(thing)
|
||||
ResearchEffects.complete_research(self, thing)
|
||||
|
||||
self._free_production_building_of_thing(thing)
|
||||
|
||||
if thing == Units.VILLAGER:
|
||||
self.villagers += 1
|
||||
self.villager_tasks[Tasks.IDLE] += 1
|
||||
self.assign_villager(Tasks.IDLE, initial_task)
|
||||
|
||||
|
||||
def _build_unit(self, unit, initial_task):
|
||||
def _start_producing(self, thing, initial_task):
|
||||
try:
|
||||
self._use_housing_and_production(unit)
|
||||
self._use_housing_and_production(thing)
|
||||
except ProductionBuildingNotAvailableException:
|
||||
self.production_queue.append(unit)
|
||||
except YallGotHousedException:
|
||||
pass
|
||||
self.production_queue.append(thing)
|
||||
else:
|
||||
update_time = self.current_time + self.build_times.build_times[unit]
|
||||
self.events[update_time].append((self._add_unit, (unit, initial_task,)))
|
||||
update_time = self.current_time + self.build_times.build_times[thing]
|
||||
self.events[update_time].append((self._add_thing, (thing, initial_task,)))
|
||||
|
||||
|
||||
def queue_unit(self, unit, initial_task=None):
|
||||
self._check_unit_dependencies(unit)
|
||||
self._pay_cost(unit)
|
||||
def _queue_thing(self, thing, initial_task=None):
|
||||
self.dependencies.check_dependencies(self, thing)
|
||||
self.costs.compute_cost(thing)
|
||||
self.pay_cost(thing)
|
||||
|
||||
self._build_unit(unit, initial_task)
|
||||
self._start_producing(thing, initial_task)
|
||||
|
||||
|
||||
def queue_research(self, research):
|
||||
self._queue_thing(research)
|
||||
|
||||
|
||||
def queue_unit(self, unit):
|
||||
self._queue_thing(unit)
|
||||
|
||||
|
||||
def queue_villager(self, initial_task):
|
||||
self.queue_unit(Units.VILLAGER, initial_task)
|
||||
|
||||
|
||||
def _gather_resources_for_duration(self, duration):
|
||||
for task, count in self.villager_tasks.items():
|
||||
rate = self.gather.gather_rates[task]
|
||||
gathered = self.gather.gathered_resources[task]
|
||||
for resource, mult in gathered.items():
|
||||
self.resources[resource] += count*rate*mult*duration
|
||||
self._queue_thing(Units.VILLAGER, initial_task)
|
||||
|
||||
|
||||
def _handle_events(self):
|
||||
@@ -526,8 +440,8 @@ class World():
|
||||
|
||||
new_age = self.age + 1
|
||||
|
||||
self._check_age_dependencies(new_age)
|
||||
self._pay_cost(new_age)
|
||||
self.dependencies.check_dependencies(new_age)
|
||||
self.pay_cost(new_age)
|
||||
|
||||
update_time = self.current_time + self.build_times.build_times[new_age]
|
||||
self.events[update_time].append((self._update_age, (new_age,)))
|
||||
@@ -564,10 +478,7 @@ class World():
|
||||
|
||||
self.build_times = Times()
|
||||
self.costs = Costs()
|
||||
self.building_deps = BuildingDependencies()
|
||||
self.age_deps = AgeDependencies()
|
||||
self.research_deps = ResearchDependencies()
|
||||
self.unit_deps = UnitDependencies()
|
||||
self.dependencies = Dependencies()
|
||||
self.housing = Housing()
|
||||
self.production = Production()
|
||||
self.gather = Gather()
|
||||
|
||||
Reference in New Issue
Block a user