Completed
Push — master ( b75f51...3da424 )
by Marek
16s queued 14s
created

ige.ospace.IGalaxy   F

Complexity

Total Complexity 126

Size/Duplication

Total Lines 543
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 436
dl 0
loc 543
rs 2
c 0
b 0
f 0
wmc 126

31 Methods

Rating   Name   Duplication   Size   Complexity  
A IGalaxy.getReferences() 0 2 1
A IGalaxy.getDescription() 0 3 1
A IGalaxy.createSystem() 0 6 1
B IGalaxy.processINITPhase() 0 33 8
B IGalaxy.connectWormHoles() 0 19 8
A IGalaxy.init() 0 25 1
A IGalaxy.enableTime() 0 11 4
A IGalaxy.getFreeStartingPosition() 0 11 4
B IGalaxy.loadDOMNode() 0 21 6
A IGalaxy.processFINALPhase() 0 13 5
A IGalaxy._isEligibleEnableTime() 0 13 5
A IGalaxy.processACTIONPhase() 0 5 2
C IGalaxy.delete() 0 36 9
C IGalaxy.update() 0 25 11
A IGalaxy.processPRODPhase() 0 5 2
B IGalaxy._trickleTimeToPlayers() 0 18 6
A IGalaxy.processSCAN2Phase() 0 12 4
B IGalaxy.loadFromXML() 0 13 6
A IGalaxy.deleteSingle() 0 6 2
A IGalaxy.processBATTLEPhase() 0 5 2
A IGalaxy._firstEnableTime() 0 24 2
A IGalaxy.toggleTime() 0 7 1
A IGalaxy.getPublicInfo() 0 14 1
A IGalaxy.createWormHole() 0 6 1
B IGalaxy.processFINAL2Phase() 0 45 8
A IGalaxy.canSendMsg() 0 6 3
A IGalaxy.canGetMsgs() 0 2 1
A IGalaxy._setupEnvironmentRenegade() 0 11 2
B IGalaxy.setupEnvironment() 0 17 6
A IGalaxy._searchForPlayer() 0 12 4
C IGalaxy._environmentGetVacantPlanets() 0 23 9

How to fix   Complexity   

Complexity

Complex classes like ige.ospace.IGalaxy 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 os.path
22
import time
23
import copy
24
import random
25
26
from xml.dom.minidom import Node, parse
27
28
import ige
29
import IPlayer
30
import IAIPlayer
31
import IAIEDENPlayer
32
import IAIMutantPlayer
33
import IAIPiratePlayer
34
import IAIRenegadePlayer
35
import Const
36
import Rules
37
import Scanner
38
import Utils
39
40
from ige import log
41
from ige.IObject import IObject
42
from ige.IDataHolder import IDataHolder
43
from ige.IObject import public
44
from ISystem import ISystem
45
from Rules import Tech
46
47
48
class IGalaxy(IObject):
49
50
    typeID = Const.T_GALAXY
51
    forums = {"PUBLIC": 112, "NEWS": 112}
52
53
    def init(self, obj):
54
        IObject.init(self, obj)
55
        #
56
        obj.name = ""
57
        obj.owner = Const.OID_NONE
58
        obj.x = 0.0
59
        obj.y = 0.0
60
        obj.radius = 0.0
61
        obj.centerWeight = 250.0
62
        obj.systems = []
63
        obj.startingPos = []
64
        obj.numOfStartPos = 0
65
        obj.timeEnabled = None # none instead of False, to know when first enablement is happening
66
        obj.timePaused = False # this is only used for player-initiated pause, prevents autoenablement
67
        obj.creationTurn = 0
68
        obj.imperator = Const.OID_NONE
69
        obj.description = ""
70
        obj.scenario = Const.SCENARIO_NONE
71
        obj.scenarioData = IDataHolder()
72
        # electromagnetic radiation
73
        obj.emrLevel = 1.0
74
        obj.emrTrend = 1.0
75
        obj.emrTime = 0
76
        # galaxy keeps track of it's own time as well (because of pauses)
77
        obj.galaxyTurn = 0
78
79
    def update(self, tran, obj):
80
        # check existence of all systems
81
        if 0:
82
            for systemID in obj.systems:
83
                if not tran.db.has_key(systemID):
84
                    log.debug("CONSISTENCY - system %d from galaxy %d does not exists" % (systemID, obj.oid))
85
                elif tran.db[systemID].type not in (Const.T_SYSTEM, Const.T_WORMHOLE):
86
                    log.debug("CONSISTENCY - system %d from galaxy %d is not a Const.T_SYSTEM or Const.T_WORMHOLE" % (systemID, obj.oid))
87
        # validate starting positions
88
        for planetID in obj.startingPos[:]:
89
            if not tran.db.has_key(planetID):
90
                log.debug("REMOVING nonexistent obj from start pos", planetID)
91
                obj.startingPos.remove(planetID)
92
                continue
93
            planet = tran.db[planetID]
94
            if planet.type != Const.T_PLANET:
95
                log.debug("REMOVING ??? from start pos", planetID)
96
                obj.startingPos.remove(planetID)
97
        # check compOf
98
        if not tran.db.has_key(obj.compOf) or tran.db[obj.compOf].type != Const.T_UNIVERSE:
99
            log.debug("CONSISTENCY invalid compOf for galaxy", obj.oid, obj.compOf)
100
        # TODO: remove after 0.5.73
101
        if not hasattr(obj, 'galaxyTurn'):
102
            obj.galaxyTurn = 0
103
        obj.timeEnabled = bool(obj.timeEnabled)
104
105
106
    update.public = 0
107
108
    def getReferences(self, tran, obj):
109
        return obj.systems
110
111
    getReferences.public = 0
112
113
    @staticmethod
114
    def getFreeStartingPosition(db, obj):
115
        while 1:
116
            planetID = random.choice(obj.startingPos)
117
            obj.startingPos.remove(planetID)
118
            log.debug('Starting point', planetID)
119
            log.debug('Starting point - owner', db[planetID].owner)
120
            if db[planetID].owner == Const.OID_NONE:
121
                return planetID
122
            if not obj.startingPos:
123
                raise ige.GameException('No free starting point in the galaxy.')
124
125
    @public(Const.AL_ADMIN)
126
    def processINITPhase(self, tran, obj, data):
127
        if not obj.timeEnabled:
128
            return
129
        # compute emr level
130
        turn = tran.db[Const.OID_UNIVERSE].turn
131
        # galaxy keeps track of it's own time (because of pauses)
132
        obj.galaxyTurn += 1
133
        obj.emrTime -= 1
134
        if obj.emrTime <= 0:
135
            modulo = turn % Rules.emrPeriod
136
            for season in Rules.emrSeasons:
137
                if modulo >= season.startTime and modulo <= season.endTime:
138
                    log.debug("EMR - season", season.name)
139
                    obj.emrTrend = Utils.rand(int(season.emrLevelMin * 100), int(season.emrLevelMax * 100) + 1) / 100.0
140
                    obj.emrTime = Utils.rand(Rules.emrMinDuration, Rules.emrMaxDuration)
141
                    log.debug("EMR - trend, time", obj.emrTrend, obj.emrTime)
142
                    message = {
143
                        "sender": "GNC",
144
                        "senderID": obj.oid,
145
                        "forum": "NEWS",
146
                        "data": (obj.oid, Const.MSG_GNC_EMR_FORECAST, obj.oid, turn, (obj.emrTrend, obj.emrTime)),
147
                        "topic": "EVENT",
148
                    }
149
                    self.cmd(obj).sendMsg(tran, obj, message)
150
                    break
151
        elif obj.emrLevel >= obj.emrTrend:
152
            obj.emrLevel -= Utils.rand(1, 6) / 100.0
153
        elif obj.emrLevel <= obj.emrTrend:
154
            obj.emrLevel += Utils.rand(1, 6) / 100.0
155
        # remove old messages
156
        self.cmd(obj).deleteOldMsgs(tran, obj)
157
        return obj.systems
158
159
    @public(Const.AL_ADMIN)
160
    def processPRODPhase(self, tran, obj, data):
161
        if not obj.timeEnabled:
162
            return
163
        return obj.systems
164
165
    @public(Const.AL_ADMIN)
166
    def processACTIONPhase(self, tran, obj, data):
167
        if not obj.timeEnabled:
168
            return
169
        return obj.systems
170
171
    @public(Const.AL_ADMIN)
172
    def processSCAN2Phase(self, tran, obj, data):
173
        # data == True means forced scan (first after generating the galaxy)
174
        if not obj.timeEnabled and not data:
175
            return
176
        # compute scanner for all objects on the map
177
        playerMap = Scanner.computeMap(self, tran, obj)
178
        # distribute map
179
        for playerID, map in playerMap.iteritems():
180
            player = tran.db[playerID]
181
            self.cmd(player).mergeScannerMap(tran, player, map)
182
        return
183
184
    @public(Const.AL_ADMIN)
185
    def processBATTLEPhase(self, tran, obj, data):
186
        if not obj.timeEnabled:
187
            return
188
        return obj.systems
189
190
    @public(Const.AL_ADMIN)
191
    def processFINALPhase(self, tran, obj, data):
192
        if not obj.timeEnabled:
193
            return
194
        # validate starting positions
195
        remove = []
196
        for planetID in obj.startingPos:
197
            planet = tran.db[planetID]
198
            if planet.owner != Const.OID_NONE:
199
                remove.append(planetID)
200
        for planetID in remove:
201
            obj.startingPos.remove(planetID)
202
        return obj.systems
203
204
    @public(Const.AL_ADMIN)
205
    def processFINAL2Phase(self, tran, obj, data):
206
        if not obj.timeEnabled:
207
            return
208
        # save history file
209
        turn = tran.db[Const.OID_UNIVERSE].turn
210
        # TODO: reneable history when it's optimized
211
        if turn % 6 == 0 and False:
212
            log.debug("Saving history for galaxy", obj.oid, obj.name)
213
            fh = open(os.path.join(tran.config.configDir,"history/galaxy%d-%06d.xml" % (obj.oid, turn), "w+"))
214
            print >>fh, '<?xml version="1.0" encoding="UTF-8"?>'
215
            print >>fh, '<history turn="%d" galaxy="%d" name="%s">' % (turn, obj.oid, obj.name)
216
            # save systems and owners
217
            players = {}
218
            print >>fh, '  <systems>'
219
            for systemID in obj.systems:
220
                system = tran.db[systemID]
221
                owners = {}
222
                for planetID in system.planets:
223
                    ownerID = tran.db[planetID].owner
224
                    if ownerID != Const.OID_NONE:
225
                        owners[ownerID] = tran.db[ownerID].name
226
                        players[ownerID] = None
227
                print >>fh, '    <sys x="%.2f" y="%.2f" name="%s" owners="%s"/>' % (
228
                    system.x,
229
                    system.y,
230
                    system.name,
231
                    ",".join(owners.values())
232
                )
233
            print >>fh, '  </systems>'
234
            # stats
235
            print >>fh, '  <stats>'
236
            for playerID in players:
237
                player = tran.db[playerID]
238
                print >>fh, '    <pl name="%s" pop="%d" planets="%d" stucts="%d" cp="%d" mp="%d" rp="%d"/>'% (
239
                    player.name,
240
                    player.stats.storPop,
241
                    player.stats.planets,
242
                    player.stats.structs,
243
                    player.stats.prodProd,
244
                    player.stats.fleetPwr,
245
                    player.stats.prodSci,
246
                )
247
            print >>fh, '  </stats>'
248
            print >>fh, '</history>'
249
250
251
    @public(Const.AL_ADMIN)
252
    def loadFromXML(self, tran, obj, file, galaxyType, x, y, name):
253
        log.message('IGalaxy', 'Parsing XML file...')
254
        dom = parse(os.path.join('data', file))
255
        log.message('IGalaxy', 'XML file parsed.')
256
        assert dom.documentElement.tagName == 'universe'
257
        for node in dom.documentElement.childNodes:
258
            if node.nodeType == Node.ELEMENT_NODE and node.tagName == 'galaxy':
259
                if node.getAttribute('galaxyType') == galaxyType:
260
                    self.loadDOMNode(tran, obj, node, x, y, name)
261
                    self.connectWormHoles(tran, obj)
262
                    return Const.SUCC
263
        raise ige.GameException('No such id %s in resource' % galaxyType)
264
265
    def loadDOMNode(self, tran, obj, node, x, y, name):
266
        obj.name = name
267
        obj.x = float(x)
268
        obj.y = float(y)
269
        xoff = x - float(node.getAttribute('x'))
270
        yoff = y - float(node.getAttribute('y'))
271
        obj.creationTurn = tran.db[Const.OID_UNIVERSE].turn
272
        for elem in node.childNodes:
273
            if elem.nodeType == Node.ELEMENT_NODE:
274
                name = elem.tagName
275
                if name == 'properties':
276
                    self.loadDOMAttrs(obj, elem)
277
                elif name == 'system':
278
                    system = tran.db[self.createSystem(tran, obj)]
279
                    self.cmd(system).loadDOMNode(tran, system, xoff, yoff, elem)
280
                elif name == 'hole':
281
                    wormHole = tran.db[self.createWormHole(tran, obj)]
282
                    self.cmd(wormHole).loadDOMNode(tran, wormHole, xoff, yoff, elem)
283
                else:
284
                    raise ige.GameException('Unknown element %s' % name)
285
        return Const.SUCC
286
287
    def connectWormHoles(self, tran, obj):
288
        wormHoles = {}
289
        for holeID in obj.systems:
290
            wormHole = tran.db[holeID]
291
            if wormHole.type == Const.T_WORMHOLE:
292
                wormHoles[wormHole.name] = holeID
293
294
        for holeID in obj.systems:
295
            wormHole = tran.db[holeID]
296
            if wormHole.type != Const.T_WORMHOLE:
297
                continue
298
            if len(wormHole.destination) == 0:
299
                raise ige.GameException('Wrong WormHole(%d) definition' % holeID)
300
            if wormHole.destination == wormHole.name:
301
                raise ige.GameException('Same destination as position for WormHole(%d)' % holeID)
302
            destinationOid = wormHoles[wormHole.destination]
303
            if destinationOid == Const.OID_NONE:
304
                raise ige.GameException('WormHole(%d) has wrong destination ''%s''' % (holeID, wormHole.destination))
305
            wormHole.destinationOid = destinationOid
306
307
    def createSystem(self, tran, obj):
308
        system = self.new(Const.T_SYSTEM)
309
        system.compOf = obj.oid
310
        oid = tran.db.create(system)
311
        obj.systems.append(oid)
312
        return oid
313
314
    def createWormHole(self, tran, galaxy):
315
        hole = self.new(Const.T_WORMHOLE)
316
        hole.compOf = galaxy.oid
317
        oid = tran.db.create(hole)
318
        galaxy.systems.append(oid)
319
        return oid
320
321
    @public(Const.AL_OWNER)
322
    def toggleTime(self, tran, obj):
323
        player = tran.db[obj.owner]
324
        obj.timeEnabled = not obj.timeEnabled
325
        obj.timePaused = not obj.timeEnabled
326
        self._trickleTimeToPlayers(tran, obj)
327
        return obj.timeEnabled
328
329
    def _trickleTimeToPlayers(self, tran, obj):
330
        # enable time for players
331
        playerIDs = set()
332
        for systemID in obj.systems:
333
            system = tran.db[systemID]
334
            for planetID in system.planets:
335
                planet = tran.db[planetID]
336
                playerIDs.add(planet.owner)
337
        playerIDs.discard(Const.OID_NONE)
338
        for playerID in playerIDs:
339
            player = tran.db[playerID]
340
            if player.timeEnabled != obj.timeEnabled:
341
                player.timeEnabled = obj.timeEnabled
342
                player.lastLogin = time.time()
343
                if player.timeEnabled:
344
                    Utils.sendMessage(tran, player, Const.MSG_ENABLED_TIME, player.oid, None)
345
                else:
346
                    Utils.sendMessage(tran, player, Const.MSG_DISABLED_TIME, player.oid, None)
347
348
    def _isEligibleEnableTime(self, tran, obj):
349
        if obj.timeEnabled or obj.timePaused:
350
            # explicitly paused galaxy needs to be explicitly unpaused
351
            return False
352
        # We have to give players some time to prepare
353
        # (as they might be waiting for very long time for this galaxy to be created).
354
        currentTurn = tran.db[Const.OID_UNIVERSE].turn
355
        if obj.creationTurn + Rules.galaxyStartDelay <= currentTurn:
356
            log.debug("Time to prepare has passed", obj.creationTurn, currentTurn)
357
            return True
358
        elif obj.scenario == Const.SCENARIO_SINGLE:
359
            return True
360
        return False
361
362
    def _firstEnableTime(self, tran, obj):
363
        # spawn rebel player on all vacant starting positions
364
        for positionID in copy.copy(obj.startingPos):
365
            obj.startingPos.remove(positionID)
366
            # create new player
367
            log.debug("Creating new Rebel player", Const.T_AIPLAYER)
368
            player = self.new(Const.T_AIPLAYER)
369
            self.cmd(player).register(tran, player, obj.oid)
370
            player.galaxy = obj.oid
371
            playerID = player.oid
372
            # TODO tweak more planet's attrs
373
            planet = tran.db[positionID]
374
            self.cmd(planet).changeOwner(tran, planet, playerID, 1)
375
            IAIPlayer.IAIPlayer.setStartingTechnologies(player)
376
            # fleet
377
            # add basic ships designs
378
            # add small fleet
379
            system = tran.db[planet.compOf]
380
            IAIPlayer.IAIPlayer.setStartingShipDesigns(player)
381
            IAIPlayer.IAIPlayer.setStartingPlanet(tran, playerID, planet)
382
            IAIPlayer.IAIPlayer.setStartingFleet(tran, playerID, system)
383
            system.scannerPwrs[playerID] = Rules.startingScannerPwr
384
        # do scanner evaluation because of all new players
385
        self.cmd(obj).processSCAN2Phase(tran, obj, None)
386
387
    @public(Const.AL_ADMIN)
388
    def enableTime(self, tran, obj, force = False):
389
        log.debug('IGalaxy', 'Checking for time...')
390
        if not force and not self._isEligibleEnableTime(tran, obj):
391
            return
392
        if obj.timeEnabled is None:
393
            self._firstEnableTime(tran, obj)
394
        # ok, enable time
395
        log.message('IGalaxy', 'Enabling time for', obj.oid)
396
        obj.timeEnabled = True
397
        self._trickleTimeToPlayers(tran, obj)
398
399
    @public(Const.AL_OWNER)
400
    def deleteSingle(self, tran, obj):
401
        if obj.scenario != Const.SCENARIO_SINGLE:
402
            raise ige.GameException('Only Single Player galaxies can be deleted this way')
403
        log.debug(obj.oid, "GALAXY - singleplayer delete")
404
        self.delete(tran, obj)
405
406
    @public(Const.AL_ADMIN)
407
    def delete(self, tran, obj):
408
        log.debug(obj.oid, "GALAXY - delete")
409
        universe = tran.db[Const.OID_UNIVERSE]
410
        # delete systems and planets
411
        for systemID in obj.systems:
412
            log.debug("Deleting system", systemID)
413
            system = tran.db[systemID]
414
            log.debug("-- planets", system.planets)
415
            log.debug("-- fleets", system.fleets, system.closeFleets)
416
            for planetID in system.planets[:]:
417
                planet = tran.db[planetID]
418
                self.cmd(planet).changeOwner(tran, planet, Const.OID_NONE, force = 1)
419
                del tran.db[planetID]
420
            for fleetID in system.closeFleets[:]:
421
                fleet = tran.db[fleetID]
422
                # this will modify system fleet and closeFleets attrs
423
                self.cmd(fleet).disbandFleet(tran, fleet)
424
            del tran.db[systemID]
425
        # delete all remaining fleets
426
        for playerID in universe.players[:]:
427
            player = tran.db[playerID]
428
            if obj.oid != player.galaxy:
429
                continue
430
            if player.fleets:
431
                log.debug("Player %d has still fleets" % playerID, player.name, player.fleets)
432
                for fleetID in player.fleets:
433
                    fleet = tran.db[fleetID]
434
                    log.debug("Fleet NOT DELETED:", fleet)
435
            if player.planets:
436
                log.debug("Player %d has still planets" % playerID, player.name, player.planets)
437
            self.cmd(player).delete(tran, player)
438
        # remove this galaxy from the list of the galaxies
439
        tran.db[Const.OID_UNIVERSE].galaxies.remove(obj.oid)
440
        del tran.db[obj.oid]
441
        return 1
442
443
    @public(Const.AL_NONE)
444
    def getPublicInfo(self, tran, obj):
445
        result = IDataHolder()
446
        result.oid = obj.oid
447
        result.x = obj.x
448
        result.y = obj.y
449
        result.radius = obj.radius
450
        result.type = obj.type
451
        result.name = obj.name
452
        result.emrLevel = obj.emrLevel
453
        result.scenario = obj.scenario
454
        result.scenarioData = obj.scenarioData
455
        result.timeEnabled = obj.timeEnabled
456
        return result
457
458
    @public(Const.AL_NONE)
459
    def getDescription(self,obj):
460
        return obj.description
461
462
    def _environmentGetVacantPlanets(self, tran, obj):
463
        vacantPlanets = {}
464
        for systemID in obj.systems:
465
            system = tran.db[systemID]
466
            for planetID in system.planets:
467
                planet = tran.db[planetID]
468
                if planet.owner != Const.OID_NONE:
469
                    continue
470
                if planet.plStratRes in (Const.SR_TL1A, Const.SR_TL1B):
471
                    playerType = Const.T_AIRENPLAYER
472
                elif planet.plStratRes in (Const.SR_TL3A, Const.SR_TL3B, Const.SR_TL3C):
473
                    playerType = Const.T_AIPIRPLAYER
474
                elif planet.plStratRes in (Const.SR_TL5A, Const.SR_TL5B, Const.SR_TL5C):
475
                    playerType = Const.T_AIEDENPLAYER
476
                elif planet.plDisease != 0:
477
                    playerType = Const.T_AIMUTPLAYER
478
                else:
479
                    continue
480
                try:
481
                    vacantPlanets[playerType].append(planetID)
482
                except KeyError:
483
                    vacantPlanets[playerType] = [planetID]
484
        return vacantPlanets
485
486
    def _searchForPlayer(self, tran, obj, playerType):
487
        universe = tran.db[Const.OID_UNIVERSE]
488
        for playerID in universe.players:
489
            player = tran.db[playerID]
490
            if obj.oid == player.galaxy and player.type == playerType:
491
                return player
492
        # create new player
493
        log.debug("Creating new player", playerType)
494
        player = self.new(playerType)
495
        self.cmd(player).register(tran, player, obj.oid)
496
        player.galaxy = obj.oid
497
        return player
498
499
    def _setupEnvironmentRenegade(self, tran, obj, vacantPlanets):
500
        renType = Const.T_AIRENPLAYER
501
        planets = vacantPlanets.pop(renType)
502
        for planetID in planets:
503
            planet = tran.db[planetID]
504
            log.debug("Creating new Renegade")
505
            player = self.new(renType)
506
            self.cmd(player).register(tran, player, obj.oid)
507
            player.galaxy = obj.oid
508
            self.cmd(planet).changeOwner(tran, planet, player.oid, 1)
509
            IAIRenegadePlayer.IAIRenegadePlayer.setStartingPlanet(tran, planet)
510
511
    @public(Const.AL_ADMIN)
512
    def setupEnvironment(self, tran, obj):
513
        vacantPlanets = self._environmentGetVacantPlanets(tran, obj)
514
        self._setupEnvironmentRenegade(tran, obj, vacantPlanets)
515
        # iterate over types, create players if needed (it should be) and fill in vacant planets
516
        for playerType in vacantPlanets:
517
            player = self._searchForPlayer(tran, obj, playerType)
518
            # now we have a player, let's iterate over vacant planets and set them up
519
            for planetID in vacantPlanets[playerType]:
520
                planet = tran.db[planetID]
521
                self.cmd(planet).changeOwner(tran, planet, player.oid, 1)
522
                if playerType == Const.T_AIPIRPLAYER:
523
                    IAIPiratePlayer.IAIPiratePlayer.setStartingPlanet(tran, planet)
524
                elif playerType == Const.T_AIEDENPLAYER:
525
                    IAIEDENPlayer.IAIEDENPlayer.setStartingPlanet(tran, planet)
526
                elif playerType == Const.T_AIMUTPLAYER:
527
                    IAIMutantPlayer.IAIMutantPlayer.setStartingPlanet(tran, planet)
528
529
    ## messaging
530
    def canGetMsgs(self, tran, obj, oid):
531
        return 1
532
533
    canGetMsgs.public = 0
534
535
    def canSendMsg(self, tran, obj, oid, forum):
536
        if forum == "PUBLIC":
537
            return 1
538
        elif forum == "NEWS":
539
            return 1
540
        return 0
541
542
    canSendMsg.public = 0
543