Mercurial > parpg-core
comparison src/parpg/charactercreationcontroller.py @ 0:1fd2201f5c36
Initial commit of parpg-core.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Sat, 14 May 2011 01:12:35 -0700 |
parents | |
children | d60f1dab8469 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1fd2201f5c36 |
---|---|
1 # This file is part of PARPG. | |
2 # | |
3 # PARPG is free software: you can redistribute it and/or modify | |
4 # it under the terms of the GNU General Public License as published by | |
5 # the Free Software Foundation, either version 3 of the License, or | |
6 # (at your option) any later version. | |
7 # | |
8 # PARPG is distributed in the hope that it will be useful, | |
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 # GNU General Public License for more details. | |
12 # | |
13 # You should have received a copy of the GNU General Public License | |
14 # along with PARPG. If not, see <http://www.gnu.org/licenses/>. | |
15 """Provides the controller that defines the behaviour of the character creation | |
16 screen.""" | |
17 | |
18 import characterstatistics as char_stats | |
19 from serializers import XmlSerializer | |
20 from controllerbase import ControllerBase | |
21 from gamescenecontroller import GameSceneController | |
22 from gamesceneview import GameSceneView | |
23 from parpg.inventory import Inventory | |
24 | |
25 DEFAULT_STAT_VALUE = 50 | |
26 | |
27 | |
28 def getStatCost(offset): | |
29 """Gets and returns the cost to increase stat based on the offset""" | |
30 if offset < 0: | |
31 offset *= -1 | |
32 if offset < 22: | |
33 return 1 | |
34 elif offset < 29: | |
35 return 2 | |
36 elif offset < 32: | |
37 return 3 | |
38 elif offset < 35: | |
39 return 4 | |
40 elif offset < 36: | |
41 return 5 | |
42 elif offset < 38: | |
43 return 6 | |
44 elif offset < 39: | |
45 return 7 | |
46 elif offset < 40: | |
47 return 8 | |
48 elif offset < 41: | |
49 return 9 | |
50 else: | |
51 return 10 | |
52 | |
53 #TODO: Should be replaced with the real character class once its possible | |
54 class SimpleCharacter(object): | |
55 """This is a simple class that is used to store the data during the | |
56 character creation""" | |
57 | |
58 def __init__(self, name, gender, origin, age, picture, traits, | |
59 primary_stats, secondary_stats, inventory): | |
60 self.name = name | |
61 self.gender = gender | |
62 self.origin = origin | |
63 self.age = age | |
64 self.picture = picture | |
65 self.traits = traits | |
66 self.statistics = {} | |
67 for primary_stat in primary_stats: | |
68 short_name = primary_stat.short_name | |
69 self.statistics[short_name] = char_stats.PrimaryStatisticValue( | |
70 primary_stat, | |
71 self, | |
72 DEFAULT_STAT_VALUE) | |
73 long_name = primary_stat.long_name | |
74 self.statistics[long_name] = char_stats.PrimaryStatisticValue( | |
75 primary_stat, | |
76 self, | |
77 DEFAULT_STAT_VALUE) | |
78 for secondary_stat in secondary_stats: | |
79 name = secondary_stat.name | |
80 self.statistics[name] = char_stats.SecondaryStatisticValue( | |
81 secondary_stat, | |
82 self) | |
83 self.inventory = inventory | |
84 | |
85 class CharacterCreationController(ControllerBase): | |
86 """Controller defining the behaviour of the character creation screen.""" | |
87 | |
88 #TODO: Change to actual values | |
89 MAX_TRAITS = 3 | |
90 MIN_AGE = 16 | |
91 MAX_AGE = 40 | |
92 ORIGINS = {"None": None,} | |
93 GENDERS = ["Male", "Female",] | |
94 PICTURES = {"Male": ["None",], "Female": ["None",],} | |
95 TRAITS = {} | |
96 def __init__(self, engine, view, model, application): | |
97 """Construct a new L{CharacterCreationController} instance. | |
98 @param engine: Rendering engine used to display the associated view. | |
99 @type engine: L{fife.Engine} | |
100 @param view: View used to display the character creation screen. | |
101 @type view: L{ViewBase} | |
102 @param model: Model of the game state. | |
103 @type model: L{GameModel} | |
104 @param application: Application used to glue the various MVC | |
105 components together. | |
106 @type application: | |
107 L{fife.extensions.basicapplication.ApplicationBase}""" | |
108 ControllerBase.__init__(self, engine, view, model, application) | |
109 self.view.start_new_game_callback = self.startNewGame | |
110 self.view.cancel_new_game_callback = self.cancelNewGame | |
111 self.view.show() | |
112 #TODO: Maybe this should not be hardcoded | |
113 stream = file("character_scripts/primary_stats.xml") | |
114 prim_stats = XmlSerializer.deserialize(stream) | |
115 stream = file("character_scripts/secondary_stats.xml") | |
116 sec_stats = XmlSerializer.deserialize(stream) | |
117 self.char_data = SimpleCharacter("", | |
118 self.GENDERS[0], | |
119 self.ORIGINS.keys()[0], | |
120 20, | |
121 self.PICTURES[self.GENDERS[0]][0], | |
122 [], | |
123 prim_stats, | |
124 sec_stats, | |
125 Inventory()) | |
126 self._stat_points = 200 | |
127 | |
128 | |
129 def startNewGame(self): | |
130 """Create the new character and start a new game. | |
131 @return: None""" | |
132 view = GameSceneView(self.engine, self.model) | |
133 controller = GameSceneController(self.engine, view, self.model, | |
134 self.application) | |
135 self.application.view = view | |
136 self.application.switchController(controller) | |
137 start_map = self.model.settings.parpg.Map | |
138 self.model.changeMap(start_map) | |
139 | |
140 def cancelNewGame(self): | |
141 """Exit the character creation view and return the to main menu. | |
142 @return: None""" | |
143 # KLUDGE Technomage 2010-12-24: This is to prevent a circular import | |
144 # but a better fix needs to be thought up. | |
145 from mainmenucontroller import MainMenuController | |
146 from mainmenuview import MainMenuView | |
147 view = MainMenuView(self.engine, self.model) | |
148 controller = MainMenuController(self.engine, view, self.model, | |
149 self.application) | |
150 self.application.view = view | |
151 self.application.switchController(controller) | |
152 | |
153 def onStop(self): | |
154 """Called when the controller is removed from the list. | |
155 @return: None""" | |
156 self.view.hide() | |
157 | |
158 @property | |
159 def name(self): | |
160 """Returns the name of the character. | |
161 @return: Name of the character""" | |
162 return self.char_data.name | |
163 | |
164 @property | |
165 def age(self): | |
166 """Returns the age of the character. | |
167 @return: Age of the character""" | |
168 return self.char_data.age | |
169 | |
170 @property | |
171 def gender(self): | |
172 """Returns the gender of the character. | |
173 @return: Gender of the character""" | |
174 return self.char_data.gender | |
175 | |
176 @property | |
177 def origin(self): | |
178 """Returns the origin of the character. | |
179 @return: Origin of the character""" | |
180 return self.char_data.origin | |
181 | |
182 @property | |
183 def picture(self): | |
184 """Returns the ID of the current picture of the character.""" | |
185 return self.char_data.picture | |
186 | |
187 def getStatPoints(self): | |
188 """Returns the remaining statistic points that can be distributed""" | |
189 return self._stat_points | |
190 | |
191 def increaseStatistic(self, statistic): | |
192 """Increases the given statistic by one. | |
193 @param statistic: Name of the statistic to increase | |
194 @type statistic: string""" | |
195 if self.canIncreaseStatistic(statistic): | |
196 cost = self.getStatisticIncreaseCost(statistic) | |
197 if cost <= self._stat_points: | |
198 self.char_data.statistics[statistic].value += 1 | |
199 self._stat_points -= cost | |
200 | |
201 def getStatisticIncreaseCost(self, statistic): | |
202 """Calculate and return the cost to increase the statistic | |
203 @param statistic: Name of the statistic to increase | |
204 @type statistic: string | |
205 @return cost to increase the statistic""" | |
206 cur_value = self.char_data.statistics[statistic].value | |
207 new_value = cur_value + 1 | |
208 offset = new_value - DEFAULT_STAT_VALUE | |
209 return getStatCost(offset) | |
210 | |
211 def canIncreaseStatistic(self, statistic): | |
212 """Checks whether the given statistic can be increased or not. | |
213 @param statistic: Name of the statistic to check | |
214 @type statistic: string | |
215 @return: True if the statistic can be increased, False if not.""" | |
216 stat = self.char_data.statistics[statistic].value | |
217 return stat < stat.statistic_type.maximum | |
218 | |
219 def decreaseStatistic(self, statistic): | |
220 """Decreases the given statistic by one. | |
221 @param statistic: Name of the statistic to decrease | |
222 @type statistic: string""" | |
223 if self.canDecreaseStatistic(statistic): | |
224 gain = self.getStatisticDecreaseGain(statistic) | |
225 self.char_data.statistics[statistic].value -= 1 | |
226 self._stat_points += gain | |
227 | |
228 def getStatisticDecreaseGain(self, statistic): | |
229 """Calculate and return the gain of decreasing the statistic | |
230 @param statistic: Name of the statistic to decrease | |
231 @type statistic: string | |
232 @return cost to decrease the statistic""" | |
233 cur_value = self.char_data.statistics[statistic].value | |
234 new_value = cur_value - 1 | |
235 offset = new_value - DEFAULT_STAT_VALUE | |
236 return getStatCost(offset) | |
237 | |
238 def canDecreaseStatistic(self, statistic): | |
239 """Checks whether the given statistic can be decreased or not. | |
240 @param statistic: Name of the statistic to check | |
241 @type statistic: string | |
242 @return: True if the statistic can be decreased, False if not.""" | |
243 stat = self.char_data.statistics[statistic].value | |
244 return stat > stat.statistic_type.minimum | |
245 | |
246 def getStatisticValue(self, statistic): | |
247 """Returns the value of the given statistic. | |
248 @param statistic: Name of the primary or secondary statistic | |
249 @type statistic: string | |
250 @return: Value of the given statistic""" | |
251 return self.char_data.statistics[statistic] | |
252 | |
253 def areAllStatisticsValid(self): | |
254 """Checks if all statistics are inside the minimum/maximum values | |
255 @return True if all statistics are valid False if not""" | |
256 for stat in self.char_data.statistics.items(): | |
257 if not (stat.value > stat.statistic_type.minumum and\ | |
258 stat.value < stat.statistic_type.maximum): | |
259 return False | |
260 return True | |
261 | |
262 def setName(self, name): | |
263 """Sets the name of the character to the given value. | |
264 @param name: New name | |
265 @type name: string""" | |
266 self.char_data.name = name | |
267 | |
268 def isNameValid(self, name): | |
269 """Checks whether the name is valid. | |
270 @param name: Name to check | |
271 @type name: string | |
272 @return: True if the name is valid, False if not""" | |
273 if name: | |
274 return True | |
275 return False | |
276 | |
277 def changeOrigin(self, origin): | |
278 """Changes the origin of the character to the given value. | |
279 @param origin: New origin | |
280 @type origin: string""" | |
281 if self.isOriginValid(origin): | |
282 self.char_data.origin = origin | |
283 #TODO: Make changes according to origin | |
284 | |
285 def isOriginValid(self, origin): | |
286 """Checks whether the origin is valid. | |
287 @param origin: Origin to check | |
288 @type origin: string | |
289 @return: True if the origin is valid, False if not""" | |
290 return origin in self.ORIGINS | |
291 | |
292 def changeGender(self, gender): | |
293 """Changes the gender of the character to the given value. | |
294 @param gender: New gender | |
295 @param gender: string""" | |
296 if self.isGenderValid(gender): | |
297 self.char_data.gender = gender | |
298 | |
299 def isGenderValid(self, gender): | |
300 """Checks whether the gender is valid. | |
301 @param gender: Gender to check | |
302 @type gender: string? | |
303 @return: True if the origin is valid, False if not""" | |
304 return gender in self.GENDERS | |
305 | |
306 def changeAge(self, age): | |
307 """Sets the age of the character to the given value. | |
308 @param age: New age | |
309 @type age: integer | |
310 """ | |
311 if self.isAgeValid(age): | |
312 self.char_data.age = age | |
313 | |
314 def isAgeValid(self, age): | |
315 """Checks whether the age is valid. | |
316 @param age: Age to check | |
317 @type age: integer | |
318 @return: True if the origin is valid, False if not""" | |
319 return age >= self.MIN_AGE and age <= self.MAX_AGE | |
320 | |
321 def setPicture(self, picture): | |
322 """Set picture of the character. | |
323 @param picture: ID of the new picture | |
324 @type picture: string""" | |
325 if self.isPictureValid(picture): | |
326 self.char_data.picture = picture | |
327 | |
328 def isPictureValid(self, picture): | |
329 """Checks whether the picture is valid. | |
330 @param picture: ID of the picture to check | |
331 @type picture: string | |
332 @return: True if the picture is valid, False if not""" | |
333 return picture in self.PICTURES[self.gender] | |
334 | |
335 def addTrait(self, trait): | |
336 """Adds a trait to the character. | |
337 @param trait: ID of the trait to add | |
338 @type trait: string""" | |
339 if self.canAddAnotherTrait() and self.isTraitValid(trait)\ | |
340 and not self.hasTrait(trait): | |
341 self.char_data.traits.append(trait) | |
342 | |
343 def canAddAnotherTrait(self): | |
344 """Checks whether another trait can be added. | |
345 @return: True if another trait can be added, False if not""" | |
346 return len(self.char_data.traits) < self.MAX_TRAITS | |
347 | |
348 def removeTrait(self, trait): | |
349 """Remove trait from character. | |
350 @param trait: ID of the trait to remove | |
351 @type trait: string""" | |
352 if self.hasTrait(trait): | |
353 self.char_data.traits.remove(trait) | |
354 | |
355 def hasTrait(self, trait): | |
356 """Checks whether the character has the trait. | |
357 @param trait: ID of the trait to check | |
358 @type trait: string | |
359 @return: True if the character has the trait, False if not""" | |
360 return trait in self.char_data.traits | |
361 | |
362 def isTraitValid(self, trait): | |
363 """Checks whether the trait is valid. | |
364 @param trait: ID of the trait to check | |
365 @type trait: string | |
366 @return: True if the trait is valid, False if not""" | |
367 return trait in self.TRAITS | |
368 | |
369 def areCurrentTraitsValid(self): | |
370 """Checks whether the characters traits are valid. | |
371 @return: True if the traits are valid, False if not""" | |
372 if len(self.char_data.traits) > self.MAX_TRAITS: | |
373 return False | |
374 for trait in self.char_data.traits: | |
375 if not self.isTraitValid(trait): | |
376 return False | |
377 return True | |
378 | |
379 def isCharacterValid(self): | |
380 """Checks whether the character as a whole is valid. | |
381 @return: True if the character is valid, False if not""" | |
382 #Single checks can be disabled by putting a "#" in front of them | |
383 if True\ | |
384 and self._stat_points >= 0\ | |
385 and self.areAllStatisticsValid() \ | |
386 and self.areCurrentTraitsValid() \ | |
387 and self.isNameValid(self.name)\ | |
388 and self.isPictureValid(self.picture)\ | |
389 and self.isAgeValid(self.age)\ | |
390 and self.isGenderValid(self.gender)\ | |
391 and self.isOriginValid(self.origin)\ | |
392 : | |
393 return True | |
394 return False |