Mercurial > sypikslang
view gamelib/missions.py @ 143:821ecb98e888
some icons and toggle button
author | Rizmari Versfeld <rizziepit@gmail.com> |
---|---|
date | Fri, 11 May 2012 03:13:22 +0200 |
parents | 14917385a0fd |
children | f1efd252e8b0 |
line wrap: on
line source
# -*- coding: utf-8 -*- # vim:fileencoding=utf-8 ai ts=4 sts=4 et sw=4 from random import randint from gamelib.constants import SUCCESS, FAILURE, GAME_WIN, M_VALS from gamelib.schematics import cat class Result(Exception): """Results of a mission. This is an exception so we can throw it from inside helper methods. """ def __init__(self, outcome, msg, money=0, rep=0, **special): self.outcome = outcome self.money = money self.reputation = rep self.text = msg self.special = special self.applied = False @property def loot(self): loot = {} if self.money != 0: loot['money'] = self.money if self.reputation != 0: loot['rep'] = self.reputation loot.update(self.special) loot.pop('new_milestone', None) # This one's special. return loot def apply(self, state): if not self.applied: state.money += self.money state.reputation += self.reputation state.apply_mission_special(self.special) self.applied = True else: raise RuntimeError('attempted to apply result twice') class Mission(object): """Base class for the mission objects. Missions have a name, short description (for list displays) and long description (which may contain clues about approaches)""" NAME = "Generic Mission" SHORT_DESCRIPTION = None LONG_DESCRIPTION = None MINIMUM_REPUTATION = None MINIMUM_MILESTONE = "neighbourhood" MINIONS_REQUIRED = 1 GENERIC_FAILURE = "You fail to inspire sufficient fear." GENERIC_SUCCESS = "Victory is sweet." NO_EQUIP_FAILURE = ( "Really? You're going in completely unequipped? How brave. And " " foolish. And ultimately unsuccessful.") def __init__(self, init_data=None): self.data = {} if init_data is not None: # Load stored state. self._load_data(init_data) else: # New instance. self._new_data() def _new_data(self): pass def _load_data(self, init_data): # Note: this does not deep-copy. self.data = init_data.copy() def save_data(self): # Note: this does not deep-copy. return self.data.copy() def get_data(self, key): return self.data.get(key, None) @classmethod def sanity_check(cls): pass def can_attempt(self, state): """Can we currently attempt the mission""" if (M_VALS[self.MINIMUM_MILESTONE] > M_VALS[state.milestone]): # Our base of operations is too small return False if self.get_data('completed'): return False if (self.MINIMUM_REPUTATION is not None and self.MINIMUM_REPUTATION > state.reputation): # Don't have the reputation required return False if self.MINIONS_REQUIRED > state.minions: # Need more minions! return False return True def fail(self, msg=None, money=0, rep=0, **special): if msg is None: msg = self.GENERIC_FAILURE raise Result(FAILURE, msg, money=money, rep=rep, **special) def succeed(self, msg=None, money=0, rep=0, **special): if msg is None: msg = self.GENERIC_SUCCESS raise Result(SUCCESS, msg, money=money, rep=rep, **special) def categorise_equipment(self, equipment): # Categorise equipment for easier decision-making. categorised = {} for item in equipment: for category in item.CATEGORIES: categorised.setdefault(category, []).append(item) return categorised def attempt_mission(self, equipment, state): """Attempt the mission with the given equipment list. Returns a result object with the results of the mission.""" # Handle error case if self.get_data('completed'): raise RuntimeError('Cannot attempt a completed mission') try: self.attempt(equipment, state) except Result, e: return e def attempt(self, equipment, state): # No equipment is usually a special case. if not equipment: return self.attempt_no_equipment(state) # Try with some equipment. self.attempt_with(self.categorise_equipment(equipment), state) # No result, so generic failure. self.fail() def attempt_no_equipment(self, state): self.fail(self.NO_EQUIP_FAILURE) def attempt_with(self, categorised, state): self.fail("You can't succceed at this mission.") class PlaygroundBully(Mission): NAME = "Rob kids in the playground" SHORT_DESCRIPTION = "Steal from those significantly weaker than yourself." LONG_DESCRIPTION = ( "It's not menancing, or lucrative, but when the bills are due, no one" " cares how you earn the money.") MINIMUM_MILESTONE = "basement" GENERIC_SUCCESS = ( "You devote your resources to robbing kids in a playpark. It's not the" " finest moment in your reign of terror, but at least you walked away" " with a surprising amount of small change.") def attempt(self, equipment, state): self.succeed(money=randint(90, 110), rep=-1) class RansomChina(Mission): NAME = "Hold China to ransom" SHORT_DESCRIPTION = "Surely a path to riches and fame." LONG_DESCRIPTION = ( "Holding China to ransom. The rewards for successfully threatening" " the largest country in the world are great, but the risks are" " significant. Without some serious firepower, the chances of success" " are small.") MINIMUM_REPUTATION = 100 MINIMUM_MILESTONE = "city" def _new_data(self): self.data['prior_attempts'] = [] def attempt_no_equipment(self, state): self.fail( "It takes three different interpreters before the Chinese" " government finally understand that you're trying to hold" " them ransom with... well... nothing. Nothing at all. This" " one will probably make a good anecdote at diplomatic" " cocktail parties. But not for you. No, not for you at all.", rep=-10) def attempt_with(self, categorised, state): dooms = categorised.get(cat.DOOMSDAY_DEVICE, []) if not dooms: self.fail( "You completely fail to inspire the requisite level of" " terror. Maybe a more impressive threat will fare better.", rep=-1) if len(dooms) > 1: self.fail( "Everyone seems confused as to how you actually plan" " to cause widepsread distruction and mayhem, and" " negotiations break down. Perhaps it's better to stick" " to one weapon of mass destruction at a time.") [doom] = dooms if doom.NAME in self.data['prior_attempts']: self.fail( "'We have devised countermeasures since last time, doctor." " You cannot threaten us with that again.'") self.data['prior_attempts'].add(doom.NAME) self.succeed( "Trembling at you threat of certain doom, the Chinese" " government pays the ransom.", money=randint(800000, 1200000), rep=10) class ToppleThirdWorldGovernment(Mission): NAME = "Topple a third-world government" SHORT_DESCRIPTION = "We could use a more amenable dictator there." LONG_DESCRIPTION = ( "It's a small and fairly useless country, but it's still an actual" " government that can be toppled. A good test bed for some of the" " larger toys in the armory.") MINIMUM_REPUTATION = 50 GENERIC_FAILURE = ( "Nobody seems to quite understand what it is you're threatening them" " with. Eventually you have to give up and go home.") NO_EQUIP_FAILURE = ( "The border post may be poorly guarded, but you need to bring *some*" " kind of weaponry along. Your troops sulk on the way home.") def attempt_with(self, categorised, state): if any(c in categorised for c in (cat.VEHICLE, cat.HAND_WEAPON)): self.succeed( "The corruption and oppression continue, but at least the" " proceeds are making their way into *your* pockets. And you" " don't even have to dirty your own jackboots.", money=randint(5000, 15000), rep=randint(3, 7)) class RobBank(Mission): NAME = "Rob the local bank" SHORT_DESCRIPTION = "A trivial challenge, but easy money." LONG_DESCRIPTION = ( "The security guards and local police are of minor concern. Walk in," " clean out the vault, walk out. Couldn't be simpler.") MINIMUM_MILESTONE = "basement" GENERIC_FAILURE = ( "The operation was a complete fiasco. Maybe you should try something a" " little less eclectic next time.") NO_EQUIP_FAILURE = ( "Your attempt to rob the bank barehanded is unsuccessful. Fortunately," " everyone is too stunned to impede your escape.") def attempt_with(self, categorised, state): loot = randint(500, 1500) if cat.VEHICLE in categorised: self.fail( "Your vehicles are impressively doom-laden, but not really" " suitable for city traffic. You intimidate the traffic" " wardens into letting you off without a fine, but by the" " time you get to the bank it's already closed.") if cat.HAND_WEAPON in categorised: self.succeed( "The threat of your weapons is enough to inspire an impressive" " level of cooperation. You make off with the loot.", money=loot) if cat.PATHOGEN in categorised: if randint(5, 15) < state.reputation: self.fail( "The clerk doesn't realise the threat of the vial you" " hold, and although watching him die in agony would be" " statisfying, you decide it's not worth wasting this on" " something so trivial.") self.succeed( "Holding up a bank with only a small vial of clear liquid. Now" " that is power.", money=loot, rep=1) class DestroyMountRushmore(Mission): NAME = "Destroy Mount Rushmore" SHORT_DESCRIPTION = "Monuments to other people? Intolerable" LONG_DESCRIPTION = ( "While potentially expensive, destroying a major monument is a" " good way to secure your reputation.") MINIMUM_REPUTATION = 20 def attempt(self, equipment, state): self.data['completed'] = True self.succeed("Mount Rushmore is remarkably easy to destroy.", rep=50) class DistributePamphlets(Mission): NAME = "Distribute pamphlets" SHORT_DESCRIPTION = "The populace need to be told the truth!" LONG_DESCRIPTION = ( "A focused pamphlet distribution campaign will combat the lies being" " spread about you. Replacing them with better lies, of course.") MINIMUM_MILESTONE = "basement" SUCCESS_MESSAGE = ( "A small army of urchins delivers thousands of cheaply printed" " pamphlets. %s") def _succ(self, message, rep): self.succeed(self.SUCCESS_MESSAGE % (message,), rep=rep) def attempt_no_equipment(self, state): rep = randint(-2, 5) if rep < 0: self._succ( "Sadly, the populace was so annoyed by the flood of flyers" " that nobody took any notice of the content.", rep) if rep == 0: self._succ("Nobody seems to have noticed.", rep) self._succ( "The public seemed mildly receptive to your propaganda.", rep) def attempt_with(self, categorised, state): if cat.MIND_CONTROL in categorised: self._succ("Your creative use of science has paid off nicely.", randint(5, 10)) return self.attempt_no_equipment(state) class TakeOverTheWorld(Mission): NAME = "Take over the world!" SHORT_DESCRIPTION = "It's for their own good." LONG_DESCRIPTION = ( "Someone has to rule the world and if it's not you it'd just be" " someone less well qualified -- and that would be worse for" " everyone.") MINIMUM_REPUTATION = 200 MINIMUM_MILESTONE = "city" NO_EQUIP_FAILURE = ( "It's going to take more than your bare hands to take over the world!") def attempt_with(self, categorised, state): if cat.MIND_CONTROL not in categorised: self.fail( "If you're going to take over the world, first you must" " control key elements within the populace.", rep=-5) raise Result(GAME_WIN, "The world is yours!", rep=100) class TakeOverTheNeighbourhood(Mission): NAME = "Take over the neighbourhood!" SHORT_DESCRIPTION = "First step toward greatness." LONG_DESCRIPTION = ( "A basement lab is a good starting point, but it's getting a bit" " cramped in here. You need to expand, but don't quite have the" " resources to take the whole world yet. Or even the city. But the" " neighbourhood... that's quite feasible.") MINIMUM_REPUTATION = 20 MINIMUM_MILESTONE = "basement" NO_EQUIP_FAILURE = ( "The neighbourhood isn't very big, but you're still not going to take" " it over bare-handed.") GENERIC_FAILURE = ( "Well, that didn't work. Maybe a better equipment selection is in" " order.") def attempt_with(self, categorised, state): if all(c in categorised for c in (cat.MIND_CONTROL, cat.HAND_WEAPON)): self.data['completed'] = True self.succeed( "Guns and persuasion, that's all you need. It's early days" " still, but you're finally out of that pokey basement and" " have some elbow room to work with. Next step: the city!", money=randint(1000, 2000), rep=randint(5, 15), new_milestone="neighbourhood") if cat.HAND_WEAPON in categorised: self.succeed( "You'll need more than guns to win the people over. But until" " then, you can take their cash.", money=randint(100, 200)) if cat.MIND_CONTROL in categorised: self.succeed( "Propaganda and persuasion are good tools, but you'll need" " some force to back them up.", rep=randint(2, 4))