Skip to content

Commit b14453e

Browse files
Merge pull request #32 from DazedNConfused-/release/v1.6.4
Prepare for v1.6.4 release
2 parents 89c4a5f + 05ce9ba commit b14453e

File tree

7 files changed

+237
-2
lines changed

7 files changed

+237
-2
lines changed

cddagl/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.6.3
1+
1.6.4

cddagl/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@
592592
CONFIG_BRANCH_STABLE = 'stable'
593593
CONFIG_BRANCH_EXPERIMENTAL = 'experimental'
594594

595+
DURATION_FORMAT = '{D:02}d {H:02}h {M:02}m {S:02}s'
595596

596597
### Path to Dirs and Files used in CDDAGL
597598
### TODO: (kurzed) centralize here and then move to a better place?

cddagl/functions.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
from cddagl.i18n import proxy_gettext as _
1212
from cddagl.sql.functions import get_config_value, config_true
1313

14+
from string import Formatter
15+
from datetime import timedelta
16+
1417
version = cddagl.__version__
1518
logger = logging.getLogger('cddagl')
1619

@@ -150,4 +153,51 @@ def safe_humanize(arrow_date, other=None, locale='en_us', only_distance=False, g
150153
except ValueError:
151154
# On final fail, use en_us locale which should be translated
152155
return arrow_date.humanize(other=other, locale='en_us', only_distance=only_distance,
153-
granularity='auto')
156+
granularity='auto')
157+
158+
def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}s', inputtype='timedelta'):
159+
"""Convert a datetime.timedelta object or a regular number to a custom-
160+
formatted string, just like the stftime() method does for datetime.datetime
161+
objects.
162+
163+
The fmt argument allows custom formatting to be specified. Fields can
164+
include seconds, minutes, hours, days, and weeks. Each field is optional.
165+
166+
Some examples:
167+
'{D:02}d {H:02}h {M:02}m {S:02}s' --> '05d 08h 04m 02s' (default)
168+
'{W}w {D}d {H}:{M:02}:{S:02}' --> '4w 5d 8:04:02'
169+
'{D:2}d {H:2}:{M:02}:{S:02}' --> ' 5d 8:04:02'
170+
'{H}h {S}s' --> '72h 800s'
171+
172+
The inputtype argument allows tdelta to be a regular number instead of the
173+
default, which is a datetime.timedelta object. Valid inputtype strings:
174+
's', 'seconds',
175+
'm', 'minutes',
176+
'h', 'hours',
177+
'd', 'days',
178+
'w', 'weeks'
179+
"""
180+
181+
# Convert tdelta to integer seconds.
182+
if inputtype == 'timedelta':
183+
remainder = int(tdelta.total_seconds())
184+
elif inputtype in ['s', 'seconds']:
185+
remainder = int(tdelta)
186+
elif inputtype in ['m', 'minutes']:
187+
remainder = int(tdelta)*60
188+
elif inputtype in ['h', 'hours']:
189+
remainder = int(tdelta)*3600
190+
elif inputtype in ['d', 'days']:
191+
remainder = int(tdelta)*86400
192+
elif inputtype in ['w', 'weeks']:
193+
remainder = int(tdelta)*604800
194+
195+
f = Formatter()
196+
desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
197+
possible_fields = ('W', 'D', 'H', 'M', 'S')
198+
constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
199+
values = {}
200+
for field in possible_fields:
201+
if field in desired_fields and field in constants:
202+
values[field], remainder = divmod(remainder, constants[field])
203+
return f.format(fmt, **values)

cddagl/ui/views/main.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def __init__(self):
6868
layout.addWidget(update_group_box)
6969
self.setLayout(layout)
7070

71+
self.played = 0
72+
7173
def set_text(self):
7274
self.game_dir_group_box.set_text()
7375
self.update_group_box.set_text()
@@ -87,6 +89,9 @@ def get_mods_tab(self):
8789
def get_backups_tab(self):
8890
return self.parentWidget().parentWidget().backups_tab
8991

92+
def get_statistics_tab(self):
93+
return self.parentWidget().parentWidget().statistics_tab
94+
9095
def disable_tab(self):
9196
self.game_dir_group_box.disable_controls()
9297
self.update_group_box.disable_controls(True)
@@ -452,6 +457,8 @@ def launch_game_process(self):
452457
settings_tab.disable_tab()
453458
backups_tab.disable_tab()
454459

460+
statistics_tab = main_tab.get_statistics_tab()
461+
455462
self.launch_game_button.setText(_('Show current game'))
456463
self.launch_game_button.setEnabled(True)
457464

@@ -477,6 +484,8 @@ def process_ended():
477484
process_wait_thread.ended.connect(process_ended)
478485
process_wait_thread.start()
479486

487+
statistics_tab.game_started()
488+
480489
self.process_wait_thread = process_wait_thread
481490

482491
def game_ended(self):
@@ -487,6 +496,10 @@ def game_ended(self):
487496
self.game_process = None
488497
self.game_started = False
489498

499+
main_tab = self.get_main_tab()
500+
statistics_tab = main_tab.get_statistics_tab()
501+
statistics_tab.game_ended()
502+
490503
main_window = self.get_main_window()
491504
status_bar = main_window.statusBar()
492505

cddagl/ui/views/statistics.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import logging
2+
from datetime import datetime
3+
from cddagl.functions import strfdelta
4+
from cddagl.constants import DURATION_FORMAT
5+
6+
from PyQt5.QtCore import (
7+
Qt, QTimer
8+
)
9+
from PyQt5.QtWidgets import (
10+
QTabWidget, QGroupBox, QGridLayout, QLabel, QVBoxLayout, QPushButton
11+
)
12+
from cddagl.sql.functions import get_config_value, set_config_value
13+
14+
logger = logging.getLogger('cddagl')
15+
16+
class StatisticsTab(QTabWidget):
17+
def __init__(self):
18+
super(StatisticsTab, self).__init__()
19+
20+
self.game_start_time = None
21+
self.last_game_duration = get_config_value('last_played', 0)
22+
23+
current_played_group_box = CurrentPlayedGroupBox()
24+
self.current_played_group_box = current_played_group_box
25+
self.reset_current_button = current_played_group_box.reset_current_button
26+
27+
total_game_duration_group_box = TotalPlayedGroupBox()
28+
self.total_game_duration_group_box = total_game_duration_group_box
29+
self.reset_total_button = total_game_duration_group_box.reset_total_button
30+
31+
layout = QVBoxLayout()
32+
layout.addWidget(current_played_group_box)
33+
layout.addWidget(total_game_duration_group_box)
34+
self.setLayout(layout)
35+
36+
def set_text(self):
37+
self.current_played_group_box.set_text()
38+
self.current_played_group_box.set_label_text()
39+
self.total_game_duration_group_box.set_text()
40+
41+
def get_main_window(self):
42+
return self.parentWidget().parentWidget().parentWidget()
43+
44+
def get_main_tab(self):
45+
return self.parentWidget().parentWidget().main_tab
46+
47+
def game_started(self):
48+
self.game_start_time = datetime.now()
49+
game_timer = QTimer()
50+
game_timer.setInterval(1000)
51+
game_timer.timeout.connect(self.game_tick)
52+
self.game_timer = game_timer
53+
game_timer.start()
54+
self.reset_current_button.setEnabled(False)
55+
self.reset_total_button.setEnabled(False)
56+
57+
def game_ended(self):
58+
total_game_duration = int(get_config_value('total_played',0))
59+
total_game_duration += self.last_game_duration
60+
set_config_value('last_played', self.last_game_duration)
61+
set_config_value('total_played', total_game_duration)
62+
self.game_start_time = None
63+
self.game_timer.stop()
64+
self.reset_current_button.setEnabled(True)
65+
self.reset_total_button.setEnabled(True)
66+
67+
def game_tick(self):
68+
elapsed = int(datetime.now().timestamp() - self.game_start_time.timestamp())
69+
self.last_game_duration = elapsed
70+
self.current_played_group_box.set_label_text()
71+
self.total_game_duration_group_box.set_label_text()
72+
73+
class CurrentPlayedGroupBox(QGroupBox):
74+
def __init__(self):
75+
super(CurrentPlayedGroupBox, self).__init__()
76+
77+
layout = QGridLayout()
78+
79+
current_played_label = QLabel()
80+
current_played_label.setStyleSheet("font-size: 32px;")
81+
layout.addWidget(current_played_label, 0, 0, Qt.AlignHCenter)
82+
self.current_played_label = current_played_label
83+
84+
reset_current_button = QPushButton()
85+
reset_current_button.setStyleSheet("font-size: 20px;")
86+
reset_current_button.clicked.connect(self.reset_current)
87+
layout.addWidget(reset_current_button, 1, 0, Qt.AlignHCenter)
88+
self.reset_current_button = reset_current_button
89+
90+
self.setLayout(layout)
91+
self.set_text()
92+
93+
def reset_current(self):
94+
self.parentWidget().last_game_duration = 0
95+
set_config_value('last_played', 0)
96+
self.set_label_text()
97+
98+
def get_main_tab(self):
99+
return self.parentWidget().get_main_tab()
100+
101+
def set_text(self):
102+
self.reset_current_button.setText(_('RESET'))
103+
last_game_duration = int(get_config_value('last_played', 0))
104+
fmt_last_game_duration = strfdelta(last_game_duration, _(DURATION_FORMAT), inputtype='s')
105+
self.current_played_label.setText(fmt_last_game_duration)
106+
self.setTitle(_('Last game duration:'))
107+
108+
def set_label_text(self):
109+
last_game_duration = self.parentWidget().last_game_duration
110+
fmt_last_game_duration = strfdelta(last_game_duration, _(DURATION_FORMAT), inputtype='s')
111+
self.current_played_label.setText(fmt_last_game_duration)
112+
113+
114+
class TotalPlayedGroupBox(QGroupBox):
115+
def __init__(self):
116+
super(TotalPlayedGroupBox, self).__init__()
117+
118+
layout = QGridLayout()
119+
120+
total_game_duration_label = QLabel()
121+
total_game_duration_label.setStyleSheet("font-size: 32px;")
122+
layout.addWidget(total_game_duration_label, 0, 0, Qt.AlignHCenter)
123+
self.total_game_duration_label = total_game_duration_label
124+
125+
reset_total_button = QPushButton()
126+
reset_total_button.setStyleSheet("font-size: 20px;")
127+
reset_total_button.clicked.connect(self.reset_total)
128+
layout.addWidget(reset_total_button, 1, 0, Qt.AlignHCenter)
129+
self.reset_total_button = reset_total_button
130+
131+
self.setLayout(layout)
132+
self.set_text()
133+
134+
def reset_total(self):
135+
set_config_value('total_played', 0)
136+
self.set_label_text()
137+
138+
def get_main_tab(self):
139+
return self.parentWidget().get_main_tab()
140+
141+
def set_text(self):
142+
self.reset_total_button.setText(_('RESET'))
143+
total_game_duration = int(get_config_value('total_played', 0))
144+
fmt_total_game_duration = strfdelta(total_game_duration, _(DURATION_FORMAT), inputtype='s')
145+
self.total_game_duration_label.setText(fmt_total_game_duration)
146+
self.setTitle(_('Total time in game:'))
147+
148+
def set_label_text(self):
149+
total_game_duration = int(get_config_value('total_played', 0)) + int(self.parentWidget().last_game_duration)
150+
fmt_total_game_duration = strfdelta(total_game_duration, _(DURATION_FORMAT), inputtype='s')
151+
self.total_game_duration_label.setText(fmt_total_game_duration)

cddagl/ui/views/tabbed.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from cddagl.ui.views.settings import SettingsTab
3535
from cddagl.ui.views.soundpacks import SoundpacksTab
3636
from cddagl.ui.views.tilesets import TilesetsTab
37+
from cddagl.ui.views.statistics import StatisticsTab
3738
from cddagl.win32 import SimpleNamedPipe
3839

3940
logger = logging.getLogger('cddagl')
@@ -422,6 +423,7 @@ def __init__(self):
422423
self.create_soundpacks_tab()
423424
#self.create_fonts_tab()
424425
self.create_settings_tab()
426+
self.create_statistics_tab()
425427

426428
def set_text(self):
427429
self.setTabText(self.indexOf(self.main_tab), _('Main'))
@@ -431,6 +433,7 @@ def set_text(self):
431433
self.setTabText(self.indexOf(self.soundpacks_tab), _('Soundpacks'))
432434
#self.setTabText(self.indexOf(self.fonts_tab), _('Fonts'))
433435
self.setTabText(self.indexOf(self.settings_tab), _('Settings'))
436+
self.setTabText(self.indexOf(self.statistics_tab), _('Statistics'))
434437

435438
self.main_tab.set_text()
436439
self.backups_tab.set_text()
@@ -439,6 +442,7 @@ def set_text(self):
439442
self.soundpacks_tab.set_text()
440443
#self.fonts_tab.set_text()
441444
self.settings_tab.set_text()
445+
self.statistics_tab.set_text()
442446

443447
def create_main_tab(self):
444448
main_tab = MainTab()
@@ -475,6 +479,11 @@ def create_settings_tab(self):
475479
self.addTab(settings_tab, _('Settings'))
476480
self.settings_tab = settings_tab
477481

482+
def create_statistics_tab(self):
483+
statistics_tab = StatisticsTab()
484+
self.addTab(statistics_tab, _('Statistics'))
485+
self.statistics_tab = statistics_tab
486+
478487

479488
class LauncherUpdateDialog(QDialog):
480489
def __init__(self, url, version, parent=0, f=0):

data/mods.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,5 +336,16 @@
336336
"size": 39136,
337337
"url": "https://github.com/Lorith/AdvancedGear-CDDA-Mod/archive/master.zip",
338338
"homepage": "https://github.com/Lorith/AdvancedGear-CDDA-Mod"
339+
},
340+
{
341+
"type": "direct_download",
342+
"ident": "arcana_magic",
343+
"name": "Arcana and Magic",
344+
"authors": [ "chaosvolt" ],
345+
"description": "Focused principally on magical items as the name implies (the mod predating the current spell mechanics), with proper spells being a valuable, powerful tool that demands hunting monsters and learning of the Beyond moreso than simple scavenging.",
346+
"category": "items",
347+
"size": 1649025,
348+
"url": "https://github.com/chaosvolt/cdda-arcana-mod/archive/master.zip",
349+
"homepage": "https://github.com/chaosvolt/cdda-arcana-mod"
339350
}
340351
]

0 commit comments

Comments
 (0)