def test_as_json(self): '''Test planet.as_json() exporter''' planet = Planet() jdata = planet.as_json() print(jdata) p_data = json.loads(jdata) self.assertTrue(p_data['uwp'] == planet.uwp()) self.assertTrue(p_data['trade_codes'] == planet.trade_codes) self.assertTrue(p_data['travel_code'] == planet.travel_code) self.assertTrue(p_data['bases'] == planet.bases) self.assertTrue(p_data['orbit'] == planet.orbit) self.assertTrue(p_data['is_mainworld'] == planet.is_mainworld)
def test_json_import(self): '''Test planet.json_import() importer''' jdata = u'{"trade_codes": ["Fl", "Lo"], "travel_code": "", ' +\ '"is_mainworld": true, "uwp": "D9A6313-3", "orbit": 5, ' +\ '"bases": "", "mainworld_type": "Planet", ' +\ '"parent_type": null, "orbit_around_parent": null }' p_data = json.loads(jdata) planet = Planet() planet.json_import(jdata) self.assertTrue(p_data['uwp'] == planet.uwp()) self.assertTrue(p_data['trade_codes'] == planet.trade_codes) self.assertTrue(p_data['travel_code'] == planet.travel_code) self.assertTrue(p_data['bases'] == planet.bases) self.assertTrue(p_data['orbit'] == planet.orbit) self.assertTrue(p_data['is_mainworld'] == planet.is_mainworld)
class System(object): '''Return a T5 basic system with the specified name and location hex''' naval_base_presence = Table() naval_base_presence.add_row('A', 6) naval_base_presence.add_row('B', 5) scout_base_presence = Table() scout_base_presence.add_row('A', 4) scout_base_presence.add_row('B', 5) scout_base_presence.add_row('C', 6) scout_base_presence.add_row('D', 7) mw_orbit_flux_table = Table() mw_orbit_flux_table.add_row(-6, -2) mw_orbit_flux_table.add_row((-5, -3), -1) mw_orbit_flux_table.add_row((-2, 2), 0) mw_orbit_flux_table.add_row((3, 5), 1) mw_orbit_flux_table.add_row(6, 2) def __init__(self, name='', location_hex='0000'): self.hex = location_hex self.name = name self.zone = '' self.stellar = Primary() self.mainworld = Planet() self.determine_mw_orbit() self.bases = self.determine_bases() self.pbg = Pbg(self.mainworld) self.allegiance = 'Na' self.determine_trade_codes() self.determine_x() self.nobility = self.determine_nobility() self.num_worlds = (self.pbg.belts + self.pbg.gasgiants + D6.roll(1) + 1) self.determine_travel_zone() def display(self): '''Display''' return '{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}'.format( self.hex, self.name, self.mainworld.uwp(), ' '.join(self.mainworld.trade_codes), str(self.importance_x), str(self.economic_x), str(self.cultural_x), self.nobility, self.bases, self.zone, str(self.pbg), self.num_worlds, self.allegiance, self.stellar.display()) def __str__(self): oformat = '{0:4} {1:20} {2:9} {3:18} {4:4} {5:7} {6:6} ' +\ '{7:7} {8:2} {9:1} {10:3} {11:2} {12:2} {13:14}' return oformat.format(self.hex, self.name, self.mainworld.uwp(), ' '.join(self.mainworld.trade_codes), str(self.importance_x), str(self.economic_x), str(self.cultural_x.display()), self.nobility, self.bases, self.zone, str(self.pbg), self.num_worlds, self.allegiance, self.stellar.display()) def determine_nobility(self): '''Determine noble representation''' nobility = 'B' # Every world gets a knight # Baronet if ('Pa' in self.mainworld.trade_codes or 'Pr' in self.mainworld.trade_codes): nobility += 'c' # Baron if ('Ag' in self.mainworld.trade_codes or 'Ri' in self.mainworld.trade_codes): nobility += 'C' if 'Pi' in self.mainworld.trade_codes: nobility += 'D' # Marquis if 'Ph' in self.mainworld.trade_codes: nobility += 'e' # Viscount # Count if ('In' in self.mainworld.trade_codes or 'Hi' in self.mainworld.trade_codes): nobility += 'E' if int(self.importance_x) >= 4: nobility += 'f' # Duke return nobility def determine_bases(self): '''Determine bases''' bases = '' # Naval base target = self.naval_base_presence.lookup(self.mainworld.starport) if target is not None: if D6.roll(2) <= target: bases += 'N' # Scout base target = self.scout_base_presence.lookup(self.mainworld.starport) if target is not None: if D6.roll(2) <= target: bases += 'S' return bases def determine_trade_codes(self): '''Determine climate trade codes''' tcs = TradeCodes(self.mainworld, self) self.mainworld.trade_codes = tcs.generate() def determine_mw_orbit(self): '''Determine mainworld orbit''' orbit = self.stellar.habitable_zone +\ self.mw_orbit_flux_table.lookup(FLUX.flux()) orbit = max(orbit, 0) self.mainworld.orbit = orbit def determine_travel_zone(self, starport_x_is_red=True): '''Determine travel zone - A or R''' self.zone = '' if int(self.mainworld.government) + \ int(self.mainworld.law_level) in [20, 21]: self.zone = 'A' self.mainworld.trade_codes.append('Da') elif int(self.mainworld.government) + \ int(self.mainworld.law_level) > 22: self.zone = 'R' if starport_x_is_red: if self.mainworld.starport == 'X': self.zone = 'R' self.mainworld.trade_codes.append('Fo') def as_json(self): '''Return JSON representation of system''' system_dict = { 'name': self.name, 'hex': self.hex, 'stellar': self.stellar.as_json(), 'mainworld': self.mainworld.as_json(), 'bases': self.bases, 'pbg': str(self.pbg), 'allegiance': self.allegiance, 'Ix': str(self.importance_x), 'Ex': str(self.economic_x), 'Cx': str(self.cultural_x), 'nobility': self.nobility, 'worlds': self.num_worlds, 'zone': self.zone } return json.dumps(system_dict) def json_import(self, jdata): '''Import from JSON''' system_dict = json.loads(jdata) self.name = system_dict['name'] self.hex = system_dict['hex'] self.bases = system_dict['bases'] self.allegiance = system_dict['allegiance'] self.nobility = system_dict['nobility'] self.num_worlds = int(system_dict['worlds']) self.zone = system_dict['zone'] self.stellar.json_import(system_dict['stellar']) self.mainworld.json_import(system_dict['mainworld']) self.pbg.json_import(system_dict['pbg']) self.importance_x.json_import(system_dict['Ix']) self.economic_x.json_import(system_dict['Ex']) self.cultural_x.json_import(system_dict['Cx']) def determine_x(self): '''Determine Ix Ex Cx values''' self.importance_x = ImportanceExtension(self.mainworld, self) self.economic_x = EconomicExtension(self.pbg, int(self.mainworld.population), int(self.mainworld.tech_level), self.mainworld.trade_codes, int(self.importance_x)) self.cultural_x = CulturalExtension(int(self.mainworld.population), int(self.importance_x), int(self.mainworld.tech_level))
class TradeCargo(object): '''Spec cargo object''' def __init__(self): self.cost = 0 self.description = '' self.interesting_trade_codes = [] self.actual_value = 0 self.price = 0 self._codes = { 'Ga': [[ 'Bulk Protein', 'Bulk Carbs', 'Bulk Fats', 'Bulk Pharma', 'Livestock', 'Seedstock' ], [ 'Flavored Waters', 'Wines', 'Juices', 'Nectars', 'Decoctions', 'Drinkable Lymphs' ], [ 'Health Foods', 'Nutraceuticals', 'Fast Drug', 'Painkillers', 'Antiseptic', 'Antibiotics' ], [ 'Incenses', 'Iridescents', 'Photonics', 'Pigments', 'Noisemakers', 'Soundmakers' ], [ 'Fine Furs', 'Meat Delicacies', 'Fruit Delicacies', 'Candies', 'Textiles', 'Exotic Sauces' ], ['_As', '_De', '_Fl', '_Ic', '_Na', '_In']], 'Fa': [[ 'Bulk Woods', 'Bulk Pets', 'Bulk Herbs', 'Bulk Spices', 'Bulk Nitrates', 'Foodstuffs' ], [ 'Flowers', 'Aromatics', 'Pheromones', 'Secretions', 'Adhesives', 'Novel Flavorings' ], [ 'Antifungals', 'Antivirals', 'Panacea', 'Pseudomones', 'Anagathics', 'Slow Drug' ], [ 'Strange Seeds', 'Motile Plants', 'Reactive Plants', 'IR Emitters', 'Lek Emitters' ], [ 'Spices', 'Organic Gems', 'Flavorings', 'Aged Meats', 'Fermented Fluids', 'Fine Aromatics' ], ['_Po', '_Ri', '_Va', '_Ic', '_Na', '_In']], 'As': [[ 'Bulk Nitrates', 'Bulk Carbon', 'Bulk Iron', 'Bulk Copper', 'Radioactive Ores', 'Bulk Ices' ], ['Ores', 'Ices', 'Carbons', 'Metals', 'Uranium', 'Chelates'], ['Platinum', 'Gold', 'Gallium', 'Silver', 'Thorium', 'Radium'], [ 'Unusual Rocks', 'Fused Metals', 'Strange Crystals', 'Fine Dusts', 'Magnetics', 'Light-Sensitives' ], [ 'Gemstones', 'Alloys', 'Iridium Sponge', 'Lanthanum', 'Isotopes', 'Anti-Matter' ], ['_Ag', '_De', '_Na', '_Po', '_Ri', '_Ic']], 'De': [[ 'Bulk Nitrates', 'Bulk Minerals', 'Bulk Abrasives', 'Bulk Particulates', 'Exotic Fauna', 'Exotic Flora' ], [ 'Archeologicals', 'Fauna', 'Flora', 'Minerals', 'Ephemerals', 'Polymers' ], [ 'Stimulants', 'Bulk Herbs', 'Palliatives', 'Pheromones', 'Antibiotics', 'Combat Drug' ], [ 'Envirosuits', 'Reclamation Suits', 'Navigators', 'Dupe Masterpieces', 'ShimmerCloth', 'ANIFX Blocker' ], [ 'Excretions', 'Flavorings', 'Nectars', 'Pelts', 'ANIFX Dyes', 'Seedstock' ], [ 'Pheromones', 'Artifacts', 'Sparx', 'Repulsant', 'Dominants', 'Fossils' ]], 'Fl': [[ 'Bulk Carbon', 'Bulk Petros', 'Bulk Precipitates', 'Exotic Fluids', 'Organic Polymers', 'Bulk Synthetics' ], [ 'Archeologicals', 'Fauna', 'Flora', 'Germanes', 'Flill', 'Chelates' ], [ 'Antifungals', 'Antivirals', 'Palliatives', 'Counter-prions', 'Antibiotics', 'Cold Sleep Pills' ], [ 'Silanes', 'Lek Emitters', 'Aware Blockers', 'Soothants', 'Self-Solving Puzzlies', 'Fluidic Timepieces' ], [ 'Flavorings', 'Unusual Fluids', 'Encapsulants', 'Insidiants', 'Corrosives', 'Exotic Aromatics' ], ['_In', '_Ri', '_Ic', '_Na', '_Ag', '_Po']], 'Ic': [[ 'Bulk Ices', 'Bulk Precipitates', 'Bulk Ephemerals', 'Exotic Flora', 'Bulk Gases', 'Bulk Oxygen' ], [ 'Archeologicals', 'Fauna', 'Flora', 'Minerals', 'Luminescents', 'Polymers' ], [ 'Antifungals', 'Antivirals', 'Palliatives', 'Counter-prions', 'Antibiotics', 'Cold Sleep Pills' ], [ 'Silanes', 'Lek Emitters', 'Aware Blockers', 'Soothants', 'Self-Solving Puzzlies', 'Fluidic Timepieces' ], [ 'Unusual Ices', 'Cryo Alloys', 'Rare Minerals', 'Unusual Fluids', 'Cryogems', 'VHDUS Dyes' ], [ 'Fossils', 'Cryogems', 'Vision Suppressant', 'Fission Suppressant', 'Wafers', 'Cold Sleep Pills' ]], 'In': [[ 'Electronics', 'Photonics', 'Magnetics', 'Fluidics', 'Polymers', 'Gravitics' ], [ 'Obsoletes', 'Used Goods', 'Reparables', 'Radioactives', 'Metals', 'Sludges' ], [ 'Biologics', 'Mechanicals', 'Textiles', 'Weapons', 'Armor', 'Robots' ], [ 'Nostrums', 'Restoratives', 'Palliatives', 'Chelates', 'Antidotes', 'Antitoxins' ], [ 'Software', 'Databases', 'Expert Systems', 'Upgrades', 'Backups', 'Raw Sensings' ], [ 'Disposables', 'Respirators', 'Filter Masks', 'Combination', 'Parts', 'Improvements' ]], 'Na': [[ 'Bulk Abrasives', 'Bulk Gases', 'Bulk Minerals', 'Bulk Precipitates', 'Exotic Fauna', 'Exotic Flora' ], [ 'Archeologicals', 'Fauna', 'Flora', 'Minerals', 'Ephemerals', 'Polymers' ], [ 'Branded Tools', 'Drinkable Lymphs', 'Strange Seeds', 'Pattern Creators', 'Pigments', 'Warm Leather' ], [ 'Hummingsand', 'Masterpieces', 'Fine Carpets', 'Isotopes', 'Pelts', 'Seedstock' ], [ 'Masterpieces', 'Unusual Rocks', 'Artifacts', 'Non-fossil Carcasses', 'Replicating Clays', 'ANIFX EMitter' ], ['_Ag', '_Ri', '_In', '_Ic', '_De', '_Fl']], 'Po': [[ 'Bulk Nutrients', 'Bulk Fibers', 'Bulk Organics', 'Bulk Minerals', 'Bulk Textiles', 'Exotic Flora' ], [ 'Art', 'Recordings', 'Writings', 'Tactiles', 'Osmancies', 'Wafers' ], [ 'Strange Crystals', 'Strange Seeds', 'Pigments', 'Emotion Lighting', 'Silanes', 'Flora' ], [ 'Gemstones', 'Antiques', 'Collectibles', 'Allotropes', 'Spices', 'Seedstock' ], [ 'Masterpieces', 'Exotic Flora', 'Antiques', 'Incomprehensibles', 'Fossils', 'VHDUS Emitter' ], ['_In', '_Ri', '_Fl', '_Ic', '_Ag', '_Va']], 'Ri': [[ 'Bulk Foodstuffs', 'Bulk Protein', 'Bulk Carbs', 'Bulk Fats', 'Exotic Flora', 'Exotic Fauna' ], [ 'Echostones', 'Self-Defenders', 'Attractants', 'Sophont Cuisine', 'Sophone Hats', 'Variable Tattoos' ], [ 'Branded Foods', 'Branded Drinks', 'Branded Clothes', 'Flavored Drinks', 'Flowers', 'Music' ], [ 'Delicacies', 'Spices', 'Tisanes', 'Nectars', 'Pelts', 'Variable Tattoos' ], [ 'Antique Art', 'Masterpieces', 'Artifacts', 'Fine Art', 'Meson Barriers', 'Famous Wafers' ], [ 'Edutainments', 'Recordings', 'Writings', 'Tactiles', 'Osmancies', 'Wafers' ]], 'Va': [[ 'Bulk Dusts', 'Bulk Minerals', 'Bulk Metals', 'Radioactive Ores', 'Bulk Particulates', 'Ephererals' ], [ 'Branded Vacc Suits', 'Awareness Pinger', 'Strange Seeds', 'Pigments', 'Unusual Minerals', 'Exotic Crystals' ], [ 'Branded Oxygen', 'Vacc Suit Scents', 'Vacc Suit Patches', 'Branded Tools', 'Holo-Companions', 'Flavored Air' ], [ 'Vacc Gems', 'Unusual Dusts', 'Insulants', 'Crafted Devices', 'Rare Minerals', 'Catalysts' ], [ 'Archeologicals', 'Fauna', 'Flora', 'Minerals', 'Ephemerals', 'Polymers' ], [ 'Obsoletes', 'Used Goods', 'Reparables', 'Plutonium', 'Metals', 'Sludges' ]], 'Cp': [[ 'Software', 'Expert Systems', 'Databases', 'Upgrades', 'Backups', 'Raw Sensings' ], [ 'Incenses', 'Contemplatives', 'Cold Welders', 'Polymer Sheets', 'Hats', 'Skin Tones' ], [ 'Branded Clothes', 'Branded Devices', 'Flavored Drinks', 'Flavorings', 'Decorations', 'Group Symbols' ], [ 'Monumental Art', 'Holo Sculpture', 'Collectible Books', 'Jewelry', 'Museum Items', 'Monumental Art' ], [ 'Coinage', 'Currency', 'Money Cards', 'Gold', 'Silver', 'Platinum' ], [ 'Regulations', 'Synchronzations', 'Expert Systems', 'Educationals', 'Mandates', 'Accountings' ]] } self.source_world = Planet() self.market_world = None self.actual_value_rolls = (None, None) self.broker_skill = None self.broker_dm = None self.commission = 0 self.net_actual_value = 0 seed() def generate_cargo(self, source_uwp, market_uwp=None, broker_skill=0): '''Generate cargo''' try: self.source_world._load_uwp(source_uwp) # noqa except (ValueError, TypeError): raise ValueError('Invalid source UWP {}'.format(source_uwp)) try: assert int(broker_skill) >= 0 self.broker_skill = int(broker_skill) except TypeError: raise ValueError('Invalid broker_skill {}'.format(broker_skill)) self.source_world.mainworld_type = None self.source_world.determine_trade_codes() self.source_world.trade_codes = self.purge_ce_trade_codes( self.source_world.trade_codes) self.description = self.select_cargo_name() self.determine_cost(self.source_world.trade_codes) self.add_detail(self.source_world.trade_codes) if market_uwp is not None: self.market_world = Planet() try: self.market_world._load_uwp(market_uwp) # noqa except ValueError: raise ValueError('Invalid market UWP {}'.format(market_uwp)) self.market_world.mainworld_type = None self.market_world.determine_trade_codes() self.market_world.trade_codes = self.purge_ce_trade_codes( self.market_world.trade_codes) self.determine_price() def select_cargo_name(self, add_detail_flag=True): '''Select cargo based on [trade_codes]''' # Pick trade code at random LOGGER.debug('Supplied trade codes = %s', self.source_world.trade_codes) if self.source_world.trade_codes == []: LOGGER.debug('No trade codes supplied, using Na') trade_code = 'Na' else: LOGGER.debug('randint = %s', randint(0, len(self.source_world.trade_codes) - 1)) trade_code = self.source_world.trade_codes[randint( 0, len(self.source_world.trade_codes) - 1)] LOGGER.debug('Selected trade code %s', trade_code) # Ag => pick either Ga or Fa at random if trade_code == 'Ag': LOGGER.debug('Trade code is Ag, select either Ga or Fa') trade_code = ('Fa' if randint(0, 1) else 'Ga') LOGGER.debug('Trade code is %s', trade_code) # Validate trade code -- use Na if it's not in the list if trade_code not in self._codes: LOGGER.debug('%s not in supported trade codes, using Na instead', trade_code) trade_code = 'Na' # Pick cargo at random LOGGER.debug('Picking cargo description for %s', trade_code) cargo = self._codes[trade_code][randint(0, 5)][randint(0, 5)] LOGGER.debug('Selected %s', cargo) # Deal with imbalance results (_Xx) if cargo.startswith('_'): LOGGER.debug('Imbalance cargo %s', cargo) add_detail_flag = False code = cargo.replace('_', '') LOGGER.debug('Rerunning with imbalance') cargo = self.select_cargo_name([code]) # Classification-specific prefix prefix = None if add_detail_flag: prefix = self.add_detail([trade_code]) if prefix: cargo = '{} {}'.format(prefix, cargo) return cargo @staticmethod def add_detail(trade_codes): '''Add detail prefix based on trade code''' LOGGER.debug('Supplied trade_codes = %s', trade_codes) prefixes = { 'As': 'Strange', 'Ba': 'Gathered', 'De': 'Mineral', 'Di': 'Artifact', 'Fl': 'Unusual', 'Ga': 'Premium', 'He': 'Strange', 'Hi': 'Processed', 'Ic': 'Cryo', 'Ni': 'Unprocessed', 'Po': 'Obscure', 'Ri': 'Quality', 'Va': 'Exotic', 'Wa': 'Infused' } descriptions = [] for code in trade_codes: LOGGER.debug('Processing code %s', code) if code in prefixes: LOGGER.debug('Found description %s for code %s', prefixes[code], code) descriptions.append(prefixes[code]) LOGGER.debug('Available descriptions = %s', descriptions) # Weed out In/Processed if 'Processed' in descriptions and 'In' in trade_codes: descriptions.remove('Processed') # Weed out As/Exotic if 'Exotic' in descriptions and 'As' in trade_codes: descriptions.remove('Exotic') # Pick one if descriptions: resp = descriptions[randint(0, len(descriptions) - 1)] else: resp = None return resp def determine_cost(self, trade_codes): ''' Process trade codes - add valid TCs to self.trade_codes''' cost_mods = { 'Ag': -1000, 'As': -1000, 'Ba': +1000, 'De': +1000, 'Fl': +1000, 'Hi': -1000, 'Ic': 0, 'In': -1000, 'Lo': +1000, 'Na': 0, 'Ni': +1000, 'Po': -1000, 'Ri': +1000, 'Va': +1000 } self.cost = 3000 self.cost += 100 * int(self.source_world.tech_level) LOGGER.debug('Cost = %s', self.cost) if trade_codes == []: trade_codes = ['Na'] valid_trade_codes = [] for trade_code in trade_codes: if trade_code in cost_mods.keys(): LOGGER.debug('Adding trade code %s', trade_code) valid_trade_codes.append(trade_code) else: LOGGER.debug('Ignoring trade code %s', trade_code) self.interesting_trade_codes = sorted(list(set(valid_trade_codes))) # Add cost modifiers for trade_code in self.interesting_trade_codes: LOGGER.debug('Processing trade code %s (cost mod = Cr %s)', trade_code, cost_mods[trade_code]) self.cost += cost_mods[trade_code] def determine_price(self): '''Determine price based on source TCs, market TCs''' market_mods = { 'Ag': (['Ag', 'As', 'De', 'Hi', 'In', 'Ri', 'Va'], 1000), 'As': (['As', 'In', 'Ri', 'Va'], 1000), 'Ba': (['In'], 1000), 'De': (['De'], 1000), 'Fl': (['Fl' 'In'], 1000), 'Hi': (['Hi'], 1000), 'In': (['Ag', 'As', 'De', 'Fl', 'Hi', 'In', 'Ri', 'Va'], 1000), 'Na': (['As', 'De', 'Va'], 1000), 'Po': (['Ag', 'Hi', 'In', 'Ri'], -1000), 'Ri': (['Ag', 'De', 'Hi', 'In', 'Ri'], 1000), 'Va': (['As', 'In', 'Va'], 1000) } self.price = 5000 # Market trade codes for trade_code in self.source_world.trade_codes: if trade_code in market_mods.keys(): for code in market_mods[trade_code][0]: LOGGER.debug('Checking source TC %s market TC %s', trade_code, code) if code in self.market_world.trade_codes: LOGGER.debug('Found match: adjustment = %s', market_mods[trade_code][1]) self.price += market_mods[trade_code][1] LOGGER.debug('Price = Cr%s', self.price) # TL effect tl_mod = 0.1 * (int(self.source_world.tech_level) - int(self.market_world.tech_level)) LOGGER.debug('Price TL modifier = %s%%', int(100 * tl_mod)) LOGGER.debug('Price TL change = %s', int(-self.price * tl_mod)) self.price = int(self.price * (1 + tl_mod)) if self.price < 0: LOGGER.debug('Price (Cr%s) < Cr0, resetting to Cr0', self.price) self.price = 0 LOGGER.debug('Price = %s', self.price) self.actual_value = int(self.price * self.determine_actual_value()) LOGGER.debug('actual value = %s', self.actual_value) self.commission = int(0.05 * self.broker_dm * self.price) LOGGER.debug('commission = %s', self.commission) self.net_actual_value = self.actual_value - self.commission def determine_actual_value(self, modifier=0): '''Determine actual value using flux roll''' broker_dm = int((self.broker_skill + 0.5) / 2) broker_dm = min(4, broker_dm) self.broker_dm = broker_dm flux = FLUX.roll() + modifier + self.broker_dm self.actual_value_rolls = (FLUX.die1, FLUX.die2) flux = max(-5, flux) flux = min(8, flux) if flux <= -4: actual_value_multiplier = float(9 + flux) / 10.0 elif flux <= 3 and flux > -4: actual_value_multiplier = float(10 + flux) / 10.0 elif flux <= 5 and flux > 3: actual_value_multiplier = float(7 + 2 * flux) / 10.0 elif flux > 5: actual_value_multiplier = float(flux - 4) / 10.0 LOGGER.debug('flux result = %s flux rolls = +%s -%s ', flux, self.actual_value_rolls[0], self.actual_value_rolls[1]) LOGGER.debug('modifier = %s actual_value_multiplier = %s', modifier, actual_value_multiplier) return actual_value_multiplier def __str__(self): source = '{}-{} Cr{:,} {}'.format( self.source_world.tech_level, ' '.join(self.interesting_trade_codes), self.cost, self.description) return source def json(self): '''JSON representation''' if self.market_world is not None: market_world_trade_codes = self.market_world.trade_codes market_world_uwp = self.market_world.uwp() else: market_world_trade_codes = [] market_world_uwp = None doc = { "cargo": str(self), "cost": self.cost, "description": self.description, "market": { "trade_codes": market_world_trade_codes, "uwp": market_world_uwp, "net_actual_value": self.net_actual_value, "gross_actual_value": self.actual_value, "broker_commission": self.commission }, "price": self.price, "source": { "trade_codes": self.source_world.trade_codes, "uwp": self.source_world.uwp() }, "tech_level": int(self.source_world.tech_level), "notes": { "actual_value_rolls": self.actual_value_rolls, "broker_skill": self.broker_skill } } return json.dumps(doc) @staticmethod def purge_ce_trade_codes(trade_codes): '''Purge CE trade codes''' try: assert isinstance(trade_codes, list) except AssertionError: raise ValueError('trade_codes must be type list') for indx, code in enumerate(trade_codes): if code in ['Ht', 'Lt']: del trade_codes[indx] return trade_codes