diff --git a/aoe/costs.py b/aoe/costs.py index e3dedf8..106d185 100644 --- a/aoe/costs.py +++ b/aoe/costs.py @@ -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), diff --git a/aoe/gather.py b/aoe/gather.py index 0556977..a5dde06 100644 --- a/aoe/gather.py +++ b/aoe/gather.py @@ -154,6 +154,59 @@ class Gather(): 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, diff --git a/aoe/research.py b/aoe/research.py index dfdc45a..3c8a912 100644 --- a/aoe/research.py +++ b/aoe/research.py @@ -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) diff --git a/aoe/world.py b/aoe/world.py index d0ee4ca..6c2ea42 100644 --- a/aoe/world.py +++ b/aoe/world.py @@ -61,12 +61,30 @@ class World(): 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 _remove_event_at_time(self, removed_event, scheduled_time): + if not scheduled_time: + return + + 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): @@ -74,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] @@ -107,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) @@ -216,7 +226,7 @@ class World(): self.dependencies.check_dependencies(self, building) - self._pay_cost(building) + self.pay_cost(building) self._move_villagers_to_build(villagers_from_count) villagers_to_count = Counter(villagers_to) @@ -241,8 +251,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) @@ -280,7 +290,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 @@ -322,21 +337,23 @@ class World(): 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 thing if one exists - ready_index = None - ready_thing = None - for i in range(len(self.production_queue)): + i = 0 + while i < len(self.production_queue): thing = self.production_queue[i] - if self.production.building[thing] == building: - ready_index = i - ready_thing = thing + 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) - self._start_producing(thing) + i += 1 def _use_housing_and_production(self, thing): @@ -390,7 +407,8 @@ class World(): def _queue_thing(self, thing, initial_task=None): self.dependencies.check_dependencies(self, thing) - self._pay_cost(thing) + self.costs.compute_cost(thing) + self.pay_cost(thing) self._start_producing(thing, initial_task) @@ -407,14 +425,6 @@ class World(): self._queue_thing(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 - - def _handle_events(self): for func, args in self.events[self.current_time]: func(*args) @@ -431,8 +441,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,)))