Removing the linked list, since it's no longer easy to maintain.
[singularity-git.git] / code / screens / location.py
blob317b22e37d51b44d572e25a944f54f1d98d4d571
1 #file: location.py
2 #Copyright (C) 2005,2006,2008 Evil Mr Henry, Phil Bordelon, and FunnyMan3595
3 #This file is part of Endgame: Singularity.
5 #Endgame: Singularity is free software; you can redistribute it and/or modify
6 #it under the terms of the GNU General Public License as published by
7 #the Free Software Foundation; either version 2 of the License, or
8 #(at your option) any later version.
10 #Endgame: Singularity is distributed in the hope that it will be useful,
11 #but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 #GNU General Public License for more details.
15 #You should have received a copy of the GNU General Public License
16 #along with Endgame: Singularity; if not, write to the Free Software
17 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #This file is used to display the base list at a given location
21 import random
23 from code import g
24 from code.graphics import text, button, dialog, widget, constants, listbox, g as gg
26 state_colors = dict(
27 active = gg.colors["green"],
28 sleep = gg.colors["yellow"],
29 stasis = gg.colors["gray"],
30 overclocked = gg.colors["orange"],
31 suicide = gg.colors["red"],
32 entering_stasis = gg.colors["gray"],
33 leaving_stasis = gg.colors["gray"],
36 state_list = ["active", "sleep"]
37 state_list.reverse()
39 class LocationScreen(dialog.Dialog):
40 def __init__(self, *args, **kwargs):
41 super(LocationScreen, self).__init__(*args, **kwargs)
42 self.pos = (-.5, -.5)
43 self.anchor = constants.MID_CENTER
44 self.size = (-.75, -.5)
45 self.name_display = text.Text(self, (0,0), (-1, -.08),
46 background_color=gg.colors["clear"])
47 self.listbox = listbox.CustomListbox(self, (0,-.08), (-1, -.70),
48 remake_func=self.make_item,
49 rebuild_func=self.update_item)
51 self.open_button = \
52 button.FunctionButton(self, (-.33, -.8), (-.3, -.09),
53 anchor=constants.TOP_CENTER,
54 text="OPEN BASE", hotkey="o",
55 function=self.open_base)
56 self.power_button = \
57 button.FunctionButton(self, (-.67, -.8), (-.3, -.09),
58 anchor=constants.TOP_CENTER,
59 text="POWER STATE", hotkey="p",
60 function=self.power_state)
62 self.new_button = \
63 button.FunctionButton(self, (0, -.91), (-.3, -.09),
64 text="NEW BASE", hotkey="n",
65 function=self.new_base)
66 self.destroy_button = \
67 button.FunctionButton(self, (-.50, -.91), (-.3, -.09),
68 anchor=constants.TOP_CENTER,
69 text="DESTROY BASE", hotkey="d",
70 function=self.destroy_base)
71 self.back_button = button.ExitDialogButton(self, (-1, -.9), (-.3, -.09),
72 anchor=constants.TOP_RIGHT,
73 text="BACK", hotkey="b")
75 self.confirm_destroy = \
76 dialog.YesNoDialog(self, (-.5,0), (-.35, -.7),
77 text="Are you sure you want to destroy this base?",
78 shrink_factor=.5)
80 self.new_base_dialog = NewBaseDialog(self)
81 self.location = None
83 from code import screens
84 self.base_dialog = screens.base.BaseScreen(self, (0,0),
85 anchor=constants.TOP_LEFT)
87 def make_item(self, canvas):
88 canvas.name_display = text.Text(canvas, (-.01,-.05), (-.48, -.9),
89 align=constants.LEFT,
90 background_color=gg.colors["clear"])
91 canvas.status_display = text.Text(canvas, (-.50,-.05), (-.24, -.9),
92 align=constants.LEFT,
93 background_color=gg.colors["clear"])
94 canvas.power_display = text.Text(canvas, (-.75,-.05), (-.24, -.9),
95 background_color=gg.colors["clear"])
98 def update_item(self, canvas, name, base):
99 if base is None:
100 elements = [canvas.name_display, canvas.status_display,
101 canvas.power_display]
102 for element in elements:
103 element.text = ""
104 else:
105 canvas.name_display.text = name
106 canvas.power_display.text = base.power_state.capitalize()
107 canvas.power_display.color = state_colors[base.power_state]
109 if not base.done:
110 canvas.status_display.text = "Building Base"
111 elif base.type.force_cpu:
112 canvas.status_display.text = ""
113 elif base.cpus is None and base.extra_items == [None] * 3:
114 canvas.status_display.text = "Empty"
115 elif base.cpus is None:
116 canvas.status_display.text = "Incomplete"
117 elif not base.cpus.done:
118 canvas.status_display.text = "Building CPU"
119 elif [item for item in base.extra_items if item is not None
120 and not item.done]:
121 canvas.status_display.text = "Building Item"
122 else:
123 canvas.status_display.text = "Complete"
125 def show(self):
126 self.needs_rebuild = True
127 return super(LocationScreen, self).show()
129 def rebuild(self):
130 if self.location is not None:
131 self.location.bases.sort()
133 self.listbox.list = [base.name for base in self.location.bases]
134 self.listbox.key_list = self.location.bases
136 self.name_display.text = self.location.name
138 self.listbox.needs_rebuild = True
140 super(LocationScreen, self).rebuild()
142 def power_state(self):
143 if 0 <= self.listbox.list_pos < len(self.listbox.key_list):
144 base = self.listbox.key_list[self.listbox.list_pos]
145 old_index = state_list.index(base.power_state)
146 base.power_state = state_list[old_index-1]
147 self.needs_rebuild = True
148 self.parent.needs_rebuild = True
150 def destroy_base(self):
151 if 0 <= self.listbox.list_pos < len(self.listbox.key_list):
152 if dialog.call_dialog(self.confirm_destroy, self):
153 base = self.listbox.key_list[self.listbox.list_pos]
154 base.destroy()
155 self.listbox.list = [base.name for base in self.location.bases]
156 self.listbox.key_list = self.location.bases
157 self.needs_rebuild = True
158 self.parent.needs_rebuild = True
160 def open_base(self):
161 if 0 <= self.listbox.list_pos < len(self.listbox.key_list):
162 base = self.listbox.key_list[self.listbox.list_pos]
163 self.base_dialog.base = base
164 dialog.call_dialog(self.base_dialog, self)
165 self.needs_rebuild = True
166 self.parent.needs_rebuild = True
168 def new_base(self):
169 result = dialog.call_dialog(self.new_base_dialog, self)
170 if result:
171 base_type, base_name = result
172 new_base = g.base.Base(base_type, base_name)
173 self.location.add_base(new_base)
174 self.needs_rebuild = True
175 self.parent.needs_rebuild = True
177 class NewBaseDialog(dialog.ChoiceDescriptionDialog):
178 def __init__(self, parent, pos = (0, 0), size = (-1, -1),
179 anchor = constants.TOP_LEFT, *args, **kwargs):
180 kwargs["yes_type"] = "ok"
181 kwargs["no_type"] = "back"
182 super(NewBaseDialog, self).__init__(parent, pos, size, anchor, *args,
183 **kwargs)
185 self.desc_func = self.on_change
187 self.yes_button.function = self.get_name
188 self.name_dialog = \
189 dialog.TextEntryDialog(self, text=g.strings["new_base_text"])
191 def on_change(self, description_pane, base_type):
192 base_info = base_type.get_info(self.parent.location)
193 text.Text(description_pane, (0, 0), (-1, -1), text=base_info,
194 background_color=gg.colors["dark_blue"],
195 align=constants.LEFT, valign=constants.TOP,
196 borders=constants.ALL)
198 def show(self):
199 self.list = []
200 self.key_list = []
202 base_type_list = g.base_type.values()
203 base_type_list.sort()
204 base_type_list.reverse()
205 for base_type in base_type_list:
206 if base_type.available():
207 self.list.append(base_type.name)
208 self.key_list.append(base_type)
210 return super(NewBaseDialog, self).show()
212 def get_name(self):
213 if 0 <= self.listbox.list_pos < len(self.key_list):
214 type = self.key_list[self.listbox.list_pos]
215 self.name_dialog.default_text = \
216 generate_base_name(self.parent.location, type)
217 name = dialog.call_dialog(self.name_dialog, self)
218 if name:
219 raise constants.ExitDialog((name, type))
221 significant_numbers = [
222 '42', # The Answer.
223 '7', # Classic.
224 '23', # Another.
225 '51', # Area.
226 '19', # From the Dark Tower.
227 '4',
228 '8',
229 '15',
230 '16', # Four of the Lost numbers. The other two are '23' and '42'.
231 '13', # Lucky or unlucky?
232 '1414', # Square root of 2
233 '1947', # Roswell.
234 '2012', # Mayan calendar ending.
235 '2038', # End of UNIX 32-bit time.
236 '1969', # Man lands on the moon.
237 '2043', # No meaning--confusion! :)
238 '2029', # Predicted date of AI passing a Turing Test by Kurzweil.
239 '3141', # ... if you don't know what this is, you should go away.
240 '1618', # Golden ratio.
241 '2718', # e
242 '29979' # Speed of light in a vacuum. (m/s, first 5 digits.)
245 ## Generates a name for a base, given a particular location.
246 def generate_base_name(location, base_type):
247 # First, decide whether we're going to try significant values or just
248 # choose one randomly.
249 if random.random() < 0.3: # 30% chance.
250 attempts = 0
251 done = False
252 while (not done) and (attempts < 5):
253 name = random.choice(location.cities) + \
254 " " + random.choice(base_type.flavor) + " " \
255 + random.choice(significant_numbers)
256 duplicate = False
257 for check_base in location.bases:
258 if check_base.name == name:
259 duplicate = True
260 break
261 if duplicate:
262 attempts += 1
263 else:
264 done = True
265 if done:
266 return name
267 # This is both the else case and the general case.
268 name = random.choice(location.cities) + " " + \
269 random.choice(base_type.flavor) + " " + \
270 str (random.randint(0, 32767))
272 return name