Mercurial > sypikslang
view gamelib/missions.py @ 131:31ab0af26bb5
Load milestone as well
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Thu, 10 May 2012 16:50:09 +0200 |
parents | be79e113d494 |
children | fb8037bc22f1 |
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, NEW_MILESTONE, M_VALS from gamelib.schematics import cat class Result(object): """Results of a mission""" def __init__(self, outcome, money, reputation, msg): self.outcome = outcome self.money = money self.reputation = reputation self.message = msg self.applied = False def apply(self, state): if not self.applied: state.money += self.money state.reputation += self.reputation 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 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 attempt(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') # No equipment is usually a special case. if not equipment: return self.attempt_no_equipment(state) # Categorise equipment for easier decision-making. categorised = {} for item in equipment: for category in item.CATEGORIES: categorised.setdefault(category, []).append(item) result = self.attempt_with(categorised, state) if result is not None: # We have a mission result. return result # Generic fallback result. return Result(FAILURE, 0, 0, ( "You fail to inspire sufficient fear.")) def attempt_no_equipment(self, state): return Result(FAILURE, 0, 0, ( "Really? You're going in completely unequipped?" " How brave. And foolish. And ultimately unsuccessful.")) def attempt_with(self, categorised, state): return Result(FAILURE, 0, 0, "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" def attempt(self, equipment, state): haul = randint(90, 110) return Result(SUCCESS, haul, -1, ( "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.")) 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): return Result(FAILURE, 0, -10, ( "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.")) def attempt_with(self, categorised, state): dooms = categorised.get(cat.DOOMSDAY_DEVICE, []) if not dooms: return Result(FAILURE, 0, -1, ( "You completely fail to inspire the requisite level of" " terror. Maybe a more impressive threat will fare" " better.")) if len(dooms) > 1: return Result(FAILURE, 0, 0, ( "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']: return Result(FAILURE, 0, 0, ( "'We have devised countermeasures since last time, doctor." " You cannot threaten us with that again.'")) self.data['prior_attempts'].add(doom.NAME) return Result(SUCCESS, 1000000, 10, ( "Trembling at you threat of certain doom, the Chinese" " government pays the ransom.")) 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 def attempt_no_equipment(self, state): return Result(FAILURE, 0, 0, ( "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)): return Result(SUCCESS, randint(5000, 15000), randint(3, 7), ( "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.")) if cat.DOOMSDAY_DEVICE in categorised: return Result(FAILURE, 0, 0, ( "Nobody seems to quite understand what it is you're" " threatening them with. Eventually you have to give up" " and go home.")) 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" def attempt_no_equipment(self, state): return Result(FAILURE, 0, 0, ( "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: return Result(FAILURE, 0, 0, ( "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: return Result(SUCCESS, loot, 0, ( "The threat of your weapons is enough to inspire an" " impressive level of cooperation. You make off with the" " loot.")) if cat.PATHOGEN in categorised: if state.reputation < 10: return Result(FAILURE, 0, 0, ( "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")) else: return Result(SUCCESS, loot, 1, ( "Holding up a bank with only a small vial of clear" " liquid. Now that is power.")) 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 return Result(SUCCESS, 0, 50, ( "Mount Rushmore is remarkably easy to destroy.")) 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 attempt_no_equipment(self, state): rep = randint(-2, 5) if rep < 0: result = ( "Sadly, the populace was so annoyed by the flood of flyers" " that nobody took any notice of the content.") elif rep == 0: result = "Nobody seems to have noticed." else: result = "The public seemed mildly receptive to your propaganda." return Result(SUCCESS, 0, rep, self.SUCCESS_MESSAGE % (result,)) def attempt_with(self, categorised, state): rep = randint(5, 10) if cat.MIND_CONTROL in categorised: result = ( "Your creative use of science has paid off nicely.") return Result(SUCCESS, 0, rep, self.SUCCESS_MESSAGE % (result,)) else: 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" def attempt_no_equipment(self, state): return Result(FAILURE, 0, 0, "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: return Result(FAILURE, 0, 5, "If you're going to take over the" " world, first you must control key elements within" " the populace.") return Result(GAME_WIN, 0, 100, "The world is yours!") 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" def attempt_no_equipment(self, state): return Result(FAILURE, 0, 0, "The neighbourhood isn't very big, but" " you're still not going to take it over bare-handed.") def attempt_with(self, categorised, state): if all(c in categorised for c in (cat.MIND_CONTROL, cat.HAND_WEAPON)): self.data['completed'] = True return Result(NEW_MILESTONE, 1000, 5, "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!") if cat.HAND_WEAPON in categorised: return Result(SUCCESS, 150, 0, "You'll need more than guns to" " win the people over. But until then, you can take" " their cash.") if cat.MIND_CONTROL in categorised: return Result(SUCCESS, 0, 7, "Propaganda and persuasion are good" " tools, but you'll need something to back them up.") return Result(FAILURE, 0, 0, "Well, that didn't work. Maybe a better" " equipment selection is in order.")