osci.dialog.TechInfoDlg.bool2Text()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
#
2
#  Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/]
3
#
4
#  This file is part of Outer Space.
5
#
6
#  Outer Space is free software; you can redistribute it and/or modify
7
#  it under the terms of the GNU General Public License as published by
8
#  the Free Software Foundation; either version 2 of the License, or
9
#  (at your option) any later version.
10
#
11
#  Outer Space is distributed in the hope that it will be useful,
12
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
#  GNU General Public License for more details.
15
#
16
#  You should have received a copy of the GNU General Public License
17
#  along with Outer Space; if not, write to the Free Software
18
#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
#
20
import string
21
22
import pygameui as ui
23
24
from ige.ospace import Rules, Utils
25
import ige.ospace.Const as Const
26
27
from osci import gdata, res, client
28
29
30
def cclass2Text(cclass):
31
    return [_("small"), _("medium"), _("large"), _("planet")][cclass]
32
33
34
def structWeapons2Text(array):
35
    string = ''
36
    i = 0
37
    j = 0
38
    for weaponNum in array:
39
        if i>3:
40
            break
41
        if weaponNum > 0:
42
            if j > 0:
43
                string += _(', ')
44
            string += _('%d') % ( weaponNum )
45
            string += [_("S"), _("M"), _("L"), _("P"), _("?"), _("?"), _("?"), _("?"), _("?"), _("?")][i]
46
            j+=1
47
        i+=1
48
    return string
49
50
51
def bool2Text(value):
52
    return _("Yes") if value else _("No")
53
54
55
def perc2Text(value):
56
    return _('%d%%') % (value * 100)
57
58
59
def percBase1_2Text(value):
60
    return _('%+d%%') % ((value - 1) * 100)
61
62
63
def perc100_2Text(value):
64
    return _('%d%%') % (value)
65
66
67
def getTechName(techID):
68
    try:
69
        return client.getFullTechInfo(techID).name
70
    except:
71
        return _('Unknown')
72
73
74
def getTechShortname(techID):
75
    tech = client.getFullTechInfo(techID)
76
    try:
77
        return tech.shortname if tech.shortname else tech.name
78
    except:
79
        return _('Unknown')
80
81
82
def getRateName(rate):
83
    return _('%d Turns') % (int(rate))
84
85
86
V_NONE = 0x00
87
V_STRUCT = 0x01
88
V_HULL = 0x02
89
V_SEQUIP = 0x04
90
V_PROJECT = 0x08
91
V_EFF = 0x10 # attr * techEff
92
V_EFF_REV = 0x20 # attr / techEff
93
V_ALL = V_STRUCT|V_HULL|V_SEQUIP|V_PROJECT
94
95
techAttrs = {}
96
97
defaultAttr = (_('Not specified'), V_NONE, True, None, int)
98
99
100
def addAttr(attr, descr, props, showIfDefault, default=0, convertor=int):
101
    global techAttrs
102
    techAttrs[attr] = (descr, props, showIfDefault, default, convertor)
103
104
105
addAttr('buildProd', _('Constr. reqs - construction points'), V_ALL, 0)
106
107
addAttr('operBio', _('Operational reqs - biomatter'), V_ALL, 0)
108
addAttr('operMin', _('Operational reqs - minerals'), V_ALL, 0)
109
addAttr('operEn', _('Operational reqs - energy'), V_ALL, 0)
110
addAttr('operWorkers', _('Operational reqs - workers'), V_ALL, 0)
111
112
addAttr('prodBio', _('Production - biomatter'), V_STRUCT | V_EFF, 0)
113
addAttr('prodMin', _('Production - minerals'), V_STRUCT | V_EFF, 0)
114
addAttr('prodEn', _('Production - energy'), V_STRUCT | V_EFF, 0)
115
addAttr('prodPop', _('Production - population'), V_STRUCT | V_EFF, 0)
116
addAttr('prodProd', _('Production - constr. points'), V_STRUCT | V_PROJECT | V_EFF, 0)
117
addAttr('prodSci', _('Production - research points'), V_STRUCT | V_PROJECT | V_EFF, 0)
118
addAttr('prodEnv', _('Production - env. effect'), V_STRUCT | V_EFF, 0)
119
120
addAttr('solarMod', _('Orbital Shift Effect'), V_STRUCT | V_EFF, 0)
121
122
addAttr('storBio', _('Storage - biomatter'), V_STRUCT | V_EFF, 0)
123
addAttr('storMin', _('Storage - minerals'), V_STRUCT | V_EFF, 0)
124
addAttr('storEn', _('Storage - energy'), V_ALL | V_EFF, 0)
125
addAttr('storPop', _('Accommodate population'), V_STRUCT | V_EFF, 0)
126
127
addAttr('revoltThr', _('Lowers revolt threshold by'), V_STRUCT | V_PROJECT | V_EFF, 0)
128
addAttr('moraleTrgt', _('Increases max morale by'), V_STRUCT | V_PROJECT | V_EFF, 0)
129
addAttr('govPwr', _('Government power'), V_STRUCT | V_EFF, 0)
130
addAttr('maxHP', _('Hit points'), V_STRUCT | V_HULL | V_SEQUIP | V_EFF, 0)
131
132
addAttr('scannerPwr', _('Scanner power'), V_STRUCT | V_SEQUIP | V_EFF, 0)
133
addAttr('planetShield', _('Planetary shield'), V_STRUCT | V_EFF, 0)
134
addAttr('systemAtt', _('Fleet attack (bonus)'), V_STRUCT | V_EFF, 0)
135
addAttr('systemDef', _('Fleet defense (bonus)'), V_STRUCT | V_EFF, 0)
136
addAttr('refuelMax', _('Maximum refuel percent'), V_STRUCT | V_EFF, 0, convertor=perc100_2Text)
137
addAttr('refuelInc', _('Refuel increase percent'), V_STRUCT | V_EFF, 0, convertor=perc100_2Text)
138
addAttr('repairShip', _('Ship repair percent'), V_STRUCT | V_EFF, 0, convertor=perc100_2Text)
139
addAttr('upgradeShip', _('Ship upgrade capacity'), V_STRUCT | V_EFF, 0)
140
addAttr('trainShipInc', _('Exp. points per turn'), V_STRUCT | V_EFF, 0, convertor=float)
141
addAttr('trainShipMax', _('Exp. cap (base exp multiple)'), V_STRUCT | V_EFF, 0)
142
addAttr('fleetSpeedBoost', _('Boost speed of fleets'), V_STRUCT | V_EFF, 0, convertor=float)
143
addAttr('structWeapons', _('Weapons'), V_STRUCT, 0, convertor=structWeapons2Text)
144
145
addAttr('weaponClass', _('Target class'), V_SEQUIP, True, convertor=cclass2Text)
146
addAttr('weaponDmgMin', _('Weapon minimum damage'), V_SEQUIP | V_EFF, 0)
147
addAttr('weaponDmgMax', _('Weapon maximum damage'), V_SEQUIP | V_EFF, 0)
148
addAttr('weaponIsMissile', _('Missile weapon (ECM counts)'), V_SEQUIP | V_HULL, 0, convertor=bool2Text)
149
addAttr('weaponIgnoreShield', _('Weapon ignore shield'), V_SEQUIP | V_HULL, 0, convertor=bool2Text)
150
addAttr('weaponAtt', _('Weapon attack'), V_SEQUIP | V_EFF, 0)
151
addAttr('weaponROF', _('Weapon Rate Of Fire'), V_SEQUIP, 0, convertor=float)
152
153
addAttr('mineclass', _('Mine Class Deployed'), V_STRUCT, 0, convertor=getTechShortname)
154
addAttr('minenum', _('Maximum Supported Mines'), V_STRUCT | V_EFF, 0, convertor=int)
155
addAttr('minerate', _('Mine Rate of Deploy'), V_STRUCT | V_EFF_REV, 0, convertor=getRateName)
156
157
addAttr('minHull', _('Minimum required hull'), V_SEQUIP | V_HULL, 0, convertor=cclass2Text)
158
addAttr('weight', _('Weight'), V_SEQUIP | V_HULL, 0)
159
addAttr('slots', _('Slots'), V_SEQUIP | V_HULL, 0)
160
addAttr('maxWeight', _('Maximum payload'), V_HULL, 0)
161
addAttr('engPwr', _('Engine power'), V_SEQUIP | V_EFF, 0)
162
addAttr('engStlPwr', _('Engine sub-light speed power'), V_SEQUIP | V_EFF, 0)
163
164
addAttr('signature', _('Scan signature'), V_SEQUIP | V_HULL, 0)
165
addAttr('signatureCloak', _('Signature visibility'), V_SEQUIP | V_HULL, 0)
166
addAttr('signatureDecloak', _('Signature visibility'), V_SEQUIP | V_HULL, 0)
167
addAttr('minSignature', _('Min. signature'), V_SEQUIP | V_HULL, 0)
168
169
addAttr('combatDef', _('Combat defence'), V_SEQUIP | V_HULL | V_EFF, 0)
170
addAttr('combatAtt', _('Combat attack'), V_SEQUIP | V_HULL | V_EFF, 0)
171
addAttr('missileDef', _('Missile defence'), V_SEQUIP | V_EFF, 0)
172
addAttr('combatAttPerc', _('Combat defense (extra)'), V_SEQUIP | V_HULL | V_EFF, 0, default=1, convertor=percBase1_2Text)
173
addAttr('combatDefPerc', _('Combat attack (extra)'), V_SEQUIP | V_HULL | V_EFF, 0, default=1, convertor=percBase1_2Text)
174
addAttr('missileDefPerc', _('Missile defence (extra)'), V_SEQUIP | V_EFF, 0, default=1, convertor=percBase1_2Text)
175
176
addAttr('shieldPerc', _('Shield strength'), V_SEQUIP | V_HULL | V_EFF, 0, convertor=perc2Text)
177
addAttr('shieldRechargeFix', _('Shield recharge fixed'), V_SEQUIP | V_HULL | V_EFF, 0)
178
addAttr('shieldRechargePerc', _('Shield recharge percent'), V_SEQUIP | V_HULL | V_EFF, 0, convertor=perc2Text)
179
addAttr('damageAbsorb', _('Armor damage absorbstion'), V_SEQUIP | V_HULL, 0)
180
181
addAttr('addMP', _('Device MP'), V_SEQUIP | V_HULL, 0)
182
183
184
class TechInfoDlg:
185
186
    def __init__(self, app):
187
        self.app = app
188
        self.createUI()
189
190
    def display(self, techID):
191
        self.techID = techID
192
        self.show()
193
        self.win.show()
194
        # register for updates
195
        if self not in gdata.updateDlgs:
196
            gdata.updateDlgs.append(self)
197
198
    def hide(self):
199
        self.win.setStatus(_("Ready."))
200
        self.win.hide()
201
        # unregister updates
202
        if self in gdata.updateDlgs:
203
            gdata.updateDlgs.remove(self)
204
205
    def update(self):
206
        self.show()
207
208
    def _getGranularDependency(self, techMod):
209
        descr = []
210
        if techMod[0]:
211
            descr.append(_(" - %d %% on planet's environment") % (techMod[0] * 100))
212
        if techMod[1]:
213
            descr.append(_(" - %d %% on planet's min. abundance") % (techMod[1] * 100))
214
        if techMod[2]:
215
            descr.append(_(" - %d %% on planet's en. abundance") % (techMod[2] * 100))
216
        if techMod[3]:
217
            descr.append(_(" - %d %% is not dependent on any planet's attribute") % (techMod[3] * 100))
218
        return descr
219
220
    def _productionDependency(self, tech):
221
        descr = []
222
        for techModName, text in [('prodBioMod', _('Bio')),
223
                                  ('prodEnMod', _('Energy')),
224
                                  ('prodProdMod', _('Constr. point')),
225
                                  ('prodSciMod', _('Research point'))]:
226
            techMod = getattr(tech, techModName)
227
            if techMod not in ([0, 0, 0, 0], [0, 0, 0, 1]):
228
                descr.append(_("%s production depends:" % text))
229
                descr.extend(self._getGranularDependency(techMod))
230
                descr.append("")
231
        return descr
232
233
    def _getStratResText(self, tech, attr):
234
        try:
235
            resourceDict = getattr(tech, attr)
236
        except AttributeError:
237
            return ""
238
        requiredStratRes = []
239
        for res in resourceDict:
240
            try:
241
                amount = resourceDict[res] / float(Rules.stratResAmountBig)
242
            except IndexError:
243
                # this is case of research resources - it's pure list, not a dictionary
244
                requiredStratRes += [gdata.stratRes[res]]
245
            else:
246
                # continuation of build resources
247
                requiredStratRes += ['{0} ({1})'.format(gdata.stratRes[res], amount)]
248
        return ', '.join(requiredStratRes)
249
250
    def _researchContext(self, tech):
251
        player = client.getPlayer()
252
253
        descr = []
254
        improvement = player.techs.get(self.techID, 0)
255
        if hasattr(tech, 'researchMod'):
256
            prefix = _('Improvement') if improvement else _('Research')
257
            descr.append(_('%s costs: %d') % (prefix, Utils.getTechRCost(player, self.techID)))
258
            descr.append('')
259
        # requires
260
        if tech.researchRequires and improvement == 0:
261
            descr.append(_('Research requires:'))
262
            for tmpTechID, improvement in tech.researchRequires:
263
                tmpTech = client.getTechInfo(tmpTechID)
264
                descr.append(_(' - %s improvement %d (TL%d)') % (tmpTech.name, improvement, tmpTech.level))
265
            if hasattr(tech, "researchReqSRes"):
266
                for stratRes in tech.researchReqSRes:
267
                    descr.append(_(" - %s (strategic resource)") % (gdata.stratRes[stratRes]))
268
            descr.append('')
269
        if hasattr(tech, "researchDisables") and tech.researchDisables:
270
            descr.append(_("Research disables:"))
271
            for tmpTechID in tech.researchDisables:
272
                tmpTech = client.getTechInfo(tmpTechID)
273
                descr.append(_(" - %s (TL%d)") % (tmpTech.name, tmpTech.level))
274
            descr.append('')
275
        return descr
276
277
    def _preResearch(self, tech):
278
        descr = []
279
        descr.append(_('Estimated use:'))
280
        descr.extend(tech.textPreRsrch.split('\n'))
281
        descr.append('')
282
        return descr
283
284
    def _getTechType(self, tech):
285
        techType = V_NONE
286
        if getattr(tech, 'isStructure', 0):
287
            techType = V_STRUCT
288
        elif getattr(tech, 'isShipHull', 0):
289
            techType = V_HULL
290
        elif getattr(tech, 'isShipEquip', 0):
291
            techType = V_SEQUIP
292
        elif getattr(tech, 'isProject', 0):
293
            techType = V_PROJECT
294
        return techType
295
296
    def _prepareTypeButtons(self, tech):
297
        techType = self._getTechType(tech)
298
299
        self.win.vStruct.pressed = techType == V_STRUCT
300
        self.win.vStruct.enabled = getattr(tech, 'isStructure', 0)
301
        self.win.vHull.pressed = techType == V_HULL
302
        self.win.vHull.enabled = getattr(tech, 'isShipHull', 0)
303
        self.win.vSEquip.pressed = techType == V_SEQUIP
304
        self.win.vSEquip.enabled = getattr(tech, 'isShipEquip', 0)
305
        self.win.vProject.pressed = techType == V_PROJECT
306
        self.win.vProject.enabled = getattr(tech, 'isProject', 0)
307
308
    def _processAttributes(self, tech):
309
        techEff = Rules.techImprEff[client.getPlayer().techs.get(self.techID, Rules.techBaseImprovement)]
310
        items = []
311
        techType = self._getTechType(tech)
312
313
        for attr in dir(tech):
314
            value = getattr(tech, attr)
315
            descr, props, showIfDef, default, convertor = techAttrs.get(attr, defaultAttr)
316
            if techType & props and (value != default or showIfDef):
317
                item = ui.Item(descr, tValue=convertor(value))
318
                if V_EFF & props:
319
                    item.font = 'normal-bold'
320
                    item.tValue = convertor(value * techEff)
321
                elif V_EFF_REV & props:
322
                    item.font = 'normal-bold'
323
                    item.tValue = convertor(value / techEff)
324
                items.append(item)
325
        return items
326
327
    def _getPlayerRace(self):
328
        player = client.getPlayer()
329
        if player.techLevel > 1:
330
            return player.race
331
332
        tech = set(player.techs).intersection(set([1990, 1991, 1992]))
333
        if len(tech):
334
            return client.getTechInfo(tech.pop()).data
335
        else:
336
            return None
337
338
    def _researchEnablement(self, tech):
339
        descr = []
340
        tmp = []
341
        raceChoosen = self._getPlayerRace()
342
343
        for improvement in range(1, 6):
344
            for tmpTechID in tech.researchEnables[improvement]:
345
                tmpTech = client.getTechInfo(tmpTechID)
346
                racesDispl = ""
347
                if 0 < len(tmpTech.researchRaces) < 3 and not raceChoosen:
348
                    racesDispl = _(", only for %s") % tmpTech.researchRaces
349
                if not raceChoosen or not tmpTech.researchRaces or raceChoosen in tmpTech.researchRaces:
350
                    tmp.append(_(' - %s (with improvement %d, on TL%d%s)') % (tmpTech.name, improvement, tmpTech.level, racesDispl))
351
        if tmp:
352
            descr.append(_('Research/Improvement enables:'))
353
            descr.extend(tmp)
354
            descr.append('')
355
        return descr
356
357
    def _stratResources(self, tech):
358
        descr = []
359
360
        requiredStratResForBuilding = self._getStratResText(tech, "buildSRes")
361
        requiredStratResForResearch = self._getStratResText(tech, "researchReqSRes")
362
        if len(requiredStratResForBuilding) > 0 or len(requiredStratResForResearch) > 0:
363
            descr.append(_("Required strategic resources:"))
364
            if len(requiredStratResForBuilding) > 0:
365
                descr.append(_(" - for building: %s") % requiredStratResForBuilding)
366
            if len(requiredStratResForResearch) > 0:
367
                descr.append(_(" - for research: %s") % requiredStratResForResearch)
368
369
            descr.append("")
370
        return descr
371
372
    def _descriptionFlavor(self, tech):
373
        descr = []
374
375
        # description
376
        descr.append(_('Description:'))
377
        if tech.textDescr != u'Not specified':
378
            descr.extend(tech.textDescr.split('\n'))
379
        else:
380
            descr.extend(tech.textPreRsrch.split('\n'))
381
        descr.append('')
382
        # flavor
383
        descr.append(_('Rumours:'))
384
        descr.extend(tech.textFlavor.split('\n'))
385
        descr.append('')
386
        return descr
387
388
    def show(self):
389
        tech = client.getTechInfo(self.techID)
390
        self.win.title = _('Technology: %s (TL%d)') % (tech.name, tech.level)
391
        # fill data
392
        # fill description
393
        descr = []
394
        descr.extend(self._researchContext(tech))
395
        if hasattr(tech, 'partialData') and hasattr(tech, 'textPreRsrch'):
396
            # preresearch info
397
            descr.extend(self._preResearch(tech))
398
        elif not hasattr(tech, 'partialData'):
399
            descr.extend(self._researchEnablement(tech))
400
            descr.extend(self._productionDependency(tech))
401
            descr.extend(self._stratResources(tech))
402
            descr.extend(self._descriptionFlavor(tech))
403
404
        if not len(descr):
405
            descr.append(_('No information available'))
406
        #
407
        self.win.vDescr.text = descr
408
409
        self._prepareTypeButtons(tech)
410
411
        self.win.vData.items = self._processAttributes(tech)
412
        self.win.vData.itemsChanged()
413
414
    def onCancel(self, widget, action, data):
415
        self.hide()
416
417
    def onClose(self, widget, action, data):
418
        self.hide()
419
420
    def createUI(self):
421
        w, h = gdata.scrnSize
422
        self.win = ui.Window(self.app,
423
                             modal=1,
424
                             escKeyClose=1,
425
                             titleOnly=w == 800 and h == 600,
426
                             movable=0,
427
                             title=_('Split Fleet'),
428
                             rect=ui.Rect((w - 800 - 4 * (w != 800)) / 2,
429
                                          (h - 600 - 4 * (h != 600)) / 2,
430
                                          800 + 4 * (w != 800),
431
                                          580 + 4 * (h != 600)),
432
                             layoutManager=ui.SimpleGridLM())
433
        self.win.subscribeAction('*', self)
434
        # tech data
435
        ui.Title(self.win, layout=(0, 0, 18, 1), text=_('Data'),
436
                 align=ui.ALIGN_W, font='normal-bold')
437
        ui.Listbox(self.win, layout=(0, 1, 18, 25), id='vData',
438
                   columns=((_('Property'), 'text', 11, ui.ALIGN_W),
439
                   (_('Value'), 'tValue', 7, ui.ALIGN_E)),
440
                   columnLabels=0)
441
        ui.Button(self.win, layout=(1, 26, 4, 1), text=_('Structure'),
442
                  id='vStruct', toggle=0, data=V_STRUCT)
443
        ui.Button(self.win, layout=(5, 26, 4, 1), text=_('Ship Hull'),
444
                  id='vHull', toggle=0, data=V_HULL)
445
        ui.Button(self.win, layout=(9, 26, 4, 1), text=_('Ship Eq.'),
446
                  id='vSEquip', toggle=0, data=V_SEQUIP)
447
        ui.Button(self.win, layout=(13, 26, 4, 1), text=_('Project'),
448
                  id='vProject', toggle=0, data=V_PROJECT)
449
        ui.Button(self.win, layout=(17, 26, 1, 1), text='',
450
                  id='vEmpty1', toggle=0)
451
        ui.Button(self.win, layout=(0, 26, 1, 1), text='',
452
                  id='vEmpty2', toggle=0)
453
        # text field
454
        ui.Title(self.win, layout=(18, 0, 22, 1), text=_('Description'),
455
                 align=ui.ALIGN_W, font='normal-bold')
456
        s = ui.Scrollbar(self.win, layout=(39, 1, 1, 26))
457
        t = ui.Text(self.win, layout=(18, 1, 21, 26), id='vDescr', editable=0)
458
        t.attachVScrollbar(s)
459
        # status bar + submit/cancel
460
        ui.TitleButton(self.win, layout=(35, 27, 5, 1), text=_('Close'), action='onClose')
461
        ui.Title(self.win, id='vStatusBar', layout=(0, 27, 35, 1), align=ui.ALIGN_W)
462