| Total Complexity | 375 |
| Total Lines | 1371 |
| Duplicated Lines | 1.17 % |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like ige.ospace.IPlayer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # |
||
| 2 | # Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/] |
||
| 3 | # |
||
| 4 | # This file is part of Outer Space. |
||
| 5 | # |
||
| 6 | # Outer Space 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 | # Outer Space 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 Outer Space; if not, write to the Free Software |
||
| 18 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||
| 19 | # |
||
| 20 | |||
| 21 | import math |
||
| 22 | import re |
||
| 23 | import time |
||
| 24 | |||
| 25 | import ige |
||
| 26 | import Rules |
||
| 27 | import Utils |
||
| 28 | import ShipUtils |
||
| 29 | |||
| 30 | from ige import log |
||
| 31 | from ige.IObject import IObject, public |
||
| 32 | from ige.IDataHolder import IDataHolder |
||
| 33 | import Const |
||
| 34 | |||
| 35 | class IPlayer(IObject): |
||
| 36 | |||
| 37 | typeID = Const.T_PLAYER |
||
| 38 | resignTo = Const.T_AIPLAYER |
||
| 39 | forums = {"INBOX": 56, "OUTBOX": 56, "EVENTS": 4} |
||
| 40 | |||
| 41 | def init(self, obj): |
||
| 42 | IObject.init(self, obj) |
||
| 43 | # |
||
| 44 | obj.login = u'' |
||
| 45 | obj.name = u'' |
||
| 46 | obj.fullName = u'' |
||
| 47 | # |
||
| 48 | obj.buoys = {} |
||
| 49 | obj.alliedBuoys = {} |
||
| 50 | obj.planets = [] |
||
| 51 | obj.fleets = [] |
||
| 52 | obj.techs = {} # techs and their sublevel |
||
| 53 | obj.obsoleteTechs = set() |
||
| 54 | obj.rsrchQueue = [] |
||
| 55 | obj.sciPoints = 0 |
||
| 56 | obj.effSciPoints = 0 |
||
| 57 | obj.techLevel = 1 |
||
| 58 | obj.shipDesigns = {} |
||
| 59 | obj.race = "H" # race Bionic, Human, Cyborg |
||
| 60 | # bonuses |
||
| 61 | obj.prodEff = 1.0 |
||
| 62 | obj.sciEff = 1.0 |
||
| 63 | # |
||
| 64 | obj.govPwr = 0 |
||
| 65 | obj.govPwrCtrlRange = 1 |
||
| 66 | # fleet support |
||
| 67 | obj.fleetUpgradePool = 0.0 |
||
| 68 | obj.fleetUpgradeInProgress = 0 |
||
| 69 | # production |
||
| 70 | obj.prodQueues = [[],[],[],[],[]] |
||
| 71 | obj.prodIncreasePool = 0.0 |
||
| 72 | # diplomacy |
||
| 73 | obj.diplomacyRels = {} |
||
| 74 | obj.defaultRelation = Rules.defaultRelation |
||
| 75 | obj.voteFor = Const.OID_NONE |
||
| 76 | obj.governorOf = Const.OID_NONE |
||
| 77 | obj.governors = [] |
||
| 78 | obj.alliance = Const.OID_NONE |
||
| 79 | obj.imperator = 0 |
||
| 80 | # combat |
||
| 81 | # anti-small, anti-medium, anti-large, shield generator |
||
| 82 | obj.planetWeapons = [None, None, None, None, None] |
||
| 83 | # |
||
| 84 | obj.staticMap = {} |
||
| 85 | obj.dynamicMap = {} |
||
| 86 | obj.galaxy = None |
||
| 87 | obj.validSystems = [] |
||
| 88 | # |
||
| 89 | obj.stats = IDataHolder() |
||
| 90 | obj.stats.type = Const.T_STATS |
||
| 91 | obj.timeEnabled = 0 |
||
| 92 | obj.stratRes = {} |
||
| 93 | obj.lastLogin = 0.0 |
||
| 94 | # |
||
| 95 | obj.shipRedirections = {} |
||
| 96 | obj.buoys = {} |
||
| 97 | # |
||
| 98 | obj.clientStats = {} |
||
| 99 | |||
| 100 | def update(self, tran, obj): |
||
| 101 | # TODO: remove after 0.5.73 |
||
| 102 | if hasattr(obj, 'galaxies'): |
||
| 103 | try: |
||
| 104 | obj.galaxy = obj.galaxies[0] |
||
| 105 | except IndexError: |
||
| 106 | obj.galaxy = None |
||
| 107 | # update all designs |
||
| 108 | for designID in obj.shipDesigns: |
||
| 109 | old = obj.shipDesigns[designID] |
||
| 110 | new = ShipUtils.makeShipMinSpec(obj, old.name, old.hullID, |
||
| 111 | old.eqIDs, old.improvements, raiseExs = False) |
||
| 112 | new.built = old.built |
||
| 113 | if hasattr(old, "upgradeTo"): |
||
| 114 | new.upgradeTo = old.upgradeTo |
||
| 115 | obj.shipDesigns[designID] = new |
||
| 116 | # check all diplomacyRels |
||
| 117 | for partyID in obj.diplomacyRels.keys(): |
||
| 118 | party = tran.db.get(partyID, None) |
||
| 119 | if not party or party.type not in Const.PLAYER_TYPES: |
||
| 120 | log.debug("Deleting party", obj.oid, partyID) |
||
| 121 | del obj.diplomacyRels[partyID] |
||
| 122 | # delete obj with low scan pwr |
||
| 123 | # check type of the objects in the map |
||
| 124 | for objID in obj.staticMap.keys(): |
||
| 125 | obj.staticMap[objID] = min(obj.staticMap[objID], Rules.maxScanPwr) |
||
| 126 | if obj.staticMap[objID] < Rules.level1InfoScanPwr: |
||
| 127 | del obj.staticMap[objID] |
||
| 128 | if not tran.db.has_key(objID) or tran.db[objID].type not in (Const.T_SYSTEM, Const.T_WORMHOLE): |
||
| 129 | log.debug("Deleting non system %d from static map of player %d" % (objID, obj.oid)) |
||
| 130 | del obj.staticMap[objID] |
||
| 131 | for objID in obj.dynamicMap.keys(): |
||
| 132 | if obj.dynamicMap[objID] < Rules.level1InfoScanPwr: |
||
| 133 | del obj.dynamicMap[objID] |
||
| 134 | if not tran.db.has_key(objID) or tran.db[objID].type not in (Const.T_FLEET, Const.T_ASTEROID): |
||
| 135 | log.debug("Deleting obj %d from dynamic map of player %d" % (objID, objID)) |
||
| 136 | del obj.dynamicMap[objID] |
||
| 137 | # check if all planets are planets |
||
| 138 | for objID in obj.planets[:]: |
||
| 139 | try: |
||
| 140 | if not tran.db.has_key(objID): |
||
| 141 | log.debug("Planet does not exists - removing", obj.oid, objID) |
||
| 142 | obj.planets.remove(objID) |
||
| 143 | if tran.db[objID].type != Const.T_PLANET: |
||
| 144 | log.debug("Planet is not a planet - removing", obj.oid, objID) |
||
| 145 | obj.planets.remove(objID) |
||
| 146 | except: |
||
| 147 | log.warning("There is a problem when processing planet - removing", obj.oid, objID) |
||
| 148 | obj.planets.remove(objID) |
||
| 149 | # check if systems in buoys are systems |
||
| 150 | for objID in obj.buoys.keys(): |
||
| 151 | try: |
||
| 152 | if not tran.db.has_key(objID): |
||
| 153 | log.debug("System for buoy does not exists - removing", obj.oid, objID) |
||
| 154 | del obj.buoys[objID] |
||
| 155 | if tran.db[objID].type not in (Const.T_SYSTEM, Const.T_WORMHOLE): |
||
| 156 | log.debug("System for buoy is not a system - removing", obj.oid, objID) |
||
| 157 | del obj.buoys[objID] |
||
| 158 | except: |
||
| 159 | log.warning("There is a problem when processing system for buoy - removing", obj.oid, objID) |
||
| 160 | del obj.buoys[objID] |
||
| 161 | # check if fleets are fleets |
||
| 162 | for objID in obj.fleets[:]: |
||
| 163 | try: |
||
| 164 | if not tran.db.has_key(objID): |
||
| 165 | log.debug("Fleet does not exists - removing", obj.oid, objID) |
||
| 166 | obj.fleets.remove(objID) |
||
| 167 | if tran.db[objID].type not in (Const.T_FLEET, Const.T_ASTEROID): |
||
| 168 | log.debug("Fleet is not a fleet - removing", obj.oid, objID) |
||
| 169 | obj.fleets.remove(objID) |
||
| 170 | except: |
||
| 171 | log.warning("There is a problem when processing planet - removing", obj.oid, objID) |
||
| 172 | # check accessible technologies |
||
| 173 | wip = 1 |
||
| 174 | while wip: |
||
| 175 | wip = 0 |
||
| 176 | for techID in obj.techs.keys(): |
||
| 177 | if techID not in Rules.techs: |
||
| 178 | wip = 1 |
||
| 179 | log.debug("Deleting nonexistent tech", techID, "player", obj.oid) |
||
| 180 | del obj.techs[techID] |
||
| 181 | continue |
||
| 182 | tech = Rules.techs[techID] |
||
| 183 | # check tech level |
||
| 184 | if tech.level > obj.techLevel: |
||
| 185 | wip = 1 |
||
| 186 | log.debug("Deleting tech", techID, "player", obj.oid) |
||
| 187 | if techID in obj.techs: del obj.techs[techID] |
||
| 188 | for rTask in obj.rsrchQueue[:]: |
||
| 189 | if rTask.techID not in Rules.techs: |
||
| 190 | log.debug("Deleting res task for nonexistent tech", rTask.techID, "player", obj.oid) |
||
| 191 | obj.rsrchQueue.remove(rTask) |
||
| 192 | continue |
||
| 193 | tech = Rules.techs[rTask.techID] |
||
| 194 | if tech.level == 99: |
||
| 195 | log.debug("Deleting res task", rTask.techID, "player", obj.oid) |
||
| 196 | obj.rsrchQueue.remove(rTask) |
||
| 197 | # check if player is in the universe |
||
| 198 | universe = tran.db[Const.OID_UNIVERSE] |
||
| 199 | if obj.oid not in universe.players and obj.oid not in (Const.OID_NATURE, Const.OID_ADMIN): |
||
| 200 | log.debug(obj.oid, "Adding player to the universe") |
||
| 201 | universe.players.append(obj.oid) |
||
| 202 | # check if player is a leader |
||
| 203 | if not obj.galaxy: |
||
| 204 | log.debug(obj.oid, obj.name, "IS NOT IN ANY GALAXY") |
||
| 205 | else: |
||
| 206 | galaxy = tran.db[obj.galaxy] |
||
| 207 | if galaxy.imperator != obj.oid and obj.imperator > 0: |
||
| 208 | log.debug(obj.oid, "Removing imperator/leader bonus") |
||
| 209 | obj.imperator = 0 |
||
| 210 | ## NON VALIDATING CODE (DERIVED ATTRS AND SO ON) |
||
| 211 | # get best technologies for planet weapons |
||
| 212 | bestScores = [0, 0, 0, 0] |
||
| 213 | obj.planetWeapons = [None, None, None, None, None] |
||
| 214 | for techID in obj.techs: |
||
| 215 | tech = Rules.techs[techID] |
||
| 216 | if tech.isShipEquip and tech.weaponDmgMin > 0 and not tech.buildSRes\ |
||
| 217 | and tech.weaponGoodForFlak: |
||
| 218 | # compute score |
||
| 219 | weaponEff = Rules.techImprEff[obj.techs.get(techID, Rules.techBaseImprovement)] |
||
| 220 | score = (tech.weaponDmgMin + tech.weaponDmgMax) / 2.0 * \ |
||
| 221 | tech.weaponROF * (tech.weaponAtt + 10.0)/10 * weaponEff |
||
| 222 | if score > bestScores[tech.weaponClass]: |
||
| 223 | obj.planetWeapons[tech.weaponClass] = techID |
||
| 224 | bestScores[tech.weaponClass] = score |
||
| 225 | #@log.debug(obj.oid, "Planet weapons", obj.planetWeapons) |
||
| 226 | # update all ship designs |
||
| 227 | for designID in obj.shipDesigns: |
||
| 228 | old = obj.shipDesigns[designID] |
||
| 229 | new = ShipUtils.makeShipMinSpec(obj, old.name, old.hullID, |
||
| 230 | old.eqIDs, old.improvements, raiseExs = False) |
||
| 231 | new.built = old.built |
||
| 232 | new.upgradeTo = old.upgradeTo |
||
| 233 | obj.shipDesigns[designID] = new |
||
| 234 | if not hasattr(obj, 'obsoleteTechs'): |
||
| 235 | obj.obsoleteTechs = set() |
||
| 236 | |||
| 237 | update.public = 0 |
||
| 238 | |||
| 239 | @staticmethod |
||
| 240 | def setStartingPlanet(tran, playerID, planet): |
||
| 241 | planet.plSlots = max(planet.plSlots, 9) |
||
| 242 | planet.plMaxSlots = max(planet.plMaxSlots, 9) |
||
| 243 | planet.plDiameter = max(planet.plDiameter, 9000) |
||
| 244 | planet.slots = [ |
||
| 245 | Utils.newStructure(tran, Rules.Tech.PWRPLANTNUK1, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 246 | Utils.newStructure(tran, Rules.Tech.FARM1, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 247 | Utils.newStructure(tran, Rules.Tech.FARM1, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 248 | Utils.newStructure(tran, Rules.Tech.FARM1, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 249 | Utils.newStructure(tran, Rules.Tech.ANCFACTORY, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 250 | Utils.newStructure(tran, Rules.Tech.ANCFACTORY, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 251 | Utils.newStructure(tran, Rules.Tech.ANCRESLAB, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 252 | Utils.newStructure(tran, Rules.Tech.REPAIR1, playerID, Const.STRUCT_STATUS_ON, Rules.structNewPlayerHpRatio), |
||
| 253 | ] |
||
| 254 | planet.storPop = Rules.startingPopulation |
||
| 255 | planet.storBio = Rules.startingBio |
||
| 256 | planet.storEn = Rules.startingEn |
||
| 257 | planet.scannerPwr = Rules.startingScannerPwr |
||
| 258 | planet.morale = Rules.maxMorale |
||
| 259 | |||
| 260 | @staticmethod |
||
| 261 | def setStartingTechnologies(obj): |
||
| 262 | obj.techLevel = 1 |
||
| 263 | for techID, tech in Rules.techs.iteritems(): |
||
| 264 | if tech.isStarting: |
||
| 265 | obj.techs[techID] = (Rules.techBaseImprovement + tech.maxImprovement) / 2 |
||
| 266 | |||
| 267 | @staticmethod |
||
| 268 | def setStartingShipDesigns(obj): |
||
| 269 | obj.shipDesigns[1] = ShipUtils.makeShipMinSpec(obj, 'Scout', Rules.Tech.SMALLHULL0, |
||
| 270 | {Rules.Tech.SCOCKPIT0:1, Rules.Tech.SCANNERMOD0:1, Rules.Tech.FTLENG0:3}, []) |
||
| 271 | obj.shipDesigns[2] = ShipUtils.makeShipMinSpec(obj, 'Fighter', Rules.Tech.SMALLHULL0, |
||
| 272 | {Rules.Tech.SCOCKPIT0:1, Rules.Tech.CANNON0:2, Rules.Tech.FTLENG0:3}, []) |
||
| 273 | obj.shipDesigns[3] = ShipUtils.makeShipMinSpec(obj, 'Bomber', Rules.Tech.SMALLHULL0, |
||
| 274 | {Rules.Tech.SCOCKPIT0:1, Rules.Tech.CONBOMB0:1, Rules.Tech.FTLENG0:3}, []) |
||
| 275 | obj.shipDesigns[4] = ShipUtils.makeShipMinSpec(obj, 'Colony Ship', Rules.Tech.MEDIUMHULL0, |
||
| 276 | {Rules.Tech.SCOCKPIT0:1, Rules.Tech.COLONYMOD0:1, Rules.Tech.FTLENG0:4}, []) |
||
| 277 | |||
| 278 | @staticmethod |
||
| 279 | def setStartingFleet(tran, playerID, system): |
||
| 280 | # add small fleet |
||
| 281 | log.debug('Creating fleet') |
||
| 282 | fleet = tran.gameMngr.cmdPool[Const.T_FLEET].new(Const.T_FLEET) |
||
| 283 | tran.db.create(fleet) |
||
| 284 | log.debug('Creating fleet - created', fleet.oid) |
||
| 285 | tran.gameMngr.cmdPool[Const.T_FLEET].create(tran, fleet, system, playerID) |
||
| 286 | log.debug('Creating fleet - addShips') |
||
| 287 | # for IDs, see setStartingShipDesigns |
||
| 288 | tran.gameMngr.cmdPool[Const.T_FLEET].addNewShip(tran, fleet, 1) |
||
| 289 | tran.gameMngr.cmdPool[Const.T_FLEET].addNewShip(tran, fleet, 1) |
||
| 290 | tran.gameMngr.cmdPool[Const.T_FLEET].addNewShip(tran, fleet, 2) |
||
| 291 | tran.gameMngr.cmdPool[Const.T_FLEET].addNewShip(tran, fleet, 2) |
||
| 292 | tran.gameMngr.cmdPool[Const.T_FLEET].addNewShip(tran, fleet, 4) |
||
| 293 | |||
| 294 | @public(Const.AL_FULL) |
||
| 295 | def startGlobalConstruction(self, tran, player, techID, quantity, isShip, reportFinished, queue): |
||
| 296 | if len(player.prodQueues) <= queue: |
||
| 297 | raise ige.GameException('Invalid queue.') |
||
| 298 | if len(player.prodQueues[queue]) > Rules.maxProdQueueLen: |
||
| 299 | raise ige.GameException('Queue is full.') |
||
| 300 | if quantity < 1: |
||
| 301 | raise ige.GameException("Quantity must be greater than 0") |
||
| 302 | if not player.techs.has_key(techID) and isShip == 0: |
||
| 303 | raise ige.GameException('You do not own this kind of technology.') |
||
| 304 | if not player.shipDesigns.has_key(techID) and isShip == 1: |
||
| 305 | raise ige.GameException('You do not own this ship design.') |
||
| 306 | if isShip: |
||
| 307 | tech = player.shipDesigns[techID] |
||
| 308 | if tech.upgradeTo: |
||
| 309 | raise ige.GameException("You cannot build obsolete ship design.") |
||
| 310 | else: |
||
| 311 | tech = Rules.techs[techID] |
||
| 312 | if tech.isStructure or not tech.isProject: |
||
| 313 | raise ige.GameException('You cannot construct this technology.') |
||
| 314 | elif tech.globalDisabled: |
||
| 315 | raise ige.GameException('You cannot construct targeted project.') |
||
| 316 | neededSR = {} |
||
| 317 | for sr in tech.buildSRes: |
||
| 318 | nSR = neededSR.get(sr, 0) + tech.buildSRes[sr] * quantity |
||
| 319 | if player.stratRes.get(sr, 0) < nSR: |
||
| 320 | raise ige.GameException("You do not own required strategic resource(s)") |
||
| 321 | neededSR[sr] = nSR |
||
| 322 | # consume strategic resources |
||
| 323 | for sr in neededSR: |
||
| 324 | player.stratRes[sr] -= neededSR[sr] |
||
| 325 | # start construction |
||
| 326 | item = IDataHolder() |
||
| 327 | item.techID = techID |
||
| 328 | item.quantity = int(quantity) |
||
| 329 | item.changePerc = 0 |
||
| 330 | item.isShip = bool(isShip) |
||
| 331 | item.reportFin = bool(reportFinished) |
||
| 332 | item.type = Const.T_TASK |
||
| 333 | player.prodQueues[queue].append(item) |
||
| 334 | return player.prodQueues[queue], player.stratRes |
||
| 335 | |||
| 336 | @public(Const.AL_FULL) |
||
| 337 | def changeGlobalConstruction(self, tran, player, queue, index, quantity): |
||
| 338 | if index < 0 or index >= len(player.prodQueues[queue]): |
||
| 339 | raise ige.GameException("No such item in the construction queue.") |
||
| 340 | |||
| 341 | if quantity < 1: |
||
| 342 | raise ige.GameException("Quantity must be greater than 0") |
||
| 343 | |||
| 344 | item = player.prodQueues[queue][index] |
||
| 345 | if item.isShip: |
||
| 346 | tech = player.shipDesigns[item.techID] |
||
| 347 | else: |
||
| 348 | tech = Rules.techs[item.techID] |
||
| 349 | |||
| 350 | quantityChange = quantity - player.prodQueues[queue][index].quantity |
||
| 351 | |||
| 352 | neededSR = {} |
||
| 353 | for sr in tech.buildSRes: |
||
| 354 | nSR = neededSR.get(sr, 0) + tech.buildSRes[sr] * quantityChange |
||
| 355 | if player.stratRes.get(sr, 0) < nSR: |
||
| 356 | raise ige.GameException("You do not own required strategic resource(s)") |
||
| 357 | neededSR[sr] = nSR |
||
| 358 | # consume strategic resources |
||
| 359 | for sr in neededSR: |
||
| 360 | player.stratRes[sr] += (-1 * neededSR[sr]) |
||
| 361 | |||
| 362 | player.prodQueues[queue][index].quantity = quantity |
||
| 363 | player.prodQueues[queue][index].const = tech.buildProd * quantity |
||
| 364 | return player.prodQueues[queue], player.stratRes |
||
| 365 | |||
| 366 | @public(Const.AL_FULL) |
||
| 367 | def abortGlobalConstruction(self, tran, player, queue, index): |
||
| 368 | if len(player.prodQueues) <= queue or queue < 0: |
||
| 369 | raise ige.GameException('Invalid queue.') |
||
| 370 | if len(player.prodQueues[queue]) <= index or index < 0: |
||
| 371 | raise ige.GameException('Invalid task.') |
||
| 372 | item = player.prodQueues[queue][index] |
||
| 373 | # return strategic resources |
||
| 374 | #is ship |
||
| 375 | if item.techID < 1000: |
||
| 376 | tech = player.shipDesigns[item.techID] |
||
| 377 | else: |
||
| 378 | tech = Rules.techs[item.techID] |
||
| 379 | for sr in tech.buildSRes: |
||
| 380 | player.stratRes[sr] += item.quantity * tech.buildSRes[sr] |
||
| 381 | player.prodQueues[queue].pop(index) |
||
| 382 | return player.prodQueues[queue], player.stratRes |
||
| 383 | |||
| 384 | @public(Const.AL_FULL) |
||
| 385 | def moveGlobalConstrItem(self, tran, player, queue, index, rel): |
||
| 386 | if index >= len(player.prodQueues[queue]): |
||
| 387 | raise ige.GameException('No such item in the construction queue.') |
||
| 388 | if index + rel < 0 or index + rel >= len(player.prodQueues[queue]): |
||
| 389 | raise ige.GameException('Cannot move.') |
||
| 390 | item = player.prodQueues[queue][index] |
||
| 391 | del player.prodQueues[queue][index] |
||
| 392 | player.prodQueues[queue].insert(index + rel, item) |
||
| 393 | return player.prodQueues[queue] |
||
| 394 | |||
| 395 | def getReferences(self, tran, obj): |
||
| 396 | return obj.fleets |
||
| 397 | |||
| 398 | getReferences.public = 0 |
||
| 399 | |||
| 400 | def loggedIn(self, tran, obj): |
||
| 401 | obj.lastLogin = time.time() |
||
| 402 | |||
| 403 | loggedIn.public = 0 |
||
| 404 | |||
| 405 | @public(Const.AL_OWNER) |
||
| 406 | def resign(self, tran, obj): |
||
| 407 | """Remove player from the game. Give remaining planets, ... to the REBELS""" |
||
| 408 | # cannot resign when time is stopped |
||
| 409 | # TODO smarted conditions (like cannot resign twice a week or so) |
||
| 410 | galaxy = tran.db[obj.galaxy] |
||
| 411 | if galaxy.scenario == Const.SCENARIO_SINGLE: |
||
| 412 | raise ige.GameException('You cannot resign current game - it is single player game.') |
||
| 413 | if not obj.timeEnabled: |
||
| 414 | raise ige.GameException('You cannot resign current game - time is stopped.') |
||
| 415 | log.debug("Resigning player", obj.oid) |
||
| 416 | # morph player to AI |
||
| 417 | obj.type = self.resignTo |
||
| 418 | self.cmd(obj).upgrade(tran, obj) |
||
| 419 | self.cmd(obj).update(tran, obj) |
||
| 420 | # reregister |
||
| 421 | tran.gameMngr.removePlayer(obj.oid) |
||
| 422 | self.cmd(obj).register(tran, obj, obj.galaxy) |
||
| 423 | |||
| 424 | @public(Const.AL_ADMIN) |
||
| 425 | def delete(self, tran, obj): |
||
| 426 | # check whether it is AI or normal player |
||
| 427 | log.debug("Deleting player", obj.oid) |
||
| 428 | # delete relations |
||
| 429 | for playerID in tran.db[Const.OID_UNIVERSE].players: |
||
| 430 | player = tran.db[playerID] |
||
| 431 | self.cmd(player).deleteDiplomacyWith(tran, player, obj.oid) |
||
| 432 | # delete fleets |
||
| 433 | for fleetID in obj.fleets: |
||
| 434 | fleet = tran.db[fleetID] |
||
| 435 | self.cmd(fleet).disbandFleet(tran, fleet) |
||
| 436 | try: |
||
| 437 | tran.gameMngr.removePlayer(obj.oid) |
||
| 438 | except Exception: |
||
| 439 | log.warning("Cannot remove player") |
||
| 440 | |||
| 441 | @public(Const.AL_ADMIN) |
||
| 442 | def giveUp(self, tran, obj, playerID): |
||
| 443 | """Remove player from the game. Give remaining planets, ... to the specified player""" |
||
| 444 | # cannot resign when time is stopped |
||
| 445 | # TODO smarted conditions (like cannot resign twice a week or so) |
||
| 446 | if not obj.timeEnabled: |
||
| 447 | raise ige.GameException('You cannot resign current game - time is stopped.') |
||
| 448 | player = tran.db[playerID] |
||
| 449 | # give planets |
||
| 450 | for planetID in obj.planets[:]: # needs a copy - changeOwner modifies this |
||
| 451 | planet = tran.db[planetID] |
||
| 452 | self.cmd(planet).changeOwner(tran, planet, playerID, force = 1) |
||
| 453 | # give fleets |
||
| 454 | for fleetID in obj.fleets[:]: |
||
| 455 | fleet = tran.db[fleetID] |
||
| 456 | fleet.owner = playerID |
||
| 457 | player.fleets.append(fleetID) |
||
| 458 | # remove player |
||
| 459 | tran.gameMngr.removePlayer(obj.oid) |
||
| 460 | try: |
||
| 461 | tran.db[Const.OID_UNIVERSE].players.remove(obj.oid) |
||
| 462 | except ValueError: |
||
| 463 | pass |
||
| 464 | |||
| 465 | @public(Const.AL_OWNER) |
||
| 466 | def addShipDesign(self, tran, obj, name, hullID, eqIDs): |
||
| 467 | """Add ship design to the database of designs.""" |
||
| 468 | # normalize design |
||
| 469 | name = name.strip() |
||
| 470 | # check technologies |
||
| 471 | if hullID not in obj.techs: |
||
| 472 | raise ige.GameException("You do not posses this hull type.") |
||
| 473 | for techID in eqIDs: |
||
| 474 | if techID not in obj.techs: |
||
| 475 | raise ige.GameException("You do not posses technology(ies) to construct this ship.") |
||
| 476 | # create spec (throws exception for invad ones) |
||
| 477 | spec = ShipUtils.makeShipMinSpec(obj, name, hullID, eqIDs, []) |
||
| 478 | # check number of designs |
||
| 479 | if len(obj.shipDesigns) > Rules.shipMaxDesigns: |
||
| 480 | raise ige.GameException("No space to store design.") |
||
| 481 | # check name of designs |
||
| 482 | for designID in obj.shipDesigns: |
||
| 483 | if obj.shipDesigns[designID].name == name: |
||
| 484 | raise ige.GameException("Design name is already used.") |
||
| 485 | if re.match("^\s*$",name): |
||
| 486 | raise ige.GameException("Design name must not be entirely whitespace.") |
||
| 487 | # find free design id |
||
| 488 | index = 1 |
||
| 489 | ids = obj.shipDesigns.keys() |
||
| 490 | while 1: |
||
| 491 | if index not in ids: |
||
| 492 | break |
||
| 493 | index += 1 |
||
| 494 | # add design |
||
| 495 | obj.shipDesigns[index] = spec |
||
| 496 | return obj.shipDesigns, index |
||
| 497 | |||
| 498 | @public(Const.AL_OWNER) |
||
| 499 | def addBuoy(self, tran, obj, systemID, text, type): |
||
| 500 | """Add new buoy to player buoys.""" |
||
| 501 | # delete buoy |
||
| 502 | if not text: |
||
| 503 | if systemID in obj.buoys: |
||
| 504 | del obj.buoys[systemID] |
||
| 505 | return obj.buoys |
||
| 506 | else: |
||
| 507 | raise ige.GameException("Buoy at specified system does not exist.") |
||
| 508 | |||
| 509 | if type not in (Const.BUOY_PRIVATE, Const.BUOY_TO_ALLY, Const.BUOY_TO_SCANNERSHARE): |
||
| 510 | raise ige.GameException("Wrong bouy type.") |
||
| 511 | |||
| 512 | # edit buoy |
||
| 513 | if systemID in obj.buoys: |
||
| 514 | obj.buoys[systemID] = (text, type) |
||
| 515 | return obj.buoys |
||
| 516 | |||
| 517 | if len(obj.buoys) >= 30: |
||
| 518 | raise ige.GameException("You cannot add more than 30 buoys.") |
||
| 519 | |||
| 520 | if tran.db[systemID].type not in (Const.T_SYSTEM, Const.T_WORMHOLE): |
||
| 521 | raise ige.GameException("You can add buoy only to system.") |
||
| 522 | |||
| 523 | # new buoy |
||
| 524 | if len(text) > 0: |
||
| 525 | obj.buoys[systemID] = (text, type) |
||
| 526 | |||
| 527 | return obj.buoys |
||
| 528 | |||
| 529 | @public(Const.AL_OWNER) |
||
| 530 | def scrapShipDesign(self, tran, obj, designID): |
||
| 531 | """Remove ship design from the database of designs and remove all |
||
| 532 | active ships using this design.""" |
||
| 533 | # check design ID |
||
| 534 | if designID not in obj.shipDesigns: |
||
| 535 | raise ige.GameException("No such design.") |
||
| 536 | # delete ships |
||
| 537 | for fleetID in obj.fleets[:]: # make copy, fleet can be deleted |
||
| 538 | fleet = tran.db[fleetID] |
||
| 539 | self.cmd(fleet).deleteDesign(tran, fleet, designID) |
||
| 540 | # delete tasks |
||
| 541 | for planetID in obj.planets: |
||
| 542 | planet = tran.db[planetID] |
||
| 543 | self.cmd(planet).deleteDesign(tran, planet, designID) |
||
| 544 | # delete from global queues |
||
| 545 | for queueID in xrange(len(obj.prodQueues)): |
||
|
|
|||
| 546 | queue = obj.prodQueues[queueID][:] |
||
| 547 | for taskID in xrange(len(queue)): |
||
| 548 | if obj.prodQueues[queueID][taskID].techID == designID: |
||
| 549 | self.cmd(obj).abortGlobalConstruction(tran, obj, queueID, taskID) |
||
| 550 | # clear upgradeTo |
||
| 551 | for tmpDesignID in obj.shipDesigns: |
||
| 552 | spec = obj.shipDesigns[tmpDesignID] |
||
| 553 | if spec.upgradeTo == designID: |
||
| 554 | spec.upgradeTo = 0 |
||
| 555 | # delete design |
||
| 556 | del obj.shipDesigns[designID] |
||
| 557 | return obj.shipDesigns, obj.fleets, obj.stratRes, obj.prodQueues |
||
| 558 | |||
| 559 | def getShipDesign(self,tran,obj,designID): |
||
| 560 | if designID not in obj.shipDesigns: |
||
| 561 | raise ige.GameException("No such design.") |
||
| 562 | return obj.shipDesigns[designID] |
||
| 563 | |||
| 564 | @public(Const.AL_OWNER) |
||
| 565 | def upgradeShipDesign(self, tran, obj, oldDesignID, newDesignID): |
||
| 566 | # check designs ID |
||
| 567 | if oldDesignID not in obj.shipDesigns: |
||
| 568 | raise ige.GameException("No such design.") |
||
| 569 | if newDesignID not in obj.shipDesigns: |
||
| 570 | raise ige.GameException("No such design.") |
||
| 571 | if oldDesignID == newDesignID: |
||
| 572 | raise ige.GameException("Designs are the same.") |
||
| 573 | oldSpec = obj.shipDesigns[oldDesignID] |
||
| 574 | newSpec = obj.shipDesigns[newDesignID] |
||
| 575 | if oldSpec.upgradeTo: |
||
| 576 | raise ige.GameException("Old design has already been made obsolete.") |
||
| 577 | if newSpec.upgradeTo: |
||
| 578 | raise ige.GameException("New design has already been made obsolete.") |
||
| 579 | if oldSpec.combatClass != newSpec.combatClass: |
||
| 580 | raise ige.GameException("Designs must be of the same combat class.") |
||
| 581 | # set old design as upgradable |
||
| 582 | oldSpec.upgradeTo = newDesignID |
||
| 583 | # if something is upgraded to oldDesign change it to new design |
||
| 584 | for desID in obj.shipDesigns: |
||
| 585 | if obj.shipDesigns[desID].upgradeTo == oldDesignID: |
||
| 586 | obj.shipDesigns[desID].upgradeTo = newDesignID |
||
| 587 | # compute strat res difference |
||
| 588 | stratRes = {} |
||
| 589 | for sr in oldSpec.buildSRes: |
||
| 590 | stratRes[sr] = stratRes.get(sr, 0) - oldSpec.buildSRes[sr] |
||
| 591 | for sr in newSpec.buildSRes: |
||
| 592 | stratRes[sr] = stratRes.get(sr, 0) + newSpec.buildSRes[sr] |
||
| 593 | if stratRes[sr] == 0: |
||
| 594 | del stratRes[sr] |
||
| 595 | log.debug("upgradeShipDesign", obj.oid, stratRes) |
||
| 596 | # modify tasks |
||
| 597 | tasksUpgraded = False |
||
| 598 | if not stratRes: |
||
| 599 | log.debug("upgradeShipDesign - upgrading tasks") |
||
| 600 | for planetID in obj.planets: |
||
| 601 | planet = tran.db[planetID] |
||
| 602 | self.cmd(planet).changeShipDesign(tran, planet, oldDesignID, newDesignID) |
||
| 603 | # upgrade global queue as well |
||
| 604 | for queue in obj.prodQueues: |
||
| 605 | for task in queue: |
||
| 606 | if task.techID == oldDesignID: |
||
| 607 | task.techID = newDesignID |
||
| 608 | tasksUpgraded = True |
||
| 609 | else: |
||
| 610 | log.debug("upgradeShipDesing - NOT upgrading tasks") |
||
| 611 | return obj.shipDesigns, obj.stratRes, tasksUpgraded, obj.prodQueues |
||
| 612 | |||
| 613 | @public(Const.AL_OWNER) |
||
| 614 | def cancelUpgradeShipDesign(self, tran, obj, designID): |
||
| 615 | # check designs ID |
||
| 616 | if designID not in obj.shipDesigns: |
||
| 617 | raise ige.GameException("No such design.") |
||
| 618 | obj.shipDesigns[designID].upgradeTo = Const.OID_NONE |
||
| 619 | return obj.shipDesigns |
||
| 620 | |||
| 621 | @public(Const.AL_FULL) |
||
| 622 | def startResearch(self, tran, obj, techID, improveToMax = 0): |
||
| 623 | if len(obj.rsrchQueue) > Rules.maxRsrchQueueLen: |
||
| 624 | ige.GameException('Queue is full.') |
||
| 625 | tech = Rules.techs[techID] |
||
| 626 | # player has to be a right race |
||
| 627 | if obj.race not in tech.researchRaces: |
||
| 628 | raise ige.GameException("Your race cannot research this technology.") |
||
| 629 | # item cannot be researched twice |
||
| 630 | for tmpTech in obj.rsrchQueue: |
||
| 631 | if tmpTech.techID == techID: |
||
| 632 | raise ige.GameException('Technology is already sheduled for research.') |
||
| 633 | # disabled? |
||
| 634 | for tmpTechID in obj.techs: |
||
| 635 | if techID in Rules.techs[tmpTechID].researchDisables: |
||
| 636 | raise ige.GameException("Previous research has disabled this technology.") |
||
| 637 | # check requirements |
||
| 638 | for tmpTechID, improvement in tech.researchRequires: |
||
| 639 | if not obj.techs.has_key(tmpTechID) or obj.techs[tmpTechID] < improvement: |
||
| 640 | raise ige.GameException('You cannot research this technology yet.') |
||
| 641 | improvement = obj.techs.get(techID, Rules.techBaseImprovement - 1) + 1 |
||
| 642 | if improvement > Rules.techMaxImprovement or improvement > tech.maxImprovement: |
||
| 643 | raise ige.GameException('You cannot improve this technology further.') |
||
| 644 | if tech.level > obj.techLevel: |
||
| 645 | raise ige.GameException("Your technological level is insufficient.") |
||
| 646 | # check strategic resources |
||
| 647 | if improvement == 1: |
||
| 648 | for stratRes in tech.researchReqSRes: |
||
| 649 | if obj.stratRes.get(stratRes, 0) < 1: |
||
| 650 | raise ige.GameException("Required strategy resource missing.") |
||
| 651 | item = IDataHolder() |
||
| 652 | item.techID = techID |
||
| 653 | item.improvement = improvement |
||
| 654 | item.currSci = 0 |
||
| 655 | item.changeSci = 0 |
||
| 656 | item.improveToMax = improveToMax |
||
| 657 | item.type = Const.T_RESTASK |
||
| 658 | obj.rsrchQueue.append(item) |
||
| 659 | return obj.rsrchQueue |
||
| 660 | |||
| 661 | @public(Const.AL_FULL) |
||
| 662 | def abortResearch(self, tran, obj, index): |
||
| 663 | if index >= len(obj.rsrchQueue) or index < 0: |
||
| 664 | ige.GameException('No such item in queue.') |
||
| 665 | del obj.rsrchQueue[index] |
||
| 666 | return obj.rsrchQueue |
||
| 667 | |||
| 668 | @public(Const.AL_FULL) |
||
| 669 | def editResearch(self, tran, obj, index, improveToMax = 0): |
||
| 670 | if index >= len(obj.rsrchQueue) or index < 0: |
||
| 671 | ige.GameException('No such item in queue.') |
||
| 672 | obj.rsrchQueue[index].improveToMax = improveToMax |
||
| 673 | return obj.rsrchQueue |
||
| 674 | |||
| 675 | @public(Const.AL_FULL) |
||
| 676 | def moveResearch(self, tran, obj, index, rel): |
||
| 677 | if index >= len(obj.rsrchQueue): |
||
| 678 | raise ige.GameException('No such item in the researcg queue.') |
||
| 679 | if index + rel < 0 or index + rel >= len(obj.rsrchQueue): |
||
| 680 | raise ige.GameException('Cannot move.') |
||
| 681 | item = obj.rsrchQueue[index] |
||
| 682 | del obj.rsrchQueue[index] |
||
| 683 | obj.rsrchQueue.insert(index + rel, item) |
||
| 684 | return obj.rsrchQueue |
||
| 685 | |||
| 686 | @public(Const.AL_FULL) |
||
| 687 | def redirectShips(self, tran, obj, sourceSystemID, targetSystemID): |
||
| 688 | # check sourceSystemID |
||
| 689 | ok = 0 |
||
| 690 | if sourceSystemID == targetSystemID: |
||
| 691 | targetSystemID = Const.OID_NONE |
||
| 692 | for planetID in tran.db[sourceSystemID].planets: |
||
| 693 | if tran.db[planetID].owner == obj.oid: |
||
| 694 | ok = 1 |
||
| 695 | if not ok: |
||
| 696 | raise ige.GameException("You must own planet in the source system") |
||
| 697 | # check targetSystemID |
||
| 698 | if targetSystemID != Const.OID_NONE and 0: # TODO: switch on |
||
| 699 | ok = 0 |
||
| 700 | for planetID in tran.db[targetSystemID].planets: |
||
| 701 | if tran.db[planetID].owner == obj.oid: |
||
| 702 | ok = 1 |
||
| 703 | if not ok: |
||
| 704 | raise ige.GameException("You must own planet in the target system") |
||
| 705 | # fine - record it |
||
| 706 | log.debug(obj.oid, "Adding redirection", sourceSystemID, targetSystemID) |
||
| 707 | if targetSystemID: |
||
| 708 | obj.shipRedirections[sourceSystemID] = targetSystemID |
||
| 709 | else: |
||
| 710 | try: |
||
| 711 | del obj.shipRedirections[sourceSystemID] |
||
| 712 | except KeyError: |
||
| 713 | pass |
||
| 714 | return obj.shipRedirections |
||
| 715 | |||
| 716 | @public(Const.AL_NONE) |
||
| 717 | def getPublicInfo(self, tran, obj): |
||
| 718 | result = IObject.getPublicInfo(self, tran, obj) |
||
| 719 | result.type = obj.type |
||
| 720 | result.name = obj.name |
||
| 721 | return result |
||
| 722 | |||
| 723 | @public(Const.AL_OWNER) |
||
| 724 | def changePactCond(self, tran, obj, playerID, pactID, state, conditions): |
||
| 725 | log.debug("changePactCond", obj.oid, playerID, pactID) |
||
| 726 | # must have a contact |
||
| 727 | if playerID not in obj.diplomacyRels: |
||
| 728 | raise ige.GameException('No contact with this player.') |
||
| 729 | player = tran.db[playerID] |
||
| 730 | # must be a player |
||
| 731 | if player.type not in Const.PLAYER_TYPES and player.type != Const.T_ALLIANCE: |
||
| 732 | raise ige.GameException('Pacts can be offered to players and aliances only.') |
||
| 733 | # check pactID |
||
| 734 | pact = Rules.pactDescrs.get(pactID, None) |
||
| 735 | if not pact: |
||
| 736 | raise ige.GameException('No such pact type.') |
||
| 737 | # check state |
||
| 738 | if state not in (Const.PACT_OFF, Const.PACT_INACTIVE, Const.PACT_ACTIVE): |
||
| 739 | raise ige.GameException("Wrong pact state") |
||
| 740 | # check conditions |
||
| 741 | for tmpPactID in conditions: |
||
| 742 | pact = Rules.pactDescrs.get(tmpPactID, None) |
||
| 743 | if not pact: |
||
| 744 | raise ige.GameException('No such pact type.') |
||
| 745 | # record pact |
||
| 746 | dipl = self.cmd(obj).getDiplomacyWith(tran, obj, playerID) |
||
| 747 | dipl.pacts[pactID] = [state] |
||
| 748 | dipl.pacts[pactID].extend(conditions) |
||
| 749 | # if state if Const.PACT_OFF, disable state on partner's side |
||
| 750 | if state == Const.PACT_OFF: |
||
| 751 | partner = tran.db[playerID] |
||
| 752 | dipl = self.cmd(partner).getDiplomacyWith(tran, partner, obj.oid) |
||
| 753 | if pactID in dipl.pacts: |
||
| 754 | dipl.pacts[pactID][0] = Const.PACT_OFF |
||
| 755 | else: |
||
| 756 | dipl.pacts[pactID] = [Const.PACT_OFF] |
||
| 757 | return obj.diplomacyRels |
||
| 758 | |||
| 759 | def getDiplomacyWith(self, tran, obj, playerID): |
||
| 760 | if obj.governorOf: |
||
| 761 | # player is a governor |
||
| 762 | leader = tran.db[obj.governorOf] |
||
| 763 | return self.cmd(leader).getDiplomacyWith(tran, leader, objID) |
||
| 764 | # player is independent |
||
| 765 | dipl = obj.diplomacyRels.get(playerID, None) |
||
| 766 | View Code Duplication | if not dipl: |
|
| 767 | # make default |
||
| 768 | dipl = IDataHolder() |
||
| 769 | dipl.type = Const.T_DIPLREL |
||
| 770 | dipl.pacts = { |
||
| 771 | Const.PACT_ALLOW_CIVILIAN_SHIPS: [Const.PACT_ACTIVE, Const.PACT_ALLOW_CIVILIAN_SHIPS] |
||
| 772 | } |
||
| 773 | dipl.relation = obj.defaultRelation |
||
| 774 | dipl.relChng = 0 |
||
| 775 | dipl.lastContact = tran.db[Const.OID_UNIVERSE].turn |
||
| 776 | dipl.contactType = Const.CONTACT_NONE |
||
| 777 | dipl.stats = None |
||
| 778 | if playerID != obj.oid: |
||
| 779 | obj.diplomacyRels[playerID] = dipl |
||
| 780 | else: |
||
| 781 | log.debug("getDiplomacyWith myself", obj.oid) |
||
| 782 | return dipl |
||
| 783 | |||
| 784 | @public(Const.AL_OWNER) |
||
| 785 | def getPartyDiplomacyRels(self, tran, obj, partyID): |
||
| 786 | if partyID not in obj.diplomacyRels: |
||
| 787 | return None, None |
||
| 788 | if obj.diplomacyRels[partyID].contactType == Const.CONTACT_NONE: |
||
| 789 | return obj.diplomacyRels[partyID], None |
||
| 790 | party = tran.db[partyID] |
||
| 791 | return obj.diplomacyRels[partyID], party.diplomacyRels.get(obj.oid, None) |
||
| 792 | |||
| 793 | def isPactActive(self, tran, obj, partnerID, pactID): |
||
| 794 | #@log.debug("isPactActive", obj.oid, partnerID, pactID) |
||
| 795 | if partnerID not in obj.diplomacyRels: |
||
| 796 | return 0 |
||
| 797 | partner = tran.db[partnerID] |
||
| 798 | partnerDipl = partner.diplomacyRels.get(obj.oid, None) |
||
| 799 | if not partnerDipl: |
||
| 800 | return 0 |
||
| 801 | return partnerDipl.pacts.get(pactID, [Const.PACT_OFF])[0] == Const.PACT_ACTIVE |
||
| 802 | |||
| 803 | def deleteDiplomacyWith(self, tran, obj, playerID): |
||
| 804 | if playerID in obj.diplomacyRels: |
||
| 805 | del obj.diplomacyRels[playerID] |
||
| 806 | |||
| 807 | @public(Const.AL_FULL) |
||
| 808 | def getRelationTo(self, tran, obj, objID): |
||
| 809 | if objID == Const.OID_NONE: |
||
| 810 | return Const.REL_UNDEF |
||
| 811 | if obj.oid == objID: |
||
| 812 | return Const.REL_UNITY |
||
| 813 | if obj.governorOf: |
||
| 814 | leader = tran.db[obj.governorOf] |
||
| 815 | return self.cmd(leader).getRelationTo(tran, leader, objID) |
||
| 816 | dipl = obj.diplomacyRels.get(objID, None) |
||
| 817 | if dipl: |
||
| 818 | return dipl.relation |
||
| 819 | else: |
||
| 820 | return obj.defaultRelation |
||
| 821 | |||
| 822 | @public(Const.AL_OWNER) |
||
| 823 | def setVoteFor(self, tran, obj, playerID): |
||
| 824 | if playerID not in obj.diplomacyRels and playerID != obj.oid and playerID != Const.OID_NONE: |
||
| 825 | raise ige.GameException("No contact with this commander.") |
||
| 826 | # check type |
||
| 827 | if playerID != Const.OID_NONE: |
||
| 828 | player = tran.db[playerID] |
||
| 829 | if player.type != Const.T_PLAYER: |
||
| 830 | raise ige.GameException("You cannot vote for this player.") |
||
| 831 | # set |
||
| 832 | obj.voteFor = playerID |
||
| 833 | return obj.voteFor |
||
| 834 | |||
| 835 | @public(Const.AL_ADMIN) |
||
| 836 | def processDIPLPhase(self, tran, obj, data): |
||
| 837 | if not obj.timeEnabled: |
||
| 838 | return |
||
| 839 | turn = tran.db[Const.OID_UNIVERSE].turn |
||
| 840 | # record changes from valid pacts |
||
| 841 | for partyID in obj.diplomacyRels: |
||
| 842 | dipl = obj.diplomacyRels[partyID] |
||
| 843 | # check contact |
||
| 844 | if dipl.contactType == Const.CONTACT_NONE: |
||
| 845 | #@log.debug("Skipping contact", obj.oid, partyID) |
||
| 846 | continue |
||
| 847 | # base change of relation |
||
| 848 | dipl.relChng += Rules.baseRelationChange |
||
| 849 | # process pacts |
||
| 850 | for pactID in dipl.pacts: |
||
| 851 | #@log.debug("Processing pact", obj.oid, partyID, pactID, dipl.pacts[pactID]) |
||
| 852 | if dipl.pacts[pactID][0] != Const.PACT_ACTIVE: |
||
| 853 | continue |
||
| 854 | pactSpec = Rules.pactDescrs[pactID] |
||
| 855 | if dipl.relation < pactSpec.validityInterval[0] or \ |
||
| 856 | dipl.relation > pactSpec.validityInterval[1] or \ |
||
| 857 | dipl.relChng < Rules.relLostWhenAttacked / 2: |
||
| 858 | # skip this non active pact, mark it as off |
||
| 859 | # mark all pact off when attacked |
||
| 860 | dipl.pacts[pactID][0] = Const.PACT_OFF |
||
| 861 | # TODO report it |
||
| 862 | continue |
||
| 863 | # pact is valid |
||
| 864 | if dipl.relation < pactSpec.targetRel: |
||
| 865 | #@log.debug("Affecting relation", pactSpec.relChng) |
||
| 866 | dipl.relChng += min(pactSpec.targetRel - dipl.relation, pactSpec.relChng) |
||
| 867 | # apply relation changes |
||
| 868 | for partyID in obj.diplomacyRels: |
||
| 869 | dipl = obj.diplomacyRels[partyID] |
||
| 870 | dipl.relation += dipl.relChng |
||
| 871 | dipl.relation = min(dipl.relation, Const.REL_ALLY_HI) |
||
| 872 | dipl.relation = max(dipl.relation, Const.REL_ENEMY_LO) |
||
| 873 | #@log.debug('IPlayer', 'Final relation', obj.oid, partyID, dipl.relation, dipl.relChng) |
||
| 874 | |||
| 875 | @public(Const.AL_OWNER) |
||
| 876 | def getScannerMap(self, tran, obj): |
||
| 877 | scanLevels = {} |
||
| 878 | # full map for the admin |
||
| 879 | if obj.oid == Const.OID_ADMIN: |
||
| 880 | universe = tran.db[Const.OID_UNIVERSE] |
||
| 881 | for galaxyID in universe.galaxies: |
||
| 882 | galaxy = tran.db[galaxyID] |
||
| 883 | for systemID in galaxy.systems: |
||
| 884 | system = tran.db[systemID] |
||
| 885 | obj.staticMap[systemID] = 111111 |
||
| 886 | for planetID in system.planets: |
||
| 887 | obj.staticMap[planetID] = 111111 |
||
| 888 | # adding systems with buoys |
||
| 889 | for objID in obj.buoys: |
||
| 890 | scanLevels[objID] = Rules.level1InfoScanPwr |
||
| 891 | # fixing system scan level for mine fields |
||
| 892 | systems = {} |
||
| 893 | for planetID in obj.planets: |
||
| 894 | systems[tran.db[planetID].compOf] = None |
||
| 895 | for systemID in systems.keys(): |
||
| 896 | scanLevels[systemID] = Rules.partnerScanPwr |
||
| 897 | # player's map |
||
| 898 | for objID in obj.staticMap: |
||
| 899 | scanLevels[objID] = max(scanLevels.get(objID, 0), obj.staticMap[objID]) |
||
| 900 | for objID in obj.dynamicMap: |
||
| 901 | scanLevels[objID] = max(scanLevels.get(objID, 0), obj.dynamicMap[objID]) |
||
| 902 | # parties' map |
||
| 903 | for partnerID in obj.diplomacyRels: |
||
| 904 | if self.cmd(obj).isPactActive(tran, obj, partnerID, Const.PACT_SHARE_SCANNER): |
||
| 905 | # load partner's map |
||
| 906 | partner = tran.db[partnerID] |
||
| 907 | for objID in partner.staticMap: |
||
| 908 | scanLevels[objID] = max(scanLevels.get(objID, 0), partner.staticMap[objID]) |
||
| 909 | for objID in partner.dynamicMap: |
||
| 910 | scanLevels[objID] = max(scanLevels.get(objID, 0), partner.dynamicMap[objID]) |
||
| 911 | # partner's fleets and planets |
||
| 912 | for objID in partner.fleets: |
||
| 913 | scanLevels[objID] = Rules.partnerScanPwr |
||
| 914 | for objID in partner.planets: |
||
| 915 | scanLevels[objID] = Rules.partnerScanPwr |
||
| 916 | |||
| 917 | # create map |
||
| 918 | map = dict() |
||
| 919 | for objID, level in scanLevels.iteritems(): |
||
| 920 | tmpObj = tran.db.get(objID, None) |
||
| 921 | if not tmpObj: |
||
| 922 | continue |
||
| 923 | # add movement validation data |
||
| 924 | if tmpObj.type in (Const.T_SYSTEM,Const.T_WORMHOLE) and objID not in obj.validSystems: |
||
| 925 | obj.validSystems.append(objID) |
||
| 926 | for info in self.cmd(tmpObj).getScanInfos(tran, tmpObj, level, obj): |
||
| 927 | if (info.oid not in map) or (info.scanPwr > map[info.oid].scanPwr): |
||
| 928 | map[info.oid] = info |
||
| 929 | |||
| 930 | return map |
||
| 931 | |||
| 932 | #@public(Const.AL_OWNER) |
||
| 933 | def mergeScannerMap(self, tran, obj, map): |
||
| 934 | #@log.debug(obj.oid, "Merging scanner map") |
||
| 935 | contacts = {} |
||
| 936 | for object, level in map.iteritems(): |
||
| 937 | objID = object.oid |
||
| 938 | if object.type in (Const.T_SYSTEM, Const.T_WORMHOLE): |
||
| 939 | obj.staticMap[objID] = max(obj.staticMap.get(objID, 0), level) |
||
| 940 | contacts.update(object.scannerPwrs) |
||
| 941 | elif object.type in (Const.T_FLEET, Const.T_ASTEROID): |
||
| 942 | obj.dynamicMap[objID] = max(obj.dynamicMap.get(objID, 0), level) |
||
| 943 | contacts[object.owner] = None |
||
| 944 | else: |
||
| 945 | raise ige.GameException("Unsupported type %d" % object.type) |
||
| 946 | if obj.oid in contacts: |
||
| 947 | del contacts[obj.oid] |
||
| 948 | if Const.OID_NONE in contacts: |
||
| 949 | del contacts[Const.OID_NONE] |
||
| 950 | for partyID in contacts: |
||
| 951 | # add to player's contacts |
||
| 952 | dipl = self.cmd(obj).getDiplomacyWith(tran, obj, partyID) |
||
| 953 | dipl.contactType = max(dipl.contactType, Const.CONTACT_DYNAMIC) |
||
| 954 | dipl.lastContact = tran.db[Const.OID_UNIVERSE].turn |
||
| 955 | # add to detected owner's contacts |
||
| 956 | owner = tran.db[partyID] |
||
| 957 | assert owner.type in Const.PLAYER_TYPES |
||
| 958 | dipl = self.cmd(obj).getDiplomacyWith(tran, owner, obj.oid) |
||
| 959 | dipl.contactType = max(dipl.contactType, Const.CONTACT_DYNAMIC) |
||
| 960 | dipl.lastContact = tran.db[Const.OID_UNIVERSE].turn |
||
| 961 | |||
| 962 | @public(Const.AL_ADMIN) |
||
| 963 | def processRSRCHPhase(self, tran, obj, data): |
||
| 964 | if not obj.timeEnabled: |
||
| 965 | return |
||
| 966 | # sci pts from allies |
||
| 967 | pts = obj.sciPoints |
||
| 968 | for partnerID in obj.diplomacyRels: |
||
| 969 | if self.cmd(obj).isPactActive(tran, obj, partnerID, Const.PACT_MINOR_SCI_COOP): |
||
| 970 | partner = tran.db[partnerID] |
||
| 971 | pactSpec = Rules.pactDescrs[Const.PACT_MINOR_SCI_COOP] |
||
| 972 | pts += min( |
||
| 973 | int(partner.sciPoints * pactSpec.effectivity), |
||
| 974 | int(obj.sciPoints * pactSpec.effectivity), |
||
| 975 | ) |
||
| 976 | if self.cmd(obj).isPactActive(tran, obj, partnerID, Const.PACT_MAJOR_SCI_COOP): |
||
| 977 | partner = tran.db[partnerID] |
||
| 978 | pactSpec = Rules.pactDescrs[Const.PACT_MAJOR_SCI_COOP] |
||
| 979 | pts += min( |
||
| 980 | int(partner.sciPoints * pactSpec.effectivity), |
||
| 981 | int(obj.sciPoints * pactSpec.effectivity), |
||
| 982 | ) |
||
| 983 | # compute effective sci pts |
||
| 984 | obj.effSciPoints = epts = pts - int(obj.stats.storPop * Rules.sciPtsPerCitizen[obj.techLevel]) |
||
| 985 | index = 0 |
||
| 986 | while epts > 0 and obj.rsrchQueue and index < len(obj.rsrchQueue): |
||
| 987 | item = obj.rsrchQueue[index] |
||
| 988 | tech = Rules.techs[item.techID] |
||
| 989 | # check requirements |
||
| 990 | canResearch = 1 |
||
| 991 | # player has to be a right race |
||
| 992 | if obj.race not in tech.researchRaces: |
||
| 993 | canResearch = 0 |
||
| 994 | for stratRes in tech.researchReqSRes: |
||
| 995 | if obj.stratRes.get(stratRes, 0) < 1 and item.improvement == 1: |
||
| 996 | Utils.sendMessage(tran, obj, Const.MSG_MISSING_STRATRES, Const.OID_NONE, stratRes) |
||
| 997 | canResearch = 0 |
||
| 998 | break |
||
| 999 | for tmpTechID in obj.techs: |
||
| 1000 | if item.techID in Rules.techs[tmpTechID].researchDisables: |
||
| 1001 | canResearch = 0 |
||
| 1002 | Utils.sendMessage(tran, obj, Const.MSG_DELETED_RESEARCH, Const.OID_NONE, item.techID) |
||
| 1003 | del obj.rsrchQueue[index] |
||
| 1004 | index -= 1 |
||
| 1005 | break |
||
| 1006 | if tech.level > obj.techLevel: |
||
| 1007 | canResearch = 0 |
||
| 1008 | Utils.sendMessage(tran, obj, Const.MSG_DELETED_RESEARCH, Const.OID_NONE, item.techID) |
||
| 1009 | del obj.rsrchQueue[index] |
||
| 1010 | index -= 1 |
||
| 1011 | if not canResearch: |
||
| 1012 | index += 1 |
||
| 1013 | continue |
||
| 1014 | researchSci = Utils.getTechRCost(obj, item.techID) |
||
| 1015 | wantSci = min(epts, researchSci - item.currSci, |
||
| 1016 | researchSci / tech.researchTurns) |
||
| 1017 | item.currSci += wantSci |
||
| 1018 | item.changeSci = wantSci |
||
| 1019 | epts -= wantSci |
||
| 1020 | if item.currSci >= researchSci: |
||
| 1021 | del obj.rsrchQueue[index] |
||
| 1022 | obj.techs[item.techID] = item.improvement |
||
| 1023 | # call finish handler |
||
| 1024 | tech = Rules.techs[item.techID] |
||
| 1025 | tech.finishResearchHandler(tran, obj, tech) |
||
| 1026 | Utils.sendMessage(tran, obj, Const.MSG_COMPLETED_RESEARCH, Const.OID_NONE, item.techID) |
||
| 1027 | # update derived attributes of player |
||
| 1028 | self.cmd(obj).update(tran, obj) |
||
| 1029 | # repeat research if required by player |
||
| 1030 | if item.improveToMax == 1 and item.improvement < Rules.techMaxImprovement: |
||
| 1031 | # reinsert the item on the top of the queue |
||
| 1032 | self.cmd(obj).startResearch(tran, obj, item.techID, improveToMax = 1) |
||
| 1033 | idx = len(obj.rsrchQueue) - 1 |
||
| 1034 | self.cmd(obj).moveResearch(tran, obj, idx, - idx) |
||
| 1035 | if epts > 0 and 0: # TODO: remove me |
||
| 1036 | Utils.sendMessage(tran, obj, Const.MSG_WASTED_SCIPTS, Const.OID_NONE, epts) |
||
| 1037 | return |
||
| 1038 | # oops we have negative epts |
||
| 1039 | while epts < 0: |
||
| 1040 | log.debug("Not enought RP", epts, obj.oid) |
||
| 1041 | if obj.rsrchQueue: |
||
| 1042 | item = obj.rsrchQueue[0] |
||
| 1043 | if item.currSci > 0: |
||
| 1044 | wantSci = min(item.currSci, - epts) |
||
| 1045 | item.currSci -= wantSci |
||
| 1046 | item.changeSci = - wantSci |
||
| 1047 | epts += wantSci |
||
| 1048 | if item.currSci == 0: |
||
| 1049 | # remove item from the queue - TODO send message to player |
||
| 1050 | del obj.rsrchQueue[0] |
||
| 1051 | # at this point, epts can be zero |
||
| 1052 | if epts == 0: |
||
| 1053 | log.debug("RP deficit satisfied", obj.oid) |
||
| 1054 | break |
||
| 1055 | # try next project |
||
| 1056 | if obj.rsrchQueue: |
||
| 1057 | continue |
||
| 1058 | # oops we must find technology to degrade |
||
| 1059 | avail = obj.techs.keys() |
||
| 1060 | # do not degrade technologies, which enables others |
||
| 1061 | for techID in obj.techs: |
||
| 1062 | tech = Rules.techs[techID] |
||
| 1063 | for tmpTechID, impr in tech.researchRequires: |
||
| 1064 | if tmpTechID in avail: |
||
| 1065 | avail.remove(tmpTechID) |
||
| 1066 | log.debug("Techs avialable for degradation", avail) |
||
| 1067 | if not avail: |
||
| 1068 | # no technology... |
||
| 1069 | break |
||
| 1070 | # from hight to low IDs |
||
| 1071 | avail.sort() |
||
| 1072 | avail.reverse() |
||
| 1073 | degraded = 0 |
||
| 1074 | for level in range(obj.techLevel, 0, -1): |
||
| 1075 | for techID in avail: |
||
| 1076 | tech = Rules.techs[techID] |
||
| 1077 | # check level |
||
| 1078 | if tech.level != level: |
||
| 1079 | continue |
||
| 1080 | # do not touch starting technologies |
||
| 1081 | if tech.isStarting and obj.techs[techID] <= 3: |
||
| 1082 | continue |
||
| 1083 | # ok we have one to degrade |
||
| 1084 | item = IDataHolder() |
||
| 1085 | item.techID = techID |
||
| 1086 | item.improvement = obj.techs[techID] |
||
| 1087 | item.currSci = Utils.getTechRCost(obj, techID, obj.techs[techID]) |
||
| 1088 | item.changeSci = 0 |
||
| 1089 | item.improveToMax = 0 |
||
| 1090 | item.type = Const.T_RESTASK |
||
| 1091 | obj.rsrchQueue.append(item) |
||
| 1092 | # degrade tech |
||
| 1093 | if obj.techs[techID] == 1: |
||
| 1094 | # TODO send message |
||
| 1095 | del obj.techs[techID] |
||
| 1096 | else: |
||
| 1097 | # TODO send message |
||
| 1098 | obj.techs[techID] -= 1 |
||
| 1099 | if tech.recheckWhenTechLost: |
||
| 1100 | # reset some attributes |
||
| 1101 | plLevel = obj.techLevel |
||
| 1102 | obj.techLevel = 1 |
||
| 1103 | # recheck remaining techs |
||
| 1104 | for level in range(1, plLevel + 1): |
||
| 1105 | for techID in obj.techs: |
||
| 1106 | tech = Rules.techs[techID] |
||
| 1107 | if tech.level != level: |
||
| 1108 | continue |
||
| 1109 | # call finish handler again |
||
| 1110 | tech.finishResearchHandler(tran, obj, tech) |
||
| 1111 | degraded = 1 |
||
| 1112 | break |
||
| 1113 | if degraded: break |
||
| 1114 | |||
| 1115 | return |
||
| 1116 | |||
| 1117 | @public(Const.AL_ADMIN) |
||
| 1118 | def processACTIONPhase(self, tran, obj, data): |
||
| 1119 | return NotImplementedError() |
||
| 1120 | |||
| 1121 | @public(Const.AL_ADMIN) |
||
| 1122 | def processINITPhase(self, tran, obj, data): |
||
| 1123 | if not obj.timeEnabled: |
||
| 1124 | return |
||
| 1125 | # reset stats |
||
| 1126 | obj.stats.storPop = 0 |
||
| 1127 | obj.stats.prodProd = 0 |
||
| 1128 | obj.stats.effProdProd = 0 |
||
| 1129 | obj.stats.prodSci = 0 |
||
| 1130 | obj.stats.effProdSci = 0 |
||
| 1131 | obj.stats.slots = 0 |
||
| 1132 | obj.stats.structs = 0 |
||
| 1133 | obj.stats.planets = 0 |
||
| 1134 | obj.stats.fleetPwr = 0 |
||
| 1135 | obj.stats.fleetSupportProd = 0 |
||
| 1136 | obj.govPwr = Rules.baseGovPwr |
||
| 1137 | # remove old messages |
||
| 1138 | self.cmd(obj).deleteOldMsgs(tran, obj) |
||
| 1139 | # clear fleet upgrade flag |
||
| 1140 | obj.fleetUpgradeInProgress = 0 |
||
| 1141 | # clear production pool |
||
| 1142 | obj.prodIncreasePool = 0 |
||
| 1143 | # clear map |
||
| 1144 | obj.dynamicMap.clear() |
||
| 1145 | # set empty population distribution |
||
| 1146 | obj.tmpPopDistr = {} |
||
| 1147 | # do not process other cmds if time disabled |
||
| 1148 | # clear contacts and delete too old rels |
||
| 1149 | turn = tran.db[Const.OID_UNIVERSE].turn |
||
| 1150 | for objID in obj.diplomacyRels.keys(): |
||
| 1151 | dipl = obj.diplomacyRels[objID] |
||
| 1152 | # reset contact type |
||
| 1153 | obj.diplomacyRels[objID].contactType = Const.CONTACT_NONE |
||
| 1154 | # delete old contacts |
||
| 1155 | if dipl.lastContact + Rules.contactTimeout < turn: |
||
| 1156 | del obj.diplomacyRels[objID] |
||
| 1157 | continue |
||
| 1158 | # lower scan powers in static map |
||
| 1159 | for objID in obj.staticMap: |
||
| 1160 | level = obj.staticMap[objID] |
||
| 1161 | if level > Rules.level3InfoScanPwr: |
||
| 1162 | obj.staticMap[objID] = max( |
||
| 1163 | Rules.level3InfoScanPwr, |
||
| 1164 | int(level * Rules.mapForgetScanPwr), |
||
| 1165 | ) |
||
| 1166 | #@log.debug(obj.oid, "player static map fix", objID, level - obj.staticMap[objID]) |
||
| 1167 | # clear relations change indicator |
||
| 1168 | for partyID in obj.diplomacyRels: |
||
| 1169 | obj.diplomacyRels[partyID].relChng = 0 |
||
| 1170 | # reset science points |
||
| 1171 | obj.sciPoints = 0 |
||
| 1172 | |||
| 1173 | @public(Const.AL_ADMIN) |
||
| 1174 | def processFINALPhase(self, tran, obj, data): |
||
| 1175 | if not obj.timeEnabled: |
||
| 1176 | return |
||
| 1177 | #try/except so that entire final process doesn't break on error in sub-phase |
||
| 1178 | try: |
||
| 1179 | self.cmd(obj).processRSRCHPhase(tran, obj, data) |
||
| 1180 | except: |
||
| 1181 | log.warning('Cannot execute FINAL/RSRCH on %d' % (obj.oid)) |
||
| 1182 | try: |
||
| 1183 | self.cmd(obj).processDIPLPhase(tran, obj, data) |
||
| 1184 | except: |
||
| 1185 | log.warning('Cannot execute FINAL/DIPL on %d' % (obj.oid)) |
||
| 1186 | # efficiency |
||
| 1187 | obj.prodEff = 1.0 |
||
| 1188 | obj.sciEff = 1.0 |
||
| 1189 | if obj.imperator == 1: |
||
| 1190 | log.debug(obj.oid, "Leader bonus") |
||
| 1191 | obj.prodEff += Rules.galLeaderBonus |
||
| 1192 | obj.sciEff += Rules.galLeaderBonus |
||
| 1193 | elif obj.imperator >= 2: |
||
| 1194 | log.debug(obj.oid, "Imperator bonus") |
||
| 1195 | obj.prodEff += Rules.galImperatorBonus |
||
| 1196 | obj.sciEff += Rules.galImperatorBonus |
||
| 1197 | #@log.debug("Fleet upgrade pool", obj.oid, obj.fleetUpgradePool, obj.fleetUpgradeInProgress) |
||
| 1198 | # compute some stats |
||
| 1199 | # TODO remove, RAW SCI PTS represented now obj.stats.prodSci = obj.effSciPoints |
||
| 1200 | obj.stats.planets = len(obj.planets) |
||
| 1201 | # fleet support |
||
| 1202 | #@log.debug("Fleet support", obj.oid, obj.stats.fleetSupportProd, obj.stats.prodProd) |
||
| 1203 | if obj.stats.fleetSupportProd > 0 and obj.stats.prodProd > 0: |
||
| 1204 | # TODO 0.1 shall be dependend on the race / government type |
||
| 1205 | obj.prodEff += min(0.1 - float(obj.stats.fleetSupportProd + obj.fleetUpgradePool * Rules.operProdRatio) / obj.stats.prodProd, 0.0) |
||
| 1206 | # delete non active player |
||
| 1207 | if obj.lastLogin + Rules.playerTimeout < time.time(): |
||
| 1208 | log.message("Resigning inactive player", obj.name, obj.oid) |
||
| 1209 | # TODO send a message? |
||
| 1210 | self.cmd(obj).resign(tran, obj) |
||
| 1211 | # delete nonactive newbie player |
||
| 1212 | if obj.lastLogin + Rules.novicePlayerTimeout < time.time() \ |
||
| 1213 | and len(obj.planets) < 4: |
||
| 1214 | log.message("Resigning inactive novice player", obj.name, obj.oid) |
||
| 1215 | # TODO send a message? |
||
| 1216 | self.cmd(obj).resign(tran, obj) |
||
| 1217 | # acquire government power |
||
| 1218 | if obj.planets: |
||
| 1219 | planet = tran.db[obj.planets[0]] |
||
| 1220 | for slot in planet.slots: |
||
| 1221 | tech = Rules.techs[slot[Const.STRUCT_IDX_TECHID]] |
||
| 1222 | if tech.govPwr > 0 and slot[Const.STRUCT_IDX_STATUS] & Const.STRUCT_STATUS_ON: |
||
| 1223 | eff = Utils.getTechEff(tran, slot[Const.STRUCT_IDX_TECHID], obj.oid) |
||
| 1224 | obj.govPwr = max(int(tech.govPwr * eff * (slot[Const.STRUCT_IDX_OPSTATUS] / 100.0)), obj.govPwr) |
||
| 1225 | # compute government controll range |
||
| 1226 | if not hasattr(obj,"tmpPopDistr"): #when player is force-resigned, tmpPopDistr is unset. This is easiest fix. |
||
| 1227 | obj.tmpPopDistr = {} |
||
| 1228 | ranges = obj.tmpPopDistr.keys() |
||
| 1229 | ranges.sort() |
||
| 1230 | sum = 0 |
||
| 1231 | range = 1 |
||
| 1232 | for range in ranges: |
||
| 1233 | sum += obj.tmpPopDistr[range] |
||
| 1234 | if sum > obj.govPwr: |
||
| 1235 | break |
||
| 1236 | obj.govPwrCtrlRange = max(1, range) |
||
| 1237 | if sum < obj.govPwr and sum > 0: |
||
| 1238 | #@log.debug(obj.oid, "GovPwr compensation", obj.govPwrCtrlRange, obj.govPwr, sum) |
||
| 1239 | obj.govPwrCtrlRange = int(obj.govPwrCtrlRange * obj.govPwr / float(sum)) |
||
| 1240 | #@log.debug(obj.oid, "GovPwr control range", obj.govPwrCtrlRange) |
||
| 1241 | # compute prodBonus and sciBonus |
||
| 1242 | sum = 0 |
||
| 1243 | for range in ranges: |
||
| 1244 | sum += obj.tmpPopDistr[range] |
||
| 1245 | if sum < obj.govPwr and sum > 0: |
||
| 1246 | ratio = float(obj.govPwr - sum) / obj.govPwr |
||
| 1247 | #@log.debug(obj.oid, "SMALL EMPIRE BONUS", ratio, "govPwr", obj.govPwr, "sum", sum) |
||
| 1248 | # TODO let user to define how much to invest into prod and to sci |
||
| 1249 | obj.prodEff += ratio / 2 |
||
| 1250 | obj.sciEff += ratio / 2 |
||
| 1251 | del obj.tmpPopDistr # delete temporary attribute |
||
| 1252 | # increase prod eff from pacts |
||
| 1253 | # CPs from allies |
||
| 1254 | sum = 0 |
||
| 1255 | for partnerID in obj.diplomacyRels: |
||
| 1256 | if self.cmd(obj).isPactActive(tran, obj, partnerID, Const.PACT_MINOR_CP_COOP): |
||
| 1257 | partner = tran.db[partnerID] |
||
| 1258 | pactSpec = Rules.pactDescrs[Const.PACT_MINOR_CP_COOP] |
||
| 1259 | sum += min( |
||
| 1260 | partner.stats.prodProd * pactSpec.effectivity, |
||
| 1261 | obj.stats.prodProd * pactSpec.effectivity, |
||
| 1262 | ) |
||
| 1263 | if self.cmd(obj).isPactActive(tran, obj, partnerID, Const.PACT_MAJOR_CP_COOP): |
||
| 1264 | partner = tran.db[partnerID] |
||
| 1265 | pactSpec = Rules.pactDescrs[Const.PACT_MAJOR_CP_COOP] |
||
| 1266 | sum += min( |
||
| 1267 | partner.stats.prodProd * pactSpec.effectivity, |
||
| 1268 | obj.stats.prodProd * pactSpec.effectivity, |
||
| 1269 | ) |
||
| 1270 | # apply production increase pool |
||
| 1271 | obj.prodIncreasePool += sum |
||
| 1272 | if obj.stats.prodProd > 0: |
||
| 1273 | ratio = (Rules.unusedProdMod * obj.prodIncreasePool) / obj.stats.prodProd |
||
| 1274 | real = min(ratio, math.sqrt(ratio)) |
||
| 1275 | #@log.debug(obj.oid, "Increase production by", ratio, "real", real) |
||
| 1276 | obj.prodEff += real |
||
| 1277 | # clean up prodEff if prodEff < 0 (prevent abuse) |
||
| 1278 | if obj.prodEff < 0: |
||
| 1279 | obj.prodEff = 0.0 |
||
| 1280 | # clean up ship redirections |
||
| 1281 | systems = {} |
||
| 1282 | for planetID in obj.planets: |
||
| 1283 | systems[tran.db[planetID].compOf] = None |
||
| 1284 | for systemID in obj.shipRedirections.keys(): |
||
| 1285 | if systemID not in systems: |
||
| 1286 | del obj.shipRedirections[systemID] |
||
| 1287 | |||
| 1288 | # delete allied bouys |
||
| 1289 | obj.alliedBuoys = {} |
||
| 1290 | |||
| 1291 | # find all allies |
||
| 1292 | for partnerID in obj.diplomacyRels.keys(): |
||
| 1293 | dipl = obj.diplomacyRels[partnerID] |
||
| 1294 | getAllyBuoys = False |
||
| 1295 | getScannerBuoys = False |
||
| 1296 | if dipl.relation >= Const.REL_ALLY_LO: |
||
| 1297 | getAllyBuoys = True |
||
| 1298 | if self.isPactActive(tran, obj, partnerID, Const.PACT_SHARE_SCANNER): |
||
| 1299 | getScannerBuoys = True |
||
| 1300 | if (getAllyBuoys or getScannerBuoys): |
||
| 1301 | partner = tran.db[partnerID] |
||
| 1302 | if hasattr(partner, "buoys"): |
||
| 1303 | for systemID in partner.buoys.keys(): |
||
| 1304 | toAllyBuoy = Const.BUOY_NONE |
||
| 1305 | if getAllyBuoys and partner.buoys[systemID][1] == Const.BUOY_TO_ALLY: |
||
| 1306 | toAllyBuoy = (partner.buoys[systemID][0], Const.BUOY_FROM_ALLY, partner.name) |
||
| 1307 | elif getScannerBuoys and partner.buoys[systemID][1] == Const.BUOY_TO_SCANNERSHARE: |
||
| 1308 | toAllyBuoy = (partner.buoys[systemID][0], Const.BUOY_FROM_ALLY, partner.name) |
||
| 1309 | if toAllyBuoy != Const.BUOY_NONE: |
||
| 1310 | if systemID in obj.alliedBuoys: |
||
| 1311 | obj.alliedBuoys[systemID].append(toAllyBuoy) |
||
| 1312 | else: |
||
| 1313 | obj.alliedBuoys[systemID] = [toAllyBuoy] |
||
| 1314 | return None |
||
| 1315 | |||
| 1316 | ## messaging |
||
| 1317 | def canSendMsg(self, tran, obj, oid, forum): |
||
| 1318 | if forum == "INBOX": |
||
| 1319 | sender = tran.db[oid] |
||
| 1320 | return oid == Const.OID_ADMIN or (oid in obj.diplomacyRels) or \ |
||
| 1321 | (obj.oid in sender.diplomacyRels) |
||
| 1322 | if forum == "OUTBOX": |
||
| 1323 | return obj.oid == oid |
||
| 1324 | return 0 |
||
| 1325 | |||
| 1326 | canSendMsg.public = 0 |
||
| 1327 | |||
| 1328 | @public(Const.AL_OWNER) |
||
| 1329 | def cleanUpMsgs(self, tran, obj): |
||
| 1330 | # get messages |
||
| 1331 | msgs = self.cmd(obj).getMsgs(tran, obj) |
||
| 1332 | # build list of events |
||
| 1333 | delete = [] |
||
| 1334 | for msg in msgs: |
||
| 1335 | if msg["forum"] == "EVENTS": |
||
| 1336 | delete.append(msg["id"]) |
||
| 1337 | # delete |
||
| 1338 | self.cmd(obj).deleteMsgs(tran, obj, delete) |
||
| 1339 | return 1 |
||
| 1340 | |||
| 1341 | @public(Const.AL_OWNER) |
||
| 1342 | def setResolution(self, tran, obj, x, y): |
||
| 1343 | if not hasattr(obj,'clientStats'): |
||
| 1344 | obj.clientStats = {} |
||
| 1345 | obj.clientStats['x'] = x; |
||
| 1346 | obj.clientStats['y'] = y; |
||
| 1347 | |||
| 1348 | def getResolution(self, obj): |
||
| 1349 | if not hasattr(obj,'clientStats'): |
||
| 1350 | obj.clientStats = {} |
||
| 1351 | if obj.clientStats.has_key('x') and obj.clientStats.has_key('y'): |
||
| 1352 | return ("%s,%s" % (obj.clientStats['x'],obj.clientStats['y'])) |
||
| 1353 | else: |
||
| 1354 | return "0,0" |
||
| 1355 | |||
| 1356 | getResolution.public = 0 |
||
| 1357 | |||
| 1358 | @public(Const.AL_FULL) |
||
| 1359 | def addObsoleteTechs(self, tran, player, techID): |
||
| 1360 | # add tech |
||
| 1361 | temp = set([techID]) |
||
| 1362 | player.obsoleteTechs = player.obsoleteTechs | temp |
||
| 1363 | return player.obsoleteTechs |
||
| 1364 | |||
| 1365 | @public(Const.AL_FULL) |
||
| 1366 | def delObsoleteTechs(self, tran, player, techID): |
||
| 1367 | # del tech |
||
| 1368 | temp = set([techID]) |
||
| 1369 | player.obsoleteTechs = player.obsoleteTechs - temp |
||
| 1370 | return player.obsoleteTechs |
||
| 1371 | |||
| 1372 |