# HG changeset patch # User Jeremy Thurgood # Date 1336342696 -7200 # Node ID efc4f90cfd63faa451fcb289bcbf2465a1d36d36 # Parent 2754c453b39b80e0f3d3c28e1ca8599cb836495a Mission refactoring and research fix. diff -r 2754c453b39b -r efc4f90cfd63 gamelib/lab.py --- a/gamelib/lab.py Sun May 06 21:56:21 2012 +0200 +++ b/gamelib/lab.py Mon May 07 00:18:16 2012 +0200 @@ -100,7 +100,7 @@ total_points += my_science.points return total_points - base_points >= extra - def find_new_products(self, research_area): + def find_new_products(self): available_products = [] for product_class in self.new_products: if self.meet_requirements(product_class): @@ -115,7 +115,8 @@ return available_research def apply_area_research(self, research): - options = self.find_new_products(research) + options = [product for product in self.find_new_products() + if type(research) in [p[0] for p in product.PREREQUISITES]] breakthroughs = [product for product in options if random() < product.ACQUISITION_CHANCE] if breakthroughs: diff -r 2754c453b39b -r efc4f90cfd63 gamelib/missions.py --- a/gamelib/missions.py Sun May 06 21:56:21 2012 +0200 +++ b/gamelib/missions.py Mon May 07 00:18:16 2012 +0200 @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # vim:fileencoding=utf-8 ai ts=4 sts=4 et sw=4 +from random import random + from products import HAND_WEAPON, VEHICLE, PATHOGEN, DOOMSDAY_DEVICE MAJOR_SETBACK, FAILURE, SUCCESS, MAJOR_SUCCESS, GAME_WIN = range(5) @@ -47,33 +49,62 @@ def attempt(self, equipment, state): """Attempt the mission with the given equipment list. + Returns a result object with the results of the mission.""" - Returns a result object with the results of the mission.""" - return Result(FAILURE, 0, 0, "You can't succceed at this 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") + 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.") def attempt(self, equipment, state): - return Result(SUCCESS, 100, -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.") + haul = 90 + int(random() * 20) + 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." + 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 def __init__(self, init_data=None): @@ -85,96 +116,115 @@ def save_data(self): return self._prior_attempts - def attempt(self, equipment, state): - failures = [] - reputation = 0 - for item in equipment: - if item.is_a(DOOMSDAY_DEVICE): - if item.NAME not in self._prior_attempts: - self._prior_attempts.add(item.NAME) - return Result(SUCCESS, 1000000, 1, ( - "Trembling at the threat of your doomsday virus," - " the chinese government pays the ransom.")) - elif item.is_a(PATHOGEN): - reputation = -1 - failures.append( - "'Hah, we've developed an antidote to your" - " pathogen, doctor. You cannot threaten us with that" - " again.'") - else: - reputation = -1 - failures.append( - "'Hah, we know how to deal with that particular" - " threat, doctor.'") - else: - failures.append("You fail to inspire fear with your %s" - % item.NAME) - return Result(FAILURE, 0, reputation, "\n".join(failures)) + 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(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._prior_attempts: + return Result(FAILURE, 0, 0, ( + "'We have devised countermeasures since last time, doctor." + " You cannot threaten us with that again.'")) + + self._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 despot there" + 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(self, equipment, state): - failures = [] - if not equipment: + 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 (VEHICLE, HAND_WEAPON)): + return Result(SUCCESS, 5000 + int(random() * 10000), 5, ( + "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 DOOMSDAY_DEVICE in categorised: 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.")) - for item in equipment: - if any(item.is_a(cat) for cat in (VEHICLE, HAND_WEAPON)): - return Result(SUCCESS, 10000, 5, ( - "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.")) - else: - failures.append("You fail to inspire fear with your %s" - % item.NAME) - return Result(FAILURE, 0, 0, "\n".join(failures)) + "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." + 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.") + + 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 = 500 + int(random() * 1000) - def attempt(self, equipment, state): - failures = [] - if not equipment: - return Result(FAILURE, 0, 0, "Your attempt to rob the bank" - " barehanded is unsuccessful. Fortunately, everyone is" - " too stunned to impede your escape.") - for item in equipment: - if item.is_a(PATHOGEN): - if state.reputation < 10: - failures.append("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, 1000, 0, "Holding up a bank with" - " only a small vial of clear liquid. Now that" - " is power.") - elif item.is_a(HAND_WEAPON): - return Result(SUCCESS, 1000, 0, "The threat of your weapons is" - " enough to inspire an impressive level of cooperation") + if 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 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 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: - failures.append("You fail to inspire fear with your %s" - % item.NAME) - return Result(FAILURE, 0, 0, "\n".join(failures)) + return Result(SUCCESS, loot, 1, ( + "Holding up a bank with only a small vial of clear" + " liquid. Now that is power.")) class DestroyMountRushmore(Mission): @@ -189,5 +239,5 @@ if not self.available: raise RuntimeError('Cannot attempt an unavailable mission') self.available = False - return Result(SUCCESS, 0, 100, - "Mount Rushmore is remarkably easy to destroy.") + return Result(SUCCESS, 0, 50, ( + "Mount Rushmore is remarkably easy to destroy.")) diff -r 2754c453b39b -r efc4f90cfd63 gamelib/tests/test_lab.py --- a/gamelib/tests/test_lab.py Sun May 06 21:56:21 2012 +0200 +++ b/gamelib/tests/test_lab.py Mon May 07 00:18:16 2012 +0200 @@ -27,7 +27,7 @@ def test_find_new_products(self): lab = Lab(LAB_DATA) - new_products = lab.find_new_products(None) + new_products = lab.find_new_products() self.assertTrue(products.TeslaTank in new_products) self.assertTrue(products.DoomsdayVirus not in new_products)