Completed
Pull Request — master (#188)
by Marek
02:14
created

IUniverse.createNewSubscribedGalaxy()   B

Complexity

Conditions 3

Size

Total Lines 26
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

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