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
|
|
|
|