-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathoptions.py
341 lines (310 loc) · 14 KB
/
options.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pylint:disable=unused-wildcard-import,wildcard-import,attribute-defined-outside-init
"""Options tab for the TKinter GUI."""
import sys
from tkinter import * # noqa: F403
from tkinter import messagebox, simpledialog
from tkinter.ttk import * # noqa: F403
from core import df, embarks, keybinds
from core.lnp import lnp
from . import binding, controls, tkhelpers
from .layout import GridLayouter
from .tab import Tab
class OptionsTab(Tab):
"""Options tab for the TKinter GUI."""
def create_variables(self):
self.keybinds = Variable()
self.embarks = Variable()
def read_data(self):
self.read_keybinds()
if lnp.df_info.version >= '0.28.181.40a':
self.read_embarks()
def create_controls(self):
options = controls.create_control_group(self, 'Gameplay Options', True)
options.pack(side=TOP, fill=BOTH, expand=N)
grid = GridLayouter(2)
grid.add(controls.create_trigger_option_button(
options, 'Population Cap', 'Maximum population in your fort. '
'Setting this too low may disable certain gameplay features.',
self.set_pop_cap, 'popcap'))
grid.add(controls.create_trigger_option_button(
options, 'Child Cap', 'Maximum children in your fort',
self.set_child_cap, 'childcap'))
if lnp.df_info.version >= '0.40.05':
grid.add(controls.create_trigger_option_button(
options, 'Strict Population Cap',
'Strict limit on population in your fort (blocks births)',
self.set_strict_pop_cap, 'strictPopcap'), 2)
grid.add(controls.create_trigger_option_button(
options, 'Visitor Cap',
'Limit on number of generic visitors in your fort',
self.set_visitor_cap, 'visitorCap'))
grid.add(controls.create_option_button(
options, 'Invaders',
'Toggles whether invaders (goblins, etc.) show up',
'invaders'))
if lnp.df_info.version >= '0.47.01':
grid.add(controls.create_trigger_option_button(
options, 'Temple Petition',
'Number of worshippers that trigger demand for a temple',
self.set_temple_count, 'templeCount'))
grid.add(controls.create_trigger_option_button(
options, 'Guild Size',
'Number of members of same profession that trigger creation of a guild',
self.set_guild_count, 'guildCount'))
grid.add(controls.create_trigger_option_button(
options, 'Invasion Soldier Cap',
'Limit on number of enemy soldiers during an invasion',
self.set_inv_soldier_cap, 'invSoldierCap'), 2)
grid.add(controls.create_trigger_option_button(
options, 'Invasion Monster Cap',
'Limit on number of enemy monsters during an invasion',
self.set_inv_monster_cap, 'invMonsterCap'), 2)
grid.add(controls.create_option_button(
options, 'Cave-ins',
'Toggles whether unsupported bits of terrain will collapse',
'caveins'))
grid.add(controls.create_option_button(
options, 'Temperature',
'Toggles whether things will burn, melt, freeze, etc.',
'temperature'))
grid.add(controls.create_option_button(
options, 'Weather', 'Rain, snow, etc.', 'weather'))
grid.add(controls.create_option_button(
options, 'Entomb Pets',
'Whether deceased pets should be entombed in coffins by default.',
'entombPets'))
grid.add(controls.create_option_button(
options, 'Artifacts',
'Whether dwarfs should enter artifact producing moods.',
'artifacts'))
grid.add(controls.create_option_button(
options, 'Aquifers', 'Whether newly created worlds will have '
'Aquifers in them (Infinite sources of underground water, but may '
'flood your fort', 'aquifers'))
grid.add(controls.create_trigger_option_button(
options, 'Graze Coefficient',
'Scales how often grazing animals need to eat. Larger numbers '
'require less food.', self.set_graze_coef, 'grazeCoef'), 2)
if lnp.df_info.version >= '0.34.03':
if lnp.df_info.version <= '0.34.06':
tooltip = 'Whether labors are enabled by default.'
else:
tooltip = (
'Which labors are enabled by default: by skill level of '
'dwarves, by their unit type, or none')
grid.add(controls.create_option_button(
options, 'Starting Labors', tooltip, 'laborLists'), 2)
keybindings, self.keybinding_entry, self.keybinding_files = \
controls.create_list_with_entry(
self, "Key Bindings", self.keybinds,
[("Save", "Save current keybindings", self.save_keybinds),
("Load", "Load keybindings", self.load_keybinds),
("Delete", "Delete keybindings", self.delete_keybinds),
("Refresh", "Refresh list", self.read_keybinds)],
entry_default="Save current keybindings as...")
keybindings.pack(side=BOTTOM, fill=BOTH, expand=N)
for seq in ("<Double-1>", "<Return>"):
self.keybinding_files.bind(seq, lambda e: self.load_keybinds())
if lnp.df_info.version >= '0.28.181.40a':
embarkframe, self.embark_files = controls.create_file_list(
self, 'Embark profiles', self.embarks, height=3)
self.embark_files.configure(selectmode="single")
refresh = controls.create_trigger_button(
embarkframe, 'Refresh Profiles', 'Refresh list of profiles',
self.read_embarks)
refresh.grid(column=0, row=3, columnspan=2, sticky="sew")
# This hack ensures the listbox never selects anything itself. This
# is much better than the alternative hack required to prevent the
# list selecting the last element when clicking in empty space.
def _deselect_all(event):
for item in event.widget.curselection():
event.widget.selection_clear(item)
self.embark_files.bind("<<ListboxSelect>>", _deselect_all)
for seq in ("<space>", "<Return>", "<1>",
"<2>" if sys.platform == 'darwin' else "<3>"):
self.embark_files.bind(seq, self.toggle_embark)
@staticmethod
def set_pop_cap():
"""Requests new population cap from the user."""
v = simpledialog.askinteger(
"Settings", "Population cap:",
initialvalue=lnp.settings.popcap)
if v is not None:
df.set_option('popcap', str(v))
binding.update()
@staticmethod
def set_strict_pop_cap():
"""Requests new strict population cap from the user."""
v = simpledialog.askinteger(
"Settings", "Strict population cap:",
initialvalue=lnp.settings.strictPopcap)
if v is not None:
df.set_option('strictPopcap', str(v))
binding.update()
@staticmethod
def set_child_cap():
"""Requests new child cap from the user."""
child_split = list(lnp.settings.childcap.split(':'))
child_split.append('0') # In case syntax is invalid
v = simpledialog.askinteger(
"Settings", "Absolute cap on babies + children:",
initialvalue=child_split[0])
if v is not None:
v2 = simpledialog.askinteger(
"Settings", "Max percentage of children in fort:\n"
"(lowest of the two values will be used as the cap)",
initialvalue=child_split[1])
if v2 is not None:
df.set_option('childcap', str(v) + ':' + str(v2))
binding.update()
@staticmethod
def set_temple_count():
"""Requests new worshippers limits from the user."""
split = list(lnp.settings.templeCount.split(':'))
split.append('0') # In case syntax is invalid
v1 = simpledialog.askinteger(
"Settings", "Min number of worshippers for a regular temple:",
initialvalue=split[0])
if v1 is not None:
v2 = simpledialog.askinteger(
"Settings", "Min number of worshippers for a grand temple:",
initialvalue=split[1])
if v2 is not None:
df.set_option('templeCount', str(v1) + ':' + str(v2))
binding.update()
@staticmethod
def set_guild_count():
"""Requests new guild members limits from the user."""
split = list(lnp.settings.guildCount.split(':'))
split.append('0') # In case syntax is invalid
v1 = simpledialog.askinteger(
"Settings", "Min number of guild members:",
initialvalue=split[0])
if v1 is not None:
v2 = simpledialog.askinteger(
"Settings", "Min number of guild members requesting a grand guildhall:",
initialvalue=split[1])
if v2 is not None:
df.set_option('guildCount', str(v1) + ':' + str(v2))
binding.update()
@staticmethod
def set_graze_coef():
"""Requests new graze coefficient from the user."""
v = simpledialog.askinteger(
"Settings", "Graze coefficient:",
initialvalue=lnp.settings.grazeCoef)
if v is not None:
df.set_option('grazeCoef', str(v))
binding.update()
@staticmethod
def set_visitor_cap():
"""Requests new visitor cap from the user."""
v = simpledialog.askinteger(
"Settings", "Visitor cap:",
initialvalue=lnp.settings.visitorCap)
if v is not None:
df.set_option('visitorCap', str(v))
binding.update()
@staticmethod
def set_inv_soldier_cap():
"""Requests new invasion soldier cap from the user."""
v = simpledialog.askinteger(
"Settings", "Cap on # of soldiers in invasion:",
initialvalue=lnp.settings.invSoldierCap)
if v is not None:
df.set_option('invSoldierCap', str(v))
binding.update()
@staticmethod
def set_inv_monster_cap():
"""Requests new invasion monster cap from the user."""
v = simpledialog.askinteger(
"Settings", "Cap on # of monsters in invasion:",
initialvalue=lnp.settings.invMonsterCap)
if v is not None:
df.set_option('invMonsterCap', str(v))
binding.update()
def read_keybinds(self):
"""Reads list of keybinding files."""
files = keybinds.read_keybinds()
self.keybinds.set(files)
current = keybinds.get_installed_file()
default_bg = Style().lookup('TListbox', 'fill')
for i, f in enumerate(files):
if f == current:
self.keybinding_files.itemconfig(i, bg='pale green')
else:
self.keybinding_files.itemconfig(i, bg=default_bg)
def load_keybinds(self):
"""Replaces keybindings with selected file."""
if not tkhelpers.check_vanilla_raws():
return
listbox = self.keybinding_files
items = listbox.curselection()
if len(items) > 0:
listbox.selection_clear(items)
keybinds.load_keybinds(listbox.get(items[0]))
self.read_keybinds()
self.keybinding_entry.delete(0, END)
def save_keybinds(self):
"""Saves keybindings to a file."""
v = self.keybinding_entry.get()
if v and not getattr(self.keybinding_entry, 'default_showing', False):
if not v.endswith('.txt'):
v = v + '.txt'
if (not keybinds.keybind_exists(v) or messagebox.askyesno(
message='Overwrite {0}?'.format(v),
icon='question', title='Overwrite file?')):
self.keybinding_entry.delete(0, END)
keybinds.save_keybinds(v)
self.read_keybinds()
def delete_keybinds(self):
"""Deletes a keybinding file."""
listbox = self.keybinding_files
if len(listbox.curselection()) > 0:
filename = listbox.get(listbox.curselection()[0])
if messagebox.askyesno(
'Delete file?',
'Are you sure you want to delete {0}?'.format(filename)):
keybinds.delete_keybinds(filename)
self.read_keybinds()
def read_embarks(self):
"""Reads list of embark profiles."""
files = embarks.read_embarks()
self.embarks.set(files)
current = embarks.get_installed_files()
default_bg = Style().lookup('TListbox', 'fill')
for i, f in enumerate(files):
if f in current:
self.embark_files.itemconfig(i, bg='pale green')
else:
self.embark_files.itemconfig(i, bg=default_bg)
def install_embarks(self, listbox):
"""
Installs selected embark profiles.
Args:
listbox: Listbox containing the list of embark profiles.
"""
if len(listbox.curselection()) != 0:
files = []
for f in listbox.curselection():
files.append(listbox.get(f))
embarks.install_embarks(files)
self.read_embarks()
def toggle_embark(self, event):
"""Toggles selected embark profile."""
item = self.embark_files.index('active')
if event.keysym == '??':
# pylint: disable=not-callable
item = self.embark_files.identify(event.y)
# pylint: enable=not-callable
if item is not None:
embark_file = self.embark_files.get(item)
files = embarks.get_installed_files()
if embark_file in files:
files.remove(embark_file)
else:
files.append(embark_file)
embarks.install_embarks(files)
self.read_embarks()