Mercurial > rinkhals
changeset 389:463802281182
Add basic level support (level choosing needs work)
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Thu, 29 Oct 2009 20:55:37 +0000 |
parents | c6f0e3e72e86 |
children | 2bcfccb8288e |
files | gamelib/animal.py gamelib/constants.py gamelib/engine.py gamelib/gameboard.py gamelib/gameover.py gamelib/level.py gamelib/main.py gamelib/mainmenu.py |
diffstat | 8 files changed, 141 insertions(+), 71 deletions(-) [+] |
line wrap: on
line diff
--- a/gamelib/animal.py Thu Oct 29 20:54:32 2009 +0000 +++ b/gamelib/animal.py Thu Oct 29 20:55:37 2009 +0000 @@ -243,6 +243,7 @@ IMAGE_FILE = 'sprites/fox.png' DEATH_ANIMATION = animations.FoxDeath DEATH_SOUND = 'kill-fox.ogg' + CONFIG_NAME = 'fox' costs = { # weighting for movement calculation @@ -459,12 +460,14 @@ STEALTH = 60 IMAGE_FILE = 'sprites/ninja_fox.png' + CONFIG_NAME = 'ninja fox' class DemoFox(Fox): """Demolition Foxes destroy fences easily""" DIG_ANIMATION = animations.FenceExplosion IMAGE_FILE = 'sprites/sapper_fox.png' + CONFIG_NAME = 'sapper fox' def __init__(self, pos): Fox.__init__(self, pos) @@ -479,6 +482,7 @@ class GreedyFox(Fox): """Greedy foxes eat more chickens""" + CONFIG_NAME = 'greedy fox' def __init__(self, pos): Fox.__init__(self, pos) @@ -496,6 +500,7 @@ """The Rinkhals has eclectic tastes""" STEALTH = 80 IMAGE_FILE = 'sprites/rinkhals.png' + CONFIG_NAME = 'rinkhals' def _catch_chicken(self, chicken, gameboard): """The Rinkhals hunts for sport, catch and release style""" @@ -527,3 +532,14 @@ distance = watcher.pos.dist(watchee.pos) - 1 roll = random.randint(1, 100) return roll > watchee.STEALTH - vision_bonus + range_penalty*distance + +# These don't have to add up to 100, but it's easier to think +# about them if they do. +DEFAULT_FOX_WEIGHTINGS = ( + (Fox, 59), + (GreedyFox, 30), + (NinjaFox, 5), + (DemoFox, 5), + (Rinkhals, 1), + ) +
--- a/gamelib/constants.py Thu Oct 29 20:54:32 2009 +0000 +++ b/gamelib/constants.py Thu Oct 29 20:55:37 2009 +0000 @@ -24,18 +24,27 @@ BUFFER = 1024 # audio buffer size in no. of samples FRAMERATE = 30 # how often to check if playback has finished -# Game constants +# Default values that can be overridden by the levels -STARTING_CASH = 1000 -SELL_PRICE_CHICKEN = 10 -SELL_PRICE_EGG = 5 -SELL_PRICE_DEAD_FOX = 15 +DEFAULT_STARTING_CASH = 1000 +DEFAULT_SELL_PRICE_CHICKEN = 10 +DEFAULT_SELL_PRICE_EGG = 5 +DEFAULT_SELL_PRICE_DEAD_FOX = 15 +DEFAULT_TURN_LIMIT = 14 +DEFAULT_GOAL_DESC = 'Survive for 2 weeks' + +DEFAULT_MAX_FOXES = 50 + +# Game constants, still to be made configurable + LOGGING_PRICE = 50 BUY_PRICE_FENCE = 50 SELL_PRICE_FENCE = 25 REPAIR_PRICE_FENCE = 25 SELL_PRICE_BROKEN_FENCE = 5 +# Toolbar constants + TOOL_SELL_CHICKEN = 1 TOOL_SELL_EGG = 2 TOOL_SELL_BUILDING = 3 @@ -46,13 +55,4 @@ NIGHT_LENGTH = 150 -TURN_LIMITS = { - 'Two weeks' : 14, - 'Three months' : 90, - 'Unlimited' : 0, - } -DEFAULT_MODE = 'Two weeks' - -ABS_MAX_NUM_FOXES = 50 # Limit possible uppoer number of foxes, due to concerns - # about performance, etc.
--- a/gamelib/engine.py Thu Oct 29 20:54:32 2009 +0000 +++ b/gamelib/engine.py Thu Oct 29 20:55:37 2009 +0000 @@ -9,15 +9,17 @@ import constants import mainmenu import helpscreen +import level from misc import check_exit class Engine(Game): - def __init__(self, main_app): + def __init__(self, main_app, level_name): self.main_app = main_app + self.level = level.Level(level_name) self.clock = pygame.time.Clock() - self.main_menu = mainmenu.make_main_menu() + self.main_menu = mainmenu.make_main_menu(self.level) self._open_window = None - self.scoreboard = gameover.ScoreTable() + self.scoreboard = gameover.ScoreTable(self.level) self.gameboard = None def tick(self): @@ -33,11 +35,8 @@ def create_game_board(self): """Create and open a gameboard window.""" - self.mode = self.main_menu.get_mode() - if not self.mode: - self.mode = constants.DEFAULT_MODE self.gameboard = gameboard.GameBoard(self.main_app, - constants.TURN_LIMITS[self.mode]) + self.level) self.open_window(self.gameboard.get_top_widget()) def set_main_menu(self): @@ -52,7 +51,7 @@ def create_game_over(self): """Create and open the Game Over window""" game_over = gameover.create_game_over(self.gameboard, - self.scoreboard[self.mode], self.mode) + self.scoreboard[self.level.level_name], self.level) self.gameboard = None self.open_window(game_over)
--- a/gamelib/gameboard.py Thu Oct 29 20:54:32 2009 +0000 +++ b/gamelib/gameboard.py Thu Oct 29 20:55:37 2009 +0000 @@ -58,7 +58,7 @@ return update_counter class ToolBar(gui.Table): - def __init__(self, gameboard, **params): + def __init__(self, gameboard, level, **params): gui.Table.__init__(self, **params) self.group = gui.Group(name='toolbar', value=None) self._next_tool_value = 0 @@ -87,9 +87,9 @@ self.add_heading("Sell ...") self.add_tool_button("Chicken", constants.TOOL_SELL_CHICKEN, - constants.SELL_PRICE_CHICKEN, cursors.cursors['sell']) + level.sell_price_chicken, cursors.cursors['sell']) self.add_tool_button("Egg", constants.TOOL_SELL_EGG, - constants.SELL_PRICE_EGG, cursors.cursors['sell']) + level.sell_price_egg, cursors.cursors['sell']) self.add_tool_button("Building", constants.TOOL_SELL_BUILDING, None, cursors.cursors['sell']) self.add_tool_button("Equipment", constants.TOOL_SELL_EQUIPMENT, @@ -275,25 +275,15 @@ WOODLAND = tiles.REVERSE_TILE_MAP['woodland'] BROKEN_FENCE = tiles.REVERSE_TILE_MAP['broken fence'] - # These don't have to add up to 100, but it's easier to think - # about them if they do. - FOX_WEIGHTINGS = ( - (animal.Fox, 59), - (animal.GreedyFox, 30), - (animal.NinjaFox, 5), - (animal.DemoFox, 5), - (animal.Rinkhals, 1), - ) - - def __init__(self, main_app, max_turns): + def __init__(self, main_app, level): self.disp = main_app + self.level = level self.tv = tiles.FarmVid() self.tv.png_folder_load_tiles('tiles') - self.tv.tga_load_level(data.filepath('levels/farm.tga')) + self.tv.tga_load_level(level.map) width, height = self.tv.size # Ensure we don't every try to create more foxes then is sane - self.max_foxes = min(height+width-15, constants.ABS_MAX_NUM_FOXES) - self.max_turns = max_turns + self.max_foxes = min(height+width-15, level.max_foxes) self.create_display() self.selected_tool = None @@ -306,7 +296,7 @@ self.eggs = 0 self.days = 0 self.killed_foxes = 0 - self.add_cash(constants.STARTING_CASH) + self.add_cash(level.starting_cash) self.day, self.night = True, False self.fix_buildings() @@ -324,7 +314,7 @@ width, height = self.disp.rect.w, self.disp.rect.h tbl = gui.Table() tbl.tr() - self.toolbar = ToolBar(self, width=self.TOOLBAR_WIDTH) + self.toolbar = ToolBar(self, self.level, width=self.TOOLBAR_WIDTH) tbl.td(self.toolbar, valign=-1) self.tvw = VidWidget(self, self.tv, width=width-self.TOOLBAR_WIDTH, height=height) tbl.td(self.tvw) @@ -443,7 +433,7 @@ for item in list(chicken.equipment): self.add_cash(item.sell_price()) chicken.unequip(item) - self.add_cash(constants.SELL_PRICE_CHICKEN) + self.add_cash(self.level.sell_price_chicken) sound.play_sound("sell-chicken.ogg") if update_button: update_button(chicken, empty=True) @@ -460,7 +450,7 @@ def sell_one_egg(self, chicken): if chicken.eggs: - self.add_cash(constants.SELL_PRICE_EGG) + self.add_cash(self.level.sell_price_egg) chicken.remove_one_egg() self.eggs -= 1 self.toolbar.update_egg_counter(self.eggs) @@ -777,10 +767,10 @@ def advance_day(self): self.days += 1 - if self.days == self.max_turns: + if self.days == self.level.turn_limit: self.toolbar.day_counter.style.color = (255, 0, 0) self.toolbar.update_day_counter("%s/%s" % (self.days, - self.max_turns if self.max_turns > 0 else "-")) + self.level.turn_limit if self.level.turn_limit > 0 else "-")) def clear_foxes(self): for fox in self.foxes.copy(): @@ -864,7 +854,7 @@ def kill_fox(self, fox): self.killed_foxes += 1 self.toolbar.update_fox_counter(self.killed_foxes) - self.add_cash(constants.SELL_PRICE_DEAD_FOX) + self.add_cash(self.level.sell_price_dead_fox) self.remove_fox(fox) def remove_fox(self, fox): @@ -899,7 +889,7 @@ self.add_chicken(chick) def _choose_fox(self, (x, y)): - fox_cls = misc.WeightedSelection(self.FOX_WEIGHTINGS).choose() + fox_cls = misc.WeightedSelection(self.level.fox_weightings).choose() return fox_cls((x, y)) def spawn_foxes(self): @@ -907,7 +897,7 @@ # Foxes spawn just outside the map x, y = 0, 0 width, height = self.tv.size - min_foxes = (self.days+3)/2 # always more than one fox + min_foxes = max(self.level.min_foxes, (self.days+3)/2) # always more than one fox new_foxes = min(random.randint(min_foxes, min_foxes*2), self.max_foxes) while len(self.foxes) < new_foxes: side = random.randint(0, 3) @@ -977,7 +967,7 @@ """Return true if we're complete""" if self.trees_left() == 0: return True - if self.max_turns > 0 and self.days >= self.max_turns: + if self.level.turn_limit > 0 and self.days >= self.level.turn_limit: return True if len(self.chickens) == 0: return True
--- a/gamelib/gameover.py Thu Oct 29 20:54:32 2009 +0000 +++ b/gamelib/gameover.py Thu Oct 29 20:55:37 2009 +0000 @@ -32,19 +32,21 @@ "What will your chickens do now?", ] -def ScoreTable(): +def ScoreTable(level): """Create and initialise a score table""" # We need a true file, so load will work, but, as we never save, # the deletion doesn't bother us. our_scores = Highs(tempfile.NamedTemporaryFile(), 4) - for mode in constants.TURN_LIMITS: - for score in range(700,1000,100): - our_scores[mode].submit(score, 'No-one', None) + #for mode in constants.TURN_LIMITS: + # for score in range(700,1000,100): + # our_scores[mode].submit(score, 'No-one', None) + for score in range(700,1000,100): + our_scores[level.level_name].submit(score, 'No-one', None) return our_scores -def create_game_over(gameboard, scores, mode): +def create_game_over(gameboard, scores, level): """Create a game over screen""" - game_over = GameOver(gameboard, scores, mode) + game_over = GameOver(gameboard, scores, level) return GameOverContainer(game_over, align=0, valign=0) class GameOverContainer(gui.Container): @@ -68,7 +70,7 @@ class GameOver(gui.Table): - def __init__(self, gameboard, scoreboard, mode, **params): + def __init__(self, gameboard, scoreboard, level, **params): gui.Table.__init__(self, **params) def return_pressed(): @@ -78,8 +80,8 @@ pygame.event.post(engine.QUIT) score = gameboard.cash + \ - constants.SELL_PRICE_CHICKEN * len(gameboard.chickens) + \ - constants.SELL_PRICE_EGG * gameboard.eggs + level.sell_price_chicken * len(gameboard.chickens) + \ + level.sell_price_egg * gameboard.eggs self.tr() made_list = scoreboard.check(score) is not None @@ -100,7 +102,7 @@ # show the scoreboard self.tr() - self.td(gui.Label('Game Mode: %s' % mode, color=constants.FG_COLOR), + self.td(gui.Label('Level: %s' % level.level_name, color=constants.FG_COLOR), colspan=3) for highscore in scoreboard:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gamelib/level.py Thu Oct 29 20:55:37 2009 +0000 @@ -0,0 +1,51 @@ +# level.py + +import constants +import data +from animal import DEFAULT_FOX_WEIGHTINGS +from ConfigParser import RawConfigParser + +class Level(object): + """Container for level details""" + + def __init__(self, level_name): + default_map = '%s.tga' % level_name + level_info = data.filepath('levels/%s.conf' % level_name) + # Load the level info file + # setup defaults + defaults = { + 'map' : default_map, + 'level name' : level_name, + 'sell price chicken' : constants.DEFAULT_SELL_PRICE_CHICKEN, + 'sell price egg' : constants.DEFAULT_SELL_PRICE_EGG, + 'sell price dead fox' : constants.DEFAULT_SELL_PRICE_DEAD_FOX, + 'turn limit' : constants.DEFAULT_TURN_LIMIT, + 'goal' : constants.DEFAULT_GOAL_DESC, + 'max foxes' : constants.DEFAULT_MAX_FOXES, + 'min foxes' : 0, + 'starting cash' : constants.DEFAULT_STARTING_CASH, + } + # Add default fox weightings + for animal, prob in DEFAULT_FOX_WEIGHTINGS: + defaults[animal.CONFIG_NAME] = prob + config = RawConfigParser(defaults) + config.read(level_info) + # NB. This assumes the level file is correctly formatted. No provision + # is made for missing sections or incorrectly specified values. + # i.e. Things may blow up + map_file = config.get('Level', 'map') + self.map = data.filepath('levels/%s' % map_file) + self.level_name = config.get('Level', 'level name') + self.goal = config.get('Level', 'goal') + self.turn_limit = config.getint('Level', 'turn limit') + self.max_foxes = config.getint('Game values', 'max foxes') + self.min_foxes = config.getint('Game values', 'min foxes') + self.sell_price_chicken = config.getint('Game values', 'sell price chicken') + self.sell_price_egg = config.getint('Game values', 'sell price egg') + self.sell_price_dead_fox = config.getint('Game values', + 'sell price dead fox') + self.starting_cash = config.getint('Game values', 'starting cash') + self.fox_weightings = [] + for animal, _prob in DEFAULT_FOX_WEIGHTINGS: + self.fox_weightings.append((animal, config.getint('Fox probablities', + animal.CONFIG_NAME)))
--- a/gamelib/main.py Thu Oct 29 20:54:32 2009 +0000 +++ b/gamelib/main.py Thu Oct 29 20:55:37 2009 +0000 @@ -14,6 +14,7 @@ from sound import init_sound import constants import data +import sys def create_main_app(screen): """Create an app with a background widget.""" @@ -33,7 +34,12 @@ from engine import Engine, MainMenuState - engine = Engine(main_app) + if len(sys.argv) > 1: + level_name = sys.argv[1] + else: + level_name = 'two_weeks' + + engine = Engine(main_app, level_name) try: engine.run(MainMenuState(engine), screen) except KeyboardInterrupt:
--- a/gamelib/mainmenu.py Thu Oct 29 20:54:32 2009 +0000 +++ b/gamelib/mainmenu.py Thu Oct 29 20:55:37 2009 +0000 @@ -6,9 +6,9 @@ import engine import imagecache -def make_main_menu(): +def make_main_menu(level): """Create a main menu""" - main_menu = MainMenu() + main_menu = MainMenu(level) c = MenuContainer(align=0, valign=0) c.add(main_menu, 0, 0) @@ -26,7 +26,7 @@ return self.widgets[0].mode class MainMenu(gui.Table): - def __init__(self, **params): + def __init__(self, level, **params): gui.Table.__init__(self, **params) self.mode = None @@ -36,10 +36,12 @@ def quit_pressed(): pygame.event.post(engine.QUIT) - def start_game(mode): - self.mode = mode + def start_game(): pygame.event.post(engine.START_DAY) + def choose_level(): + print 'Needs to be implemented. Specify the level name as a parameter' + def help_pressed(): pygame.event.post(engine.GO_HELP_SCREEN) @@ -50,12 +52,16 @@ "align": 0, "style": style, } - - for mode in constants.TURN_LIMITS: - button = gui.Button(mode) - button.connect(gui.CLICK, start_game, mode) - self.tr() - self.td(button, **td_kwargs) + + change_button = gui.Button('Choose level') + change_button.connect(gui.CLICK, choose_level) + self.tr() + self.td(change_button, **td_kwargs) + + start_button = gui.Button(level.level_name) + start_button.connect(gui.CLICK, start_game) + self.tr() + self.td(start_button, **td_kwargs) quit_button = gui.Button("Quit") quit_button.connect(gui.CLICK, quit_pressed)