Mercurial > parpg-core
view src/parpg/charactercreationcontroller.py @ 11:4706e0194af3
Various improvements to the build process including support for self-contained builds.
* Note that despite all of these changes PARPG still does not run because asset paths are not standardized,
* Modified the SCons script so that by default running `scons` with no arguments creates a self-contained "build" under a build subdirectory to make in-source testing easier. To install PARPG, use `scons install` instead.
* Got rid of the binary launcher and replaced it with a shell script for unix and a batch script for Windows (batch script is untested). The binary turned out to be too much trouble to maintain.
* Modified the parpg.settings module and parpg.main entry script so that PARPG searches through several default search paths for configuration file(s). PARPG thus no longer crashes if it can't find a configuration file in any particular search path, but will crash it if can't find any configuration files.
* Paths supplied to parpg.main are now appended as search paths for the configuration file(s).
* Changed the default configuration file name to "parpg.cfg" to simplify searches.
* Created the site_scons directory tree where SCons extensions and tools should be placed.
* Created a new SCons builder, CopyRecurse, which can copy only certain files and folders from a directory tree using filters (files and folders that start with a leading dot "." e.g. ".svn" are ignored by default).
* Added the CPython SCons tool (stands for Compile-Python - I didn't name it!), which provides the InstallPython builder for pre-compiling python sources before they are installed. However, it is currently broken and only installs the python sources.
author | M. George Hansen <technopolitica@gmail.com> |
---|---|
date | Tue, 31 May 2011 02:46:20 -0700 |
parents | 1fd2201f5c36 |
children | d60f1dab8469 |
line wrap: on
line source
# This file is part of PARPG. # # PARPG is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # PARPG is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PARPG. If not, see <http://www.gnu.org/licenses/>. """Provides the controller that defines the behaviour of the character creation screen.""" import characterstatistics as char_stats from serializers import XmlSerializer from controllerbase import ControllerBase from gamescenecontroller import GameSceneController from gamesceneview import GameSceneView from parpg.inventory import Inventory DEFAULT_STAT_VALUE = 50 def getStatCost(offset): """Gets and returns the cost to increase stat based on the offset""" if offset < 0: offset *= -1 if offset < 22: return 1 elif offset < 29: return 2 elif offset < 32: return 3 elif offset < 35: return 4 elif offset < 36: return 5 elif offset < 38: return 6 elif offset < 39: return 7 elif offset < 40: return 8 elif offset < 41: return 9 else: return 10 #TODO: Should be replaced with the real character class once its possible class SimpleCharacter(object): """This is a simple class that is used to store the data during the character creation""" def __init__(self, name, gender, origin, age, picture, traits, primary_stats, secondary_stats, inventory): self.name = name self.gender = gender self.origin = origin self.age = age self.picture = picture self.traits = traits self.statistics = {} for primary_stat in primary_stats: short_name = primary_stat.short_name self.statistics[short_name] = char_stats.PrimaryStatisticValue( primary_stat, self, DEFAULT_STAT_VALUE) long_name = primary_stat.long_name self.statistics[long_name] = char_stats.PrimaryStatisticValue( primary_stat, self, DEFAULT_STAT_VALUE) for secondary_stat in secondary_stats: name = secondary_stat.name self.statistics[name] = char_stats.SecondaryStatisticValue( secondary_stat, self) self.inventory = inventory class CharacterCreationController(ControllerBase): """Controller defining the behaviour of the character creation screen.""" #TODO: Change to actual values MAX_TRAITS = 3 MIN_AGE = 16 MAX_AGE = 40 ORIGINS = {"None": None,} GENDERS = ["Male", "Female",] PICTURES = {"Male": ["None",], "Female": ["None",],} TRAITS = {} def __init__(self, engine, view, model, application): """Construct a new L{CharacterCreationController} instance. @param engine: Rendering engine used to display the associated view. @type engine: L{fife.Engine} @param view: View used to display the character creation screen. @type view: L{ViewBase} @param model: Model of the game state. @type model: L{GameModel} @param application: Application used to glue the various MVC components together. @type application: L{fife.extensions.basicapplication.ApplicationBase}""" ControllerBase.__init__(self, engine, view, model, application) self.view.start_new_game_callback = self.startNewGame self.view.cancel_new_game_callback = self.cancelNewGame self.view.show() #TODO: Maybe this should not be hardcoded stream = file("character_scripts/primary_stats.xml") prim_stats = XmlSerializer.deserialize(stream) stream = file("character_scripts/secondary_stats.xml") sec_stats = XmlSerializer.deserialize(stream) self.char_data = SimpleCharacter("", self.GENDERS[0], self.ORIGINS.keys()[0], 20, self.PICTURES[self.GENDERS[0]][0], [], prim_stats, sec_stats, Inventory()) self._stat_points = 200 def startNewGame(self): """Create the new character and start a new game. @return: None""" view = GameSceneView(self.engine, self.model) controller = GameSceneController(self.engine, view, self.model, self.application) self.application.view = view self.application.switchController(controller) start_map = self.model.settings.parpg.Map self.model.changeMap(start_map) def cancelNewGame(self): """Exit the character creation view and return the to main menu. @return: None""" # KLUDGE Technomage 2010-12-24: This is to prevent a circular import # but a better fix needs to be thought up. from mainmenucontroller import MainMenuController from mainmenuview import MainMenuView view = MainMenuView(self.engine, self.model) controller = MainMenuController(self.engine, view, self.model, self.application) self.application.view = view self.application.switchController(controller) def onStop(self): """Called when the controller is removed from the list. @return: None""" self.view.hide() @property def name(self): """Returns the name of the character. @return: Name of the character""" return self.char_data.name @property def age(self): """Returns the age of the character. @return: Age of the character""" return self.char_data.age @property def gender(self): """Returns the gender of the character. @return: Gender of the character""" return self.char_data.gender @property def origin(self): """Returns the origin of the character. @return: Origin of the character""" return self.char_data.origin @property def picture(self): """Returns the ID of the current picture of the character.""" return self.char_data.picture def getStatPoints(self): """Returns the remaining statistic points that can be distributed""" return self._stat_points def increaseStatistic(self, statistic): """Increases the given statistic by one. @param statistic: Name of the statistic to increase @type statistic: string""" if self.canIncreaseStatistic(statistic): cost = self.getStatisticIncreaseCost(statistic) if cost <= self._stat_points: self.char_data.statistics[statistic].value += 1 self._stat_points -= cost def getStatisticIncreaseCost(self, statistic): """Calculate and return the cost to increase the statistic @param statistic: Name of the statistic to increase @type statistic: string @return cost to increase the statistic""" cur_value = self.char_data.statistics[statistic].value new_value = cur_value + 1 offset = new_value - DEFAULT_STAT_VALUE return getStatCost(offset) def canIncreaseStatistic(self, statistic): """Checks whether the given statistic can be increased or not. @param statistic: Name of the statistic to check @type statistic: string @return: True if the statistic can be increased, False if not.""" stat = self.char_data.statistics[statistic].value return stat < stat.statistic_type.maximum def decreaseStatistic(self, statistic): """Decreases the given statistic by one. @param statistic: Name of the statistic to decrease @type statistic: string""" if self.canDecreaseStatistic(statistic): gain = self.getStatisticDecreaseGain(statistic) self.char_data.statistics[statistic].value -= 1 self._stat_points += gain def getStatisticDecreaseGain(self, statistic): """Calculate and return the gain of decreasing the statistic @param statistic: Name of the statistic to decrease @type statistic: string @return cost to decrease the statistic""" cur_value = self.char_data.statistics[statistic].value new_value = cur_value - 1 offset = new_value - DEFAULT_STAT_VALUE return getStatCost(offset) def canDecreaseStatistic(self, statistic): """Checks whether the given statistic can be decreased or not. @param statistic: Name of the statistic to check @type statistic: string @return: True if the statistic can be decreased, False if not.""" stat = self.char_data.statistics[statistic].value return stat > stat.statistic_type.minimum def getStatisticValue(self, statistic): """Returns the value of the given statistic. @param statistic: Name of the primary or secondary statistic @type statistic: string @return: Value of the given statistic""" return self.char_data.statistics[statistic] def areAllStatisticsValid(self): """Checks if all statistics are inside the minimum/maximum values @return True if all statistics are valid False if not""" for stat in self.char_data.statistics.items(): if not (stat.value > stat.statistic_type.minumum and\ stat.value < stat.statistic_type.maximum): return False return True def setName(self, name): """Sets the name of the character to the given value. @param name: New name @type name: string""" self.char_data.name = name def isNameValid(self, name): """Checks whether the name is valid. @param name: Name to check @type name: string @return: True if the name is valid, False if not""" if name: return True return False def changeOrigin(self, origin): """Changes the origin of the character to the given value. @param origin: New origin @type origin: string""" if self.isOriginValid(origin): self.char_data.origin = origin #TODO: Make changes according to origin def isOriginValid(self, origin): """Checks whether the origin is valid. @param origin: Origin to check @type origin: string @return: True if the origin is valid, False if not""" return origin in self.ORIGINS def changeGender(self, gender): """Changes the gender of the character to the given value. @param gender: New gender @param gender: string""" if self.isGenderValid(gender): self.char_data.gender = gender def isGenderValid(self, gender): """Checks whether the gender is valid. @param gender: Gender to check @type gender: string? @return: True if the origin is valid, False if not""" return gender in self.GENDERS def changeAge(self, age): """Sets the age of the character to the given value. @param age: New age @type age: integer """ if self.isAgeValid(age): self.char_data.age = age def isAgeValid(self, age): """Checks whether the age is valid. @param age: Age to check @type age: integer @return: True if the origin is valid, False if not""" return age >= self.MIN_AGE and age <= self.MAX_AGE def setPicture(self, picture): """Set picture of the character. @param picture: ID of the new picture @type picture: string""" if self.isPictureValid(picture): self.char_data.picture = picture def isPictureValid(self, picture): """Checks whether the picture is valid. @param picture: ID of the picture to check @type picture: string @return: True if the picture is valid, False if not""" return picture in self.PICTURES[self.gender] def addTrait(self, trait): """Adds a trait to the character. @param trait: ID of the trait to add @type trait: string""" if self.canAddAnotherTrait() and self.isTraitValid(trait)\ and not self.hasTrait(trait): self.char_data.traits.append(trait) def canAddAnotherTrait(self): """Checks whether another trait can be added. @return: True if another trait can be added, False if not""" return len(self.char_data.traits) < self.MAX_TRAITS def removeTrait(self, trait): """Remove trait from character. @param trait: ID of the trait to remove @type trait: string""" if self.hasTrait(trait): self.char_data.traits.remove(trait) def hasTrait(self, trait): """Checks whether the character has the trait. @param trait: ID of the trait to check @type trait: string @return: True if the character has the trait, False if not""" return trait in self.char_data.traits def isTraitValid(self, trait): """Checks whether the trait is valid. @param trait: ID of the trait to check @type trait: string @return: True if the trait is valid, False if not""" return trait in self.TRAITS def areCurrentTraitsValid(self): """Checks whether the characters traits are valid. @return: True if the traits are valid, False if not""" if len(self.char_data.traits) > self.MAX_TRAITS: return False for trait in self.char_data.traits: if not self.isTraitValid(trait): return False return True def isCharacterValid(self): """Checks whether the character as a whole is valid. @return: True if the character is valid, False if not""" #Single checks can be disabled by putting a "#" in front of them if True\ and self._stat_points >= 0\ and self.areAllStatisticsValid() \ and self.areCurrentTraitsValid() \ and self.isNameValid(self.name)\ and self.isPictureValid(self.picture)\ and self.isAgeValid(self.age)\ and self.isGenderValid(self.gender)\ and self.isOriginValid(self.origin)\ : return True return False