Package horizons :: Package ai :: Package aiplayer :: Package mission :: Module foundsettlement
[hide private]
[frames] | no frames]

Source Code for Module horizons.ai.aiplayer.mission.foundsettlement

  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  from horizons.ai.aiplayer.basicbuilder import BasicBuilder 
 23  from horizons.ai.aiplayer.mission import ShipMission 
 24  from horizons.constants import BUILDINGS 
 25  from horizons.entities import Entities 
 26  from horizons.ext.enum import Enum 
 27  from horizons.util.python.callback import Callback 
 28  from horizons.util.shapes import Circle, Point 
 29  from horizons.util.worldobject import WorldObject 
30 31 32 -class FoundSettlement(ShipMission):
33 """ 34 Given a ship with the required resources and the coordinates of the future warehouse 35 the ship is taken near the end location and a warehouse is built. 36 """ 37 38 missionStates = Enum('created', 'moving') 39
40 - def __init__(self, success_callback, failure_callback, land_manager, ship, coords):
41 super().__init__(success_callback, failure_callback, ship) 42 self.land_manager = land_manager 43 self.coords = coords 44 self.warehouse = None 45 self.state = self.missionStates.created
46
47 - def save(self, db):
48 super().save(db) 49 db("INSERT INTO ai_mission_found_settlement(rowid, land_manager, ship, x, y, state) VALUES(?, ?, ?, ?, ?, ?)", 50 self.worldid, self.land_manager.worldid, self.ship.worldid, self.coords[0], self.coords[1], self.state.index)
51 52 @classmethod
53 - def load(cls, db, worldid, success_callback, failure_callback):
54 self = cls.__new__(cls) 55 self._load(db, worldid, success_callback, failure_callback) 56 return self
57
58 - def _load(self, db, worldid, success_callback, failure_callback):
59 db_result = db("SELECT land_manager, ship, x, y, state FROM ai_mission_found_settlement WHERE rowid = ?", worldid)[0] 60 self.land_manager = WorldObject.get_object_by_id(db_result[0]) 61 self.coords = (int(db_result[2]), int(db_result[3])) 62 self.warehouse = None 63 self.state = self.missionStates[db_result[4]] 64 super().load(db, worldid, success_callback, failure_callback, WorldObject.get_object_by_id(db_result[1])) 65 66 if self.state == self.missionStates.moving: 67 self.ship.add_move_callback(Callback(self._reached_destination_area)) 68 self.ship.add_blocked_callback(Callback(self._move_to_destination_area)) 69 else: 70 assert False, 'invalid state'
71
72 - def start(self):
73 self.state = self.missionStates.moving 74 self._move_to_destination_area()
75
77 if self.coords is None: 78 self.report_failure('No possible warehouse location') 79 return 80 81 self._move_to_warehouse_area( 82 Point(*self.coords), Callback(self._reached_destination_area), 83 Callback(self._move_to_destination_area), 'Move not possible')
84
86 self.log.info('%s reached BO area', self) 87 88 builder = BasicBuilder(BUILDINGS.WAREHOUSE, self.coords, 0) 89 if not builder.have_resources(self.land_manager, ship=self.ship): 90 self.report_failure('Not enough resources for a warehouse at {}'.format(str(self.coords))) 91 return 92 93 self.warehouse = builder.execute(self.land_manager, ship=self.ship) 94 assert self.warehouse 95 96 self.land_manager.settlement = self.warehouse.settlement 97 self.log.info('%s built the warehouse', self) 98 99 self._unload_all_resources(self.land_manager.settlement) 100 self.report_success('Built the warehouse, transferred resources')
101 102 @classmethod
103 - def find_warehouse_location(cls, ship, land_manager):
104 """Return the coordinates of a location for the warehouse on the given island.""" 105 warehouse_class = Entities.buildings[BUILDINGS.WAREHOUSE] 106 pos_offsets = [] 107 for dx in range(warehouse_class.width): 108 for dy in range(warehouse_class.height): 109 pos_offsets.append((dx, dy)) 110 111 island = land_manager.island 112 personality = land_manager.owner.personality_manager.get('FoundSettlement') 113 114 available_spots_list = list(sorted(island.terrain_cache.cache[warehouse_class.terrain_type][warehouse_class.size].intersection(island.available_land_cache.cache[warehouse_class.size]))) 115 available_spots_list = [x for x in available_spots_list 116 if warehouse_class.check_build(land_manager.session, Point(*x), check_settlement=False)] 117 if not available_spots_list: 118 return None 119 120 options = [] 121 limited_spots = island.session.random.sample(available_spots_list, min(len(available_spots_list), personality.max_options)) 122 for (x, y) in limited_spots: 123 cost = 0 124 for (x2, y2) in land_manager.village: 125 dx = x2 - x 126 dy = y2 - y 127 distance = (dx * dx + dy * dy) ** 0.5 128 if distance < personality.too_close_penalty_threshold: 129 cost += personality.too_close_constant_penalty + personality.too_close_linear_penalty / (distance + 1.0) 130 else: 131 cost += distance 132 133 for settlement_manager in land_manager.owner.settlement_managers: 134 cost += settlement_manager.settlement.warehouse.position.distance((x, y)) * personality.linear_warehouse_penalty 135 options.append((cost, x, y)) 136 137 for _, x, y in sorted(options): 138 if ship.check_move(Circle(Point(x + warehouse_class.width // 2, y + warehouse_class.height // 2), BUILDINGS.BUILD.MAX_BUILDING_SHIP_DISTANCE)): 139 return (x, y) 140 return None
141 142 @classmethod
143 - def create(cls, ship, land_manager, success_callback, failure_callback):
144 coords = cls.find_warehouse_location(ship, land_manager) 145 return FoundSettlement(success_callback, failure_callback, land_manager, ship, coords)
146