Package horizons :: Package world :: Module playerstats
[hide private]
[frames] | no frames]

Source Code for Module horizons.world.playerstats

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22  import math 
 23  from collections import defaultdict 
 24   
 25  from horizons.component.collectingcomponent import CollectingComponent 
 26  from horizons.component.selectablecomponent import SelectableComponent 
 27  from horizons.component.storagecomponent import StorageComponent 
 28  from horizons.constants import BUILDINGS, PRODUCTION, RES, TIER, UNITS 
 29  from horizons.entities import Entities 
 30  from horizons.scheduler import Scheduler 
 31  from horizons.util.worldobject import WorldObject 
 32  from horizons.world.production.producer import Producer 
 33   
 34   
35 -class PlayerStats(WorldObject):
36 - def __init__(self, player):
37 super().__init__() 38 self.player = player 39 self.db = player.session.db 40 self._collect_info() 41 self.collection_tick = Scheduler().cur_tick
42
43 - def _collect_info(self):
44 settlers = defaultdict(int) 45 settler_buildings = defaultdict(int) 46 settler_resources_provided = defaultdict(int) 47 buildings = defaultdict(int) 48 available_resources = defaultdict(int) 49 total_resources = defaultdict(int) 50 ships = defaultdict(int) 51 running_costs = 0 52 taxes = 0 53 usable_land = 0 54 settlements = 0 55 56 for settlement in self.player.settlements: 57 for building in settlement.buildings: 58 buildings[building.id] += 1 59 60 # collect info about settlers 61 if building.id == BUILDINGS.RESIDENTIAL: 62 settlers[building.level] += building.inhabitants 63 settler_buildings[building.level] += 1 64 for production in building.get_component(Producer).get_productions(): 65 if production.get_state() is PRODUCTION.STATES.producing: 66 produced_resources = production.get_produced_resources() 67 if RES.HAPPINESS in produced_resources: 68 happiness = produced_resources[RES.HAPPINESS] 69 for resource_id in production.get_consumed_resources(): 70 settler_resources_provided[resource_id] += happiness / production.get_production_time() 71 72 # resources held in buildings 73 if building.has_component(StorageComponent) and building.id not in [BUILDINGS.WAREHOUSE, BUILDINGS.STORAGE, BUILDINGS.MAIN_SQUARE]: 74 for resource_id, amount in building.get_component(StorageComponent).inventory.itercontents(): 75 total_resources[resource_id] += amount 76 77 # resources held by collectors 78 if building.has_component(CollectingComponent): 79 for collector in building.get_component(CollectingComponent).get_local_collectors(): 80 for resource_id, amount in collector.get_component(StorageComponent).inventory.itercontents(): 81 total_resources[resource_id] += amount 82 83 # resources in settlement inventories 84 for resource_id, amount in settlement.get_component(StorageComponent).inventory.itercontents(): 85 available_resources[resource_id] += amount 86 87 # land that could be built on (the building on it may need to be destroyed first) 88 for tile in settlement.ground_map.values(): 89 if 'constructible' in tile.classes: 90 usable_land += 1 91 92 settlements += 1 93 running_costs += settlement.cumulative_running_costs 94 taxes += settlement.cumulative_taxes 95 96 # resources in player controlled ships 97 for ship in self.player.session.world.ships: 98 if ship.owner is self.player: 99 ships[ship.id] += 1 100 if ship.has_component(SelectableComponent): 101 for resource_id, amount in ship.get_component(StorageComponent).inventory.itercontents(): 102 available_resources[resource_id] += amount 103 104 for resource_id, amount in available_resources.items(): 105 total_resources[resource_id] += amount 106 107 self._calculate_settler_score(settlers, settler_buildings, settler_resources_provided) 108 self._calculate_building_score(buildings) 109 self._calculate_resource_score(available_resources, total_resources) 110 self._calculate_unit_score(ships) 111 self._calculate_land_score(usable_land, settlements) 112 self._calculate_money_score(running_costs, taxes, self.player.get_component(StorageComponent).inventory[RES.GOLD]) 113 self._calculate_total_score()
114 115 settler_values = { 116 TIER.SAILORS: 2, 117 TIER.PIONEERS: 3, 118 TIER.SETTLERS: 7, 119 TIER.CITIZENS: 15, 120 TIER.MERCHANTS: 20, 121 } 122 settler_building_values = { 123 TIER.SAILORS: 3, 124 TIER.PIONEERS: 5, 125 TIER.SETTLERS: 11, 126 TIER.CITIZENS: 19, 127 TIER.MERCHANTS: 25, 128 } 129 settler_resource_provided_coefficient = 0.1 130 settler_score_coefficient = 0.3 131
132 - def _calculate_settler_score(self, settlers, settler_buildings, settler_resources_provided):
133 total = 0 134 for level, number in settlers.items(): 135 total += self.settler_values[level] * number 136 for level, number in settler_buildings.items(): 137 total += self.settler_building_values[level] * number 138 for amount in settler_resources_provided.values(): 139 total += amount * self.settler_resource_provided_coefficient 140 self.settler_score = int(total * self.settler_score_coefficient)
141 142 building_score_coefficient = 0.006 143
144 - def _calculate_building_score(self, buildings):
145 total = 0 146 resources = defaultdict(int) 147 for building_id, amount in buildings.items(): 148 for resource_id, res_amount in Entities.buildings[building_id].costs.items(): 149 resources[resource_id] += amount * res_amount 150 for resource_id, amount in resources.items(): 151 if resource_id == RES.GOLD: 152 total += amount # for some reason the value of gold is 0 by default 153 else: 154 total += amount * self.db.get_res_value(resource_id) 155 self.building_score = int(total * self.building_score_coefficient)
156 157 unavailable_resource_coefficient = 0.3 # the resource exists but isn't usable so it is worth less 158 overridden_resource_values = {RES.RAW_CLAY: 1, RES.RAW_IRON: 3} 159 resource_score_coefficient = 0.01 160
161 - def _calculate_resource_score(self, available_resources, total_resources):
162 total = 0 163 for resource_id, amount in available_resources.items(): 164 if resource_id in self.overridden_resource_values: # natural resources have 0 value by default 165 total += amount * self.overridden_resource_values[resource_id] 166 else: 167 value = self.db.get_res_value(resource_id) 168 if value is not None: # happiness and some coverage resources have no value 169 total += amount * value 170 for resource_id, amount in total_resources.items(): 171 extra_amount = (amount - available_resources[resource_id]) 172 if resource_id in self.overridden_resource_values: # natural resources have 0 value by default 173 total += extra_amount * self.overridden_resource_values[resource_id] * self.unavailable_resource_coefficient 174 else: 175 value = self.db.get_res_value(resource_id) 176 if value is not None: # happiness and some coverage resources have no value 177 total += extra_amount * value * self.unavailable_resource_coefficient 178 self.resource_score = int(total * self.resource_score_coefficient)
179 180 unit_value = {UNITS.FRIGATE: 1.5, UNITS.PLAYER_SHIP: 1, UNITS.USABLE_FISHER_BOAT: 1, UNITS.FISHER_BOAT: 0.05} 181 unit_score_coefficient = 10 182
183 - def _calculate_unit_score(self, ships):
184 total = 0 185 for unit_id, amount in ships.items(): 186 total += self.unit_value[unit_id] * amount 187 self.unit_score = int(total * self.unit_score_coefficient)
188 189 settlement_value = 30 190 land_score_coefficient = 0.03 191
192 - def _calculate_land_score(self, usable_land, settlements):
193 total = 0 194 total += usable_land 195 total += self.settlement_value * settlements 196 self.land_score = int(total * self.land_score_coefficient)
197 198 running_cost_coefficient = 10 199 minimum_money = 500 200 money_power = 0.4 201 money_score_coefficient = 1.3 202
203 - def _calculate_money_score(self, running_costs, taxes, money):
204 total = 0 205 total += money 206 total += self.running_cost_coefficient * (taxes - running_costs) 207 total = math.pow(max(self.minimum_money, total), self.money_power) 208 self.money_score = int(total * self.money_score_coefficient)
209
210 - def _calculate_total_score(self):
211 self.total_score = self.settler_score + self.building_score + self.resource_score + self.unit_score + self.land_score + self.money_score
212