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

ISystem.getSystemCombatBonuses()   B

Complexity

Conditions 6

Size

Total Lines 13
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nop 4
dl 0
loc 13
rs 8
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
import random
21
import copy
22
23
from xml.dom.minidom import Node
24
25
import ige
26
import Rules
27
import Utils
28
29
from Const import *
30
from ige import log
31
from ige.IObject import IObject
32
from ige.IDataHolder import IDataHolder
33
34
class ISystem(IObject):
35
36
    typeID = T_SYSTEM
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_SYSTEM does not seem to be defined.
Loading history...
37
38
    def init(self, obj):
39
        IObject.init(self, obj)
40
        #
41
        obj.x = 0.0
42
        obj.y = 0.0
43
        obj.planets = []
44
        obj.fleets = []
45
        obj.closeFleets = []
46
        obj.starClass = u'---' # Star clasification
47
        obj.signature = 100
48
        # rotation
49
        #~ obj.dist = 0.0
50
        #~ obj.dAngle = 0.0
51
        #~ obj.sAngle = 0.0
52
        # renaming
53
        obj.lastNameChng = 0
54
        # combat
55
        obj.combatCounter = 0
56
        # system wide data
57
        obj.scannerPwrs = {}
58
        # mine field
59
        obj.minefield = {}  # for every owner (key) list of minefield (triplet) exists (mine_id, amount, last_deployed)
60
61
    def update(self, tran, obj):
62
        # check existence of all planets
63
        if 0:
64
            for planetID in obj.planets:
65
                if not tran.db.has_key(planetID):
66
                    log.debug("CONSISTENCY - planet %d from system %d does not exists" % (planetID, obj.oid))
67
                elif tran.db[planetID].type != T_PLANET:
68
                    log.debug("CONSISTENCY - planet %d from system %d is not a T_PLANET" % (planetID, obj.oid))
69
        if not hasattr(obj,'minefield'):
70
            obj.minefield = {}
71
        # TODO: only needed for 0.5.72 update
72
        old_minefields = False
73
        for ownerID in obj.minefield:
74
            if obj.minefield[ownerID] and type(obj.minefield[ownerID][0]) is not tuple:
75
                old_minefields = True
76
        if old_minefields:
77
            for ownerID in obj.minefield:
78
                temp_mine_dict = {}
79
                for mine_id in obj.minefield[ownerID]:
80
                    try:
81
                        temp_mine_dict[mine_id] += 1
82
                    except KeyError:
83
                        temp_mine_dict[mine_id] = 1
84
                # now translate dictionary into list of tuples
85
                owners_minefields = []
86
                turn = tran.db[OID_UNIVERSE].turn
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_UNIVERSE does not seem to be defined.
Loading history...
87
                for mine_id, amount in temp_mine_dict.iteritems():
88
                    owners_minefields.append((mine_id, amount, turn))
89
                obj.minefield[ownerID] = owners_minefields
90
91
        # check that all .fleet are in .closeFleets
92
        for fleetID in obj.fleets:
93
            if fleetID not in obj.closeFleets:
94
                log.debug("CONSISTENCY - fleet %d is in .fleet but not in .closeFleets - adding" % fleetID)
95
                obj.closeFleets.append(fleetID)
96
        # check existence of all fleets
97
        for fleetID in obj.closeFleets:
98
            if not tran.db.has_key(fleetID):
99
                log.debug("CONSISTENCY - fleet %d from system %d does not exists" % (fleetID, obj.oid))
100
            elif tran.db[fleetID].type not in (T_FLEET, T_ASTEROID):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_FLEET does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable T_ASTEROID does not seem to be defined.
Loading history...
101
                log.debug("CONSISTENCY - fleet %d from system %d is not a T_FLEET" % (fleetID, obj.oid))
102
        # delete nonexistent fleets
103
        index = 0
104
        while index < len(obj.closeFleets) and obj.closeFleets:
105
            fleet = tran.db.get(obj.closeFleets[index], None)
106
            if fleet == None:
107
                log.debug("CONSISTENCY - fleet %d does not exists" % obj.closeFleets[index])
108
                fleetID = obj.closeFleets[index]
109
                obj.closeFleets.remove(fleetID)
110
                obj.fleets.remove(fleetID)
111
            else:
112
                index += 1
113
        # check compOf
114
        if not tran.db.has_key(obj.compOf) or tran.db[obj.compOf].type != T_GALAXY:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_GALAXY does not seem to be defined.
Loading history...
115
            log.debug("CONSISTENCY invalid compOf for system", obj.oid)
116
        # rebuild closeFleets attribute
117
        old = obj.closeFleets
118
        obj.closeFleets = []
119
        for fleetID in old:
120
            fleet = tran.db.get(fleetID, None)
121
            if fleet and fleet.closeSystem == obj.oid and fleetID not in obj.closeFleets:
122
                obj.closeFleets.append(fleetID)
123
        if old != obj.closeFleets:
124
            log.debug("System close fleets fixed", obj.oid, old, obj.closeFleets)
125
        # TODO: remove, no need to start players on random systems
126
        # try to find starting planets
127
        #starting = 0
128
        #free = 1
129
        #for planetID in obj.planets:
130
        #    planet = tran.db[planetID]
131
        #    if planet.plStarting:
132
        #        starting = planetID
133
        #    if planet.owner != OID_NONE:
134
        #        free = 0
135
        #if starting and free:
136
        #    # good starting position
137
        #    #@log.debug("Found starting position", obj.oid, starting)
138
        #    # get galaxy
139
        #    galaxy = tran.db[obj.compOf]
140
        #    if starting not in galaxy.startingPos:
141
        #        log.debug("Adding to starting positions of galaxy", galaxy.oid)
142
        #        galaxy.startingPos.append(starting)
143
        # check if system has planets
144
        hasHabitable = 0
145
        for planetID in obj.planets:
146
            if tran.db[planetID].plSlots > 0:
147
                hasHabitable = 1
148
                break
149
        if (not obj.planets or not hasHabitable) and obj.starClass[0] != "b" and obj.starClass != "wW0":
150
            log.debug("No planet for system", obj.oid, obj.name, obj.starClass)
151
            # delete old planets
152
            for planetID in obj.planets:
153
                del tran.db[planetID]
154
            obj.planets = []
155
            # find matching systems
156
            avail = []
157
            for systemID in tran.db[obj.compOf].systems:
158
                system = tran.db[systemID]
159
                if system.starClass[1] == obj.starClass[1] \
160
                    or (obj.starClass[1] == "G" and system.starClass[1] == "F"):
161
                    ok = 0
162
                    for planetID in system.planets:
163
                        planet = tran.db[planetID]
164
                        if planet.plStarting:
165
                            ok = 0
166
                            break
167
                        if planet.plSlots > 0:
168
                            ok = 1
169
                    if ok and system.planets:
170
                        avail.append(systemID)
171
            # select random system
172
            log.debug("Can copy", avail)
173
            try:
174
                systemID = random.choice(avail)
175
                # copy it
176
                log.debug("Will copy system", systemID)
177
                nType = Utils.getPlanetNamesType()
178
                orbit = 1
179
                for planetID in tran.db[systemID].planets:
180
                    orig = tran.db[planetID]
181
                    planet = tran.db[self.createPlanet(tran, obj)]
182
                    planet.name = Utils.getPlanetName(obj.name, nType, orbit - 1)
183
                    planet.x = obj.x
184
                    planet.y = obj.y
185
                    planet.plDiameter = orig.plDiameter
186
                    planet.plType = orig.plType
187
                    planet.plMin = orig.plMin
188
                    planet.plBio = orig.plBio
189
                    planet.plEn = orig.plEn
190
                    planet.plEnv = orig.plEnv
191
                    planet.plSlots = orig.plSlots
192
                    planet.plMaxSlots = orig.plMaxSlots
193
                    planet.plStratRes = 0
194
                    planet.plDisease = 0
195
                    planet.plStarting = 0
196
                    planet.orbit = orbit
197
                    planet.storPop = 0
198
                    planet.slots = []
199
                    orbit += 1
200
            except:
201
                log.debug("Copy failed")
202
        # TODO: remove in version 0.5.73
203
        if True:
204
            owners = []
205
            for planetID in obj.planets:
206
                planet = tran.db[planetID]
207
                if planet.owner not in owners + [OID_NONE]:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_NONE does not seem to be defined.
Loading history...
208
                    owners.append(planet.owner)
209
            for owner_id in owners:
210
                for tech, struct in self.getSystemMineLauncher(tran, obj, owner_id):
211
                    if not struct[STRUCT_IDX_STATUS] & STRUCT_STATUS_ON:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_IDX_STATUS does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable STRUCT_STATUS_ON does not seem to be defined.
Loading history...
212
                        # structure is offline, reset timer
213
                        self.addMine(tran, obj, owner_id, tech.mineclass, 0)
214
                        continue
215
                    efficiency = struct[STRUCT_IDX_HP] / float(tech.maxHP)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_IDX_HP does not seem to be defined.
Loading history...
216
                    minenum = int(tech.minenum * efficiency)
217
                    # by setting minerate to None, we are forcing a creation of one - so it grabs
218
                    # galaxyTurn instead of universe.turn
219
                    if self.addMine(tran, obj, owner_id, tech.mineclass, None, None):
220
                        log.debug('ISystem', 'Mine timer reset for owner %d in system %d' % (owner_id, obj.oid))
221
222
    update.public = 0
223
224
    def getReferences(self, tran, obj):
225
        return obj.planets
226
227
    getReferences.public = 0
228
229
    def getScanInfos(self, tran, obj, scanPwr, player):
230
        result = IDataHolder()
231
        results = [result]
232
        if scanPwr >= Rules.level1InfoScanPwr:
233
            result._type = T_SCAN
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_SCAN does not seem to be defined.
Loading history...
234
            result.scanPwr = scanPwr
235
            result.oid = obj.oid
236
            result.x = obj.x
237
            result.y = obj.y
238
            if hasattr(obj, 'destinationOid'):
239
                result.destinationOid = obj.destinationOid
240
            # multiply by 1000 to increase accuracy
241
            #~ result.dist = obj.dist * 1000
242
            #~ result.dAngle = obj.dAngle * 1000
243
            #~ result.sAngle = obj.sAngle * 1000
244
            result.signature = obj.signature
245
            result.type = obj.type
246
            result.compOf = obj.compOf
247
            result.starClass = obj.starClass
248
        if scanPwr >= Rules.level2InfoScanPwr:
249
            result.name = obj.name
250
            result.combatCounter = obj.combatCounter
251
        if scanPwr >= Rules.level3InfoScanPwr:
252
            result.planets = obj.planets
253
            result.owner = obj.owner
254
            for planetID in obj.planets:
255
                planet = tran.db[planetID]
256
                if planet.owner == player: ####### This was player.owner, which made no sense. Hope this change doesn't break something
257
                    continue
258
                newPwr = scanPwr * planet.signature / obj.signature
259
                results.extend(self.cmd(planet).getScanInfos(tran, planet, newPwr, player))
260
        if scanPwr >= Rules.level4InfoScanPwr:
261
            result.fleets = obj.fleets
262
            for fleetID in obj.fleets:
263
                fleet = tran.db[fleetID]
264
                if fleet.owner == player:
265
                    continue
266
                newPwr = scanPwr * fleet.signature / obj.signature
267
                results.extend(self.cmd(fleet).getScanInfos(tran, fleet, newPwr, player))
268
            result.hasmines = 0 # no
269
            if len(obj.minefield) > 0:
270
                result.hasmines = 1 # yes
271
            result.minefield = self.getMines(obj, player.oid) # only shows mines you own
272
            if len(obj.minefield) > 1 or (len(obj.minefield) == 1 and len(result.minefield) == 0):
273
                result.hasmines = 2 # yes, and some aren't my mines
274
        return results
275
276
    def processINITPhase(self, tran, obj, data):
277
        obj.scannerPwrs = {}
278
279
        return obj.planets
280
281
    processINITPhase.public = 1
282
    processINITPhase.accLevel = AL_ADMIN
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable AL_ADMIN does not seem to be defined.
Loading history...
283
284
    def processPRODPhase(self, tran, obj, data):
285
        # mine deployment
286
        owners = []
287
        for planetID in obj.planets:
288
            planet = tran.db[planetID]
289
            if planet.owner not in owners + [OID_NONE]:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_NONE does not seem to be defined.
Loading history...
290
                owners.append(planet.owner)
291
        for owner_id in owners:
292
            self.deployMines(tran, obj, owner_id)
293
        return obj.planets
294
295
    processPRODPhase.public = 1
296
    processPRODPhase.accLevel = AL_ADMIN
297
298
    def processACTIONPhase(self, tran, obj, data):
299
        # distribute resources
300
        planets = {}
301
        # group planets by owner
302
        for planetID in obj.planets:
303
            planet = tran.db[planetID]
304
            if planet.owner != OID_NONE:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_NONE does not seem to be defined.
Loading history...
305
                tmp = planets.get(planet.owner, [])
306
                tmp.append(planet)
307
                planets[planet.owner] = tmp
308
        # group planets if owners are allied
309
        # TODO
310
        # process each group
311
        for owner in planets.keys():
312
            # skip alone planets
313
            if len(planets[owner]) < 2:
314
                continue
315
            # process each resource
316
            for resName in ('Bio', 'En'):
317
                donors = []
318
                donees = []
319
                minRes = 'min%s' % resName
320
                maxRes = 'max%s' % resName
321
                storRes = 'stor%s' % resName
322
                donorsSum = 0
323
                doneesSum = 0
324
                # put planets into donors/donees
325
                for planet in planets[owner]:
326
                    if getattr(planet, storRes) > getattr(planet, minRes):
327
                        donors.append(planet)
328
                        donorsSum += getattr(planet, storRes) - getattr(planet, minRes)
329
                    elif getattr(planet, storRes) < getattr(planet, minRes):
330
                        donees.append(planet)
331
                        doneesSum += getattr(planet, minRes) - getattr(planet, storRes)
332
                #@log.debug('ISystem', obj.oid, 'Donors / donees for %s' % resName, donorsSum, doneesSum)
333
                # there are requests for donation and there is somebody able to donate
334
                if doneesSum > 0 and donorsSum > 0:
335
                    #@log.debug('ISystem', 'Redistributin %s for' % resName, owner)
336
                    # give
337
                    balance = 0
338
                    tmpRatio = min(float(doneesSum) / donorsSum, 1.0)
339
                    for planet in donees:
340
                        diff = getattr(planet, minRes) - getattr(planet, storRes)
341
                        amount = int(float(diff) / doneesSum * donorsSum * tmpRatio)
342
                        #@log.debug('ISystem', 'Give res', planet.oid, amount)
343
                        balance -= amount
344
                        setattr(planet, storRes, getattr(planet, storRes) + amount)
345
                    # take
346
                    assert donorsSum + balance >= 0
347
                    lastPlanet = None
348
                    tmpRatio = min(float(donorsSum) / doneesSum, 1.0)
349
                    for planet in donors:
350
                        diff = getattr(planet, storRes) - getattr(planet, minRes)
351
                        amount = int(float(diff) / donorsSum * doneesSum * tmpRatio)
352
                        balance += amount
353
                        #@log.debug('ISystem', 'Take res', planet.oid, amount)
354
                        setattr(planet, storRes, getattr(planet, storRes) - amount)
355
                        lastPlanet = planet
356
                    # fix rounding error
357
                    setattr(lastPlanet, storRes, getattr(lastPlanet, storRes) + balance)
358
                    #@log.debug('ISystem', 'Rounding error', balance)
359
                # try to move additional resources to the other planets
360
                for planet in planets[owner]:
361
                    if getattr(planet, storRes) > getattr(planet, maxRes):
362
                        excess = getattr(planet, storRes) - getattr(planet, maxRes)
363
                        #@log.debug('ISystem', 'Trying to move excess rsrcs from', planet.oid, excess)
364
                        for planet2 in planets[owner]:
365
                            if planet == planet2:
366
                                continue
367
                            if getattr(planet2, storRes) < getattr(planet2, maxRes):
368
                                space = getattr(planet2, maxRes) - getattr(planet2, storRes)
369
                                amount = min(space, excess)
370
                                #@log.debug('ISystem', 'Moved to', planet2.oid, amount)
371
                                setattr(planet2, storRes, getattr(planet2, storRes) + amount)
372
                                excess -= amount
373
                                if excess == 0:
374
                                    break
375
                        #@log.debug('ISystem', 'Cannot move excess rsrcs on', planet.oid, excess)
376
                        setattr(planet, storRes, getattr(planet, maxRes) + excess)
377
        #~ # rotate system around the galaxy core
378
        #~ #log.debug("Rotate, old coords", obj.x, obj.y)
379
        #~ turn = tran.db[OID_UNIVERSE].turn
380
        #~ galaxy = tran.db[obj.compOf]
381
        #~ angle = obj.sAngle + (turn / Rules.rotationMod) * obj.dAngle
382
        #~ obj.x = galaxy.x + obj.dist * math.cos(angle)
383
        #~ obj.y = galaxy.y + obj.dist * math.sin(angle)
384
        #~ #log.debug("Rotate, new coords", obj.x, obj.y)
385
        #~ # change positions of planets and orbitting fleets
386
        #~ for planetID in obj.planets:
387
            #~ planet = tran.db[planetID]
388
            #~ planet.x = obj.x
389
            #~ planet.y = obj.y
390
        #~ for fleetID in obj.fleets:
391
            #~ fleet = tran.db[fleetID]
392
            #~ fleet.x = obj.x
393
            #~ fleet.y = obj.y
394
        # process planets and fleets
395
        #@log.debug("System close fleets", obj.oid, obj.closeFleets)
396
        return obj.planets[:] + obj.closeFleets[:]
397
398
    processACTIONPhase.public = 1
399
    processACTIONPhase.accLevel = AL_ADMIN
400
401
    def getObjectsInSpace(self, tran, obj):
402
        inSpace = obj.closeFleets[:]
403
        for fleetID in obj.fleets:
404
            try:
405
                inSpace.remove(fleetID)
406
            except ValueError:
407
                log.warning(obj.oid, "Cannot remove fleet from closeFleets", fleetID, obj.fleets, obj.closeFleets)
408
        return inSpace
409
410
    getObjectsInSpace.public = 1
411
    getObjectsInSpace.accLevel = AL_ADMIN
412
413
    def processBATTLEPhase(self, tran, obj, data):
414
        system = obj
415
        #@log.debug('ISystem', 'BATTLE - system', obj.oid)
416
        # we are processing fleets, planets, ...
417
        objects = obj.planets[:] + obj.fleets[:]
418
        # shuffle them to prevent predetermined one-sided battles (temporary hack)
419
        random.shuffle(objects)
420
        # store owners of objects
421
        # find enemies and allies
422
        attack = {}
423
        allies = {}
424
        owners = {}
425
        ownerIDs = {}
426
        systemAtt = {}
427
        systemDef = {}
428
        hasMine = {}
429
        isOwnedObject = 0
430
        for objID in objects:
431
            attack[objID] = []
432
            allies[objID] = []
433
            owner = tran.db[objID].owner
434
            owners[objID] = owner
435
            ownerIDs[owner] = owner
436
            if owner != OID_NONE:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_NONE does not seem to be defined.
Loading history...
437
                isOwnedObject = 1
438
        for owner in ownerIDs:
439
            tempAtt, tempDef = self.getSystemCombatBonuses(tran, system, owner)
440
            systemAtt[owner] = tempAtt
441
            systemDef[owner] = tempDef
442
            hasMine[owner] = self.getSystemMineSource(tran, system, owner)
443
        if not isOwnedObject:
444
            #@log.debug('ISystem', 'No combat')
445
            # reset combat counters
446
            system.combatCounter = 0
447
            return
448
        # first - direct ones
449
        index = 1
450
        for obj1ID in objects:
451
            obj1 = tran.db[obj1ID]
452
            if obj1.owner == OID_NONE:
453
                index += 1
454
                continue
455
            commander = tran.db[obj1.owner]
456
            # relationships
457
            #for obj2ID in objects[index:]:
458
            for obj2ID in objects:
459
                obj2 = tran.db[obj2ID]
460
                if obj2.owner == OID_NONE or obj1 is obj2:
461
                    continue
462
                if obj1.owner == obj2.owner:
463
                    allies[obj1ID].append(obj2ID)
464
                    allies[obj2ID].append(obj1ID)
465
                    continue
466
                # planet and military object
467
                elif obj1.type == T_PLANET and obj2.isMilitary and \
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_PLANET does not seem to be defined.
Loading history...
468
                    not self.cmd(commander).isPactActive(tran, commander, obj2.owner, PACT_ALLOW_MILITARY_SHIPS):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PACT_ALLOW_MILITARY_SHIPS does not seem to be defined.
Loading history...
469
                    #@log.debug("ISystem pl - mil", obj1ID, obj2ID)
470
                    if obj2ID not in attack[obj1ID]:
471
                        attack[obj1ID].append(obj2ID)
472
                    if obj1ID not in attack[obj2ID]:
473
                        attack[obj2ID].append(obj1ID)
474
                # planet and civilian object
475
                elif obj1.type == T_PLANET and not obj2.isMilitary and \
476
                    not self.cmd(commander).isPactActive(tran, commander, obj2.owner, PACT_ALLOW_CIVILIAN_SHIPS):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable PACT_ALLOW_CIVILIAN_SHIPS does not seem to be defined.
Loading history...
477
                    #@log.debug("ISystem pl - civ", obj1ID, obj2ID)
478
                    if obj2ID not in attack[obj1ID]:
479
                        attack[obj1ID].append(obj2ID)
480
                    if obj1ID not in attack[obj2ID]:
481
                        attack[obj2ID].append(obj1ID)
482
                # military and military object
483
                elif obj1.isMilitary and obj2.isMilitary and \
484
                    not self.cmd(commander).isPactActive(tran, commander, obj2.owner, PACT_ALLOW_MILITARY_SHIPS):
485
                    #@log.debug("ISystem mil - mil", obj1ID, obj2ID)
486
                    if obj2ID not in attack[obj1ID]:
487
                        attack[obj1ID].append(obj2ID)
488
                    if obj1ID not in attack[obj2ID]:
489
                        attack[obj2ID].append(obj1ID)
490
                # military and civilian object
491
                elif obj1.isMilitary and not obj2.isMilitary and \
492
                    not self.cmd(commander).isPactActive(tran, commander, obj2.owner, PACT_ALLOW_CIVILIAN_SHIPS):
493
                    #@log.debug("ISystem mil - civ", obj1ID, obj2ID)
494
                    if obj2ID not in attack[obj1ID]:
495
                        attack[obj1ID].append(obj2ID)
496
                    if obj1ID not in attack[obj2ID]:
497
                        attack[obj2ID].append(obj1ID)
498
                # planet and fleet
499
                #elif obj1.type == T_PLANET and obj2.type == T_FLEET and \
500
                #    self.cmd(commander).isPactActive(tran, commander, obj2.owner, PACT_MUTUAL_DEFENCE):
501
                #    allies[obj1ID].append(obj2ID)
502
                #    allies[obj2ID].append(obj1ID)
503
                # fleet and fleet
504
                #elif obj1.type == T_FLEET and obj2.type == T_FLEET and \
505
                #    self.cmd(commander).isPactActive(tran, commander, obj2.owner, PACT_MUTUAL_OFFENCE):
506
                #    allies[obj1ID].append(obj2ID)
507
                #    allies[obj2ID].append(obj1ID)
508
                # asteroid
509
                if obj2.type == T_ASTEROID:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_ASTEROID does not seem to be defined.
Loading history...
510
                    attack[obj1ID].append(obj2ID)
511
                    attack[obj2ID].append(obj1ID)
512
            index += 1
513
        #@log.debug('ISystem', 'Targets:', targets)
514
        #@log.debug('ISystem', 'Allies:', allies)
515
        # find indirect a/e
516
        #for objID in objects:
517
        #    iTargets = []
518
        #    iAllies = []
519
        #    # find indirect a/e
520
        #    todo = allies[objID][:]
521
        #    while todo:
522
        #        id = todo.pop(0)
523
        #        iTargets.extend(targets[id])
524
        #        for tmpID in allies[id]:
525
        #            if tmpID not in iAllies:
526
        #                todo.append(tmpID)
527
        #                iAllies.append(tmpID)
528
        #    # remove allies from targets
529
        #    for id in iAllies:
530
        #        if id in iTargets:
531
        #            iTargets.remove(id)
532
        #    # IMPORTATNT preffer NOT to fire at possible allies
533
        #    # add my targets
534
        #    #for id in targets[objID]:
535
        #    #    if id not in iTargets:
536
        #    #        iTargets.append(id)
537
        #    # that's all folks
538
        #    for id in iTargets:
539
        #        if objID not in attack[id]:
540
        #            attack[id].append(objID)
541
        #        if id not in attack[objID]:
542
        #            attack[objID].append(id)
543
        # NOT VALID: objects with action ACTION_ATTACK will attack only their targets
544
        # check, if there are any targets
545
        isCombat = 0
546
        for objID in objects:
547
            if attack[objID]:
548
                isCombat = 1
549
                break #end loop
550
        if not isCombat:
551
            #@log.debug('ISystem', 'No combat')
552
            # reset combat counters
553
            system.combatCounter = 0
554
            for fleetID in system.fleets:
555
                tran.db[fleetID].combatCounter = 0
556
            return
557
        # increase combat counters
558
        system.combatCounter += 1
559
        for fleetID in system.fleets:
560
            tran.db[fleetID].combatCounter += 1
561
        # debug
562
        log.debug('ISystem', 'Final attacks in system %d:' % system.oid, attack)
563
        # mines detonate before battle
564
        shots = {}
565
        targets = {}
566
        firing = {}
567
        damageCaused = {}
568
        killsCaused = {}
569
        damageTaken = {}
570
        shipsLost = {}
571
        minesTriggered = {}
572
        fleetOwners = {}
573
        isCombat = False
574
        isMineCombat = False
575
        for owner in ownerIDs:
576
            if owner not in hasMine: # no planets
577
                continue
578
            if not hasMine[owner]: # no planet with control structure
579
                continue
580
            controlPlanetID = hasMine[owner][0]  # there is list returned, all planets have same effect
581
            if len(self.getMines(system, owner)) == 0:
582
                continue # no mines, something broke
583
            if len(attack[controlPlanetID]) == 0:
584
                continue # no targets
585
            isMineFired = True
586
            mineTargets = copy.copy(attack[controlPlanetID])
587
            while isMineFired:
588
                while len(mineTargets) > 0:
589
                    targetID = random.choice(mineTargets) # select random target
590
                    targetobj = tran.db.get(targetID, None)
591
                    try:
592
                        if targetobj.type == T_FLEET:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_FLEET does not seem to be defined.
Loading history...
593
                            fleetOwners[targetID] = targetobj.owner
594
                            break # target found
595
                        mineTargets.remove(targetID)  # remove an object type that a mine can't hit from the temporary targets list
596
                    except:
597
                        mineTargets.remove(targetID)  # remove a dead fleet from the temporary targets list
598
599
                if len(mineTargets) == 0:
600
                    break # no fleet targets for mines
601
                temp, temp, firing[targetID] = self.cmd(targetobj).getPreCombatData(tran, targetobj)  # fix firing for "surrender to" section
0 ignored issues
show
introduced by
The variable targetobj does not seem to be defined for all execution paths.
Loading history...
602
                damage, att, ignoreshield, mineID = self.cmd(obj).fireMine(system, owner)
603
                if not damage: # no more mines
604
                    isMineFired = False
605
                    break
606
                log.debug('ISystem', 'Mine Shooting (damage, att, ignore shield):', damage, att, ignoreshield)
607
                isMineCombat = True
608
                minesTriggered[mineID] = minesTriggered.get(mineID, 0) + 1
609
                # Process Combat
610
                # for now we assume only one ship can be destroyed by one mine
611
                dmg, destroyed = self.cmd(targetobj).applyMine(tran, targetobj, att, damage, ignoreshield)
612
                #log.debug('ISystem-Mines', 'Actual Damage Done:',dmg)
613
                if dmg > 0:
614
                    damageTaken[targetID] = damageTaken.get(targetID, 0) + dmg
0 ignored issues
show
introduced by
The variable targetID does not seem to be defined for all execution paths.
Loading history...
615
                    shipsLost[targetID] = shipsLost.get(targetID, 0) + destroyed
616
                    killsCaused[mineID] = killsCaused.get(mineID, 0) + destroyed
617
                if dmg > 0:
618
                    damageCaused[mineID] = damageCaused.get(mineID, 0) + dmg
619
            # send messages about mine effects to the owner of the minefield
620
            # collect hit players
621
            players = {}
622
            for triggerID in firing.keys():
623
                players[owners[triggerID]] = None
624
            controllerPlanet = tran.db.get(controlPlanetID, None)
625
            damageCausedSum = 0
626
            killsCausedSum = 0
627
            for mineID in damageCaused.keys():
628
                damageCausedSum = damageCausedSum + damageCaused.get(mineID, 0)
629
                killsCausedSum = killsCausedSum + killsCaused.get(mineID, 0)
630
            Utils.sendMessage(tran, controllerPlanet, MSG_MINES_OWNER_RESULTS, system.oid, (players.keys(),(damageCaused, killsCaused, minesTriggered),damageCausedSum,killsCausedSum))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_MINES_OWNER_RESULTS does not seem to be defined.
Loading history...
631
        # send messages to the players whose fleets got hit by minefields
632
        for targetID in damageTaken.keys():
633
            targetFleet = tran.db.get(targetID, None)
634
            if targetFleet:
635
                Utils.sendMessage(tran, targetFleet, MSG_MINES_FLEET_RESULTS, system.oid, (damageTaken[targetID], shipsLost[targetID]))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_MINES_FLEET_RESULTS does not seem to be defined.
Loading history...
636
            else:
637
                targetFleet = IDataHolder()
638
                targetFleet.oid = fleetOwners[targetID]
639
                Utils.sendMessage(tran, targetFleet, MSG_MINES_FLEET_RESULTS, system.oid, (damageTaken[targetID], shipsLost[targetID]))
640
                Utils.sendMessage(tran, targetFleet, MSG_DESTROYED_FLEET, system.oid, ())
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_DESTROYED_FLEET does not seem to be defined.
Loading history...
641
        damageCaused = {}
642
        killsCaused = {}
643
        damageTaken = {}
644
        shipsLost = {}
645
        # now to battle
646
        for objID in objects:
647
            obj = tran.db.get(objID, None)
648
            # get shots from object, should be sorted by weaponClass
649
            # shots = [ shot, ...], shot = (combatAtt, weaponID)
650
            # get target classes and numbers
651
            # (class1, class2, class3, class4)
652
            # cls0 == fighters, cls1 == midships, cls2 == capital ships, cls3 == planet installations
653
            #@log.debug(objID, obj.name, "getting pre combat data")
654
            if obj: # source already destroyed; ignore
655
                shots[objID], targets[objID], firing[objID] = self.cmd(obj).getPreCombatData(tran, obj)
656
                if firing[objID]:
657
                    isCombat = True
658
        if not isCombat and not isMineCombat:
659
            # no shots has been fired
660
            #@log.debug('ISystem', 'No combat')
661
            # reset combat counters
662
            system.combatCounter = 0
663
            for fleetID in system.fleets:
664
                tran.db[fleetID].combatCounter = 0
665
            return
666
        #@log.debug("Shots:", shots)
667
        #@log.debug("Targets", targets)
668
        if isCombat:
669
            for shotIdx in (3, 2, 1, 0):
670
                for objID in objects:
671
                    # obj CAN be deleted at this point
672
                    obj = tran.db.get(objID, None)
673
                    if obj == None:
674
                        continue # source already destroyed; move to next source
675
                    # if object is fleet, then it's signature is max
676
                    if obj and obj.type == T_FLEET:
677
                        obj.signature = Rules.maxSignature
678
                    # target preselection
679
                    totalClass = [0, 0, 0, 0]
680
                    total = 0
681
                    for targetID in attack[objID]:
682
                        totalClass[0] += targets[targetID][0]
683
                        totalClass[1] += targets[targetID][1]
684
                        totalClass[2] += targets[targetID][2]
685
                        totalClass[3] += targets[targetID][3]
686
                    total = totalClass[0] + totalClass[1] + totalClass[2] + totalClass[3]
687
                    # process shots
688
                    for combatAtt, weaponID in shots[objID][shotIdx]:
689
                        weapon = Rules.techs[weaponID]
690
                        weaponClass = weapon.weaponClass
691
                        if total == 0:
692
                            # there are no targets
693
                            break
694
                        #@log.debug('ISystem', 'Processing shot', objID, weapon.name, weaponClass)
695
                        # process from weaponClass up
696
                        # never shoot on smaller ships than weaponClass
697
                        applied = 0
698
                        for tmpWpnClass in xrange(weaponClass, 4):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable xrange does not seem to be defined.
Loading history...
699
                            #@log.debug('ISystem', 'Trying target class', tmpWpnClass, totalClass[tmpWpnClass])
700
                            # select target
701
                            if totalClass[tmpWpnClass]:
702
                                target = Utils.rand(0, totalClass[tmpWpnClass])
703
                                #@log.debug('ISystem', 'Target rnd num', target, totalClass[tmpWpnClass])
704
                                for targetID in attack[objID]:
705
                                    if target < targets[targetID][tmpWpnClass]:
706
                                        #@log.debug(objID, 'attacks', targetID, tmpWpnClass)
707
                                        # targetID can be deleted at this point
708
                                        anObj = tran.db.get(targetID, None)
709
                                        if anObj:
710
                                            dmg, destroyed, destroyedClass = self.cmd(anObj).applyShot(tran, anObj, systemDef[owners[targetID]], combatAtt + systemAtt[owners[objID]], weaponID, tmpWpnClass, target)
711
                                            #@log.debug("ISystem result", dmg, destroyed, destroyedClass, tmpWpnClass)
712
                                            #@print objID, 'dmg, destroyed', dmg, destroyed
713
                                            damageTaken[targetID] = damageTaken.get(targetID, 0) + dmg
714
                                            if destroyed > 0:
715
                                                shipsLost[targetID] = shipsLost.get(targetID, 0) + destroyed
716
                                                total -= destroyed
717
                                                totalClass[destroyedClass] -= destroyed
718
                                            if dmg > 0 and obj:
719
                                                obj.combatExp += dmg
720
                                                damageCaused[objID] = damageCaused.get(objID, 0) + dmg
721
                                            applied = 1
722
                                        else:
723
                                            continue # target already destroyed, move to next target
724
                                        break
725
                                    else:
726
                                        #@log.debug('ISystem', 'Lovering target by', targets[targetID][tmpWpnClass])
727
                                        target -= targets[targetID][tmpWpnClass]
728
                            if applied:
729
                                break
730
        # send messages and modify diplomacy relations
731
        # distribute experience pts
732
        for objID in objects:
733
            obj = tran.db.get(objID, None)
734
            if obj:
735
                self.cmd(obj).distributeExp(tran, obj)
736
            if attack[objID]:
737
                source = obj or tran.db[owners[objID]]
738
                # collect players
739
                players = {}
740
                for attackerID in attack[objID]:
741
                    players[owners[attackerID]] = None
742
                d1 = damageTaken.get(objID,0)
743
                d2 = damageCaused.get(objID,0)
744
                l = shipsLost.get(objID, 0)
745
                if d1 or d2 or l:
746
                    # send only if damage is taken/caused
747
                    Utils.sendMessage(tran, source, MSG_COMBAT_RESULTS, system.oid, (d1, d2, l, players.keys()))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_COMBAT_RESULTS does not seem to be defined.
Loading history...
748
                if not obj:
749
                    # report DESTROYED status
750
                    Utils.sendMessage(tran, source, MSG_DESTROYED_FLEET, system.oid, ())
751
                # modify diplomacy relations
752
                objOwner = tran.db[owners[objID]]
753
                for attackerID in attack[objID]:
754
                    attOwner = tran.db.get(owners[attackerID], None)
755
                    # owner of the fleet
756
                    rel = self.cmd(objOwner).getDiplomacyWith(tran, objOwner, attOwner.oid)
757
                    rel.relChng = Rules.relLostWhenAttacked
758
                    # attacker
759
                    rel = self.cmd(attOwner).getDiplomacyWith(tran, attOwner, objOwner.oid)
760
                    rel.rechChng = Rules.relLostWhenAttacked
761
        # check if object surrenders
762
        for objID in objects:
763
            # object surrender IFF it and its allies had target and was not able
764
            # to fire at it, planet is not counted as ally in this case
765
            obj = tran.db.get(objID, None)
766
            if firing[objID] and obj:
767
                continue
768
            surrenderTo = []
769
            for attID in attack[objID]:
770
                if firing[attID] and tran.db.has_key(attID):
771
                    surrenderTo.append(tran.db[attID].owner)
772
            for allyID in allies[objID]:
773
                if not tran.db.has_key(allyID):
774
                    continue
775
                ally = tran.db[allyID]
776
                if firing[allyID] and ally.type != T_PLANET:
777
                    surrenderTo = []
778
                    break
779
            if surrenderTo:
780
                index = Utils.rand(0, len(surrenderTo))
781
                if obj:
782
                    if self.cmd(obj).surrenderTo(tran, obj, surrenderTo[index]):
783
                        winner = tran.db[surrenderTo[index]]
784
                        source = tran.db.get(owners[objID], None)
785
                        log.debug('ISystem', 'BATTLE - surrender', objID, surrenderTo[index], surrenderTo)
786
                        if source:
787
                            Utils.sendMessage(tran, source, MSG_COMBAT_LOST, system.oid, winner.oid)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_COMBAT_LOST does not seem to be defined.
Loading history...
788
                            Utils.sendMessage(tran, winner, MSG_COMBAT_WON, system.oid, source.oid)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable MSG_COMBAT_WON does not seem to be defined.
Loading history...
789
                        else:
790
                            Utils.sendMessage(tran, winner, MSG_COMBAT_WON, system.oid, obj.oid)
791
                else:
792
                    winner = tran.db[surrenderTo[index]]
793
                    source = tran.db[owners[objID]]
794
                    log.debug('ISystem', 'BATTLE - surrender', objID, surrenderTo[index], surrenderTo)
795
                    Utils.sendMessage(tran, source, MSG_COMBAT_LOST, system.oid, winner.oid)
796
                    Utils.sendMessage(tran, winner, MSG_COMBAT_WON, system.oid, source.oid)
797
        return
798
799
    processBATTLEPhase.public = 1
800
    processBATTLEPhase.accLevel = AL_ADMIN
801
802
    def processFINALPhase(self, tran, obj, data):
803
        # TODO find new starting points
804
        # clean up mines if system ownership was lost
805
        owners = []
806
        for planetID in obj.planets:
807
            planet = tran.db[planetID]
808
            if planet.owner not in owners:
809
                owners.append(planet.owner)
810
        for ownerid in obj.minefield:
811
            if ownerid not in owners:
812
                self.clearMines(obj, ownerid)
813
        return obj.planets[:] + obj.closeFleets[:]
814
815
    processFINALPhase.public = 1
816
    processFINALPhase.accLevel = AL_ADMIN
817
818
    def sortPlanets(self, tran, obj, data):
819
        obj.planets.sort(key=lambda planetID: tran.db[planetID].plEn, reverse = True)
820
        orbit = 1
821
        for planetID in obj.planets:
822
            planet = tran.db[planetID]
823
            planet.orbit = orbit
824
            orbit += 1
825
826
    sortPlanets.public = 0
827
828
    def rename(self, tran, obj, newName, nType):
829
        newName = newName.strip()
830
        # you have to own all planets
831
        # TODO: Throw another cmdr exc AFTER you have no planet
832
        haveOne = 0
833
        anotherComm = 0
834
        for planetID in obj.planets:
835
            planet = tran.db[planetID]
836
            if planet.owner != tran.session.cid and planet.owner != OID_NONE:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_NONE does not seem to be defined.
Loading history...
837
                anotherComm = 1
838
            if planet.owner == tran.session.cid:
839
                haveOne = 1
840
        if not haveOne:
841
            raise ige.GameException('You cannot change name of this system - you have no planet in this system.')
842
        if anotherComm:
843
            raise ige.GameException('You cannot change name of this system - another commander in system.')
844
        # check validity of name
845
        if not Utils.isCorrectName(newName):
846
            raise ige.GameException('Invalid name. Only characters, digits, space, dot and dash permitted, max. length is 30 characters.')
847
        # check if there is other system with this name
848
        galaxy = tran.db[obj.compOf]
849
        for systemID in galaxy.systems:
850
            if tran.db[systemID].name == newName and systemID != obj.oid:
851
                raise ige.GameException('This name is already used.')
852
        # TODO you have to own this system longer than previous owner
853
        # one change per 1 day allowed
854
        turn = tran.db[OID_UNIVERSE].turn
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OID_UNIVERSE does not seem to be defined.
Loading history...
855
        if obj.lastNameChng + Rules.turnsPerDay <= turn:
856
            # rename system
857
            obj.name = newName
858
            # rename planets
859
            newNames = [obj.name]
860
            for planetID in obj.planets:
861
                planet = tran.db[planetID]
862
                planet.name = Utils.getPlanetName(obj.name, nType, planet.orbit - 1)
863
                newNames.append(planet.name)
864
            obj.lastNameChng = turn
865
        else:
866
            raise ige.GameException('You cannot change name of this system - name has been changed recently (try it one day later).')
867
        return newNames
868
869
    rename.public = 1
870
    rename.accLevel = AL_NONE
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable AL_NONE does not seem to be defined.
Loading history...
871
872
    def createPlanet(self, tran, obj):
873
        planet = self.new(T_PLANET)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable T_PLANET does not seem to be defined.
Loading history...
874
        planet.compOf = obj.oid
875
        oid = tran.db.create(planet)
876
        obj.planets.append(oid)
877
        return oid
878
879
    def deployMines(self, tran, obj, owner_id):
880
        """ Go through all mine control structures and attempt to add mines.
881
882
        """
883
        for tech, struct in self.getSystemMineLauncher(tran, obj, owner_id):
884
            if not struct[STRUCT_IDX_STATUS] & STRUCT_STATUS_ON:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_IDX_STATUS does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable STRUCT_STATUS_ON does not seem to be defined.
Loading history...
885
                # structure is offline, reset timer
886
                self.addMine(tran, obj, owner_id, tech.mineclass, 0)
887
                continue
888
            efficiency = struct[STRUCT_IDX_HP] / float(tech.maxHP)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_IDX_HP does not seem to be defined.
Loading history...
889
            minerate = int(tech.minerate / efficiency)
890
            minenum = int(tech.minenum * efficiency)
891
            if self.addMine(tran, obj, owner_id, tech.mineclass, minenum, minerate):
892
                log.debug('ISystem', 'Mine deployed for owner %d in system %d' % (owner_id, obj.oid))
893
894
    deployMines.public = 1
895
    deployMines.accLevel = AL_ADMIN
896
897
898
    def addMine(self, tran, obj, owner_id, mine_tech_id, max_amount=None, mine_rate=None):
899
        """ Increment amount within particular minefield of particular player.
900
        Set current turn as a date of latest deployment.
901
902
        Returns True if mine was added.
903
904
        """
905
        current_turn = tran.db[obj.compOf].galaxyTurn
906
        if owner_id in obj.minefield:
907
            index = -1
908
            for mine_id, amount, deploy_turn in obj.minefield[owner_id]:
909
                index += 1
910
                if mine_id != mine_tech_id:
911
                    continue
912
                if max_amount is not None and amount >= max_amount:
913
                    # cannot add more, thus update deploy turn to current one
914
                    # (so replenish starts after that amount of turns if needed)
915
                    obj.minefield[owner_id][index] = (mine_id, amount, current_turn)
916
                    return False
917
                if mine_rate and (current_turn - deploy_turn) < mine_rate:
918
                    # need more time to deploy new mine
919
                    return False
920
                obj.minefield[owner_id][index] = (mine_id, amount + 1, current_turn)
921
                return True
922
            # owner has some minefield, but not this type
923
            obj.minefield[owner_id].append((mine_id, 1, current_turn))
0 ignored issues
show
introduced by
The variable mine_id does not seem to be defined in case the for loop on line 908 is not entered. Are you sure this can never be the case?
Loading history...
924
            return True
925
        else:
926
            # this will be owner's first minefield in this system
927
            obj.minefield[owner_id]= [(mine_tech_id, 1, current_turn)]
928
            return True
929
930
    addMine.public = 1
931
    addMine.accLevel = AL_ADMIN
932
933
    def removeMine(self, obj, owner_id, mine_tech_id):
934
        """ Decrement amount within particular minefield of particular player.
935
        If amount drops to zero, remove minefield.
936
        If all minefields are removed, remove player minefield record.
937
938
        """
939
        if owner_id in obj.minefield:
940
            index = -1
941
            for mine_id, amount, deploy_turn in obj.minefield[owner_id]:
942
                index += 1
943
                if mine_id != mine_tech_id:
944
                    continue
945
                amount -= 1
946
                if amount > 0:
947
                    obj.minefield[owner_id][index] = (mine_id, amount, deploy_turn)
948
                else:
949
                    # we have depleted the minefield, remove any notion of it
950
                    del obj.minefield[owner_id][index]
951
                break
952
            if not len(obj.minefield[owner_id]):
953
                # all minefields are depleted, remove player record
954
                del obj.minefield[owner_id]
955
956
    removeMine.public = 1
957
    removeMine.accLevel = AL_ADMIN
958
959
960
    def getMines(self, obj, owner_id):
961
        """ Return list of tuples representing each minefield.
962
963
        """
964
        if owner_id in obj.minefield:
965
            return obj.minefield[owner_id]
966
        else:
967
            return []
968
969
    getMines.public = 1
970
    getMines.accLevel = AL_ADMIN
971
972
    def clearMines(self, obj, owner_id):
973
        """ Remove all minefields of given owner from the system.
974
975
        """
976
        if owner_id in obj.minefield:
977
            del obj.minefield[owner_id]
978
979
    clearMines.public = 0
980
981
    def fireMine(self, obj, owner_id): # shoot the mine
982
        if owner_id not in obj.minefield:
983
            return False, False, False, False
984
985
        mine_ids = []
986
        amounts = []
987
        for mine_id, amount, deploy_turn in obj.minefield[owner_id]:
988
            mine_ids.append(mine_id)
989
            amounts.append(amount)
990
        mine = Utils.weightedRandom(mine_ids, amounts) # select random mine to detonate
991
        self.removeMine(obj, owner_id, mine)
992
        tech = Rules.techs[mine]
993
        damage = random.randrange(tech.weaponDmgMin, tech.weaponDmgMax)
994
        attack = tech.weaponAtt
995
        ignore_shield = tech.weaponIgnoreShield
996
        return damage, attack, ignore_shield, mine
997
998
    fireMine.public = 1
999
    fireMine.accLevel = AL_ADMIN
1000
1001
    def getSystemMineLauncher(self, tran, obj, playerID):
1002
        launchers = []
1003
        for planetID in obj.planets:
1004
            planet = tran.db[planetID]
1005
            if planet.owner == playerID:
1006
                for struct in planet.slots:
1007
                    tech = Rules.techs[struct[STRUCT_IDX_TECHID]]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_IDX_TECHID does not seem to be defined.
Loading history...
1008
                    if tech.mineclass:
1009
                        launchtech = tech
1010
                        launchers.append((launchtech, struct))
1011
        return launchers
1012
1013
    getSystemMineLauncher.public = 0
1014
1015
    def getSystemMineSource(self, tran, obj, playerID):
1016
        sources = []
1017
        for planetID in obj.planets:
1018
            planet = tran.db[planetID]
1019
            if planet.owner == playerID:
1020
                for struct in planet.slots:
1021
                    tech = Rules.techs[struct[STRUCT_IDX_TECHID]]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_IDX_TECHID does not seem to be defined.
Loading history...
1022
                    if tech.mineclass:
1023
                        sources.append(planetID)
1024
        return sources
1025
1026
    getSystemMineSource.public = 0
1027
1028
    def getSystemCombatBonuses(self, tran, obj, playerID):
1029
        systemAtt = 0;
1030
        systemDef = 0;
1031
        for planetID in obj.planets:
1032
            planet = tran.db[planetID]
1033
            if planet.owner == playerID:
1034
                for struct in planet.slots:
1035
                    tech = Rules.techs[struct[STRUCT_IDX_TECHID]]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable STRUCT_IDX_TECHID does not seem to be defined.
Loading history...
1036
                    techEff = Utils.getTechEff(tran, struct[STRUCT_IDX_TECHID], planet.owner)
1037
                    if tech.systemAtt > 0 or tech.systemDef > 0:
1038
                        systemAtt = max(systemAtt, tech.systemAtt * techEff)
1039
                        systemDef = max(systemDef, tech.systemDef * techEff)
1040
        return (systemAtt, systemDef)
1041
1042
    getSystemCombatBonuses.public = 0
1043
1044
    def loadDOMNode(self, tran, obj, xoff, yoff, node):
1045
        obj.x = float(node.getAttribute('x')) + xoff
1046
        obj.y = float(node.getAttribute('y')) + yoff
1047
        orbit = 1
1048
        nType = Utils.getPlanetNamesType()
1049
        for elem in node.childNodes:
1050
            if elem.nodeType == Node.ELEMENT_NODE:
1051
                name = elem.tagName
1052
                if name == 'properties':
1053
                    self.loadDOMAttrs(obj, elem)
1054
                elif name == 'planet':
1055
                    # create planet
1056
                    planet = tran.db[self.createPlanet(tran, obj)]
1057
                    self.cmd(planet).loadDOMNode(tran, planet, obj.x, obj.y, orbit, elem)
1058
                    # planet.name = u'%s %s' % (obj.name, '-ABCDEFGHIJKLMNOPQRSTUVWXYZ'[orbit])
1059
                    planet.name = Utils.getPlanetName(obj.name, nType, orbit - 1)
1060
                    orbit += 1
1061
                else:
1062
                    raise ige.GameException('Unknown element %s' % name)
1063
        #~ # compute rotational constants
1064
        #~ galaxy = tran.db[obj.compOf]
1065
        #~ dx = obj.x - galaxy.x
1066
        #~ dy = obj.y - galaxy.y
1067
        #~ obj.dist = math.sqrt(dx * dx + dy * dy)
1068
        #~ if obj.dist > 0:
1069
            #~ obj.dAngle = math.sqrt(galaxy.centerWeight / obj.dist) / obj.dist
1070
        #~ else:
1071
            #~ obj.dAngle = 0.0
1072
        #~ if dx != 0:
1073
            #~ obj.sAngle = math.atan(dy / dx)
1074
            #~ if dx < 0: obj.sAngle += math.pi
1075
        #~ elif dy > 0:
1076
            #~ obj.sAngle = math.pi / 2
1077
        #~ elif dx < 0:
1078
            #~ obj.sAngle = math.pi * 3 / 2
1079
        #~ # this is a check only
1080
        #~ angle = obj.sAngle + (0 / 384.0) * obj.dAngle
1081
        #~ x = galaxy.x + obj.dist * math.cos(angle)
1082
        #~ y = galaxy.y + obj.dist * math.sin(angle)
1083
        #~ if x != obj.x or y != obj.y:
1084
            #~ log.warning(obj.name, obj.x, obj.y, dx, dy, obj.dist, obj.dAngle, obj.sAngle, x, y)
1085
        return SUCC
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SUCC does not seem to be defined.
Loading history...
1086