Passed
Pull Request — master (#291)
by Marek
02:19
created

ResearchDlg.onRQueueTechInfo()   A

Complexity

Conditions 2

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nop 4
dl 0
loc 3
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 math
21
22
import pygameui as ui
23
24
import ige
25
from ige.ospace import Rules, Utils, TechHandlers
26
import ige.ospace.Const as Const
27
28
from osci import client, res, gdata
29
30
from TechInfoDlg import TechInfoDlg
31
from ConfirmDlg import ConfirmDlg
32
33
class ResearchDlg:
34
35
    def __init__(self, app):
36
        self.app = app
37
        self.techInfoDlg = TechInfoDlg(app)
38
        self.confirmDlg = ConfirmDlg(app)
39
        self.showCompleted = 0
40
        self.showObsolete = 0
41
        self.createUI()
42
43
    def display(self):
44
        self.win.vUnObs.enabled = 0
45
        self.win.vObs.enabled = 0
46
        self.show()
47
        # show window
48
        if not self.win.visible:
49
            self.win.show()
50
        # register for updates
51
        if self not in gdata.updateDlgs:
52
            gdata.updateDlgs.append(self)
53
54
    def hide(self):
55
        self.win.setStatus(_("Ready."))
56
        self.win.hide()
57
        # unregister updates
58
        if self in gdata.updateDlgs:
59
            gdata.updateDlgs.remove(self)
60
61
    def update(self):
62
        if self.win.visible:
63
            self.show()
64
65
    def _processResearchableTech(self, tech):
66
        player = client.getPlayer()
67
68
        item = ui.Item(tech.name, tLevel=tech.level, techID=tech.id)
69
        item.tStruct = '*' if getattr(tech, 'isStructure', None) else ''
70
        item.tShip = '*' if getattr(tech, 'isShipEquip', None) else ''
71
72
        neededSci = Utils.getTechRCost(player, tech.id)
73
        item.tETC = res.formatTime(float(neededSci) / player.effSciPoints) if player.effSciPoints > 0 else _("N/A")
74
        item.foreground = None
75
76
        if client.getFullTechInfo(tech.id).finishResearchHandler == TechHandlers.finishResTLAdvance:
77
            item.foreground = gdata.sevColors[gdata.CRI]
78
        elif getattr(tech, "researchDisables", None):
79
            item.foreground = (0xff, 0xff, 0x00)
80
        return item
81
82
    def _processResearchable(self, disabled, queued):
83
        player = client.getPlayer()
84
85
        items = []
86
        for techID in client.getAllTechIDs():
87
            if techID in player.techs or techID in queued or techID in disabled:
88
                continue
89
            tech = client.getTechInfo(techID)
90
            if not hasattr(tech, 'partialData') or not hasattr(tech, 'researchMod'):
91
                continue
92
            items.append(self._processResearchableTech(tech))
93
        self.win.vRTechs.items = items
94
        self.win.vRTechs.itemsChanged()
95
96
    def _processResearchQueueTask(self, task):
97
        player = client.getPlayer()
98
        tech = client.getTechInfo(task.techID)
99
        fulltech = client.getFullTechInfo(task.techID)
100
        researchSci = Utils.getTechRCost(player, task.techID, task.improvement)
101
        item = ui.Item(tech.name, techID=task.techID)
102
        item.tooltipTitle = _("Details")
103
        item.tooltip = _("Research points %d/%d, change %d pts/turn.") % (task.currSci, researchSci, task.changeSci)
104
        item.statustip = item.tooltip
105
        item.tImpToMax = "*" if task.improveToMax else ""
106
        item.tImproveToMax = task.improveToMax
107
        item.tProgress = _("%d %%") % int(task.currSci * 100 / researchSci) if task.currSci > 0 else _("-")
108
        totalSci = 0
109
        if task.changeSci > 0:
110
            etc = float(researchSci - task.currSci) / max(task.changeSci, player.effSciPoints)
111
            totalSci += researchSci - task.currSci
112
            if player.effSciPoints > 0:
113
                item.tETC = res.formatTime(etc)
114
            else:
115
                item.tETC = res.getNA()
116
        elif task.changeSci < 0:
117
            etc = - float(task.currSci) / min(task.changeSci, player.effSciPoints)
118
            item.tETC = _("[%s]") % res.formatTime(etc)
119
        elif player.effSciPoints > 0:
120
            etc = float(researchSci) / player.effSciPoints
121
            totalSci += researchSci
122
            item.tETC = res.formatTime(etc)
123
        else:
124
            item.tETC = res.getNA()
125
126
        if task.improveToMax:
127
            for impr in range(task.improvement + 1, fulltech.maxImprovement + 1):
128
                totalSci += Utils.getTechRCost(player, task.techID, impr)
129
        item.tLevel = _("%d-%d") % (tech.level, task.improvement)
130
        return item, totalSci
131
132
    def _processResearchQueue(self):
133
        player = client.getPlayer()
134
135
        items = []
136
        index = 0
137
        queued = []
138
        totalSci = 0
139
        for task in player.rsrchQueue:
140
            queued.append(task.techID)
141
            item, taskSci = self._processResearchQueueTask(task)
142
            item.index = index
143
            items.append(item)
144
            totalSci += taskSci
145
            index += 1
146
        totalSci = math.ceil(float(totalSci) / player.effSciPoints)
147
        self.win.vRQueue.items = items
148
        self.win.vRQueue.itemsChanged()
149
        self.win.vRQueueTop.enabled = 0
150
        self.win.vRQueueUp.enabled = 0
151
        self.win.vRQueueDown.enabled = 0
152
        self.win.vRQueueAbort.enabled = 0
153
        self.win.vRQueueRepat.enabled = 0
154
        self.win.vRQueueRepat.pressed = 0
155
        self.win.vRQueueInfo.enabled = 0
156
        self.win.vRTotal.text = res.formatTime(totalSci) if totalSci else _("N/A")
157
        return queued
158
159
    def _processImprovableTech(self, tech, scheduledIDs):
160
        player = client.getPlayer()
161
162
        item = ui.Item(tech.name,
163
                       techID=tech.id,
164
                       tLevel='%d-%d' % (tech.level, player.techs[tech.id]),
165
                       tStruct=(' ', '*')[tech.isStructure],
166
                       tShip=(' ', '*')[tech.isShipEquip])
167
        neededSci = Utils.getTechRCost(player, tech.id)
168
        item.tETC = res.formatTime(float(neededSci) / player.effSciPoints) if player.effSciPoints > 0 else _("N/A")
169
        item.foreground = (0xd0, 0xd0, 0xd0) if tech.id in scheduledIDs else None
170
        item.foreground = (0x80, 0x40, 0x40) if tech.id in player.obsoleteTechs else item.foreground
171
        return item
172
173
    def _processKnownTech(self):
174
        player = client.getPlayer()
175
176
        items = []
177
        disabled = []
178
        scheduledIDs = set([task.techID for task in player.rsrchQueue])
179
        for techID in player.techs.keys():
180
            if techID in player.obsoleteTechs and not self.showObsolete:
181
                continue
182
            tech = client.getTechInfo(techID)
183
            improvement = player.techs[techID]
184
            if improvement == tech.maxImprovement and not self.showCompleted:
185
                continue
186
            items.append(self._processImprovableTech(tech, scheduledIDs))
187
            disabled.extend(tech.researchDisables)
188
        self.win.vKTechs.items = items
189
        self.win.vKTechs.itemsChanged()
190
        return disabled
191
192
    def show(self):
193
        player = client.getPlayer()
194
        # title
195
        self.win.vRQueueTitle.text = _('Research queue [%d pts/turn]') % (
196
            player.effSciPoints,
197
        )
198
        self.win.title = _("Research [TL%d]") % player.techLevel
199
200
        disabled = self._processKnownTech()
201
        queued = self._processResearchQueue()
202
        self._processResearchable(disabled, queued)
203
204
    def onSelectKTech(self, widget, action, data):
205
        techID = self.win.vKTechs.selection[0].techID
206
        player = client.getPlayer()
207
        if techID in player.obsoleteTechs:
208
            self.win.vObs.enabled = 0
209
            self.win.vUnObs.enabled = 1
210
        else:
211
            self.win.vUnObs.enabled = 0
212
            self.win.vObs.enabled = 1
213
214
    def onKTechInfo(self, widget, action, data):
215
        if self.win.vKTechs.selection:
216
            self.techInfoDlg.display(self.win.vKTechs.selection[0].techID)
217
218
    def onSelectRTech(self, widget, action, data):
219
        # TODO implement
220
        pass
221
222
    def onRTechInfo(self, widget, action, data):
223
        if self.win.vRTechs.selection:
224
            self.techInfoDlg.display(self.win.vRTechs.selection[0].techID)
225
226
    def onSelectRQueueTech(self, widget, action, data):
227
        index = self.win.vRQueue.items.index(self.win.vRQueue.selection[0])
228
        self.win.vRQueueTop.enabled = index > 0
229
        self.win.vRQueueUp.enabled = index > 0
230
        self.win.vRQueueDown.enabled = index < len(self.win.vRQueue.items) - 1
231
        self.win.vRQueueAbort.enabled = 1
232
        self.win.vRQueueRepat.enabled = 1
233
        self.win.vRQueueRepat.pressed = self.win.vRQueue.selection[0].tImproveToMax
234
        self.win.vRQueueInfo.enabled = 1
235
236
    def onRQueueTechInfo(self, widget, action, data):
237
        if self.win.vRQueue.selection:
238
            self.techInfoDlg.display(self.win.vRQueue.selection[0].techID)
239
240
    def onCloseDlg(self, widget, action, data):
241
        self.hide()
242
243
    def onStartResearch(self, widget, action, data):
244
        if not self.win.vRTechs.selection:
245
            self.win.setStatus(_('Select technology to research.'))
246
            return
247
        else:
248
            techID = self.win.vRTechs.selection[0].techID
249
        try:
250
            self.win.setStatus(_('Executing START RESEARCH command...'))
251
            player = client.getPlayer()
252
            player.rsrchQueue = client.cmdProxy.startResearch(player.oid, techID)
253
            self.win.setStatus(_('Command has been executed.'))
254
        except ige.GameException, e:
255
            self.win.setStatus(e.args[0])
256
            return
257
        self.update()
258
259
    def onStartImprovement(self, widget, action, data):
260
        if not self.win.vKTechs.selection:
261
            self.win.setStatus(_('Select technology to improve.'))
262
            return
263
        else:
264
            techID = self.win.vKTechs.selection[0].techID
265
        try:
266
            self.win.setStatus(_('Executing START RESEARCH command...'))
267
            player = client.getPlayer()
268
            player.rsrchQueue = client.cmdProxy.startResearch(player.oid, techID)
269
            self.win.setStatus(_('Command has been executed.'))
270
        except ige.GameException, e:
271
            self.win.setStatus(e.args[0])
272
            return
273
        self.update()
274
275
    def onRTaskMove(self, widget, action, data):
276
        self.win.setStatus(_('Executing MOVE RESEARCH command...'))
277
        player = client.getPlayer()
278
        index = self.win.vRQueue.items.index(self.win.vRQueue.selection[0])
279
        # fix -9999 (move to top)
280
        amount = widget.data
281
        if index + amount < 0: amount = - index
282
        # execute command
283
        player.rsrchQueue = client.cmdProxy.moveResearch(player.oid, index, amount)
284
        self.update()
285
        index += amount
286
        self.win.vRQueue.selectItem(self.win.vRQueue.items[index])
287
        self.win.setStatus(_('Command has been executed.'))
288
        self.onSelectRQueueTech(widget, action, None)
289
290
    def onRTaskRepeat(self, widget, action, data):
291
        self.win.setStatus(_('Executing EDIT RESEARCH command...'))
292
        player = client.getPlayer()
293
        index = self.win.vRQueue.items.index(self.win.vRQueue.selection[0])
294
        repeat = not self.win.vRQueue.selection[0].tImproveToMax
295
        # execute command
296
        player.rsrchQueue = client.cmdProxy.editResearch(player.oid, index, repeat)
297
        self.update()
298
        self.win.vRQueue.selectItem(self.win.vRQueue.items[index])
299
        self.win.setStatus(_('Command has been executed.'))
300
        self.onSelectRQueueTech(widget, action, None)
301
302
    def onToggleCompleted(self, widget, action, data):
303
        self.showCompleted = self.win.vSCompl.pressed
304
        self.update()
305
306
    def onRTaskAbort(self, widget, action, data):
307
        self.confirmDlg.display(_("Abort this research task?"),
308
            _("Yes"), _("No"), self.onRTaskAbortConfirmed)
309
310
    def onRTaskAbortConfirmed(self):
311
        self.win.setStatus(_('Executing ABORT RESEARCH command...'))
312
        player = client.getPlayer()
313
        index = self.win.vRQueue.items.index(self.win.vRQueue.selection[0])
314
        player.rsrchQueue = client.cmdProxy.abortResearch(player.oid, index)
315
        self.update()
316
        self.win.setStatus(_('Command has been executed.'))
317
318
    def onSetObsolete(self, widget, action, data):
319
        if not self.win.vKTechs.selection:
320
            self.win.setStatus(_('Select technology to obsolete.'))
321
            return
322
        else:
323
            techID = self.win.vKTechs.selection[0].techID
324
        try:
325
            self.win.setStatus(_('Executing OBSOLETTE command...'))
326
            player = client.getPlayer()
327
            player.obsoleteTechs = client.cmdProxy.addObsoleteTechs(player.oid, techID)
328
            self.win.setStatus(_('Command has been executed.'))
329
        except ige.GameException, e:
330
            self.win.setStatus(e.args[0])
331
            return
332
        self.update()
333
334
    def onUnsetObsolete(self, widget, action, data):
335
        if not self.win.vKTechs.selection:
336
            self.win.setStatus(_('Select technology to un-obsolete.'))
337
            return
338
        else:
339
            techID = self.win.vKTechs.selection[0].techID
340
        try:
341
            self.win.setStatus(_('Executing UN-OBSOLETTE command...'))
342
            player = client.getPlayer()
343
            player.obsoleteTechs = client.cmdProxy.delObsoleteTechs(player.oid, techID)
344
            self.win.setStatus(_('Command has been executed.'))
345
        except ige.GameException, e:
346
            self.win.setStatus(e.args[0])
347
            return
348
        self.update()
349
350
    def onToggleObsolete(self, widget, action, data):
351
        self.showObsolete = self.win.vSObsl.pressed
352
        self.update()
353
354
    def createUI(self):
355
        w, h = gdata.scrnSize
356
        self.win = ui.Window(self.app,
357
                             modal=1,
358
                             escKeyClose=1,
359
                             titleOnly=w == 800 and h == 600,
360
                             movable=0,
361
                             title=_('Research'),
362
                             rect=ui.Rect((w - 800 - 4 * (w != 800)) / 2, (h - 600 - 4 * (h != 600)) / 2, 800 + 4 * (w != 800), 580 + 4 * (h != 600)),
363
                             layoutManager=ui.SimpleGridLM(),
364
        )
365
        self.win.subscribeAction('*', self)
366
        ui.Title(self.win, layout=(0, 27, 35, 1), id='vStatusBar',
367
                 align=ui.ALIGN_W)
368
        ui.TitleButton(self.win, layout=(35, 27, 5, 1), text=_('Close'),
369
                       action='onCloseDlg')
370
        # known techs
371
        ui.Title(self.win, layout=(0, 0, 20, 1), text=_('Known technologies'),
372
                 align=ui.ALIGN_W, font='normal-bold')
373
        ui.Listbox(self.win, layout=(0, 1, 20, 24), id='vKTechs',
374
                   columns=((_('Name'), 'text', 10, ui.ALIGN_W), (_('Lvl'), 'tLevel', 1.5, 0),
375
                   (_('Str'), 'tStruct', 1, 0), (_('Sh'), 'tShip', 1, 0),
376
                   (_('ETC'), 'tETC', 0, ui.ALIGN_E)), columnLabels=1, action='onSelectKTech')
377
        ui.Button(self.win, layout=(0, 25, 5, 1), text=_('Improve'),
378
                  action='onStartImprovement')
379
        ui.Button(self.win, layout=(5, 25, 5, 1), id="vSCompl", text=_('Show completed'),
380
                  action='onToggleCompleted', toggle=1, pressed=0)
381
        ui.Button(self.win, layout=(15, 25, 5, 1), text=_('Info'),
382
                  action='onKTechInfo')
383
        ui.Button(self.win, layout=(0, 26, 5, 1), id='vUnObs', text=_('Un-Obsolete'),
384
                  action='onUnsetObsolete')
385
        ui.Button(self.win, layout=(0, 26, 5, 1), id='vObs', text=_('Obsolete'),
386
                  action='onSetObsolete')
387
        ui.Button(self.win, layout=(5, 26, 5, 1), id="vSObsl", text=_('Show obsolete'),
388
                  action='onToggleObsolete', toggle=1, pressed=0)
389
        # unknown techs
390
        ui.Title(self.win, layout=(20, 0, 20, 1), text=_('Researchable technologies'),
391
                 align=ui.ALIGN_W, font='normal-bold')
392
        ui.Listbox(self.win, layout=(20, 1, 20, 12), id='vRTechs',
393
                   columns=((_('Name'), 'text', 10, ui.ALIGN_W), (_('Lvl'), 'tLevel', 1.5, 0),
394
                   (_('Str'), 'tStruct', 1, 0), (_('Sh'), 'tShip', 1, 0),
395
                   (_('ETC'), 'tETC', 0, ui.ALIGN_E)), columnLabels=1, action='onSelectRTech')
396
        ui.Button(self.win, layout=(20, 13, 5, 1), text=_('Research'),
397
                  action='onStartResearch')
398
        ui.Button(self.win, layout=(35, 13, 5, 1), text=_('Info'),
399
                  action='onRTechInfo')
400
        # research queue
401
        ui.Title(self.win, layout=(20, 14, 20, 1), text=_('Research queue'),
402
                 align=ui.ALIGN_W, id='vRQueueTitle', font='normal-bold')
403
        ui.Listbox(self.win, layout=(20, 15, 20, 11), id='vRQueue',
404
                   columns=((_('R'), 'tImpToMax', 1, ui.ALIGN_NONE),
405
                            (_('Name'), 'text', 10, ui.ALIGN_W),
406
                            (_('Lvl'), 'tLevel', 1.5, 0),
407
                            (_('Progress'), 'tProgress', 3.5, ui.ALIGN_E),
408
                            (_('ETC'), 'tETC', 0, ui.ALIGN_E)),
409
                   columnLabels=1, action='onSelectRQueueTech', sortable=False)
410
        ui.Button(self.win, layout=(20, 26, 2, 1), text=_("TOP"),
411
                  id='vRQueueTop', action='onRTaskMove', data=-9999,
412
                  tooltip=_("Move selected technology to the top of the queue."))
413
        ui.ArrowButton(self.win, layout=(22, 26, 1, 1), direction=ui.ALIGN_N,
414
                       id='vRQueueUp', action='onRTaskMove', data=-1)
415
        ui.ArrowButton(self.win, layout=(23, 26, 1, 1), direction=ui.ALIGN_S,
416
                       id='vRQueueDown', action='onRTaskMove', data=1)
417
        ui.Button(self.win, layout=(24, 26, 4, 1), text=_('Repeat'),
418
                  id='vRQueueRepat', action='onRTaskRepeat', toggle=1,
419
                  tooltip=_("Repeat research of this technology until the technology is fully improved."))
420
        ui.Button(self.win, layout=(28, 26, 3, 1), text=_('Abort'),
421
                  id='vRQueueAbort', action='onRTaskAbort')
422
        ui.Button(self.win, layout=(31, 26, 4, 1), text=_('Info'),
423
                  id='vRQueueInfo', action='onRQueueTechInfo')
424
        ui.Label(self.win, layout=(35, 26, 4, 1), id="vRTotal", align=ui.ALIGN_E,
425
                 tooltip=_("Total amount of time needed to research all technologies in the queue"))
426
427