Completed
Push — master ( 994cf3...bb27bc )
by Marek
17s queued 14s
created

IUniverse.createNewSubscribedGalaxy()   B

Complexity

Conditions 3

Size

Total Lines 27
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

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