ige.ospace.IUniverse.IUniverse.processINITPhase()   F
last analyzed

Complexity

Conditions 20

Size

Total Lines 64
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 47
nop 4
dl 0
loc 64
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like ige.ospace.IUniverse.IUniverse.processINITPhase() 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 os
23
import random
24
import tempfile
25
import time
26
27
import ige
28
import ige.version
29
30
import Const
31
import GalaxyGenerator
32
import Rules
33
34
from ige import log
35
from ige.IObject import IObject, public
36
from ige.IDataHolder import IDataHolder
37
from ige import GameException, NoSuchObjectException
38
39
class IUniverse(IObject):
40
41
    typeID = Const.T_UNIVERSE
42
43
    forums = {
44
        # Official English forums
45
        "NEWS": 112, "PUBLIC": 112,
46
    }
47
48
    def init(self, obj):
49
        IObject.init(self, obj)
50
        #
51
        obj.name = "Outer Space"
52
        obj.turn = 0
53
        obj.owner = Const.OID_ADMIN
54
        obj.galaxies = []
55
        obj.players = []
56
        obj.waitingPlayers = []
57
        # auto loading of galaxies
58
        obj.galX = 0.0
59
        obj.galY = 0.0
60
        obj.galXStep = 100.0
61
        obj.galYStep = 100.0
62
        obj.galFilename = ''
63
        obj.galID = ''
64
65
    @public(Const.AL_NONE)
66
    def getIntroInfo(self, tran, obj):
67
        result = IDataHolder()
68
        result.cid = tran.cid
69
        result.turn = obj.turn
70
        result.serverTime = time.time()
71
        result.version = ige.version.version
72
        return result
73
74
    @public(Const.AL_NONE)
75
    def multiGetInfo(self, tran, obj, objIDs):
76
        result = []
77
        messages = []
78
        # perform getInfo or getPublicInfo command for each objID
79
        for objID in objIDs:
80
            try:
81
                tmpObj, tmpMsgs = tran.gameMngr.execute(tran.session.sid, 'getInfo', objID)
82
            except ige.SecurityException:
83
                tmpObj, tmpMsgs = tran.gameMngr.execute(tran.session.sid, 'getPublicInfo', objID)
84
            except ige.NoSuchObjectException:
85
                tmpObj = None
86
            if tmpObj:
87
                result.append(tmpObj)
88
                messages.extend(tmpMsgs)
89
        # restore messages
90
        for msgID, data in messages:
91
            tran.session.messages[msgID] = data
92
        return result
93
94
    @public(Const.AL_NONE)
95
    def multiGetMsgs(self, tran, obj, mailboxes):
96
        result = []
97
        messages = []
98
        # perform getMsgs
99
        for objID, lastID in mailboxes:
100
            data, tmpMsgs = tran.gameMngr.execute(tran.session.sid, 'getMsgs', objID, lastID)
101
            result.append((objID, data))
102
            messages.extend(tmpMsgs)
103
        # restore messages
104
        for msgID, data in messages:
105
            tran.session.messages[msgID] = data
106
        return result
107
108
    @public(Const.AL_ADMIN)
109
    def createGalaxy(self, tran, obj):
110
        galaxy = self.new(Const.T_GALAXY)
111
        galaxy.compOf = obj.oid
112
        oid = tran.db.create(galaxy)
113
        obj.galaxies.append(oid)
114
        return oid
115
116
    @public(Const.AL_ADMIN)
117
    def processINITPhase(self, tran, obj, data):
118
        for galaxyID in obj.galaxies:
119
            galaxy = tran.db[galaxyID]
120
            self.cmd(galaxy).enableTime(tran, galaxy)
121
        try:
122
            ## find active/inactive pacts
123
            # set all active/on pacts to active
124
            for playerID in obj.players:
125
                #@log.debug("Processing player", playerID)
126
                player = tran.db[playerID]
127
                for partyID in player.diplomacyRels:
128
                    #@log.debug("Processing party", partyID)
129
                    dipl = player.diplomacyRels[partyID]
130
                    for pactID in dipl.pacts.keys():
131
                        if pactID not in Rules.pactDescrs:
132
                            # this is invalid pactID
133
                            log.debug(playerID, "Deleting invalid pact with", partyID, "pact", pactID)
134
                            del dipl.pacts[pactID]
135
                            continue
136
                        if dipl.pacts[pactID][0] > Const.PACT_OFF:
137
                            dipl.pacts[pactID][0] = Const.PACT_ACTIVE
138
            # inactivate all pact that does not satisfy conditions
139
            changed = 1
140
            defaultPact = [Const.PACT_OFF]
141
            while changed:
142
                changed = 0
143
                log.debug("Inactivate pacts iteration starting...")
144
                for playerID in obj.players:
145
                    #@log.debug("Processing player", playerID)
146
                    player = tran.db[playerID]
147
                    # all parties of a player
148
                    for partyID in player.diplomacyRels:
149
                        #@log.debug("Processing party", partyID)
150
                        party = tran.db[partyID]
151
                        partyDipl = party.diplomacyRels.get(playerID, None)
152
                        if not partyDipl:
153
                            continue
154
                        dipl = player.diplomacyRels[partyID]
155
                        # correct relations
156
                        dipl.relation = min(dipl.relation, partyDipl.relation)
157
                        # all pacts with party
158
                        for pactID in dipl.pacts:
159
                            # check validity interval
160
                            pactSpec = Rules.pactDescrs[pactID]
161
                            if (dipl.relation < pactSpec.validityInterval[0] or \
162
                                dipl.relation > pactSpec.validityInterval[1]) and \
163
                                dipl.pacts[pactID][0] == Const.PACT_ACTIVE:
164
                                #@log.debug("Inactivating pact (validity interval)", playerID, pactID)
165
                                dipl.pacts[pactID][0] = Const.PACT_INACTIVE
166
                                changed = 1
167
                            # check conditions for the pact if pact is active
168
                            if dipl.pacts[pactID][0] == Const.PACT_ACTIVE:
169
                                for condPactID in dipl.pacts[pactID][1:]:
170
                                    #@log.debug("Checking", playerID, pactID, "against", partyID, condPactID)
171
                                    if partyDipl and partyDipl.pacts.get(condPactID, defaultPact)[0] != Const.PACT_ACTIVE:
172
                                        dipl.pacts[pactID][0] = Const.PACT_INACTIVE
173
                                        changed = 1
174
        except Exception:
175
            log.warning("Cannot process diplomacy initialization")
176
        # TODO - send notifications if pacts are changed
177
        # remove old messages
178
        self.cmd(obj).deleteOldMsgs(tran, obj)
179
        return obj.players[:] + [Const.OID_NATURE]
180
181
    @public(Const.AL_ADMIN)
182
    def processPRODPhase(self, tran, obj, data):
183
        raise NotImplementedError()
184
185
    @public(Const.AL_ADMIN)
186
    def processACTIONPhase(self, tran, obj, data):
187
        raise NotImplementedError()
188
189
    @public(Const.AL_ADMIN)
190
    def processBATTLEPhase(self, tran, obj, data):
191
        raise NotImplementedError()
192
193
    @public(Const.AL_ADMIN)
194
    def processFINALPhase(self, tran, obj, data):
195
        return obj.players[:] + [Const.OID_NATURE]
196
197
    @public(Const.AL_ADMIN)
198
    def processFINAL2Phase(self, tran, obj, data):
199
        # distribute stats to contacts
200
        for playerID in obj.players:
201
            player = tran.db[playerID]
202
            for partyID in player.diplomacyRels:
203
                dipl = player.diplomacyRels[partyID]
204
                if dipl.contactType > Const.CONTACT_NONE and tran.db.has_key(partyID):
205
                    dipl.stats = tran.db[partyID].stats
206
                else:
207
                    dipl.stats = None
208
209
        # process each galaxy winning checking routines
210
        for galaxyID in obj.galaxies:
211
            log.debug("Voting for galaxy", galaxyID)
212
            galaxy = tran.db[galaxyID]
213
            if not galaxy.timeEnabled:
214
                # skip this galaxy
215
                continue
216
            if galaxy.scenario == Const.SCENARIO_OUTERSPACE:
217
                self.processScenarioOuterspace(tran, obj, galaxy)
218
                continue
219
            elif galaxy.scenario == Const.SCENARIO_SINGLE:
220
                self.processScenarioSingle(tran, obj, galaxy)
221
                continue
222
            elif galaxy.scenario == Const.SCENARIO_COOP:
223
                self.processScenarioCoop(tran, obj, galaxy)
224
                continue
225
            elif galaxy.scenario == Const.SCENARIO_BRAWL:
226
                self.processScenarioBrawl(tran, obj, galaxy)
227
                continue
228
229
        # collect mailboxes
230
        used = [self.cmd(obj).getMailboxName(tran, obj)]
231
        for galaxyID in obj.galaxies:
232
            tmpObj = tran.db[galaxyID]
233
            used.append(self.cmd(tmpObj).getMailboxName(tran, tmpObj))
234
        for playerID in obj.players:
235
            tmpObj = tran.db[playerID]
236
            used.append(self.cmd(tmpObj).getMailboxName(tran, tmpObj))
237
        # trash unused mailboxes
238
        tran.gameMngr.msgMngr.trashUnusedMailboxes(used)
239
        return obj.galaxies
240
241
    def _announceImperatorVoting(self, tran, obj, galaxy):
242
        message = {
243
            "sender": "GNC",
244
            "senderID": galaxy.oid,
245
            "forum": "NEWS",
246
            "data": (galaxy.oid, Const.MSG_GNC_VOTING_COMING, galaxy.oid, obj.turn, Rules.voteForImpAnnounceOffset),
247
            "topic": "EVENT",
248
        }
249
        self.cmd(galaxy).sendMsg(tran, galaxy, message)
250
251
    def _countVotes(self, tran, obj, galaxy):
252
        VALID_TYPES = [Const.T_PLAYER, Const.T_AIPLAYER]
253
        log.debug("Voting for galaxy", galaxy.oid)
254
        # compute votes
255
        votesByName = {}
256
        votesByID = {}
257
        voterNames = {}
258
        for playerID in obj.players:
259
            player = tran.db[playerID]
260
            if galaxy.oid != player.galaxy:
261
                continue
262
            if player.type not in VALID_TYPES:
263
                continue
264
            # add to sum
265
            log.debug(playerID, "votes for", player.voteFor, "with votes", player.stats.slots)
266
267
            tmpPlayer = tran.db.get(player.voteFor, None)
268
            if not tmpPlayer or tmpPlayer.type not in VALID_TYPES:
269
                # reset vote
270
                player.voteFor = Const.OID_NONE
271
                votedName = None
272
            else:
273
                votedName = tmpPlayer.name
274
275
            # count votes
276
            votesByName[votedName] = votesByName.get(votedName, 0) + player.stats.slots
277
            votesByID[player.voteFor] = votesByID.get(player.voteFor, 0) + player.stats.slots
278
            try:
279
                voterNames[votedName].append(player.name)
280
            except KeyError:
281
                voterNames[votedName] = [player.name]
282
        return votesByName, votesByID, voterNames
283
284
    def _processElectedImperator(self, tran, obj, galaxy, imperator, votesByName, voterNames):
285
        # 2 imperator, 3+ winner
286
        imperator.imperator = max(2, imperator.imperator + 1)
287
        if galaxy.imperator != Const.OID_NONE and galaxy.imperator != imperator.oid:
288
            tran.db[galaxy.imperator].imperator = 0
289
        galaxy.imperator = imperator.oid
290
        # send message
291
        message = {
292
            "sender": "GNC",
293
            "senderID": galaxy.oid,
294
            "forum": "NEWS",
295
            "data": (galaxy.oid, Const.MSG_GNC_VOTING_IMPERATOR, galaxy.oid, obj.turn, (imperator.name, (votesByName, voterNames))),
296
            "topic": "EVENT",
297
        }
298
        self.cmd(galaxy).sendMsg(tran, galaxy, message)
299
300
    def _processElectedLeader(self, tran, obj, galaxy, leader, votesByName, voterNames):
301
        leader.imperator = 1
302
        if galaxy.imperator != Const.OID_NONE and galaxy.imperator != leader.oid:
303
            tran.db[galaxy.imperator].imperator = 0
304
        galaxy.imperator = leader.oid
305
        # send message
306
        message = {
307
            "sender": "GNC",
308
            "senderID": galaxy.oid,
309
            "forum": "NEWS",
310
            "data": (galaxy.oid, Const.MSG_GNC_VOTING_LEADER, galaxy.oid, obj.turn, (leader.name, (votesByName, voterNames))),
311
            "topic": "EVENT",
312
        }
313
        self.cmd(galaxy).sendMsg(tran, galaxy, message)
314
315
    def _processNoWinner(self, tran, obj, galaxy, votesByName, voterNames):
316
        # nobody wins
317
        if galaxy.imperator != Const.OID_NONE:
318
            tran.db[galaxy.imperator].imperator = 0
319
            galaxy.imperator = Const.OID_NONE
320
        message = {
321
            "sender": "GNC",
322
            "senderID": galaxy.oid,
323
            "forum": "NEWS",
324
            "data": (galaxy.oid, Const.MSG_GNC_VOTING_NOWINNER, galaxy.oid, obj.turn, ((votesByName, voterNames),)),
325
            "topic": "EVENT",
326
        }
327
        self.cmd(galaxy).sendMsg(tran, galaxy, message)
328
329
    def _processImperatorVoting(self, tran, obj, galaxy):
330
        votesByName, votesByID, voterNames = self._countVotes(tran, obj, galaxy)
331
        # check winner
332
        totalVotes = sum(votesByID.values())
333
        nominated = sorted(votesByID, key=lambda a: votesByID[a], reverse = True)
334
        winnerID = Const.OID_NONE
335
        # Const.OID_NONE is not valid target
336
        if Const.OID_NONE in nominated:
337
            nominated.remove(Const.OID_NONE)
338
        # check winner
339
        try:
340
            winnerID = nominated[0]
341
            winner = tran.db[winnerID]
342
            if float(votesByID[winnerID]) / totalVotes >= Rules.ratioNeededForImp:
343
                self._processElectedImperator(tran, obj, galaxy, winner, votesByName, voterNames)
344
            elif len(nominated) > 1 and votesByID[winnerID] == votesByID[nominated[1]]:
345
                # oh no, more than one winner
346
                self._processNoWinner(tran, obj, galaxy, votesByName, voterNames)
347
            else:
348
                self._processElectedLeader(tran, obj, galaxy, winner, votesByName, voterNames)
349
        except IndexError:
350
            # no nominations?
351
            self._processNoWinner(tran, obj, galaxy, votesByName, voterNames)
352
353
    def _autoFinishOuterspace(self, tran, obj, galaxy):
354
        if tran.gameMngr.config.server.mode != "normal":
355
            # check autoend conditions, but only in normal mode
356
            # development mode does not end galaxies
357
            return
358
        for playerID in obj.players:
359
            player = tran.db[playerID]
360
            if galaxy.oid != player.galaxy:
361
                continue
362
            if player.type == Const.T_PIRPLAYER:
363
                piratePlayer = True
364
                activePlayerCount += 1
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable activePlayerCount does not seem to be defined.
Loading history...
365
                continue
366
            if player.type != Const.T_PLAYER:
367
                continue
368
            selfName = player.name
369
            activePlayerCount += 1
370
371
        if activePlayerCount <= 1:
372
            log.message("AUTO FINISHING GALAXY", galaxy.oid)
373
            if activePlayerCount == 0:
374
                self.finishGalaxyAutomated(tran, obj, galaxy.oid, ["The galaxy was ended with no active players."])
375
            elif piratePlayer: #if the pirate is still alive, then he must be the winner.
0 ignored issues
show
introduced by
The variable piratePlayer does not seem to be defined in case the for loop on line 358 is not entered. Are you sure this can never be the case?
Loading history...
376
                self.finishGalaxyAutomated(tran, obj, galaxy.oid, ["The galaxy was automatically ended with the Pirate as a winner!"])
377
            elif selfName: #if there is only one player, selfName must be themselves if it isn't null
0 ignored issues
show
introduced by
The variable selfName does not seem to be defined for all execution paths.
Loading history...
378
                self.finishGalaxyAutomated(tran, obj, galaxy.oid, ["The galaxy was automatically ended with commander %s as the only remaining player." % selfName])
379
380
    def processScenarioOuterspace(self, tran, obj, galaxy):
381
        if (galaxy.galaxyTurn + Rules.voteForImpAnnounceOffset) % Rules.voteForImpPeriod == 0:
382
            self._announceImperatorVoting(tran, obj, galaxy)
383
        if galaxy.galaxyTurn % Rules.voteForImpPeriod == 0:
384
            # voting
385
            self._processImperatorVoting(tran, obj, galaxy)
386
        self._autoFinishOuterspace(tran, obj, galaxy)
387
388
    def processScenarioSingle(self, tran, obj, galaxy):
389
        """ If owner of the galaxy is not present anymore, remove it.
390
        There are no winning conditions right now.
391
        """
392
        try:
393
            player = tran.db[galaxy.owner]
394
            if galaxy.oid == player.galaxy:
395
                # all is well
396
                return True
397
            # new player has nothing to do with this galaxy
398
        except NoSuchObjectException:
399
            # there is no object with owner OID
400
            pass
401
        except AttributeError:
402
            # there is object with owner OID, but it's not player object
403
            pass
404
        # let's clean it
405
        if tran.gameMngr.config.server.mode == "normal":
406
            self.cmd(galaxy).delete(tran, galaxy)
407
408
    def processScenarioCoop(self, tran, obj, galaxy):
409
        ENEMIES = [Const.T_AIEDENPLAYER, Const.T_AIMUTPLAYER, Const.T_AIPIRPLAYER]
410
        clear = True
411
        players = []
412
        for playerID in obj.players:
413
            player = tran.db[playerID]
414
            if galaxy.oid != player.galaxy:
415
                continue
416
            if player.type in ENEMIES:
417
                clear = False
418
                continue
419
            if player.type == Const.T_AIPLAYER:
420
                players.append(player)
421
            if player.type != Const.T_PLAYER:
422
                # skip non-regular players
423
                continue
424
            players.append(player)
425
        if not len(players):
426
            # no player left? what a strange state! Let's delete it quick!
427
            self.cmd(galaxy).delete(tran, galaxy)
428
            return False
429
        if not clear:
430
            # struggle is ongoing
431
            return True
432
        # no enemies left, let's celebrate by sending a message, and finish the galaxy
433
        victors = map(lambda x: x.name, players)
434
        message = {
435
            "sender": "Galaxy %s" % galaxy.name,
436
            "senderID": tran.cid,
437
            "forum": "NEWS",
438
            "data": (galaxy.oid, Const.MSG_GNC_GALAXY_COOP_WON, galaxy.oid, obj.turn, (galaxy.name, victors)),
439
            "topic": "EVENT",
440
        }
441
        self.cmd(obj).sendMsg(tran, obj, message)
442
        self.cmd(galaxy).delete(tran, galaxy)
443
444
    def processScenarioBrawl(self, tran, obj, galaxy):
445
        players = []
446
        for playerID in obj.players:
447
            player = tran.db[playerID]
448
            if galaxy.oid != player.galaxy:
449
                continue
450
            if player.type != Const.T_PLAYER:
451
                # skip non-regular players
452
                continue
453
            players.append(player)
454
        if len(players) > 1:
455
            # fight continues
456
            return True
457
        if not len(players):
458
            # no player left? what a strange state! Let's delete it quick!
459
            self.cmd(galaxy).delete(tran, galaxy)
460
            return False
461
        # last man standing! Let's send announcement, and change the galaxy
462
        # to Const.SCENARIO_SINGLE for winner to enjoy it (and pause / finish at will)
463
        winner = players[0]
464
        message = {
465
            "sender": "Galaxy %s" % galaxy.name,
466
            "senderID": tran.cid,
467
            "forum": "NEWS",
468
            "data": (galaxy.oid, Const.MSG_GNC_GALAXY_BRAWL_WON, galaxy.oid, obj.turn, (galaxy.name, winner.name)),
469
            "topic": "EVENT",
470
        }
471
        self.cmd(obj).sendMsg(tran, obj, message)
472
        galaxy.scenario = Const.SCENARIO_SINGLE
473
        galaxy.name += " won on {0}".format(obj.turn)
474
        galaxy.owner = winner.oid
475
        return False
476
477
    def update(self, tran, obj):
478
        # check existence of all galaxies
479
        log.debug('Game turn is',obj.turn)
480
        if 0:
481
            for galaxyID in obj.galaxies:
482
                if not tran.db.has_key(galaxyID):
483
                    log.debug("CONSISTENCY - galaxy %d from universe %d does not exists" % (galaxyID, obj.oid))
484
                elif tran.db[galaxyID].type != Const.T_GALAXY:
485
                    log.debug("CONSISTENCY - galaxy %d from universe %d is not a Const.T_GALAXY" % (galaxyID, obj.oid))
486
        # check existence of all players
487
        for playerID in obj.players[:]:
488
            if not tran.db.has_key(playerID):
489
                log.debug("CONSISTENCY - player %d from universe %d does not exists" % (playerID, obj.oid))
490
                log.debug("Removing reference to player", playerID)
491
                obj.players.remove(playerID)
492
            elif tran.db[playerID].type not in Const.PLAYER_TYPES:
493
                log.debug("CONSISTENCY - player %d from universe %d is not a %s, it's %d" % (playerID, obj.oid, str(Const.PLAYER_TYPES), tran.db[playerID].type))
494
                log.debug("Removing reference to player", playerID)
495
                obj.players.remove(playerID)
496
497
    def getReferences(self, tran, obj):
498
        return obj.players[:] + obj.galaxies[:] + [Const.OID_NATURE]
499
500
    @public(Const.AL_ADMIN)
501
    def getActivePlayers(self, tran, obj):
502
        playerNames = []
503
        for playerID in obj.players:
504
            player = tran.db[playerID]
505
            if not player.type in Const.AI_PLAYER_TYPES:
506
                playerNames.append(player.name)
507
        return playerNames
508
509
    @public(Const.AL_NONE)
510
    def getPublicInfo(self, tran, obj):
511
        result = IDataHolder()
512
        result.oid = obj.oid
513
        result.type = obj.type
514
        result.name = obj.name
515
        result.turn = obj.turn
516
        return result
517
518
    ## messaging
519
    def canGetMsgs(self, tran, obj, oid):
520
        return 1
521
522
    def canSendMsg(self, tran, obj, oid, forum):
523
        if forum.endswith("PUBLIC"):
524
            return 1
525
        elif forum.endswith("NEWS"):
526
            return 1
527
        return 0
528
    
529
    @public(Const.AL_NONE)
530
    def finishGalaxyImperator(self, tran, obj, galaxyID, imperatorMessage):
531
        log.debug("Finishing Galaxy", galaxyID)
532
        galaxy = tran.db[galaxyID]
533
        if galaxy.scenario == Const.SCENARIO_OUTERSPACE:
534
            if galaxy.imperator == 0 or galaxy.imperator != tran.cid:
535
                raise GameException('Only galaxy imperator can finish galaxy')
536
537
            imperator = tran.db[tran.cid]
538
            if imperator.imperator < 3:
539
                raise GameException('Only imperator elected three times and more can finish galaxy')
540
541
            log.debug("Sending message", imperatorMessage)
542
            message = {
543
                "sender": imperator.name,
544
                "senderID": tran.cid,
545
                "forum": "NEWS",
546
                "data": (galaxyID, Const.MSG_GNC_GALAXY_FINISHED, galaxyID, obj.turn, (imperator.name, galaxy.name, imperatorMessage)),
547
                "topic": "EVENT",
548
            }
549
            self.cmd(obj).sendMsg(tran, obj, message)
550
        else:
551
            raise GameException('Galaxy finish not permitted.')
552
553
        log.debug("Deleting galaxy", galaxyID)
554
        self.cmd(galaxy).delete(tran, galaxy)
555
556
    @public(Const.AL_ADMIN)
557
    def finishGalaxyAutomated(self, tran, obj, galaxyID, imperatorMessage): #server-initiated restart
558
        log.debug("Restarting Galaxy", galaxyID)
559
        log.debug("Sending message", imperatorMessage)
560
        galaxy = tran.db[galaxyID]
561
        message = {
562
            "sender": "Galaxy %s" % galaxy.name,
563
            "senderID": tran.cid,
564
            "forum": "NEWS",
565
            "data": (galaxyID, Const.MSG_GNC_GALAXY_AUTO_FINISHED, galaxyID, obj.turn, (galaxy.name, imperatorMessage)),
566
            "topic": "EVENT",
567
        }
568
        self.cmd(obj).sendMsg(tran, obj, message)
569
        log.debug("Deleting galaxy", galaxyID)
570
        self.cmd(galaxy).delete(tran, galaxy)
571
572
    def _sendCreationMessage(self, tran, obj, galaxy):
573
        message = {
574
            "sender": "GNC",
575
            "senderID": galaxy.oid,
576
            "forum": "NEWS",
577
            "data": (galaxy.oid, Const.MSG_GNC_GALAXY_CREATED, galaxy.oid, obj.turn, (obj.turn)),
578
            "topic": "EVENT",
579
        }
580
        self.cmd(galaxy).sendMsg(tran, galaxy, message)
581
582
    @public(Const.AL_ADMIN)
583
    def createNewSubscribedGalaxy(self, tran, obj, galaxyName, galaxyType, listOfPlayers):
584
        galGen = GalaxyGenerator.GalaxyGenerator()
585
        galaxyRadius = galGen.getGalaxyTemplate(galaxyType).radius
586
        posX, posY = self.cmd(obj).findSpotForGalaxy(tran, obj, galaxyRadius)
587
        log.message("Adding new galaxy '%s' to (%d, %d)" % (galaxyType, posX, posY))
588
        galaxyFileName = galGen.generateGalaxy(galaxyType)
589
        log.debug("Creating new galaxy")
590
        newGalaxyID = self.createGalaxy(tran, obj)
591
        log.debug("Created new galaxy", newGalaxyID)
592
        newGalaxy = tran.db[newGalaxyID]
593
        log.debug("Loading new ", newGalaxyID)
594
        self.cmd(newGalaxy).loadFromXML(tran, newGalaxy, galaxyFileName, galaxyType, posX, posY, galaxyName)
595
596
        log.debug("Setup Enviroment", newGalaxyID)
597
        self.cmd(newGalaxy).setupEnvironment(tran, newGalaxy)
598
        log.debug("Sending Announcement Message", newGalaxyID)
599
        #self.cmd(newGalaxy).announceGalaxy(tran,newGalaxy)
600
        log.debug("Removing temp file", galaxyFileName)
601
        os.remove(galaxyFileName)
602
        for playerLogin in listOfPlayers:
603
            tran.gameMngr.createNewSubscribedPlayer(playerLogin, newGalaxyID)
604
        if newGalaxy.scenario != Const.SCENARIO_SINGLE:
605
            # no point in announcing single scenario - it starts ticking right away
606
            self._sendCreationMessage(tran, obj, newGalaxy)
607
        log.debug("Galaxy creation END")
608
        return newGalaxyID
609
610
    @public(Const.AL_ADMIN)
611
    def deleteGalaxy(self, tran, galaxyID):
612
        galaxy = tran.db[galaxyID]
613
        log.debug("Deleting galaxy", galaxyID)
614
        self.cmd(galaxy).delete(tran, galaxy)
615
616
    @public(Const.AL_ADMIN)
617
    def findSpotForGalaxy(self, tran, obj, new_gal_radius):
618
        """ We start with sum of surfaces of active galaxies (with borders) with this,
619
            we count the hypothetical square all galaxies should fit together. We then
620
            increase the size a bit, and try to place the new galaxy there randomly.
621
            If not successful, increase again and repeat.
622
        """
623
        log.debug("Seeking position for new galaxy")
624
625
        attempts_amount = 10000 # number of placement attempts within one resize
626
        magic_constant = 1.1
627
        magic_constant_step = 0.1
628
        border = 50
629
630
        # count surface required
631
        whole_surface = 0
632
        for galaxy_id in obj.galaxies:
633
            galaxy = tran.db[galaxy_id]
634
            # border is counted only once as it can overlap
635
            whole_surface += (galaxy.radius * 2 + border) ** 2
636
        # adding whole_surface of the galaxy currently processed
637
        whole_surface += (new_gal_radius * 2 + border) ** 2
638
639
        search = True
640
        attempts = attempts_amount
641
        low_limit = new_gal_radius # only positive coordinates
642
        while search:
643
            high_limit = math.ceil(whole_surface ** 0.5 * magic_constant)
644
            attempts -= 1
645
            pos_x = int(random.randrange(low_limit, high_limit))
646
            pos_y = int(random.randrange(low_limit, high_limit))
647
            is_blocked = False
648
            for galaxy_id in obj.galaxies:
649
                galaxy = tran.db[galaxy_id]
650
                needed_space = galaxy.radius + border + new_gal_radius
651
                if math.hypot(galaxy.x - pos_x, galaxy.y - pos_y) < needed_space:
652
                    is_blocked = True
653
                    break
654
            search = is_blocked
655
            if not attempts:
656
                magic_constant += magic_constant_step
657
                attempts = attempts_amount
658
        return (pos_x, pos_y)
0 ignored issues
show
introduced by
The variable pos_y does not seem to be defined in case the while loop on line 642 is not entered. Are you sure this can never be the case?
Loading history...
introduced by
The variable pos_x does not seem to be defined in case the while loop on line 642 is not entered. Are you sure this can never be the case?
Loading history...
659