osci.StarMap.StarMap.drawSystems()   F
last analyzed

Complexity

Conditions 28

Size

Total Lines 103
Code Lines 97

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 28
eloc 97
nop 2
dl 0
loc 103
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

Complexity

Complex classes like osci.StarMap.StarMap.drawSystems() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
#
3
#  Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/]
4
#
5
#  This file is part of Outer Space.
6
#
7
#  Outer Space is free software; you can redistribute it and/or modify
8
#  it under the terms of the GNU General Public License as published by
9
#  the Free Software Foundation; either version 2 of the License, or
10
#  (at your option) any later version.
11
#
12
#  Outer Space is distributed in the hope that it will be useful,
13
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
#  GNU General Public License for more details.
16
#
17
#  You should have received a copy of the GNU General Public License
18
#  along with Outer Space; if not, write to the Free Software
19
#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
#
21
22
from pygameui import Fonts
23
import ige.ospace.Const as Const
24
from ige.ospace import Rules, Utils
25
import pygame, pygame.draw, pygame.key, pygame.image
26
import gdata, client, res, math, string
27
from ige import log
28
29
buoyColors = [(0xff, 0xff, 0x00), (0x00, 0xff, 0xff), (0xff, 0x00, 0xff), (0xb0, 0xb0, 0xff)]
30
MAX_BOUY_DISPLAY_LEN = 30
31
CONTROLRANGE = 5
32
MAXCONTROLRANGE = 30 #square of CONTROLRANGE + small amount
33
34
class StarMap(object):
35
    MAP_SCANNER1 = 1
36
    MAP_SYSTEMS = 3
37
    MAP_PLANETS = 4
38
    MAP_FLEETS = 5
39
    MAP_FORDERS = 6
40
    MAP_OTHERS = 7
41
    MAP_FREDIRECTS = 8
42
    MAP_GATESYSTEMS = 10
43
    MAP_CONTROLAREA = 11
44
45
    def __init__(self, modes):
46
        self.rect = None # will be set later - rect during init phase is not precise
47
        # map
48
        self._map = {
49
            self.MAP_SCANNER1: [],
50
            self.MAP_SYSTEMS: [],
51
            self.MAP_PLANETS: [],
52
            self.MAP_FLEETS: [],
53
            self.MAP_FORDERS: [],
54
            self.MAP_OTHERS: [],
55
            self.MAP_FREDIRECTS: [],
56
            self.MAP_GATESYSTEMS: [],
57
            self.MAP_CONTROLAREA: {}
58
        }
59
        self._popupInfo = {}
60
        self._fleetRanges = {}
61
        self._fleetTarget = {}
62
        self._fordersTarget = {}
63
        self._actAreas = {}
64
        self._actBuoyAreas = {}
65
        self.currX = 0.0
66
        self.currY = 0.0
67
        self.scale = 50.0
68
        self.textSize = 'normal'
69
        #modes
70
        self.control_modes = modes
71
        # overlay system
72
        self.overlayMode = gdata.OVERLAY_OWNER
73
        self._overlayZone = False
74
75
    def chronicle_draw(self):
76
        galaxy_id = client.getPlayer().galaxy
77
        galaxy = client.get(galaxy_id, noUpdate = 1)
78
        saved_x, saved_y = self.currX, self.currY
79
        self.currX, self.currY = galaxy.x, galaxy.y
80
        surface_side = (galaxy.radius + 2) * 2 * self.scale
81
        new_surf, empty, empty = self.draw(pygame.Surface((surface_side, surface_side)))
82
        self.currX, self.currY = saved_x, saved_y
83
        return new_surf
84
85
86
    def precompute(self):
87
        player_highlight = -1
88
        if gdata.config.game.highlight != None:
89
            player_highlight = gdata.config.game.highlight
90
        self._map = {
91
            self.MAP_SCANNER1: [],
92
            self.MAP_SYSTEMS: [],
93
            self.MAP_PLANETS: [],
94
            self.MAP_FLEETS: [],
95
            self.MAP_FORDERS: [],
96
            self.MAP_OTHERS: [],
97
            self.MAP_FREDIRECTS: [],
98
            self.MAP_GATESYSTEMS: [],
99
            self.MAP_CONTROLAREA: {}
100
        }
101
        self._popupInfo = {}
102
        self._fleetRanges = {}
103
        # find all pirate planets
104
        pirate_systems = self.precomputePirateSystems()
105
        # process objects
106
        self.fleetOrbit = {}
107
        anyX = 0.0
108
        anyY = 0.0
109
        player = client.getPlayer()
110
        for objID in client.db.keys():
111
            if objID < Const.OID_FREESTART:
112
                continue
113
            obj = client.get(objID, noUpdate = 1)
114
            if not hasattr(obj, "type"):
115
                continue
116
            if obj.type == Const.T_PLAYER:
117
                continue
118
            try:
119
                if hasattr(obj, "x"):
120
                    anyX = obj.x
121
                if hasattr(obj, "y"):
122
                    anyY = obj.y
123
            except AttributeError, e:
124
                log.warning('StarMap', 'Cannot render objID = %d' % objID)
125
                continue
126
            if obj.type == Const.T_SYSTEM:
127
                self.precomputeSystems(obj, player, pirate_systems)
128
            elif obj.type == Const.T_WORMHOLE:
129
                self.precomputeWormholes(obj, player, pirate_systems)
130
            elif obj.type == Const.T_PLANET:
131
                self.precomputePlanets(obj, player, pirate_systems)
132
            elif obj.type == Const.T_FLEET:
133
                self.precomputeFleet(obj)
134
            elif obj.type in (Const.T_GALAXY, Const.T_AIPLAYER, Const.T_AIRENPLAYER, Const.T_AIMUTPLAYER, Const.T_AIPIRPLAYER, Const.T_AIEDENPLAYER, Const.T_PIRPLAYER):
135
                pass
136
            elif obj.type == Const.T_UNKNOWN:
137
                # pop up info
138
                info = []
139
                info.append(_('Unknown object [ID: %d]') % obj.oid)
140
                if hasattr(obj, 'scanPwr'):
141
                    info.append(_('Scan pwr: %d') % obj.scanPwr)
142
                self._popupInfo[obj.oid] = info
143
            else:
144
                log.warning('StarMap', 'Unknown object type %d' % obj.type)
145
        # redirections
146
        self.precomputeRedirections()
147
        # set position (typically on first show)
148
        if self.currX == 0.0 and self.currY == 0.0:
149
            self.currX = anyX
150
            self.currY = anyY
151
152
153
    def precomputePirateSystems(self):
154
        pirate_systems = {}
155
        log.debug("Checking pirate planets and wormholes")
156
        for objID in client.db.keys():
157
            if objID < Const.OID_FREESTART:
158
                continue
159
            obj = client.get(objID, noUpdate = 1)
160
            if not hasattr(obj, "type"):
161
                continue
162
            if obj.type == Const.T_WORMHOLE and not hasattr(obj, 'destinationOid'):
163
                obj = client.get(objID, forceUpdate = 1, publicOnly = 1)
164
            if obj.type == Const.T_PLANET and hasattr(obj, "x"):
165
                ownerID = getattr(obj, 'owner', Const.OID_NONE)
166
                if ownerID == Const.OID_NONE:
167
                    continue
168
                owner = client.get(ownerID, publicOnly = 1)
169
                if hasattr(owner, "type") and (owner.type == Const.T_PIRPLAYER or\
170
                                                owner.type == Const.T_AIPIRPLAYER):
171
                    pirate_systems[obj.x, obj.y] = None
172
        return pirate_systems
173
174
    def precomputeSystems(self, obj, player, pirate_systems):
175
        img = res.getSmallStarImg(obj.starClass[1]) # TODO correct me
176
        icons = []
177
        name = getattr(obj, 'name', None)
178
        # TODO compute real relationship
179
        #rel = Const.REL_UNDEF
180
        refuelMax = 0
181
        refuelInc = 0
182
        hasRefuel = False
183
        upgradeShip = 0
184
        repairShip = 0
185
        speedBoost = 0
186
        moraleCount = 0
187
        morale = 200
188
        constPoints = 0
189
        sciPoints = 0
190
        minerals = -1
191
        bio = -1
192
        slots = 0
193
        numPlanets = 0
194
        stratRes = Const.SR_NONE
195
        isGovCentral = False
196
        #owner2 = 0
197
        ownerID = Const.OID_NONE
198
        explored = False
199
        if hasattr(obj, 'planets'):
200
            hasPirate = False
201
            for planetID in obj.planets:
202
                planet = client.get(planetID, noUpdate = 1)
203
                owner = getattr(planet, 'owner', Const.OID_NONE)
204
                if hasattr(planet, "plType") and planet.plType not in ("A", "G"):
205
                    numPlanets += 1
206
                if hasattr(planet, "plMin"):
207
                    minerals = max(minerals,planet.plMin)
208
                if hasattr(planet, "plBio"):
209
                    bio = max(bio,planet.plBio)
210
                if hasattr(planet, "plSlots"):
211
                    slots += planet.plSlots
212
                if hasattr(planet, "plStratRes") and planet.plStratRes != Const.SR_NONE:
213
                    stratRes = planet.plStratRes
214
                    stratRes = planet.plStratRes
215
                    icons.append(res.icons["sr_%d" % planet.plStratRes])
216
                if owner:
217
                    ownerID = owner
218
                    if hasattr(planet, "morale"):
219
                        morale = min(morale,planet.morale)
220
                    if hasattr(planet, "refuelMax"):
221
                        refuelMax = max(refuelMax, planet.refuelMax)
222
                        refuelInc = max(refuelInc, planet.refuelInc)
223
                    if hasattr(planet, "repairShip"):
224
                        upgradeShip += planet.upgradeShip
225
                        repairShip = max(repairShip, planet.repairShip)
226
                    hasRefuel = hasRefuel or getattr(planet, 'hasRefuel', False)
227
                    if hasattr(planet, "fleetSpeedBoost"):
228
                        speedBoost = max(speedBoost, planet.fleetSpeedBoost)
229
                    if hasattr(planet, "effProdProd"):
230
                        constPoints += planet.effProdProd
231
                    if hasattr(planet, "effProdSci"):
232
                        sciPoints += planet.effProdSci
233
                    if hasattr(planet, "slots"):
234
                        for struct in planet.slots:
235
                            tech = Rules.techs[struct[Const.STRUCT_IDX_TECHID]]
236
                            if not tech.govPwr == 0:
237
                                isGovCentral = True
238
                            if not hasattr(planet, "morale"): # ugly way to say "planets of other players"
239
                                # operational status and tech effectivity
240
                                maxTechHP = tech.maxHP
241
                                opStatus = struct[Const.STRUCT_IDX_OPSTATUS]/100.0
242
                                if opStatus != 0:
243
                                    currHP = struct[Const.STRUCT_IDX_HP]
244
                                    techEff = (currHP / opStatus) / maxTechHP
245
                                else:
246
                                    techEff = 0
247
                                # production
248
                                b, m, e, d = tech.prodProdMod
249
                                prodMod = (b * planet.plBio + m * planet.plMin + e * planet.plEn + d * 100) / 100
250
                                constPoints += int(tech.prodProd * prodMod * techEff * opStatus)
251
                                # science
252
                                b, m, e, d = tech.prodSciMod
253
                                prodMod = (b * planet.plBio + m * planet.plMin + e * planet.plEn + d * 100) / 100
254
                                sciPoints += int(tech.prodSci * prodMod * techEff * opStatus)
255
                # uncharted system
256
                if hasattr(planet, 'plBio') and hasattr(planet, 'plEn'):
257
                    explored = True
258
        if not explored and name != None:
259
            name = "[%s]" % (name)
260
        #if moraleCount > 0:
261
        #    morale = morale/moraleCount
262
        if morale==200:
263
            morale = -1
264
        pirProb = self.precomputePiratesProbability(obj, pirate_systems, icons)
265
        if (player.type == Const.T_PIRPLAYER or\
266
                player.type == Const.T_AIPIRPLAYER):
267
            pirateFameCost = self.getPirateFameCost(player.oid,obj.oid,len(player.planets),pirate_systems)
268
        # refuelling
269
        if refuelMax > 0:
270
            if refuelMax >= 87:
271
                icons.append(res.icons["fuel_99"])
272
            elif refuelMax >= 62:
273
                icons.append(res.icons["fuel_75"])
274
            elif refuelMax >= 37:
275
                icons.append(res.icons["fuel_50"])
276
            elif refuelMax >= 12:
277
                icons.append(res.icons["fuel_25"])
278
        elif hasRefuel:
279
            icons.append(res.icons["fuel_-"])
280
        # repair and upgrade
281
        if upgradeShip > 10 and repairShip > 0.02:
282
            icons.append(res.icons["rep_10"])
283
        elif upgradeShip > 0 and repairShip > 0:
284
            icons.append(res.icons["rep_1"])
285
286
        self.precomputeCombat(obj, icons)
287
        self.precomputeMines(obj, icons)
288
        self.precomputeBuoys(obj, player, icons)
289
        # star gates
290
        if speedBoost > 1.0:
291
            icons.append(res.icons["sg_%02d" % round(speedBoost)])
292
            self._map[self.MAP_GATESYSTEMS].append((obj.x, obj.y, speedBoost))
293
        #if owner2 != 0:
294
        #   color = gdata.playerHighlightColor
295
        #else:
296
        #   color = res.getFFColorCode(rel)
297
        if (player.type == Const.T_PIRPLAYER or\
298
                player.type == Const.T_AIPIRPLAYER):
299
            colors = res.getStarmapWidgetSystemColor(ownerID,bio,minerals,slots,numPlanets,speedBoost, refuelInc, upgradeShip, pirProb*100, stratRes, morale, pirateFameCost)
300
        else:
301
            colors = res.getStarmapWidgetSystemColor(ownerID,bio,minerals,slots,numPlanets,speedBoost, refuelInc, upgradeShip, pirProb*100, stratRes, morale)
302
        namecolor = res.getPlayerColor(ownerID)
303
        controlcolor = res.getControlColor(ownerID)
304
        if controlcolor:
305
            groupCenterX = int(obj.x)
306
            groupCenterY = int(obj.y)
307
            for rX in range(-CONTROLRANGE,CONTROLRANGE):
308
                for rY in range(-CONTROLRANGE,CONTROLRANGE):
309
                    if rX*rX+rY*rY < MAXCONTROLRANGE:
310
                        ctrlid = "%d:%d" % (groupCenterX+rX,groupCenterY+rY)
311
                        dist = pow(obj.x-(groupCenterX+rX+0.5),2) + pow(obj.y-(groupCenterY+rY+0.5),2)
312
                        if ctrlid in self._map[self.MAP_CONTROLAREA]:
313
                            oldCtrl = self._map[self.MAP_CONTROLAREA][ctrlid]
314
                            if dist > oldCtrl[1]:
315
                                continue
316
                        self._map[self.MAP_CONTROLAREA][ctrlid] = (controlcolor,dist)
317
        self._map[self.MAP_SYSTEMS].append((obj.oid, obj.x, obj.y, name, img, colors, namecolor, False, icons, constPoints, sciPoints, isGovCentral))
318
        # pop up info
319
        info = []
320
        info.append(_('System: %s [ID: %d]') % (name or res.getUnknownName(), obj.oid))
321
        info.append(_('Coordinates: [%.2f, %.2f]') % (obj.x, obj.y))
322
        info.append(_('Scan pwr: %d') % obj.scanPwr)
323
        info.append(_('Star Class: %s') % obj.starClass[1:])
324
        info.append(_('Star Type: %s') % _(gdata.starTypes[obj.starClass[0]]))
325
        if (player.type == Const.T_PIRPLAYER or\
326
                player.type == Const.T_AIPIRPLAYER):
327
            info.append(_('Fame to Colonize: %d') % pirateFameCost)
328
        if refuelMax > 0:
329
            info.append(_("Refuel: %d %%/turn [%d %% max]") % (refuelInc, refuelMax))
330
        if repairShip > 0:
331
            info.append(_("Repair ratio: %d %%/turn") % (repairShip * 100))
332
        if upgradeShip > 0:
333
            info.append(_("Upgrade points: %d/turn") % upgradeShip)
334
        if speedBoost > 0:
335
            info.append(_("Fleet speed: +%d %%") % (speedBoost * 100))
336
        if pirProb > 0.0:
337
            info.append(_("Pirate get fame chance: %d %%") % (pirProb * 100))
338
        self._popupInfo[obj.oid] = info
339
340
    def precomputeWormholes(self, obj, player, pirate_systems):
341
        log.debug("Displaying wormhole",obj.oid)
342
        img = res.getSmallStarImg(obj.starClass[1])
343
        icons = []
344
        name = getattr(obj, 'name', None)
345
        pirProb = self.precomputePiratesProbability(obj, pirate_systems, icons)
346
        self.precomputeCombat(obj, icons)
347
        self.precomputeMines(obj, icons)
348
        self.precomputeBuoys(obj, player, icons)
349
        color = res.getPlayerColor(Const.OID_NONE)
350
        namecolor = res.getPlayerColor(Const.OID_NONE)
351
        constPoints = 0
352
        sciPoints = 0
353
        isGovCentral = False
354
        self._map[self.MAP_SYSTEMS].append((obj.oid, obj.x, obj.y, name, img, color, namecolor, True, icons, constPoints, sciPoints, isGovCentral))
355
        # pop up info
356
        info = []
357
        info.append(_('Worm hole: %s [ID: %d]') % (name or res.getUnknownName(), obj.oid))
358
        info.append(_('Coordinates: [%.2f, %.2f]') % (obj.x, obj.y))
359
        try:
360
            log.debug("Attempting to get wormhole destination (",obj.destinationOid,") from client.")
361
            whDestObj = client.get(obj.destinationOid, noUpdate = 1) #except if the client doesn't have this in their DB
362
            whDestName = getattr(whDestObj, 'name', None)
363
            info.append(_('Destination: %s [ID: %d]') % (whDestName or res.getUnknownName(), obj.oid))
364
            info.append(_('Dest. Coords: [%.2f, %.2f]') % (whDestObj.x, whDestObj.y))
365
        except:
366
            log.debug("Failed getting wormhole destination from client.")
367
            info.append(_('Destination: ? [ID: ?]'))
368
            info.append(_('Dest. Coords: [?, ?]'))
369
        if pirProb > 0.0:
370
            info.append(_("Pirate get fame chance: %d %%") % (pirProb * 100))
371
        self._popupInfo[obj.oid] = info
372
373
    def precomputePlanets(self, obj, player, pirate_systems):
374
        owner = getattr(obj, 'owner', Const.OID_NONE)
375
        # set up color reference data
376
        biodata = -1
377
        mindata = -1
378
        slotdata = 0
379
        stargatedata = 0
380
        dockrefueldata = 0
381
        dockupgradedata = 0
382
        stratresdata = Const.SR_NONE
383
        moraledata = -1
384
        pirProb = self.precomputePiratesProbability(obj, pirate_systems, False)
385
        famedata = pirProb*100
386
        biodata = getattr(obj, 'plBio', -1)
387
        mindata = getattr(obj, 'plMin', -1)
388
        slotdata = getattr(obj, 'plSlots', 0)
389
        dockrefueldata = getattr(obj, 'refuelInc', 0)
390
        dockupgradedata = getattr(obj, 'upgradeShip', 0)
391
        stargatedata = getattr(obj, 'fleetSpeedBoost', 0)
392
        stratresdata = getattr(obj, 'plStratRes', Const.SR_NONE)
393
        moraledata = getattr(obj, 'morale', -1)
394
        if (player.type == Const.T_PIRPLAYER or\
395
                player.type == Const.T_AIPIRPLAYER):
396
            pirateFameCost = self.getPirateFameCost(player.oid,obj.compOf,len(player.planets),pirate_systems)
397
        # build system
398
        name = getattr(obj, 'name', None) or res.getUnknownName()
399
        singlet = True
400
        if hasattr(obj, "plType") and obj.plType in ("A", "G"):
401
            colors = gdata.sevColors[gdata.DISABLED]
402
        else:
403
            singlet = False
404
            if (player.type == Const.T_PIRPLAYER or\
405
                    player.type == Const.T_AIPIRPLAYER):
406
                colors = res.getStarmapWidgetPlanetColor(owner,biodata,mindata,slotdata,stargatedata, dockrefueldata, dockupgradedata, famedata, stratresdata, moraledata, pirateFameCost)
407
            else:
408
                colors = res.getStarmapWidgetPlanetColor(owner,biodata,mindata,slotdata,stargatedata, dockrefueldata, dockupgradedata, famedata, stratresdata, moraledata)
409
        self._map[self.MAP_PLANETS].append((obj.oid, obj.x, obj.y, obj.orbit, colors, singlet))
410
        scannerPwr = getattr(obj, 'scannerPwr', 0)
411
        if scannerPwr:
412
            self._map[self.MAP_SCANNER1].append((obj.x, obj.y, scannerPwr))
413
        # pop up info
414
        info = []
415
        info.append(_('Planet: %s [ID: %d]') % (name, obj.oid))
416
        if hasattr(obj, 'scanPwr'): info.append(_('Scan pwr: %d') % obj.scanPwr)
417
        elif hasattr(obj, 'scannerPwr'): info.append(_('Scanner pwr: %d') % obj.scannerPwr)
418
        plType = gdata.planetTypes[getattr(obj, 'plType', None)]
419
        info.append(_('Type: %s') % _(plType))
420
        if (player.type == Const.T_PIRPLAYER or\
421
                player.type == Const.T_AIPIRPLAYER):
422
            info.append(_('Fame to Colonize: %d') % pirateFameCost)
423
        if hasattr(obj, 'plBio'): info.append(_('Environment: %d') % obj.plBio)
424
        if hasattr(obj, 'plMin'): info.append(_('Minerals: %d') % obj.plMin)
425
        if hasattr(obj, 'plEn'): info.append(_('Energy: %d') % obj.plEn)
426
        if hasattr(obj, 'plSlots'): info.append(_('Slots: %d') % obj.plSlots)
427
        if hasattr(obj, "plStratRes") and obj.plStratRes != Const.SR_NONE:
428
            info.append(_("Strat. resource: %s") % _(gdata.stratRes[obj.plStratRes]))
429
        if owner:
430
            ownerobj = client.get(owner, publicOnly = 1)
431
            info.append(_('Owner: %s [ID: %s]') % (
432
                getattr(ownerobj, 'name', res.getUnknownName()),
433
                getattr(ownerobj, 'oid', '?')
434
            ))
435
        self._popupInfo[obj.oid] = info
436
437
    def getPirateFameCost(self, playerID, systemID, numPiratePlanets, pirate_systems):
438
        mod = 1
439
        system = client.get(systemID, noUpdate = 1)
440
        if hasattr(system,'planets') and system.planets:
441
            for planetID in system.planets:
442
                planet = client.get(planetID, noUpdate = 1)
443
                if getattr(planet, 'owner', Const.OID_NONE) == playerID:
444
                    # minimum reached, don't check rest
445
                    return 0.0
446
                elif getattr(planet, 'plStratRes', None) in (Const.SR_TL3A, Const.SR_TL3B, Const.SR_TL3C):
447
                    mod = min(mod, Rules.pirateTL3StratResColonyCostMod)
448
        dist = 10000
449
        for pirX, pirY in pirate_systems:
450
            dist = min(dist, math.hypot(system.x - pirX, system.y - pirY))
451
        if Rules.pirateGainFamePropability(dist) > 0:
452
            mod = Rules.pirateColonyFameZoneCost(dist)
453
        else:
454
            mod = Rules.pirateColonyPlayerZoneCost(dist)
455
        return mod * numPiratePlanets * Rules.pirateColonyCostMod
456
457
    def precomputeRedirections(self,repaint=False): #also called from Mass Redirector
458
        player = client.getPlayer()
459
        for sourceID in player.shipRedirections:
460
            targetID = player.shipRedirections[sourceID]
461
            source = client.get(sourceID, noUpdate = 1)
462
            target = client.get(targetID, noUpdate = 1)
463
            if hasattr(source, "x") and hasattr(target, "y"):
464
                self._map[self.MAP_FREDIRECTS].append((source.x, source.y, target.x, target.y))
465
466
    def precomputeFleet(self,obj):
467
468
        owner = getattr(obj, 'owner', Const.OID_NONE)
469
        if hasattr(obj,'customname') and obj.customname:
470
            name = obj.customname
471
        else:
472
            name = getattr(obj, 'name', res.getUnknownName())
473
        color = res.getPlayerColor(owner)
474
        # fleet scanner setup
475
        scannerPwr = getattr(obj, 'scannerPwr', 0)
476
        if hasattr(obj, "scannerOn") and not obj.scannerOn:
477
            scannerPwr = 0
478
        if scannerPwr:
479
            self._map[self.MAP_SCANNER1].append((obj.x, obj.y, scannerPwr))
480
        #  get orbital position
481
        orbit = -1
482
        if obj.orbiting != Const.OID_NONE:
483
            orbit = self.fleetOrbit.get(obj.orbiting, 0)
484
            self.fleetOrbit[obj.orbiting] = orbit + 1
485
        # set path and times
486
        eta = getattr(obj, 'eta', 0)
487
        self._map[self.MAP_FLEETS].append((obj.oid, obj.x, obj.y, obj.oldX, obj.oldY, orbit, res.formatTime(eta), color,
488
            obj.signature / 25, getattr(obj, "isMilitary", 1)))
489
        # pop up info
490
        info = []
491
        info.append(_('Fleet: %s [ID: %d]') % (name, obj.oid))
492
        if hasattr(obj, 'scanPwr'):    info.append(_('Scan pwr: %d') % obj.scanPwr)
493
        if hasattr(obj, 'scannerPwr'): info.append(_('Scanner pwr: %d') % obj.scannerPwr)
494
        info.append(_('Coordinates: [%.2f, %.2f]') % (obj.x, obj.y))
495
        info.append(_('Signature: %d') % obj.signature)
496
        if hasattr(obj, 'speed'): info.append(_(u'Speed: %3.2f') % obj.speed)
497
        elif eta:
498
            info.append(_(u'Speed: %3.2f') % (24*((obj.y-obj.oldY)**2+(obj.x-obj.oldX)**2)**.5))
499
        if eta:
500
            info.append(_('ETA: %s') % res.formatTime(eta))
501
        if owner:
502
            ownerobj = client.get(owner, publicOnly = 1)
503
            info.append(_('Owner: %s [ID: %s]') % (
504
                getattr(ownerobj, 'name', res.getUnknownName()),
505
                getattr(ownerobj, 'oid', '?')
506
            ))
507
        if hasattr(obj, 'storEn'):
508
            if obj.maxEn > 0: full = 100 * obj.storEn / obj.maxEn
509
            else: full = 0
510
            info.append(_('Tanks: %d / %d [%d %%]') % (obj.storEn, obj.maxEn, full))
511
            info.append(_('Support (fuel): %d/turn') % (obj.operEn))
512
            info.append(_('Support (const. pts): %d/turn') % (obj.operProd))
513
        if hasattr(obj, 'combatPwr'):
514
            info.append(_('Military power: %d') % obj.combatPwr)
515
        # ranges
516
        if hasattr(obj, 'storEn') and hasattr(obj, 'operEn'):
517
            turns = 100000
518
            if obj.operEn > 0: turns = obj.storEn / obj.operEn
519
            range = turns * obj.speed / Rules.turnsPerDay
520
            self._fleetRanges[obj.oid] = (obj.x, obj.y, range, range  / 2., range / 3., obj.speed * 6 / Rules.turnsPerDay, turns)
521
            info.append(_("Operational time: %s") % res.formatTime(turns))
522
        if hasattr(obj, 'target') and obj.target != Const.OID_NONE:
523
            target = client.get(obj.target, noUpdate=1)
524
            if hasattr(target, "x"):
525
                self._fleetTarget[obj.oid] = (obj.x, obj.y, target.x, target.y)
526
            info.append(_('Target: %s') % getattr(target, "name", res.getUnknownName()))
527
        # pop up info (continued)
528
        if hasattr(obj, 'ships'):
529
            info.append(_('Ships:'))
530
            number = {}
531
            for designID, hp, shield, exp in obj.ships:
532
                tech = client.get(owner).shipDesigns[designID]
533
                level = Rules.shipExpToLevel.get(int(exp / tech.baseExp), Rules.shipDefLevel)
534
                if designID not in number:
535
                    number[designID] = [0, 0, 0, 0, 0]
536
                number[designID][level - 1] += 1
537
            order = number.keys()
538
            order.sort()
539
            for designID in order:
540
                tech = client.get(owner).shipDesigns[designID]
541
                levels = number[designID]
542
                info.append(_('  %d x %s   [%d, %d, %d, %d, %d]') % (
543
                        levels[0] + levels[1] + levels[2] + levels[3] + levels[4],
544
                        tech.name,
545
                        levels[0], levels[1], levels[2], levels[3], levels[4],
546
                    )
547
                )
548
        elif hasattr(obj, 'shipScan'):
549
            info.append(_('Ships:'))
550
            for name, shipClass, isMilitary in obj.shipScan:
551
                if isMilitary:
552
                    sType = _("military")
553
                else:
554
                    sType = _("civilian")
555
                info.append(_("  %d x %s [%s %s ship]") % (
556
                    obj.shipScan[name, shipClass, isMilitary],
557
                    name,
558
                    _(gdata.shipClasses[shipClass]),
559
                    sType
560
                ))
561
        if hasattr(obj, 'actionIndex') and not Utils.isIdleFleet(obj):
562
            action, target, data = obj.actions[obj.actionIndex]
563
            if target != Const.OID_NONE:
564
                targetName = getattr(client.get(target, noUpdate = 1), 'name', res.getUnknownName())
565
            else:
566
                targetName = ""
567
            info.append(_("Command: %s %s") % (
568
                gdata.fleetActions[action],
569
                targetName,
570
            ))
571
        self._popupInfo[obj.oid] = info
572
        # orders
573
        if hasattr(obj, 'actions'):
574
            oldX = obj.x
575
            oldY = obj.y
576
            self._fordersTarget[obj.oid]=[]
577
            for action, target, aData in obj.actions[obj.actionIndex:]:
578
                if target:
579
                    # TODO add action colors
580
                    if action == Const.FLACTION_REFUEL: color = (0x00, 0x90, 0x00)
581
                    elif action == Const.FLACTION_DEPLOY: color = (0x90, 0x90, 0x00)
582
                    elif action == Const.FLACTION_REDIRECT: color = (0x20, 0x20, 0x80)
583
                    else: color = (0x90, 0x90, 0x90)
584
                    trgt = client.get(target, noUpdate = 1)
585
                    if hasattr(trgt, 'x'):
586
                        self._map[self.MAP_FORDERS].append((oldX, oldY, trgt.x, trgt.y, color, getattr(obj, "isMilitary", 0)))
587
                        self._fordersTarget[obj.oid].append((oldX, oldY, trgt.x, trgt.y, color))
588
                        oldX, oldY = trgt.x, trgt.y
589
590
    def precomputePiratesProbability(self, system, pirate_systems, icons = False):
591
        dist = 10000
592
        for pirX, pirY in pirate_systems:
593
            dist = min(dist, math.hypot(system.x - pirX, system.y - pirY))
594
        pirProb = Rules.pirateGainFamePropability(dist)
595
        if icons != False:
596
            if pirProb >= 1.0:
597
                icons.append(res.icons["pir_99"])
598
            elif pirProb > 0.0:
599
                icons.append(res.icons["pir_00"])
600
        return pirProb
601
602
    def precomputeMines(self, system, icons):
603
        if getattr(system, "minefield", False):
604
            # ok, system has our mines - as minefield is identified
605
            icons.append(res.icons["mines_ours"])
606
            if getattr(system, "hasmines", 0) == 2:
607
                # there are also unknown mines!
608
                icons.append(res.icons["mines_unknown"])
609
        elif getattr(system, "hasmines", 0):
610
            # there are only unknown mines
611
            icons.append(res.icons["mines_unknown"])
612
613
614
615
    def precomputeCombat(self, system, icons):
616
        if hasattr(system, "combatCounter") and system.combatCounter > 0:
617
            icons.append(res.icons["combat"])
618
619
    def precomputeBuoys(self, system, player, icons):
620
        if hasattr(player, "buoys") and system.oid in player.buoys:
621
            icons.append(res.icons["buoy_%d" % player.buoys[system.oid][1]])
622
        if hasattr(player, "alliedBuoys") and system.oid in player.alliedBuoys and len(player.alliedBuoys[system.oid]) > 0:
623
            buoyName = "buoy_%d" % player.alliedBuoys[system.oid][0][1]
624
            if len(player.alliedBuoys[system.oid]) > 1:
625
                buoyName = "%s_plus" % buoyName
626
            icons.append(res.icons[buoyName])
627
628
629
    def draw(self, mapSurf):
630
        self._actAreas = {}
631
        # clear active areas for buoy texts
632
        self._actBuoyAreas = {}
633
        mapSurf.fill((0x00, 0x00, 0x00))
634
        ## scanners
635
        # scanner ranges and control areas
636
        if self.control_modes['scanners'] or self.control_modes['control_areas']:
637
            if self.control_modes['control_areas']:
638
                self.drawControlAreas(mapSurf)
639
            else:
640
                self.drawScanners(mapSurf)
641
        # pirate area
642
        if self.control_modes['pirate_areas']:
643
            pass # TODO
644
        # grid
645
        if self.control_modes['map_grid']:
646
            self.drawGrid(mapSurf)
647
        # redirections
648
        if self.control_modes['redirects']:
649
            self.drawRedirects(mapSurf)
650
        # gate systems
651
        if self.control_modes['gate_systems']:
652
            self.drawGateSystems(mapSurf)
653
        # stars
654
        if self.control_modes['systems']:
655
            self.drawSystems(mapSurf)
656
        # planets
657
        if self.control_modes['planets']:
658
            self.drawPlanets(mapSurf)
659
        # fleets
660
        if self.control_modes['fleets']:
661
            self.drawFleets(mapSurf)
662
        self.drawOverlayEffects(mapSurf)
663
        return mapSurf, self._actAreas, self._actBuoyAreas
664
665
    def drawScanners(self, mapSurf):
666
        # default scanner ranges (inner and outer circles)
667
        scanner1range = 1.0/10
668
        scanner2range = 1.0/16
669
        # coordinates
670
        centerX, centerY = mapSurf.get_rect().center
671
        maxX = mapSurf.get_rect().width
672
        maxY = mapSurf.get_rect().height
673
        currX = self.currX
674
        currY = self.currY
675
        scale = self.scale
676
        scannerCalced = []
677
        # draw
678
        for x, y, scan_range in self._map[self.MAP_SCANNER1]:
679
            sx = int((x - currX) * scale) + centerX
680
            sy = maxY - (int((y - currY) * scale) + centerY)
681
            currRange = int(scan_range * scale * scanner1range + 2)
682
            range1 = int(scan_range * scale * scanner1range)
683
            range2 = int(scan_range * scale * scanner2range)
684
            if sx+currRange > 0 and sx-currRange < maxX and sy+currRange > 0 and sy-currRange < maxY:
685
                pygame.draw.circle(mapSurf, (0x00, 0x00, 0x60), (sx, sy), currRange, 2)
686
                scannerCalced.append((sx,sy,range1,range2))
687
        for sx, sy, range1, range2 in scannerCalced:
688
            pygame.draw.circle(mapSurf, (0x00, 0x00, 0x30), (sx, sy), range1, 0)
689
        for sx, sy, range1, range2 in scannerCalced:
690
            pygame.draw.circle(mapSurf, (0x00, 0x00, 0x40), (sx, sy), range2, 0)
691
#        log.debug("Total scanner circles:",len(self._map[self.MAP_SCANNER1]))
692
#        log.debug("Drawn scanner circles:",len(scannerCalced))
693
694
    def drawControlAreas(self, mapSurf):
695
        centerX, centerY = mapSurf.get_rect().center
696
        maxY = mapSurf.get_rect().height
697
        currX = self.currX
698
        currY = self.currY
699
        scale = self.scale
700
        first = True
701
        for xy in self._map[self.MAP_CONTROLAREA].keys():
702
            x,y = xy.split(':',2)
703
            sx = int((int(x) - currX) * scale) + centerX + 1
704
            sy = maxY - (int((int(y) + 1 - currY) * scale) + centerY) # use y+1 because we have to draw from top down rather than bottom up
705
            if sy > centerY: sy += 1 #fix a bug with the draw system
706
            dx = scale
707
            dy = scale
708
            mapSurf.fill(self._map[self.MAP_CONTROLAREA][xy][0], pygame.Rect(sx, sy, dx, dy), 0)
709
710
    def drawRedirects(self, mapSurf):
711
        # coordinates
712
        centerX, centerY = mapSurf.get_rect().center
713
        maxY = mapSurf.get_rect().height
714
        currX = self.currX
715
        currY = self.currY
716
        scale = self.scale
717
        for sx, sy, tx, ty in self._map[self.MAP_FREDIRECTS]:
718
            sx = int((sx - currX) * scale) + centerX
719
            sy = maxY - (int((sy - currY) * scale) + centerY)
720
            tx = int((tx - currX) * scale) + centerX
721
            ty = maxY - (int((ty - currY) * scale) + centerY)
722
            # TODO: change do polygon (triangle), but needs to start
723
            # perpendicular to the redirect
724
            #pygame.draw.polygon(mapSurf, (0x20, 0x20, 0x80), [(sx+2, sy), (sx-2, sy), (tx, ty)])
725
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx, sy), (tx, ty), 1)
726
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx + 1, sy), (tx, ty), 1)
727
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx - 1, sy), (tx, ty), 1)
728
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx, sy + 1), (tx, ty), 1)
729
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx, sy - 1), (tx, ty), 1)
730
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx + 1, sy + 1), (tx, ty), 1)
731
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx + 1, sy - 1), (tx, ty), 1)
732
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx - 1, sy + 1), (tx, ty), 1)
733
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx - 1, sy - 1), (tx, ty), 1)
734
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx + 2, sy), (tx, ty), 1)
735
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx - 2, sy), (tx, ty), 1)
736
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx, sy + 2), (tx, ty), 1)
737
            pygame.draw.line(mapSurf, (0x20, 0x20, 0x80), (sx, sy - 2), (tx, ty), 1)
738
739
    def drawSystems(self, mapSurf):
740
        # coordinates
741
        centerX, centerY = mapSurf.get_rect().center
742
        maxY = mapSurf.get_rect().height
743
        currX = self.currX
744
        currY = self.currY
745
        scale = self.scale
746
        namecolor = res.getPlayerColor(Const.OID_NONE)
747
        if scale >= 30:
748
            for objID, x, y, name, img, color, namecolor, singlet, icons, constPoints, sciPoints, isGovCentral in self._map[self.MAP_SYSTEMS]:
749
                sx = int((x - currX) * scale) + centerX
750
                sy = maxY - (int((y - currY) * scale) + centerY)
751
                w, h = img.get_size()
752
                x = sx - w / 2
753
                y = sy - h / 2
754
                mapSurf.blit(img, (x, y))
755
                # images are now smaller - TODO fix images of stars
756
                w = 22
757
                h = 22
758
                if name:
759
                    if self.overlayMode != gdata.OVERLAY_OWNER:
760
                        namecolor = res.fadeColor(namecolor)
761
                    img = Fonts.renderText(self.textSize, name, 1, namecolor)
762
                    mapSurf.blit(img, (sx - img.get_width() / 2, sy + h / 2))
763
                buoy = self.getBuoy(objID)
764
                if buoy != None and not self.control_modes['alternative_mode']:
765
                    if not name: #if name not set and there is a bouy, set "?" as the name
766
                        if self.overlayMode != gdata.OVERLAY_OWNER:
767
                            namecolor = res.fadeColor(namecolor)
768
                        img = Fonts.renderText(self.textSize, '[ ? ]', 1, namecolor)
769
                        mapSurf.blit(img, (sx - img.get_width() / 2, sy + h / 2))
770
                        nSy = sy + h / 2 + img.get_height()
771
                    nSy = sy + h / 2 + img.get_height()
772
                    lines = buoy[0].split("\n")
773
                    maxW = 0
774
                    hh = 0
775
                    for line in lines:
776
                        if len(line) == 0:
777
                            break
778
                        if len(line) > MAX_BOUY_DISPLAY_LEN:
779
                            line = u"%s..." % line[:MAX_BOUY_DISPLAY_LEN]
780
                        if self.overlayMode == gdata.OVERLAY_OWNER:
781
                            bouycolor = buoyColors[buoy[1] - 1]
782
                        else:
783
                            bouycolor = res.fadeColor(buoyColors[buoy[1] - 1])
784
                        img = Fonts.renderText(self.textSize, line, 1, bouycolor)
785
                        maxW = max(img.get_width(), maxW)
786
                        mapSurf.blit(img, (sx - img.get_width() / 2, nSy + hh))
787
                        hh += img.get_height()
788
                    if maxW > 0:
789
                        actRect = pygame.Rect(sx - maxW / 2, nSy, maxW, hh)
790
                        actRect.move_ip(self.rect.left, self.rect.top)
791
                        self._actBuoyAreas[objID] = actRect
792
                elif self.control_modes['alternative_mode']:
793
                    alternative = name
794
                    nSy = sy + h / 2 + img.get_height()
795
                    if constPoints != 0 or sciPoints != 0:
796
                        img = Fonts.renderText(self.textSize, u"CP: %d RP: %d" % (constPoints, sciPoints), 1, namecolor)
797
                        mapSurf.blit(img, (sx - img.get_width() / 2, nSy))
798
                    if isGovCentral:
799
                        img = Fonts.renderText(self.textSize, u"Central system", 1, (255, 255, 255))
800
                        mapSurf.blit(img, (sx - img.get_width() / 2, nSy + img.get_height()))
801
                for icon in icons:
802
                    mapSurf.blit(icon, (x, y))
803
                    x += icon.get_width() + 1
804
                # active rectangle
805
                actRect = pygame.Rect(sx - w / 2, sy - h / 2, w, h)
806
                actRect.move_ip(self.rect.left, self.rect.top)
807
                self._actAreas[objID] = actRect
808
        else:
809
            for objID, x, y, name, img, color, namecolor, singlet, icons, constPoints, sciPoints, isGovCentral in self._map[self.MAP_SYSTEMS]:
810
                if not singlet:
811
                    color = color[self.overlayMode]
812
                sx = int((x - currX) * scale) + centerX
813
                sy = maxY - (int((y - currY) * scale) + centerY)
814
                pygame.draw.circle(mapSurf, color, (sx, sy), 5, 1)
815
                pygame.draw.circle(mapSurf, color, (sx, sy), 4, 0)
816
                if name and scale > 15:
817
                    if self.overlayMode != gdata.OVERLAY_OWNER:
818
                        namecolor = res.fadeColor(namecolor)
819
                    img = Fonts.renderText(self.textSize, name, 1, namecolor)
820
                    mapSurf.blit(img, (sx - img.get_width() / 2, sy + 6 / 2))
821
                    buoy = self.getBuoy(objID)
822
                    if buoy != None:
823
                        lines = buoy[0].split("\n")
824
                        nSy = sy + 6 / 2 + img.get_height()
825
                        maxW = 0
826
                        hh = 0
827
                        for line in lines:
828
                            if len(line) == 0:
829
                                break
830
                            img = Fonts.renderText(self.textSize, line, 1, buoyColors[buoy[1] - 1])
831
                            maxW = max(img.get_width(), maxW)
832
                            mapSurf.blit(img, (sx - img.get_width() / 2, nSy + hh))
833
                            hh += img.get_height()
834
                        if maxW > 0:
835
                            actRect = pygame.Rect(sx - maxW / 2, nSy, maxW, hh)
836
                            actRect.move_ip(self.rect.left, self.rect.top)
837
                            self._actBuoyAreas[objID] = actRect
838
                # active rectangle
839
                actRect = pygame.Rect(sx - 6 / 2, sy - 6 / 2, 6, 6)
840
                actRect.move_ip(self.rect.left, self.rect.top)
841
                self._actAreas[objID] = actRect
842
843
    def drawGateSystems(self, mapSurf):
844
        # coordinates
845
        centerX, centerY = mapSurf.get_rect().center
846
        maxY = mapSurf.get_rect().height
847
        currX = self.currX
848
        currY = self.currY
849
        scale = self.scale
850
        minRadius = 8
851
        radiusMult = 3
852
        if scale < 30:
853
            for x, y, speed in self._map[self.MAP_GATESYSTEMS]:
854
                sx = int((x - currX) * scale) + centerX
855
                sy = maxY - (int((y - currY) * scale) + centerY)
856
                for curSpeed in range(1,int(speed+1)):
857
                    radius = (curSpeed-1)* radiusMult + minRadius
858
                    color = res.getStargateColorCode(curSpeed)
859
                    pygame.draw.circle(mapSurf, color, (sx, sy), radius, 1)
860
861
    def drawPlanets(self, mapSurf):
862
        # coordinates
863
        centerX, centerY = mapSurf.get_rect().center
864
        maxY = mapSurf.get_rect().height
865
        currX = self.currX
866
        currY = self.currY
867
        scale = self.scale
868
        if scale >= 30:
869
            rectSize = max(int(gdata.config.defaults.minplanetsymbolsize), math.floor(scale/6))
870
            if not int(gdata.config.defaults.maxplanetsymbolsize) == 0:
871
                rectSize = min(int(gdata.config.defaults.maxplanetsymbolsize), rectSize)
872
            rectSpace = rectSize + math.floor(rectSize/5)
873
            for objID, x, y, orbit, color, singlet in self._map[self.MAP_PLANETS]:
874
                if not singlet:
875
                    color = color[self.overlayMode]
876
                sx = int((x - currX) * scale) + centerX
877
                sy = maxY - (int((y - currY) * scale) + centerY)
878
                orbit -= 1
879
                actRect = pygame.Rect(sx + (orbit % 8) * rectSpace + 13, sy + 6 * (orbit / 8) - rectSize , rectSize, rectSize)
880
881
                mapSurf.fill(color, actRect)
882
                actRect.move_ip(self.rect.left, self.rect.top)
883
                self._actAreas[objID] = actRect
884
        elif scale > 20:
885
            for objID, x, y, orbit, color, singlet in self._map[self.MAP_PLANETS]:
886
                if not singlet:
887
                    color = color[self.overlayMode]
888
                sx = int((x - currX) * scale) + centerX
889
                sy = maxY - (int((y - currY) * scale) + centerY)
890
                orbit -= 1
891
                actRect = pygame.Rect(sx + (orbit % 8) * 3 + 7, sy - 3 * (orbit / 8) - 1, 2, 2)
892
                mapSurf.fill(color, actRect)
893
                actRect.move_ip(self.rect.left, self.rect.top)
894
                self._actAreas[objID] = actRect
895
896
    def drawFleets(self, mapSurf):
897
        # coordinates
898
        centerX, centerY = mapSurf.get_rect().center
899
        maxY = mapSurf.get_rect().height
900
        currX = self.currX
901
        currY = self.currY
902
        scale = self.scale
903
        minSize = int(gdata.config.defaults.minfleetsymbolsize)
904
        rectSize = max(minSize, math.floor(scale / 7) - math.floor(scale / 7) % 2)
905
        if not int(gdata.config.defaults.maxfleetsymbolsize) == 0:
906
            rectSize = min(int(gdata.config.defaults.maxfleetsymbolsize), rectSize)
907
        rectSpace = rectSize + math.floor(rectSize/5)
908
        # draw orders lines
909
        if self.control_modes['fleet_lines']:
910
            for x1, y1, x2, y2, color, military in self._map[self.MAP_FORDERS]:
911
                if not self.control_modes['civilian_fleets'] and not military:
912
                    continue
913
                sx1 = int((x1 - currX) * scale) + centerX
914
                sy1 = maxY - (int((y1 - currY) * scale) + centerY)
915
                sx2 = int((x2 - currX) * scale) + centerX
916
                sy2 = maxY - (int((y2 - currY) * scale) + centerY)
917
                pygame.draw.line(mapSurf, color, (sx1, sy1), (sx2, sy2), 1)
918
        # draw fleet symbol
919
        for objID, x, y, oldX, oldY, orbit, eta, color, size, military in self._map[self.MAP_FLEETS]:
920
            if not self.control_modes['civilian_fleets'] and not military:
921
                continue
922
            if self.overlayMode != gdata.OVERLAY_OWNER:
923
                color = res.fadeColor(color)
924
            sx = int((x - currX) * scale) + centerX
925
            sy = maxY - (int((y - currY) * scale) + centerY)
926
            if orbit >= 0 and scale >= 30:
927
                actRect = pygame.Rect(sx + (orbit % 7) * rectSpace + 13 + 2 * (orbit % 7), sy + scale/6 * (orbit / 7) + 6, rectSize, rectSize)
928
                # TODO this is a workaround - fix it when pygame gets fixed
929
                # pygame.draw.polygon(mapSurf, color,
930
                #    (actRect.midleft, actRect.midtop, actRect.midright, actRect.midbottom), 1)
931
                pygame.draw.polygon(mapSurf, color,
932
                    (actRect.midleft, actRect.midtop, actRect.midright, actRect.midbottom), 0)
933
                actRect.move_ip(self.rect.left, self.rect.top)
934
                self._actAreas[objID] = actRect
935
            elif orbit < 0:
936
                rectSizeFlying = rectSize+2
937
                sox = int((oldX - currX) * scale) + centerX
938
                soy = maxY - (int((oldY - currY) * scale) + centerY)
939
                actRect = pygame.Rect(sx - rectSizeFlying / 2, sy - rectSizeFlying / 2, rectSizeFlying , rectSizeFlying)
940
                if military:
941
                    mColor = color
942
                else:
943
                    mColor = (0xff, 0xff, 0xff)
944
                pygame.draw.line(mapSurf, mColor, (sx, sy), (sox, soy), size + 1)
945
                # TODO rotate triangle
946
                pygame.draw.polygon(mapSurf, color,
947
                    (actRect.midleft, actRect.midtop, actRect.midright, actRect.midbottom), 1)
948
                pygame.draw.polygon(mapSurf, color,
949
                    (actRect.midleft, actRect.midtop, actRect.midright, actRect.midbottom), 0)
950
                if eta and scale > 15:
951
                    img = Fonts.renderText(self.textSize, eta, 1, color)
952
                    mapSurf.blit(img, actRect.topright)
953
                actRect.move_ip(self.rect.left, self.rect.top)
954
                self._actAreas[objID] = actRect
955
956
    def drawOverlayEffects(self, mapSurf):
957
        # coordinates
958
        centerX, centerY = mapSurf.get_rect().center
959
        maxY = mapSurf.get_rect().height
960
        currX = self.currX
961
        currY = self.currY
962
        scale = self.scale
963
        # draw overlay specific features, coloring itself is applied in drawPlanets etc.
964
        if self.overlayMode == gdata.OVERLAY_MORALE:
965
            player = client.getPlayer()
966
            if hasattr(player, "planets"):
967
                centralPlanet = client.get(player.planets[0])
968
                govPCR = player.govPwrCtrlRange
969
                player.stats.storPop, player.govPwr
970
                maxMorale = int(Rules.maxMorale)
971
                minAchievedMorale = int(max(Rules.minMoraleTrgt - 1, 107.5 - 37.5 * player.stats.storPop / player.govPwr))
972
                for step in xrange(maxMorale, minAchievedMorale - 1 , -10):
973
                    moraleColor = res.getMoraleColors(step)
974
                    centralX = int((centralPlanet.x - currX) * scale) + centerX
975
                    centralY = maxY - (int((centralPlanet.y - currY) * scale) + centerY)
976
                    radius = int((107.5 - step) * govPCR / 37.5 * scale)
977
                    pygame.draw.circle(mapSurf, moraleColor, (centralX, centralY), radius, 1)
978
                    text = Fonts.renderText(self.textSize, step, 1, moraleColor)
979
                    #maxW = max(text.get_width(), maxW)
980
                    mapSurf.blit(text, (centralX + radius, centralY))
981
982
983
984
985
986
    def drawGrid(self, mapSurf):
987
        rect = mapSurf.get_rect()
988
        centerX, centerY = rect.center
989
        maxY = rect.height
990
        currX = self.currX
991
        currY = self.currY
992
        scale = self.scale
993
        left = int((int(currX) - currX) * scale) + centerX - int(rect.width / scale / 2) * scale
994
        x = left
995
        while x < left + rect.width + scale:
996
            value =  math.floor((x - centerX) / scale + currX)
997
            if value % 5 == 0:
998
                pygame.draw.line(mapSurf, (0x00, 0x00, 0x90),
999
                    (x, rect.top), (x, rect.bottom), 1)
1000
                if self.control_modes['map_grid_coords']:
1001
                    textSrfc = Fonts.renderText(self.textSize, int(value), 1, (0x70, 0x70, 0x80))
1002
                    mapSurf.blit(textSrfc, (x + 2, rect.height - textSrfc.get_height()))
1003
            else:
1004
                pygame.draw.line(mapSurf, (0x33, 0x33, 0x66),
1005
                    (x, rect.top), (x, rect.bottom), 1)
1006
            x += scale
1007
        top = int((int(currY) - currY) * scale) + centerY - int(rect.height / scale / 2) * scale
1008
        y = top
1009
        while y < top + rect.height + scale:
1010
            yScrn = maxY - y
1011
            value =  math.floor(((maxY - yScrn) - centerY) / scale + currY)
1012
            if value % 5 == 0:
1013
                pygame.draw.line(mapSurf, (0x00, 0x00, 0x90),
1014
                    (rect.left, yScrn), (rect.right, yScrn), 1)
1015
                textSrfc = Fonts.renderText(self.textSize, int(value), 1, (0x70, 0x70, 0x80))
1016
                mapSurf.blit(textSrfc, (0, yScrn))
1017
            else:
1018
                pygame.draw.line(mapSurf, (0x33, 0x33, 0x66),
1019
                    (rect.left, yScrn), (rect.right, yScrn), 1)
1020
            y += scale
1021
1022
1023
    def getBuoy(self, objID):
1024
        player = client.getPlayer()
1025
        if hasattr(player, "buoys") and objID in player.buoys:
1026
            lines = player.buoys[objID][0].split("\n")
1027
            if len(lines) > 2:
1028
                return (u"%s\n%s" % (lines[0], lines[1]), player.buoys[objID][1])
1029
            else:
1030
                return player.buoys[objID]
1031
        else:
1032
            if hasattr(player, "alliedBuoys") and objID in player.alliedBuoys:
1033
                if len(player.alliedBuoys[objID]) > 0:
1034
                    lines = player.alliedBuoys[objID][0][0].split("\n")
1035
                    if len(lines) > 2:
1036
                        return (u"%s\n%s" % (lines[0], lines[1]), player.alliedBuoys[objID][0][1])
1037
                    else:
1038
                        return player.alliedBuoys[objID][0]
1039
                else:
1040
                    return None
1041
            else:
1042
                return None
1043
1044