diff --git a/src/commander.py b/src/commander.py index c37de79..14a2380 100644 --- a/src/commander.py +++ b/src/commander.py @@ -8,69 +8,8 @@ import random -from .constants import INSURANCE_RATE, INTEREST_RATE, MAXSKILL, MERCENARYNAMES, Skills - - -class CriminalRecord: - PSYCHOPATH = 0 - VILLAIN = 1 - CRIMINAL = 2 - CROOK = 3 - DUBIOUS = 4 - CLEAN = 5 - LAWFUL = 6 - TRUSTED = 7 - LIKED = 8 - HERO = 9 - ERRNO = 10 - - NAMES = { - PSYCHOPATH: "Psychopath", - VILLAIN: "Villain", - CRIMINAL: "Criminal", - CROOK: "Crook", - DUBIOUS: "Dubious", - CLEAN: "Clean", - LAWFUL: "Lawful", - TRUSTED: "Trusted", - LIKED: "Liked", - HERO: "Hero", - ERRNO: "ERRNO", - } - - @staticmethod - def get_record_string(record: int) -> str: - return CriminalRecord.NAMES[record] - - -class CombatReputation: - HARMLESS = 0 - MOSTLY_HARMLESS = 1 - POOR = 2 - AVERAGE = 3 - ABOVE_AVERAGE = 4 - COMPETENT = 5 - DANGEROUS = 6 - DEADLY = 7 - ELITE = 8 - BORG = 9 - - NAMES = { - HARMLESS: "Harmless", - MOSTLY_HARMLESS: "Mostly Harmless", - POOR: "Poor", - AVERAGE: "Average", - ABOVE_AVERAGE: "Above Average", - COMPETENT: "Competent", - DANGEROUS: "Dangerous", - DEADLY: "Deadly", - ELITE: "Elite", - BORG: "Borg", - } - - @staticmethod - def get_reputation_string(reputation: int) -> str: - return CombatReputation.NAMES[reputation] +from .constants import INSURANCE_RATE, INTEREST_RATE, MAXSKILL, MERCENARYNAMES, CombatReputation, CriminalRecord, Skills +from .economy import SHIPS, Ship class Commander: @@ -83,7 +22,7 @@ def __init__(self, name, pilot_skill, fighter_skill, trader_skill, engineer_skil self.engineerSkill = engineer_skill self.credits = 1000 self.debt = 0 - self.ship = 1 + self.ship = SHIPS[Ship.GNAT] self.kills = 0 self.reputation = 0 self.policeRecord = 0 @@ -98,7 +37,7 @@ def pprint(self) -> str: Skills: {self.pilotSkill}/{self.fighterSkill}/{self.traderSkill}/{self.engineerSkill}\n \ Credits: {self.credits}\n \ Debt: {self.debt}\n \ - Ship: {self.ship}\n \ + Ship: {self.ship.name}\n \ Kills: {self.kills}\n \ Reputation: {self.reputation}\n \ Police Record: {self.policeRecord}\n \ diff --git a/src/constants.py b/src/constants.py index f24a7e8..ca9e5df 100644 --- a/src/constants.py +++ b/src/constants.py @@ -269,27 +269,93 @@ def name(cls, difficulty: int) -> str: return cls.NAMES[difficulty] -# Gamestate codes -class GameStateID: - SPLASH = 0 - CHAR_CREATE = 1 - SYSTEM_INFO = 2 - B_CARGO = 3 - S_CARGO = 4 - Y_SHIPYARD = 5 - W_SHORTRANGE = 6 - BUY_SHIP = 7 - BUY_EQUIPMENT = 8 - SELL_EQUIPMENT = 9 - PERSONNEL = 10 - BANK = 11 - STATUS = 12 - QUESTS = 13 - SHIP_INFO = 14 - SPECIAL_CARGO = 15 - GALACTIC_CHART = 16 - TARGET_SYSTEM = 17 - AVG_PRICES = 18 +class CriminalRecord: + PSYCHOPATH = 0 + VILLAIN = 1 + CRIMINAL = 2 + CROOK = 3 + DUBIOUS = 4 + CLEAN = 5 + LAWFUL = 6 + TRUSTED = 7 + LIKED = 8 + HERO = 9 + ERRNO = 10 + + NAMES = { + PSYCHOPATH: "Psychopath", + VILLAIN: "Villain", + CRIMINAL: "Criminal", + CROOK: "Crook", + DUBIOUS: "Dubious", + CLEAN: "Clean", + LAWFUL: "Lawful", + TRUSTED: "Trusted", + LIKED: "Liked", + HERO: "Hero", + ERRNO: "ERRNO", + } + + SCORES = { + PSYCHOPATH: -100, + VILLAIN: -70, + CRIMINAL: -30, + CROOK: -10, + DUBIOUS: -5, + CLEAN: 0, + LAWFUL: 5, + TRUSTED: 10, + LIKED: 25, + HERO: 75, + ERRNO: 100, + } + + @staticmethod + def get_record_string(record: int) -> str: + return CriminalRecord.NAMES[record] + + +class CombatReputation: + HARMLESS = 0 + MOSTLY_HARMLESS = 1 + POOR = 2 + AVERAGE = 3 + ABOVE_AVERAGE = 4 + COMPETENT = 5 + DANGEROUS = 6 + DEADLY = 7 + ELITE = 8 + BORG = 9 + + NAMES = { + HARMLESS: "Harmless", + MOSTLY_HARMLESS: "Mostly Harmless", + POOR: "Poor", + AVERAGE: "Average", + ABOVE_AVERAGE: "Above Average", + COMPETENT: "Competent", + DANGEROUS: "Dangerous", + DEADLY: "Deadly", + ELITE: "Elite", + BORG: "Borg", + } + + SCORES = { + HARMLESS: 0, + MOSTLY_HARMLESS: 10, + POOR: 20, + AVERAGE: 40, + ABOVE_AVERAGE: 80, + COMPETENT: 150, + DANGEROUS: 300, + DEADLY: 600, + ELITE: 1500, + BORG: 3000, + } + + @staticmethod + def get_reputation_string(reputation: int) -> str: + return CombatReputation.NAMES[reputation] # TODO Unknown values/usage diff --git a/src/economy.py b/src/economy.py index 48fe046..707f9fc 100644 --- a/src/economy.py +++ b/src/economy.py @@ -6,8 +6,86 @@ This module contains the classes and functions for the game economy such as trade wares and prices. """ +from .constants import Activity, Size, Skills, TechLevel + + +class PoliticalSystem: + ANARCHY = 0 + CAPITALIST = 1 + COMMUNIST = 2 + CONFEDERACY = 3 + CORPORATE = 4 + CYBERNETIC = 5 + DEMOCRACY = 6 + DICTATORSHIP = 7 + FASCIST = 8 + FEUDAL = 9 + MILITARY = 10 + MONARCHY = 11 + PACIFIST = 12 + SOCIALIST = 13 + SATORI = 14 + TECHNOCRACY = 15 + THEOCRACY = 16 + + def __init__( + self, + name: str, + stability: int, + law: int, + crime: int, + economy: int, + minTech: int, + maxTech: int, + bribe_difficulty: int, + drug_tolerance: bool, + firearm_tolerance: bool, + tradeItemId: int, + ): + self.name = name + self.stability = stability + self.law = law + self.crime = crime + self.economy = economy + self.minTech = minTech + self.maxTech = maxTech + self.bribe_difficulty = bribe_difficulty + self.drug_tolerance = drug_tolerance + self.firearm_tolerance = firearm_tolerance + self.tradeItemId = tradeItemId + + def __str__(self): + return self.name + + def __repr__(self): + return f"{self.name} ({self.stability}, {self.law}, {self.crime}, {self.economy})" + + def firearms_ok(self) -> bool: + return self.firearm_tolerance + + def drugs_ok(self) -> bool: + return self.drug_tolerance + + +class Ware: + """ + Class containing the trade wares and their respective attributes. + + params: name - Trade item name + params: tech_level_prod - Tech level needed for production + params: tech_level_min - Tech level needed to use + params: tech_level_max - Tech level which produces this item the most + params: max_price - Medium price at lowest tech level + params: min_price - Price increase per tech level + params: pressure_price - Max percentage above or below calculated price + params: pressure - Price increases considerably when this event occurs + params: special_resource_drop - When this resource is available, this trade item is cheap + params: special_resource_hike - When this resource is available, this trade item is expensive + params: min_prod - Minimum price to buy/sell in orbit + params: max_prod - Maximum price to buy/sell in orbit + params: quantity - Roundoff price for trade in orbit + """ -class TradeItemId: WATER = 0 FURS = 1 FOOD = 2 @@ -39,26 +117,6 @@ def lst() -> list[str]: "Robots", ] - -class Ware: - """ - Class containing the trade wares and their respective attributes. - - params: name - Trade item name - params: tech_level_prod - Tech level needed for production - params: tech_level_min - Tech level needed to use - params: tech_level_max - Tech level which produces this item the most - params: max_price - Medium price at lowest tech level - params: min_price - Price increase per tech level - params: pressure_price - Max percentage above or below calculated price - params: pressure - Price increases considerably when this event occurs - params: special_resource_drop - When this resource is available, this trade item is cheap - params: special_resource_hike - When this resource is available, this trade item is expensive - params: min_prod - Minimum price to buy/sell in orbit - params: max_prod - Maximum price to buy/sell in orbit - params: quantity - Roundoff price for trade in orbit - """ - # TODO min and max price descriptions need to be checked against code # TODO min_prod and max_prod descriptions need to be checked against code, seem duplicated def __init__( @@ -96,3 +154,492 @@ def __str__(self): def __repr__(self): return self.name + + +class Equipment: + WEAPON = 0 + SHIELD = 1 + GADGET = 2 + + def __init__(self, id, price, tech_level): + self.id = id + self.price = price + self.tech_level = tech_level + + @staticmethod + def sale_list() -> list[str]: + return [ + "Pulse laser", + "Beam laser", + "Military laser", + "Energy shield", + "Reflective shield", + "5 extra cargo bays", + "Auto-repair system", + "Navigation system", + "Targeting system", + "Cloaking device", + ] + + +class Weapon(Equipment): + + PULSELASER = 0 + BEAMLASER = 1 + MILITARYLASER = 2 + MORGANSLASER = 3 + PHOTONDISRUPTOR = 4 + QUANTUMDISRUPTOR = 5 + + def __init__(self, id, damage, unk_bool, price, tech_level, unknown): + super().__init__(id, price, tech_level) + self.damage = damage + self.unk_bool = unk_bool + self.unknown = unknown + + +class Shield(Equipment): + ENERGY = 0 + REFLECTIVE = 1 + LIGHTNING = 2 + + # TODO what are points and unknown? + def __init__(self, id, points, price, tech_level, unknown): + super().__init__(id, price, tech_level) + self.points = points + self.unknown = unknown + + +class Gadget(Equipment): + CARGOBAYS = 0 + AUTOREPAIR = 1 + NAVIGATION = 2 + TARGETING = 3 + CLOAKING = 4 + FUELCOMPACTOR = 5 + SMUGGLERHOLD = 6 + + def __init__(self, id, skill, price, tech_level, unknown): + super().__init__(id, price, tech_level) + self.skill = skill + self.unknown = unknown + + +class Ship: + + # ESCAPEPOD = 0 #? Not in source + FLEA = 0 + GNAT = 1 + FIREFLY = 2 + MOSQUITO = 3 + BUMBLEBEE = 4 + BEETLE = 5 + HORNET = 6 + GRASSHOPPER = 7 + TERMITE = 8 + WASP = 9 + SPACEMONSTER = 10 + DRAGONFLY = 11 + MANTIS = 12 + SCARAB = 13 + BOTTLE = 14 + CUSTOM = 15 + SCORPION = 16 + + @staticmethod + def enum() -> list[int]: + return range(17) + + @staticmethod + def lst() -> list[str]: + return [ + "Flea", + "Gnat", + "Firefly", + "Mosquito", + "Bumblebee", + "Beetle", + "Hornet", + "Grasshopper", + "Termite", + "Wasp", + "Space Monster", + "Dragonfly", + "Mantis", + "Scarab", + "Bottle", + "Custom", + "Scorpion", + ] + + @staticmethod + def sale_lst() -> list[str]: + return [ + "Flea", + "Gnat", + "Firefly", + "Mosquito", + "Bumblebee", + "Beetle", + "Hornet", + "Grasshopper", + "Termite", + "Wasp", + ] + + def __init__( + self, + name: str, + size: int, + cargo: int, + weapon_slots: int, + shield_slots: int, + gadget_slots: int, + crew: int, + fuel: int, + fuel_cost: int, + hull: int, + repair_cost: int, + price: int, + unknown_percent: int, + police_use: int, + pirate_use: int, + trader_use: int, + tech_level: int, + ): + self.name = name + self.size = size + self.cargo = cargo + self.weapon_slots = weapon_slots + self.shield_slots = shield_slots + self.gadget_slots = gadget_slots + self.crew = crew + self.fuel = fuel + self.fuel_cost = fuel_cost + self.hull = hull + self.repair_cost = repair_cost + self.price = price + self.unknown_percent = unknown_percent + self.police_use = police_use + self.pirate_use = pirate_use + self.trader_use = trader_use + self.tech_level = tech_level + + def get_value(self) -> int: + return self.price + + +SHIPS = { + Ship.FLEA: Ship( + "Flea", + Size.TINY, + 10, + 0, + 0, + 0, + 1, + 20, + 1, + 25, + 1, + 2000, + 2, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + Activity.ABSENT, + TechLevel.EARLY_INDUSTRIAL, + ), + Ship.GNAT: Ship( + "Gnat", + Size.SMALL, + 15, + 1, + 0, + 1, + 1, + 14, + 1, + 100, + 2, + 10000, + 28, + Activity.ABSENT, + Activity.ABSENT, + Activity.ABSENT, + TechLevel.INDUSTRIAL, + ), + Ship.FIREFLY: Ship( + "Firefly", + Size.SMALL, + 20, + 1, + 1, + 1, + 1, + 17, + 1, + 100, + 3, + 25000, + 20, + Activity.ABSENT, + Activity.ABSENT, + Activity.ABSENT, + TechLevel.INDUSTRIAL, + ), + Ship.MOSQUITO: Ship( + "Mosquito", + Size.SMALL, + 15, + 2, + 1, + 1, + 1, + 13, + 1, + 100, + 5, + 30000, + 20, + Activity.ABSENT, + Activity.MINIMAL, + Activity.ABSENT, + TechLevel.INDUSTRIAL, + ), + Ship.BUMBLEBEE: Ship( + "Bumblebee", + Size.MEDIUM, + 25, + 1, + 2, + 2, + 2, + 15, + 1, + 100, + 7, + 60000, + 15, + Activity.MINIMAL, + Activity.MINIMAL, + Activity.ABSENT, + TechLevel.INDUSTRIAL, + ), + Ship.BEETLE: Ship( + "Beetle", + Size.MEDIUM, + 50, + 0, + 1, + 1, + 3, + 14, + 1, + 50, + 10, + 80000, + 3, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + Activity.ABSENT, + TechLevel.INDUSTRIAL, + ), + Ship.HORNET: Ship( + "Hornet", + Size.LARGE, + 20, + 3, + 2, + 1, + 2, + 16, + 2, + 150, + 15, + 100000, + 6, + Activity.FEW, + Activity.SOME, + Activity.MINIMAL, + TechLevel.POST_INDUSTRIAL, + ), + Ship.GRASSHOPPER: Ship( + "Grasshopper", + Size.LARGE, + 30, + 2, + 2, + 3, + 3, + 15, + 3, + 150, + 15, + 150000, + 2, + Activity.SOME, + Activity.MODERATE, + Activity.FEW, + TechLevel.POST_INDUSTRIAL, + ), + Ship.TERMITE: Ship( + "Termite", + Size.HUGE, + 60, + 1, + 3, + 2, + 3, + 13, + 4, + 200, + 20, + 225000, + 2, + Activity.MODERATE, + Activity.MANY, + Activity.SOME, + TechLevel.HI_TECH, + ), + Ship.WASP: Ship( + "Wasp", + Size.HUGE, + 35, + 3, + 2, + 2, + 3, + 14, + 5, + 200, + 20, + 300000, + 2, + Activity.MANY, + Activity.ABUNDANT, + Activity.MODERATE, + TechLevel.HI_TECH, + ), + # The ships below can't be bought (mostly) + Ship.SPACEMONSTER: Ship( + "Space Monster", + Size.HUGE, + 0, + 3, + 0, + 0, + 1, + 1, + 1, + 500, + 1, + 500000, + 0, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + TechLevel.UNAVAILABLE, + ), + Ship.DRAGONFLY: Ship( + "Dragonfly", + Size.SMALL, + 0, + 2, + 3, + 2, + 1, + 1, + 1, + 10, + 1, + 500000, + 0, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + TechLevel.UNAVAILABLE, + ), + Ship.MANTIS: Ship( + "Mantis", + Size.MEDIUM, + 0, + 3, + 1, + 3, + 3, + 1, + 1, + 300, + 1, + 500000, + 0, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + TechLevel.UNAVAILABLE, + ), + Ship.SCARAB: Ship( + "Scarab", + Size.LARGE, + 20, + 2, + 0, + 0, + 2, + 1, + 1, + 400, + 1, + 500000, + 0, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + TechLevel.UNAVAILABLE, + ), + Ship.SCORPION: Ship( + "Scorpion", + Size.HUGE, + 30, + 2, + 2, + 2, + 2, + 1, + 1, + 300, + 1, + 500000, + 0, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + Activity.UNAVAILABLE, + TechLevel.UNAVAILABLE, + ), +} + +WEAPONS = { + Weapon.PULSELASER: Weapon(Weapon.PULSELASER, 15, False, 2000, TechLevel.INDUSTRIAL, 50), + Weapon.BEAMLASER: Weapon(Weapon.BEAMLASER, 25, False, 12500, TechLevel.POST_INDUSTRIAL, 35), + Weapon.MILITARYLASER: Weapon(Weapon.MILITARYLASER, 35, False, 35000, TechLevel.HI_TECH, 15), + Weapon.MORGANSLASER: Weapon(Weapon.MORGANSLASER, 85, False, 50000, TechLevel.UNAVAILABLE, 0), + Weapon.PHOTONDISRUPTOR: Weapon(Weapon.PHOTONDISRUPTOR, 20, True, 15000, TechLevel.UNAVAILABLE, 0), + Weapon.QUANTUMDISRUPTOR: Weapon(Weapon.QUANTUMDISRUPTOR, 60, True, 50000, TechLevel.UNAVAILABLE, 0), +} + +SHIELDS = { + Shield.ENERGY: Shield(Shield.ENERGY, 100, 5000, TechLevel.INDUSTRIAL, 70), + Shield.REFLECTIVE: Shield(Shield.REFLECTIVE, 200, 20000, TechLevel.POST_INDUSTRIAL, 30), + Shield.LIGHTNING: Shield(Shield.LIGHTNING, 350, 45000, TechLevel.UNAVAILABLE, 0), +} + +GADGETS = { + Gadget.CARGOBAYS: Gadget(Gadget.CARGOBAYS, Skills.NONE, 2500, TechLevel.EARLY_INDUSTRIAL, 35), + Gadget.AUTOREPAIR: Gadget(Gadget.AUTOREPAIR, Skills.ENGINEER, 7500, TechLevel.INDUSTRIAL, 20), + Gadget.NAVIGATION: Gadget(Gadget.NAVIGATION, Skills.PILOT, 15000, TechLevel.POST_INDUSTRIAL, 20), + Gadget.TARGETING: Gadget(Gadget.TARGETING, Skills.FIGHTER, 2500, TechLevel.POST_INDUSTRIAL, 20), + Gadget.CLOAKING: Gadget(Gadget.CLOAKING, Skills.PILOT, 100000, TechLevel.HI_TECH, 5), + # Gadgets below can't be bought + Gadget.FUELCOMPACTOR: Gadget(Gadget.FUELCOMPACTOR, Skills.NONE, 30000, TechLevel.UNAVAILABLE, 0), + Gadget.SMUGGLERHOLD: Gadget(Gadget.SMUGGLERHOLD, Skills.NONE, 60000, TechLevel.UNAVAILABLE, 0), +} diff --git a/src/game_data.py b/src/game_data.py deleted file mode 100644 index 7321fa5..0000000 --- a/src/game_data.py +++ /dev/null @@ -1,877 +0,0 @@ -""" - Space Trader (PalmOS) | RPINerd, 2024 - - Game data is stored in this module. - Each dictionary in this module contains the possible values for a specific game element such - as government attributes, ship stats, or trade item tech level limits. This was done in an - effort to declutter the class definition files as much as possible to improve readability. -""" - -from .commander import CombatReputation, CriminalRecord -from .constants import Activity, Size, Skills, SocietalPressure, SpecialResource, TechLevel -from .economy import TradeItemId, Ware -from .government import GovernmentId, PoliticalSystem -from .ships import Gadget, GadgetID, SheildID, Shield, Ship, ShipID, Weapon, WeaponID - -PLANET_NAMES = { - 0: "Acamar", - 1: "Adahn", - 2: "Aldea", - 3: "Andevian", - 4: "Antedi", - 5: "Balosnee", - 6: "Baratas", - 7: "Bob", - 8: "Brax", - 9: "Bretel", - 10: "Calondia", - 11: "Campor", - 12: "Capelle", - 13: "Carzon", - 14: "Castor", - 15: "Cestus", - 16: "Cheron", - 17: "Courteney", - 18: "Daled", - 19: "Damast", - 20: "Davlos", - 21: "Deneb", - 22: "Deneva", - 23: "Devidia", - 24: "Draylon", - 25: "Drema", - 26: "Endor", - 27: "Esmee", - 28: "Exo", - 29: "Ferris", - 30: "Festen", - 31: "Fourmi", - 32: "Frolix", - 33: "Gemulon", - 34: "Guinifer", - 35: "Hades", - 36: "Hamlet", - 37: "Helena", - 38: "Hulst", - 39: "Iodine", - 40: "Iralius", - 41: "Janus", - 42: "Japori", - 43: "Jarada", - 44: "Jason", - 45: "Kaylon", - 46: "Khefka", - 47: "Kira", - 48: "Klaatu", - 49: "Klaestron", - 50: "Korma", - 51: "Kravat", - 52: "Krios", - 53: "Laertes", - 54: "Largo", - 55: "Lave", - 56: "Ligon", - 57: "Lowry", - 58: "Magrat", - 59: "Malcoria", - 60: "Melina", - 61: "Mentar", - 62: "Merik", - 63: "Mintaka", - 64: "Montor", - 65: "Mordan", - 66: "Myrthe", - 67: "Nelvana", - 68: "Nix", - 69: "Nyle", - 70: "Odet", - 71: "Og", - 72: "Omega", - 73: "Omphalos", - 74: "Orias", - 75: "Othello", - 76: "Parade", - 77: "Penthara", - 78: "Picard", - 79: "Pollux", - 80: "Quator", - 81: "Rakhar", - 82: "Ran", - 83: "Regulas", - 84: "Relva", - 85: "Rhymus", - 86: "Rochani", - 87: "Rubicum", - 88: "Rutia", - 89: "Sarpeidon", - 90: "Sefalla", - 91: "Seltrice", - 92: "Sigma", - 93: "Sol", - 94: "Somari", - 95: "Stakoron", - 96: "Styris", - 97: "Talani", - 98: "Tamus", - 99: "Tantalos", - 100: "Tanuga", - 101: "Tarchannen", - 102: "Terosa", - 103: "Thera", - 104: "Titan", - 105: "Torin", - 106: "Triacus", - 107: "Turkana", - 108: "Tyrus", - 109: "Umberlee", - 110: "Utopia", - 111: "Vadera", - 112: "Vagra", - 113: "Vandor", - 114: "Ventax", - 115: "Xenon", - 116: "Xerxes", - 117: "Yew", - 118: "Yojimbo", - 119: "Zalkon", - 120: "Zuul", -} - -GOVERNMENTS = { - GovernmentId.ANARCHY: PoliticalSystem( - "Anarchy", - 0, - Activity.ABSENT, - Activity.SWARMS, - Activity.MINIMAL, - TechLevel.PRE_AGRICULTURAL, - TechLevel.INDUSTRIAL, - 7, - True, - True, - TradeItemId.FOOD, - ), - GovernmentId.CAPITALIST: PoliticalSystem( - "Capitalist", - 2, - Activity.SOME, - Activity.FEW, - Activity.SWARMS, - TechLevel.EARLY_INDUSTRIAL, - TechLevel.HI_TECH, - 1, - True, - True, - TradeItemId.ORE, - ), - GovernmentId.COMMUNIST: PoliticalSystem( - "Communist", - 6, - Activity.ABUNDANT, - Activity.MODERATE, - Activity.MODERATE, - TechLevel.AGRICULTURAL, - TechLevel.INDUSTRIAL, - 5, - True, - True, - TradeItemId.NONE, - ), - GovernmentId.CONFEDERACY: PoliticalSystem( - "Confederacy", - 5, - Activity.MODERATE, - Activity.SOME, - Activity.MANY, - TechLevel.AGRICULTURAL, - TechLevel.POST_INDUSTRIAL, - 3, - True, - True, - TradeItemId.GAMES, - ), - GovernmentId.CORPORATE: PoliticalSystem( - "Corporate", - 2, - Activity.ABUNDANT, - Activity.FEW, - Activity.SWARMS, - TechLevel.EARLY_INDUSTRIAL, - TechLevel.HI_TECH, - 2, - True, - True, - TradeItemId.ROBOTS, - ), - GovernmentId.CYBERNETIC: PoliticalSystem( - "Cybernetic", - 0, - Activity.SWARMS, - Activity.SWARMS, - Activity.MANY, - TechLevel.POST_INDUSTRIAL, - TechLevel.HI_TECH, - 0, - False, - False, - TradeItemId.ORE, - ), - GovernmentId.DEMOCRACY: PoliticalSystem( - "Democracy", - 4, - Activity.SOME, - Activity.FEW, - Activity.MANY, - TechLevel.RENAISSANCE, - TechLevel.HI_TECH, - 2, - True, - True, - TradeItemId.GAMES, - ), - GovernmentId.DICTATORSHIP: PoliticalSystem( - "Dictatorship", - 3, - Activity.MODERATE, - Activity.MANY, - Activity.SOME, - TechLevel.PRE_AGRICULTURAL, - TechLevel.HI_TECH, - 2, - True, - True, - TradeItemId.NONE, - ), - GovernmentId.FASCIST: PoliticalSystem( - "Fascist", - 7, - Activity.SWARMS, - Activity.SWARMS, - Activity.MINIMAL, - TechLevel.EARLY_INDUSTRIAL, - TechLevel.HI_TECH, - 0, - False, - True, - TradeItemId.MACHINERY, - ), - GovernmentId.FEUDAL: PoliticalSystem( - "Feudal", - 1, - Activity.MINIMAL, - Activity.ABUNDANT, - Activity.FEW, - TechLevel.PRE_AGRICULTURAL, - TechLevel.RENAISSANCE, - 6, - True, - True, - TradeItemId.FIREARMS, - ), - GovernmentId.MILITARY: PoliticalSystem( - "Military", - 7, - Activity.SWARMS, - Activity.ABSENT, - Activity.ABUNDANT, - TechLevel.MEDIEVAL, - TechLevel.HI_TECH, - 0, - False, - True, - TradeItemId.ROBOTS, - ), - GovernmentId.MONARCHY: PoliticalSystem( - "Monarchy", - 3, - Activity.MODERATE, - Activity.SOME, - Activity.MODERATE, - TechLevel.PRE_AGRICULTURAL, - TechLevel.INDUSTRIAL, - 4, - True, - True, - TradeItemId.MEDICINE, - ), - GovernmentId.PACIFIST: PoliticalSystem( - "Pacifist", - 7, - Activity.FEW, - Activity.MINIMAL, - Activity.MANY, - TechLevel.PRE_AGRICULTURAL, - TechLevel.RENAISSANCE, - 1, - True, - False, - TradeItemId.NONE, - ), - GovernmentId.SOCIALIST: PoliticalSystem( - "Socialist", - 4, - Activity.FEW, - Activity.MANY, - Activity.SOME, - TechLevel.PRE_AGRICULTURAL, - TechLevel.INDUSTRIAL, - 6, - True, - True, - TradeItemId.NONE, - ), - GovernmentId.SATORI: PoliticalSystem( - "Satori", - 0, - Activity.MINIMAL, - Activity.MINIMAL, - Activity.MINIMAL, - TechLevel.PRE_AGRICULTURAL, - TechLevel.AGRICULTURAL, - 0, - False, - False, - TradeItemId.NONE, - ), - GovernmentId.TECHNOCRACY: PoliticalSystem( - "Technocracy", - 1, - Activity.ABUNDANT, - Activity.SOME, - Activity.ABUNDANT, - TechLevel.EARLY_INDUSTRIAL, - TechLevel.HI_TECH, - 2, - True, - True, - TradeItemId.WATER, - ), - GovernmentId.THEOCRACY: PoliticalSystem( - "Theocracy", - 5, - Activity.ABUNDANT, - Activity.MINIMAL, - Activity.MODERATE, - TechLevel.PRE_AGRICULTURAL, - TechLevel.EARLY_INDUSTRIAL, - 0, - True, - True, - TradeItemId.NARCOTICS, - ), -} - -GOVT_NAMES = { - GovernmentId.ANARCHY: "Anarchy", - GovernmentId.CAPITALIST: "Capitalist", - GovernmentId.COMMUNIST: "Communist", - GovernmentId.CONFEDERACY: "Confederacy", - GovernmentId.CORPORATE: "Corporate", - GovernmentId.CYBERNETIC: "Cybernetic", - GovernmentId.DEMOCRACY: "Democracy", - GovernmentId.DICTATORSHIP: "Dictatorship", - GovernmentId.FASCIST: "Facist", - GovernmentId.FEUDAL: "Feudal", - GovernmentId.MILITARY: "Military", - GovernmentId.MONARCHY: "Monarchy", - GovernmentId.PACIFIST: "Pacifist", - GovernmentId.SOCIALIST: "Socialist", - GovernmentId.SATORI: "Satori", - GovernmentId.TECHNOCRACY: "Technocracy", - GovernmentId.THEOCRACY: "Theocracy", -} - -TRADEITEMS = { - TradeItemId.WATER: Ware( - "Water", - TechLevel.PRE_AGRICULTURAL, - TechLevel.PRE_AGRICULTURAL, - TechLevel.MEDIEVAL, - 30, - 3, - 4, - SocietalPressure.DROUGHT, - SpecialResource.SWEETOCEANS, - SpecialResource.DESERT, - 30, - 50, - 1, - ), - TradeItemId.FURS: Ware( - "Furs", - TechLevel.PRE_AGRICULTURAL, - TechLevel.PRE_AGRICULTURAL, - TechLevel.PRE_AGRICULTURAL, - 250, - 10, - 10, - SocietalPressure.COLD, - SpecialResource.RICHFAUNA, - SpecialResource.LIFELESS, - 230, - 280, - 5, - ), - TradeItemId.FOOD: Ware( - "Food", - TechLevel.AGRICULTURAL, - TechLevel.PRE_AGRICULTURAL, - TechLevel.AGRICULTURAL, - 100, - 5, - 5, - SocietalPressure.CROPFAILURE, - SpecialResource.RICHSOIL, - SpecialResource.POORSOIL, - 90, - 160, - 5, - ), - TradeItemId.ORE: Ware( - "Ore", - TechLevel.MEDIEVAL, - TechLevel.MEDIEVAL, - TechLevel.RENAISSANCE, - 350, - 20, - 10, - SocietalPressure.WAR, - SpecialResource.MINERAL_RICH, - SpecialResource.MINERAL_POOR, - 350, - 420, - 10, - ), - TradeItemId.GAMES: Ware( - "Games", - TechLevel.RENAISSANCE, - TechLevel.AGRICULTURAL, - TechLevel.POST_INDUSTRIAL, - 250, - -10, - 5, - SocietalPressure.BOREDOM, - SpecialResource.ARTISTIC, - SpecialResource.NOTHING, - 160, - 270, - 5, - ), - TradeItemId.FIREARMS: Ware( - "Firearms", - TechLevel.RENAISSANCE, - TechLevel.AGRICULTURAL, - TechLevel.INDUSTRIAL, - 1250, - -75, - 100, - SocietalPressure.WAR, - SpecialResource.WARLIKE, - SpecialResource.NOTHING, - 600, - 1100, - 25, - ), - TradeItemId.MEDICINE: Ware( - "Medicine", - TechLevel.EARLY_INDUSTRIAL, - TechLevel.AGRICULTURAL, - TechLevel.POST_INDUSTRIAL, - 650, - -20, - 10, - SocietalPressure.PLAGUE, - SpecialResource.SPECIALHERBS, - SpecialResource.NOTHING, - 400, - 700, - 25, - ), - TradeItemId.MACHINERY: Ware( - "Machinery", - TechLevel.EARLY_INDUSTRIAL, - TechLevel.RENAISSANCE, - TechLevel.INDUSTRIAL, - 900, - -30, - 5, - SocietalPressure.EMPLOYMENT, - SpecialResource.NOTHING, - SpecialResource.NOTHING, - 600, - 800, - 25, - ), - TradeItemId.NARCOTICS: Ware( - "Narrcotics", - TechLevel.INDUSTRIAL, - TechLevel.PRE_AGRICULTURAL, - TechLevel.INDUSTRIAL, - 3500, - -125, - 150, - SocietalPressure.BOREDOM, - SpecialResource.WEIRDMUSHROOMS, - SpecialResource.NOTHING, - 2000, - 3000, - 50, - ), - TradeItemId.ROBOTS: Ware( - "Robots", - TechLevel.POST_INDUSTRIAL, - TechLevel.EARLY_INDUSTRIAL, - TechLevel.HI_TECH, - 5000, - -150, - 100, - SocietalPressure.EMPLOYMENT, - SpecialResource.NOTHING, - SpecialResource.NOTHING, - 3500, - 5000, - 100, - ), -} - -SHIPS = { - ShipID.FLEA: Ship( - "Flea", - Size.TINY, - 10, - 0, - 0, - 0, - 1, - 20, - 1, - 25, - 1, - 2000, - 2, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - Activity.ABSENT, - TechLevel.EARLY_INDUSTRIAL, - ), - ShipID.GNAT: Ship( - "Gnat", - Size.SMALL, - 15, - 1, - 0, - 1, - 1, - 14, - 1, - 100, - 2, - 10000, - 28, - Activity.ABSENT, - Activity.ABSENT, - Activity.ABSENT, - TechLevel.INDUSTRIAL, - ), - ShipID.FIREFLY: Ship( - "Firefly", - Size.SMALL, - 20, - 1, - 1, - 1, - 1, - 17, - 1, - 100, - 3, - 25000, - 20, - Activity.ABSENT, - Activity.ABSENT, - Activity.ABSENT, - TechLevel.INDUSTRIAL, - ), - ShipID.MOSQUITO: Ship( - "Mosquito", - Size.SMALL, - 15, - 2, - 1, - 1, - 1, - 13, - 1, - 100, - 5, - 30000, - 20, - Activity.ABSENT, - Activity.MINIMAL, - Activity.ABSENT, - TechLevel.INDUSTRIAL, - ), - ShipID.BUMBLEBEE: Ship( - "Bumblebee", - Size.MEDIUM, - 25, - 1, - 2, - 2, - 2, - 15, - 1, - 100, - 7, - 60000, - 15, - Activity.MINIMAL, - Activity.MINIMAL, - Activity.ABSENT, - TechLevel.INDUSTRIAL, - ), - ShipID.BEETLE: Ship( - "Beetle", - Size.MEDIUM, - 50, - 0, - 1, - 1, - 3, - 14, - 1, - 50, - 10, - 80000, - 3, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - Activity.ABSENT, - TechLevel.INDUSTRIAL, - ), - ShipID.HORNET: Ship( - "Hornet", - Size.LARGE, - 20, - 3, - 2, - 1, - 2, - 16, - 2, - 150, - 15, - 100000, - 6, - Activity.FEW, - Activity.SOME, - Activity.MINIMAL, - TechLevel.POST_INDUSTRIAL, - ), - ShipID.GRASSHOPPER: Ship( - "Grasshopper", - Size.LARGE, - 30, - 2, - 2, - 3, - 3, - 15, - 3, - 150, - 15, - 150000, - 2, - Activity.SOME, - Activity.MODERATE, - Activity.FEW, - TechLevel.POST_INDUSTRIAL, - ), - ShipID.TERMITE: Ship( - "Termite", - Size.HUGE, - 60, - 1, - 3, - 2, - 3, - 13, - 4, - 200, - 20, - 225000, - 2, - Activity.MODERATE, - Activity.MANY, - Activity.SOME, - TechLevel.HI_TECH, - ), - ShipID.WASP: Ship( - "Wasp", - Size.HUGE, - 35, - 3, - 2, - 2, - 3, - 14, - 5, - 200, - 20, - 300000, - 2, - Activity.MANY, - Activity.ABUNDANT, - Activity.MODERATE, - TechLevel.HI_TECH, - ), - # The ships below can't be bought (mostly) - ShipID.SPACEMONSTER: Ship( - "Space Monster", - Size.HUGE, - 0, - 3, - 0, - 0, - 1, - 1, - 1, - 500, - 1, - 500000, - 0, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - TechLevel.UNAVAILABLE, - ), - ShipID.DRAGONFLY: Ship( - "Dragonfly", - Size.SMALL, - 0, - 2, - 3, - 2, - 1, - 1, - 1, - 10, - 1, - 500000, - 0, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - TechLevel.UNAVAILABLE, - ), - ShipID.MANTIS: Ship( - "Mantis", - Size.MEDIUM, - 0, - 3, - 1, - 3, - 3, - 1, - 1, - 300, - 1, - 500000, - 0, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - TechLevel.UNAVAILABLE, - ), - ShipID.SCARAB: Ship( - "Scarab", - Size.LARGE, - 20, - 2, - 0, - 0, - 2, - 1, - 1, - 400, - 1, - 500000, - 0, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - TechLevel.UNAVAILABLE, - ), - ShipID.SCORPION: Ship( - "Scorpion", - Size.HUGE, - 30, - 2, - 2, - 2, - 2, - 1, - 1, - 300, - 1, - 500000, - 0, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - Activity.UNAVAILABLE, - TechLevel.UNAVAILABLE, - ), -} - -WEAPONS = { - WeaponID.PULSELASER: Weapon(WeaponID.PULSELASER, 15, False, 2000, TechLevel.INDUSTRIAL, 50), - WeaponID.BEAMLASER: Weapon(WeaponID.BEAMLASER, 25, False, 12500, TechLevel.POST_INDUSTRIAL, 35), - WeaponID.MILITARYLASER: Weapon(WeaponID.MILITARYLASER, 35, False, 35000, TechLevel.HI_TECH, 15), - WeaponID.MORGANSLASER: Weapon(WeaponID.MORGANSLASER, 85, False, 50000, TechLevel.UNAVAILABLE, 0), - WeaponID.PHOTONDISRUPTOR: Weapon(WeaponID.PHOTONDISRUPTOR, 20, True, 15000, TechLevel.UNAVAILABLE, 0), - WeaponID.QUANTUMDISRUPTOR: Weapon(WeaponID.QUANTUMDISRUPTOR, 60, True, 50000, TechLevel.UNAVAILABLE, 0), -} - -SHIELDS = { - SheildID.ENERGY: Shield(SheildID.ENERGY, 100, 5000, TechLevel.INDUSTRIAL, 70), - SheildID.REFLECTIVE: Shield(SheildID.REFLECTIVE, 200, 20000, TechLevel.POST_INDUSTRIAL, 30), - SheildID.LIGHTNING: Shield(SheildID.LIGHTNING, 350, 45000, TechLevel.UNAVAILABLE, 0), -} - -GADGETS = { - GadgetID.CARGOBAYS: Gadget(GadgetID.CARGOBAYS, Skills.NONE, 2500, TechLevel.EARLY_INDUSTRIAL, 35), - GadgetID.AUTOREPAIR: Gadget(GadgetID.AUTOREPAIR, Skills.ENGINEER, 7500, TechLevel.INDUSTRIAL, 20), - GadgetID.NAVIGATION: Gadget(GadgetID.NAVIGATION, Skills.PILOT, 15000, TechLevel.POST_INDUSTRIAL, 20), - GadgetID.TARGETING: Gadget(GadgetID.TARGETING, Skills.FIGHTER, 2500, TechLevel.POST_INDUSTRIAL, 20), - GadgetID.CLOAKING: Gadget(GadgetID.CLOAKING, Skills.PILOT, 100000, TechLevel.HI_TECH, 5), - # Gadgets below can't be bought - GadgetID.FUELCOMPACTOR: Gadget(GadgetID.FUELCOMPACTOR, Skills.NONE, 30000, TechLevel.UNAVAILABLE, 0), - GadgetID.SMUGGLERHOLD: Gadget(GadgetID.SMUGGLERHOLD, Skills.NONE, 60000, TechLevel.UNAVAILABLE, 0), -} - -POLICE_RECORDS = { - CriminalRecord.PSYCHOPATH: -100, - CriminalRecord.VILLAIN: -70, - CriminalRecord.CRIMINAL: -30, - CriminalRecord.CROOK: -10, - CriminalRecord.DUBIOUS: -5, - CriminalRecord.CLEAN: 0, - CriminalRecord.LAWFUL: 5, - CriminalRecord.TRUSTED: 10, - CriminalRecord.LIKED: 25, - CriminalRecord.HERO: 75, - CriminalRecord.ERRNO: 100, -} - -REPUTATION = { - CombatReputation.HARMLESS: 0, - CombatReputation.MOSTLY_HARMLESS: 10, - CombatReputation.POOR: 20, - CombatReputation.AVERAGE: 40, - CombatReputation.ABOVE_AVERAGE: 80, - CombatReputation.COMPETENT: 150, - CombatReputation.DANGEROUS: 300, - CombatReputation.DEADLY: 600, - CombatReputation.ELITE: 1500, - CombatReputation.BORG: 3000, -} diff --git a/src/government.py b/src/government.py deleted file mode 100644 index 770bfbf..0000000 --- a/src/government.py +++ /dev/null @@ -1,69 +0,0 @@ -""" - Space Trader | RPINerd, 2024 - An elite-inspired space trading RPG originally on PalmOS - - Government Module - These classes and functions define the political systems and their - respective traits as a result of the government. -""" - - -class GovernmentId: - ANARCHY = 0 - CAPITALIST = 1 - COMMUNIST = 2 - CONFEDERACY = 3 - CORPORATE = 4 - CYBERNETIC = 5 - DEMOCRACY = 6 - DICTATORSHIP = 7 - FASCIST = 8 - FEUDAL = 9 - MILITARY = 10 - MONARCHY = 11 - PACIFIST = 12 - SOCIALIST = 13 - SATORI = 14 - TECHNOCRACY = 15 - THEOCRACY = 16 - - -class PoliticalSystem: - - def __init__( - self, - name: str, - stability: int, - law: int, - crime: int, - economy: int, - minTech: int, - maxTech: int, - bribe_difficulty: int, - drug_tolerance: bool, - firearm_tolerance: bool, - tradeItemId: int, - ): - self.name = name - self.stability = stability - self.law = law - self.crime = crime - self.economy = economy - self.minTech = minTech - self.maxTech = maxTech - self.bribe_difficulty = bribe_difficulty - self.drug_tolerance = drug_tolerance - self.firearm_tolerance = firearm_tolerance - self.tradeItemId = tradeItemId - - def __str__(self): - return self.name - - def __repr__(self): - return f"{self.name} ({self.stability}, {self.law}, {self.crime}, {self.economy})" - - def firearms_ok(self) -> bool: - return self.firearm_tolerance - - def drugs_ok(self) -> bool: - return self.drug_tolerance diff --git a/src/planet.py b/src/planet.py deleted file mode 100644 index 0dd1077..0000000 --- a/src/planet.py +++ /dev/null @@ -1,443 +0,0 @@ -""" - Space Trader | RPINerd, 2024 - An elite-inspired space trading RPG originally on PalmOS - - Planet Module - This module houses the classes and functions for a planet object. - This subsequently includes the planets' government, economy, and tech level. -""" - -from math import floor, pow, sqrt -from random import randint - -from .constants import Activity, Size, SpecialResource, TechLevel -from .economy import TradeItemId -from .game_data import TRADEITEMS -from .government import PoliticalSystem - -TMPGAMEDIFFICULTY = 1 - - -class Planet: - """ - Object representing a single planet in the game world. - - params: name - planet name - params: x - x coordinate of the planet - params: y - y coordinate of the planet - params: size - planet size - params: tech_level - tech level of the planet - params: government - political system type of the planet - params: soci_pressure - current pressure on the planet - params: special_resource - current special resource of the planet - params: quest_system - whether the planet is a quest host - params: trade_items - items available for trade on the planet - #? params: count_down - countdown - params: visited - whether the planet has been visited - #? params: shipyard_id - id of the shipyard in the system - """ - - def __init__( - self, - name, - x: int, - y: int, - size: int, - government: PoliticalSystem, - tech_level: int, - soci_pressure: int, - special_resource: int, - ): - self.name = name - self.x = x - self.y = y - self.size = size - self.government = government - self.tech_level = tech_level - self.soci_pressure = soci_pressure - self.special_resource = special_resource - self.quest_system = False - self.trade_items = [0] * 10 - self.count_down = 0 - self.visited = False - self.shipyard_id = None - - self.initialize_trade_items() - - # Basic Info Interfaces - def __str__(self) -> str: - return self.name - - def __repr__(self) -> str: - repr_str = f"{self.name} ({self.x}, {self.y}), \ - {Size.name(self.size)}, {self.get_government_name()}, \ - {self.get_tech_level()}, {SpecialResource.name(self.special_resource)}, \ - {self.soci_pressure}, {self.government.law}, {self.government.crime}" - return repr_str - - def pprint(self) -> str: - info = f"""--------------- - Planet: {self.name} at ({self.x}, {self.y})\n \ - Size: {Size.name(self.size)}\n \ - Tech Level: {self.tech_level}\n \ - Government: {self.get_government_name()}\n \ - Resources: {SpecialResource.name(self.special_resource)}\n \ - Police: {self.government.law}\n \ - Pirates: {self.government.crime}\n \ - Pressure: {self.soci_pressure}\n \ - --------------- - """ - return info - - @staticmethod - def system_info_headers() -> list[str]: - """Reference for making window""" - # ? Maybe should be in a "UI" data module? - return [ - "Name:", - "Size:", - "Tech level:", - "Government:", - "Resources:", - "Police:", - "Pirates:", - ] - - def system_info(self) -> list[str]: - return [ - self.name, - Size.name(self.size), - TechLevel.name(self.tech_level), - self.get_government_name(), - SpecialResource.name(self.special_resource), - Activity.name(self.government.law), - Activity.name(self.government.crime), - ] - - def get_location(self) -> tuple[int, int]: - return (self.x, self.y) - - def get_size(self) -> int: - return self.size - - def get_tech_level(self) -> int: - return self.tech_level - - def set_visited(self) -> None: - self.visited = True - - def set_tech_level(self, value) -> None: - self.tech_level = value - - # TODO implement - def dest_is_ok(self) -> bool: - """ - Check if the destination is reachable with the current fuel level - Also account for wormholes - - return: bool - whether the destination is reachable - """ - raise NotImplementedError("Planet.dest_is_ok not implemented") - # comm = Game.current_game.commander - # return self != comm.current_system and ( - # self.get_distance() <= comm.ship.fuel or Functions.wormhole_exists(comm.current_system, self) - # ) - - def get_distance(self, target_planet=None): - return int(floor(sqrt(pow(self.x - target_planet.x, 2) + pow(self.y - target_planet.y, 2)))) - - # Political Interfaces - # TODO maybe change to alter_ and handle political shift logic here - def set_govt_type(self, value) -> None: - self.government = value - - def get_govt_type(self) -> PoliticalSystem: - return self.government - - def get_government_name(self) -> str: - return str(self.government) - - # Economic Interfaces - def get_pressure(self) -> int: - """ - Societal pressures: - - 0 = under no particular pressure; Uneventful - 1 = at war; Ore and Weapons in demand - 2 = ravaged by a plague; Medicine in demand - 3 = suffering from a drought; Water in demand - 4 = suffering from extreme boredom; Games and Narcotics in demand - 5 = suffering from a cold spell; Furs in demand - 6 = suffering from a crop failure; Food in demand - 7 = lacking enough workers; Machinery and Robots in demand - """ - return self.soci_pressure - - def set_pressure(self, value: int) -> None: - self.soci_pressure = value - - def get_special_resource(self) -> int: - """ - Special resources: - - 0 = Nothing Special - 1 = Mineral Rich - 2 = Mineral Poor - 3 = Desert - 4 = Sweetwater Oceans - 5 = Rich Soil - 6 = Poor Soil - 7 = Rich Fauna - 8 = Lifeless - 9 = Weird Mushrooms - 10 = Special Herbs - 11 = Artistic Populace - 12 = Warlike Populace - """ - if self.visited: - return self.special_resource - # TODO maybe not random here? - else: - self.special_resource = SpecialResource.random() - return self.special_resource - - def initialize_trade_items(self): - """ - Set the starting quantity of each trade good for the planet - """ - - for item_id in TradeItemId.enum(): - - # Make sure the item is allowed to be traded - if not self.is_item_traded(item_id): - self.trade_items[item_id] = 0 - else: - # Quantity is dictated by the planet tech level, size, and a bit of randomness - self.trade_items[item_id] = (self.size + 1) * ( - randint(9, 14) - abs(TRADEITEMS[item_id].tech_level_max - self.tech_level) - ) - - # Because of the enormous profitssss possible, - # there shouldn't be too many robots or narcotics available - if item_id >= TradeItemId.NARCOTICS: - self.trade_items[item_id] = ( - (self.trade_items[item_id] * (5 - TMPGAMEDIFFICULTY)) / (6 - TMPGAMEDIFFICULTY) - ) + 1 - - # Adjust for special resources and societal pressures - if self.special_resource == TRADEITEMS[item_id].special_resource_drop: - self.trade_items[item_id] = self.trade_items[item_id] * 4 / 3 - if self.special_resource == TRADEITEMS[item_id].special_resource_hike: - self.trade_items[item_id] = self.trade_items[item_id] * 3 / 4 - if self.soci_pressure == TRADEITEMS[item_id].pressure: - self.trade_items[item_id] = self.trade_items[item_id] / 5 - - # Another small random factor - self.trade_items[item_id] = self.trade_items[item_id] - randint(1, 10) + randint(1, 10) - - # Finally just make sure it's not negative - if self.trade_items[item_id] < 0: - self.trade_items[item_id] = 0 - - def is_item_traded(self, item) -> bool: - """ - Given an item ID, check with the planets political system to see if it can be traded - - params: item - item ID to check - - return: bool - whether the item can be traded - """ - - if item not in [TradeItemId.FIREARMS, TradeItemId.NARCOTICS]: - return True - - if item == TradeItemId.FIREARMS: - return self.government.firearms_ok() - - elif item == TradeItemId.NARCOTICS: - return self.government.drugs_ok() - - else: - raise ValueError(f"Item ID {item} not valid!") - - def item_used(self, item): - raise NotImplementedError("Planet.item_used not implemented") - # return ( - # (item.item_type != d.NARCOTICS or self.get_political_system().is_drugs_ok()) - # and (item.item_type != d.FIREARMS or self.get_political_system().is_firearms_ok()) - # and self.tech_level.cast_to_int() >= item.tech_usage.cast_to_int() - # ) - - def get_inventory(self): - return self.trade_items - - # Misc Interfaces - # TODO implement - def get_mercenaries_for_hire(self) -> list: - """ - Commander cmdr = Game.CurrentGame.Commander; - CrewMember[] mercs = Game.CurrentGame.Mercenaries; - ArrayList forHire = new ArrayList(3); - - for (int i = 1; i < mercs.Length; i++) - { - if (mercs[i].CurrentSystem == cmdr.CurrentSystem && !cmdr.Ship.HasCrew(mercs[i].Id)) - forHire.Add(mercs[i]); - } - - return (CrewMember[])forHire.ToArray(typeof(CrewMember)); - """ - raise NotImplementedError("Planet.get_mercenaries_for_hire not implemented") - # cmdr = Game.current_game.commander - # return [ - # merc - # for merc in Game.current_game.mercenaries.values() - # if merc.is_mercenary() and merc.current_system == cmdr.current_system and not cmdr.ship.has_crew(merc.id) - # ] - - def is_quest_system(self) -> bool: - return self.quest_system - - def set_quest_system(self, value) -> None: - self.quest_system = value - - # TODO implement - def show_quest_button(self): - """ - public bool ShowSpecialButton() - { - Game game = Game.CurrentGame; - bool show = false; - - switch (SpecialEventType) - { - case SpecialEventType.Artifact: - case SpecialEventType.Dragonfly: - case SpecialEventType.Experiment: - case SpecialEventType.Jarek: - show = game.Commander.PoliceRecordScore >= Consts.PoliceRecordScoreDubious; - break; - case SpecialEventType.ArtifactDelivery: - show = game.Commander.Ship.ArtifactOnBoard; - break; - case SpecialEventType.CargoForSale: - show = game.Commander.Ship.FreeCargoBays >= 3; - break; - case SpecialEventType.DragonflyBaratas: - show = game.QuestStatusDragonfly > SpecialEvent.StatusDragonflyNotStarted && - game.QuestStatusDragonfly < SpecialEvent.StatusDragonflyDestroyed; - break; - case SpecialEventType.DragonflyDestroyed: - show = game.QuestStatusDragonfly == SpecialEvent.StatusDragonflyDestroyed; - break; - case SpecialEventType.DragonflyMelina: - show = game.QuestStatusDragonfly > SpecialEvent.StatusDragonflyFlyBaratas && - game.QuestStatusDragonfly < SpecialEvent.StatusDragonflyDestroyed; - break; - case SpecialEventType.DragonflyRegulas: - show = game.QuestStatusDragonfly > SpecialEvent.StatusDragonflyFlyMelina && - game.QuestStatusDragonfly < SpecialEvent.StatusDragonflyDestroyed; - break; - case SpecialEventType.DragonflyShield: - case SpecialEventType.ExperimentFailed: - case SpecialEventType.Gemulon: - case SpecialEventType.GemulonFuel: - case SpecialEventType.GemulonInvaded: - case SpecialEventType.Lottery: - case SpecialEventType.ReactorLaser: - case SpecialEventType.PrincessQuantum: - case SpecialEventType.SculptureHiddenBays: - case SpecialEventType.Skill: - case SpecialEventType.SpaceMonster: - case SpecialEventType.Tribble: - show = true; - break; - case SpecialEventType.EraseRecord: - case SpecialEventType.Wild: - show = game.Commander.PoliceRecordScore < Consts.PoliceRecordScoreDubious; - break; - case SpecialEventType.ExperimentStopped: - show = game.QuestStatusExperiment > SpecialEvent.StatusExperimentNotStarted && - game.QuestStatusExperiment < SpecialEvent.StatusExperimentPerformed; - break; - case SpecialEventType.GemulonRescued: - show = game.QuestStatusGemulon > SpecialEvent.StatusGemulonNotStarted && - game.QuestStatusGemulon < SpecialEvent.StatusGemulonTooLate; - break; - case SpecialEventType.Japori: - show = game.QuestStatusJapori == SpecialEvent.StatusJaporiNotStarted && - game.Commander.PoliceRecordScore >= Consts.PoliceRecordScoreDubious; - break; - case SpecialEventType.JaporiDelivery: - show = game.QuestStatusJapori == SpecialEvent.StatusJaporiInTransit; - break; - case SpecialEventType.JarekGetsOut: - show = game.Commander.Ship.JarekOnBoard; - break; - case SpecialEventType.Moon: - show = game.QuestStatusMoon == SpecialEvent.StatusMoonNotStarted && - game.Commander.Worth > SpecialEvent.MoonCost * .8; - break; - case SpecialEventType.MoonRetirement: - show = game.QuestStatusMoon == SpecialEvent.StatusMoonBought; - break; - case SpecialEventType.Princess: - show = game.Commander.PoliceRecordScore >= Consts.PoliceRecordScoreLawful && - game.Commander.ReputationScore >= Consts.ReputationScoreAverage; - break; - case SpecialEventType.PrincessCentauri: - show = game.QuestStatusPrincess >= SpecialEvent.StatusPrincessFlyCentauri && - game.QuestStatusPrincess <= SpecialEvent.StatusPrincessFlyQonos; - break; - case SpecialEventType.PrincessInthara: - show = game.QuestStatusPrincess >= SpecialEvent.StatusPrincessFlyInthara && - game.QuestStatusPrincess <= SpecialEvent.StatusPrincessFlyQonos; - break; - case SpecialEventType.PrincessQonos: - show = game.QuestStatusPrincess == SpecialEvent.StatusPrincessRescued && - !game.Commander.Ship.PrincessOnBoard; - break; - case SpecialEventType.PrincessReturned: - show = game.Commander.Ship.PrincessOnBoard; - break; - case SpecialEventType.Reactor: - show = game.QuestStatusReactor == SpecialEvent.StatusReactorNotStarted && - game.Commander.PoliceRecordScore < Consts.PoliceRecordScoreDubious && - game.Commander.ReputationScore >= Consts.ReputationScoreAverage; - break; - case SpecialEventType.ReactorDelivered: - show = game.Commander.Ship.ReactorOnBoard; - break; - case SpecialEventType.Scarab: - show = game.QuestStatusScarab == SpecialEvent.StatusScarabNotStarted && - game.Commander.ReputationScore >= Consts.ReputationScoreAverage; - break; - case SpecialEventType.ScarabDestroyed: - case SpecialEventType.ScarabUpgradeHull: - show = game.QuestStatusScarab == SpecialEvent.StatusScarabDestroyed; - break; - case SpecialEventType.Sculpture: - show = game.QuestStatusSculpture == SpecialEvent.StatusSculptureNotStarted && - game.Commander.PoliceRecordScore < Consts.PoliceRecordScoreDubious && - game.Commander.ReputationScore >= Consts.ReputationScoreAverage; - break; - case SpecialEventType.SculptureDelivered: - show = game.QuestStatusSculpture == SpecialEvent.StatusSculptureInTransit; - break; - case SpecialEventType.SpaceMonsterKilled: - show = game.QuestStatusSpaceMonster == SpecialEvent.StatusSpaceMonsterDestroyed; - break; - case SpecialEventType.TribbleBuyer: - show = game.Commander.Ship.Tribbles > 0; - break; - case SpecialEventType.WildGetsOut: - show = game.Commander.Ship.WildOnBoard; - break; - default: - break; - } - - return show; - } - """ - raise NotImplementedError("Planet.show_quest_button not implemented") diff --git a/src/screens/char_create.py b/src/screens/char_create.py index 536f6b2..e85f67c 100644 --- a/src/screens/char_create.py +++ b/src/screens/char_create.py @@ -88,7 +88,7 @@ def create_widgets(self): self.difficulty_dec = ttk.Button(self.difficulty_frame, style="TButton", text="-", command=self.dec_difficulty) self.difficulty_current = ttk.Label( self.difficulty_frame, - text="Normal", + text=Difficulty.name(self.diff_current_value), ) self.difficulty_inc = ttk.Button(self.difficulty_frame, text="+", command=self.inc_difficulty) self.difficulty_label.pack(side="left") @@ -121,20 +121,26 @@ def create_widgets(self): self.start_button.pack(expand=True) def dec_difficulty(self) -> None: - self.diff_current_value - diff_current_value = max(self.diff_current_value - 1, 0) - if diff_current_value == 0: + print("Decreasing difficulty") + print("Current value:", self.diff_current_value) + new_difficulty = max(self.diff_current_value - 1, 0) + print("New value:", new_difficulty) + if new_difficulty == 0: self.difficulty_dec["state"] = "disabled" self.difficulty_inc["state"] = "enabled" - self.difficulty_current["text"] = Difficulty.name(diff_current_value) + self.difficulty_current["text"] = Difficulty.name(new_difficulty) + self.diff_current_value = new_difficulty def inc_difficulty(self) -> None: - self.diff_current_value - diff_current_value = min(self.diff_current_value + 1, 4) - if diff_current_value == 4: + print("Increasing difficulty") + print("Current value:", self.diff_current_value) + new_difficulty = min(self.diff_current_value + 1, 4) + print("New value:", new_difficulty) + if new_difficulty == 4: self.difficulty_inc["state"] = "disabled" self.difficulty_dec["state"] = "enabled" - self.difficulty_current["text"] = Difficulty.name(diff_current_value) + self.difficulty_current["text"] = Difficulty.name(new_difficulty) + self.diff_current_value = new_difficulty def cmdr_create(self) -> None: @@ -154,6 +160,7 @@ def cmdr_create(self) -> None: self.engineer_skill.get_value(), ) GAME["commander"] = cmdr + GAME["difficulty"] = self.diff_current_value print(cmdr.pprint()) self.destroy() self.parent.manager.build_screens() diff --git a/src/screens/commander_status.py b/src/screens/gamescreens.py similarity index 54% rename from src/screens/commander_status.py rename to src/screens/gamescreens.py index 3d73aba..751fec2 100644 --- a/src/screens/commander_status.py +++ b/src/screens/gamescreens.py @@ -1,22 +1,169 @@ -""" - Space Trader (PalmOS) | RPINerd, 2024 - - Commander Status Screen - Shows your stats, time played, etc. -""" - import tkinter as tk +from random import randint from tkinter import ttk import src.ui_actions as actions -# from ..constants import BKG_COLOR, GameStateID from .screens import Screen +FUEL_STATUS = "You have fuel to fly {0} parsecs." +FULL_TANK = "Your tank cannot hold more fuel." +HULL_STATUS = "Your hull strength is at {0}%." +FULL_HULL = "No repairs are needed." +SHIP_SALES = "No new ships are for sale." +ESCAPE_POD = "No escape pods are for sale." NO_QUARTER = "No quarters available" NO_HIRE = "No one for hire" +class SystemInfo(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + def create_widgets(self): + + system_info, pressure = actions.get_system_info() + + # Info Frame + self.info_frame = ttk.Frame(self) + self.info_frame.columnconfigure(0, weight=1) + self.info_frame.columnconfigure(1, weight=1) + info_headings = ["Name:", "Size:", "Tech Level:", "Government:", "Resources:", "Police:", "Pirates:"] + for i, heading in enumerate(info_headings): + ttk.Label(self.info_frame, text=heading, style="Heading.TLabel", justify="left").grid( + row=i, column=0, sticky="ew" + ) + #! Placeholder content + for i, stat in enumerate(system_info): + ttk.Label(self.info_frame, text=stat, justify="left").grid(row=i, column=1, sticky="ew") + self.info_frame.pack(fill="x", expand=True) + + # Pressure Frame + self.pressure_frame = ttk.Frame(self) + ttk.Label(self.pressure_frame, text=pressure).grid(row=0, column=0) + self.pressure_frame.pack(side="top", fill="both", expand=True) + + # Shortcut Frame + self.shortcut_frame = ttk.Frame(self) + ttk.Button(self.shortcut_frame, text="News", command=actions.buy_news).pack(side="left") + self.shortcut_frame.pack(side="top", fill="both", expand=True) + + def change_screen(self, event): + # TODO probably can be a super method + pass + + +class ShortRange(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + +class LongRange(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + +class TargetSystem(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + +class AvgPrices(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + +class BuyCargo(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + def create_widgets(self): + self.table_frame = ttk.Frame(self) + for i, value in enumerate(actions.get_ware_list()): + ttk.Button(self.table_frame, text=randint(0, 42)).grid(row=i, column=0) + ttk.Label(self.table_frame, text=value).grid(row=i, column=1) + ttk.Button(self.table_frame, text="Max", command=actions.buy_good).grid(row=i, column=2) + ttk.Label(self.table_frame, text="1234 cr.").grid(row=i, column=3) + self.table_frame.pack(fill="both", expand=True) + + +class SellCargo(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + def create_widgets(self): + self.table_frame = ttk.Frame(self) + for i, value in enumerate(actions.get_ware_list()): + ttk.Button(self.table_frame, text="0").grid(row=i, column=0) + ttk.Label(self.table_frame, text=value).grid(row=i, column=1) + ttk.Button(self.table_frame, text="All", command=actions.sell_good).grid(row=i, column=2) + ttk.Label(self.table_frame, text="15cr").grid(row=i, column=3) + self.table_frame.pack(fill="both", expand=True) + + +class BuyEquipment(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + +class SellEquipment(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + +class Bank(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + +class Shipyard(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + def create_widgets(self): + + # Fuel Frame + self.fuel_frame = ttk.Frame(self) + ttk.Label(self.fuel_frame, text=FUEL_STATUS.format(0), font=("Palm Pilot Small", 14)).pack() + ttk.Button(self.fuel_frame, text="Refuel", command=actions.buy_fuel).pack() + self.fuel_frame.pack(side="top", fill="both", expand=True) + + # Hull Frame + self.hull_frame = ttk.Frame(self) + ttk.Label(self.hull_frame, text=HULL_STATUS.format(0), font=("Palm Pilot Small", 14)).pack() + ttk.Button(self.hull_frame, text="Repair", command=actions.repair).pack() + self.hull_frame.pack(side="top", fill="both", expand=True) + + # Escape Pod Frame + self.escape_pod_frame = ttk.Frame(self) + ttk.Label(self.escape_pod_frame, text=ESCAPE_POD, font=("Palm Pilot Small", 14)).pack() + ttk.Button(self.escape_pod_frame, text="Buy Escape Pod", command=actions.buy_pod).pack() + self.escape_pod_frame.pack(side="top", fill="both", expand=True) + + # Ship Sales Frame + self.ship_sales_frame = ttk.Frame(self) + ttk.Label(self.ship_sales_frame, text=SHIP_SALES, font=("Palm Pilot Small", 14)).pack() + ttk.Button(self.ship_sales_frame, text="Buy Ship", command=actions.buy_ship).pack() + self.ship_sales_frame.pack(side="top", fill="both", expand=True) + + +class BuyShip(Screen): + + def __init__(self, parent, screen_title, manager) -> None: + super().__init__(parent, screen_title, manager) + + class CommanderInfo(Screen): def __init__(self, parent, screen_title, manager) -> None: diff --git a/src/screens/markets.py b/src/screens/markets.py deleted file mode 100644 index aec2c9c..0000000 --- a/src/screens/markets.py +++ /dev/null @@ -1,63 +0,0 @@ -""" - Space Trader (PalmOS) | RPINerd, 2024 - - Buy Cargo Screen -""" - -import tkinter as tk -from random import randint -from tkinter import ttk - -import src.ui_actions as actions - -# from ..constants import BKG_COLOR, GameStateID -from ..economy import TradeItemId -from .screens import Screen - - -class BuyCargo(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - def create_widgets(self): - self.table_frame = ttk.Frame(self) - for i, value in enumerate(TradeItemId.lst()): - ttk.Button(self.table_frame, text=randint(0, 42)).grid(row=i, column=0) - ttk.Label(self.table_frame, text=value).grid(row=i, column=1) - ttk.Button(self.table_frame, text="Max", command=actions.buy_good).grid(row=i, column=2) - ttk.Label(self.table_frame, text="1234 cr.").grid(row=i, column=3) - self.table_frame.pack(fill="both", expand=True) - - -class SellCargo(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - def create_widgets(self): - self.table_frame = ttk.Frame(self) - for i, value in enumerate(TradeItemId.lst()): - ttk.Button(self.table_frame, text="0").grid(row=i, column=0) - ttk.Label(self.table_frame, text=value).grid(row=i, column=1) - ttk.Button(self.table_frame, text="All", command=actions.sell_good).grid(row=i, column=2) - ttk.Label(self.table_frame, text="15cr").grid(row=i, column=3) - self.table_frame.pack(fill="both", expand=True) - - -class BuyEquipment(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - -class SellEquipment(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - -class Bank(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) diff --git a/src/screens/screen_manager.py b/src/screens/screen_manager.py index 70be2d4..0485fd5 100644 --- a/src/screens/screen_manager.py +++ b/src/screens/screen_manager.py @@ -1,8 +1,23 @@ -from .commander_status import CommanderInfo, Personnel, Quests, ShipInfo, SpecialCargo -from .markets import Bank, BuyCargo, BuyEquipment, SellCargo, SellEquipment +from .gamescreens import ( + AvgPrices, + Bank, + BuyCargo, + BuyEquipment, + BuyShip, + CommanderInfo, + LongRange, + Personnel, + Quests, + SellCargo, + SellEquipment, + ShipInfo, + Shipyard, + ShortRange, + SpecialCargo, + SystemInfo, + TargetSystem, +) from .screens import Screen -from .shipyard import BuyShip, Shipyard -from .system_info import AvgPrices, LongRange, ShortRange, SystemInfo, TargetSystem SCREENS = { "I": { diff --git a/src/screens/shipyard.py b/src/screens/shipyard.py deleted file mode 100644 index f512abd..0000000 --- a/src/screens/shipyard.py +++ /dev/null @@ -1,61 +0,0 @@ -""" - Space Trader (PalmOS) | RPINerd, 2024 - - Shipyard Screen - Counterintuitively, not actually where you buy ships. - Houses refuel, repair, escape pod purchase and then link to ship sales. -""" - -import tkinter as tk -from tkinter import ttk - -# from ..constants import BKG_COLOR -# from ..game_data import ShipID -import src.ui_actions as actions - -from .screens import Screen - -FUEL_STATUS = "You have fuel to fly {0} parsecs." -FULL_TANK = "Your tank cannot hold more fuel." -HULL_STATUS = "Your hull strength is at {0}%." -FULL_HULL = "No repairs are needed." -SHIP_SALES = "No new ships are for sale." -ESCAPE_POD = "No escape pods are for sale." - - -class Shipyard(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - def create_widgets(self): - - # Fuel Frame - self.fuel_frame = ttk.Frame(self) - ttk.Label(self.fuel_frame, text=FUEL_STATUS.format(0), font=("Palm Pilot Small", 14)).pack() - ttk.Button(self.fuel_frame, text="Refuel", command=actions.buy_fuel).pack() - self.fuel_frame.pack(side="top", fill="both", expand=True) - - # Hull Frame - self.hull_frame = ttk.Frame(self) - ttk.Label(self.hull_frame, text=HULL_STATUS.format(0), font=("Palm Pilot Small", 14)).pack() - ttk.Button(self.hull_frame, text="Repair", command=actions.repair).pack() - self.hull_frame.pack(side="top", fill="both", expand=True) - - # Escape Pod Frame - self.escape_pod_frame = ttk.Frame(self) - ttk.Label(self.escape_pod_frame, text=ESCAPE_POD, font=("Palm Pilot Small", 14)).pack() - ttk.Button(self.escape_pod_frame, text="Buy Escape Pod", command=actions.buy_pod).pack() - self.escape_pod_frame.pack(side="top", fill="both", expand=True) - - # Ship Sales Frame - self.ship_sales_frame = ttk.Frame(self) - ttk.Label(self.ship_sales_frame, text=SHIP_SALES, font=("Palm Pilot Small", 14)).pack() - ttk.Button(self.ship_sales_frame, text="Buy Ship", command=actions.buy_ship).pack() - self.ship_sales_frame.pack(side="top", fill="both", expand=True) - - -class BuyShip(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) diff --git a/src/screens/system_info.py b/src/screens/system_info.py deleted file mode 100644 index 0d3916d..0000000 --- a/src/screens/system_info.py +++ /dev/null @@ -1,74 +0,0 @@ -""" - Space Trader (PalmOS) | RPINerd, 2024 - - Basic system information screen -""" - -import tkinter as tk -from tkinter import ttk - -import src.ui_actions as actions - -from .screens import Screen - - -class SystemInfo(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - def create_widgets(self): - - system_info, pressure = actions.get_system_info() - - # Info Frame - self.info_frame = ttk.Frame(self) - self.info_frame.columnconfigure(0, weight=1) - self.info_frame.columnconfigure(1, weight=1) - info_headings = ["Name:", "Size:", "Tech Level:", "Government:", "Resources:", "Police:", "Pirates:"] - for i, heading in enumerate(info_headings): - ttk.Label(self.info_frame, text=heading, style="Heading.TLabel", justify="left").grid( - row=i, column=0, sticky="ew" - ) - #! Placeholder content - for i, stat in enumerate(system_info): - ttk.Label(self.info_frame, text=stat, justify="left").grid(row=i, column=1, sticky="ew") - self.info_frame.pack(fill="x", expand=True) - - # Pressure Frame - self.pressure_frame = ttk.Frame(self) - ttk.Label(self.pressure_frame, text=pressure).grid(row=0, column=0) - self.pressure_frame.pack(side="top", fill="both", expand=True) - - # Shortcut Frame - self.shortcut_frame = ttk.Frame(self) - ttk.Button(self.shortcut_frame, text="News", command=actions.buy_news).pack(side="left") - self.shortcut_frame.pack(side="top", fill="both", expand=True) - - def change_screen(self, event): - # TODO probably can be a super method - pass - - -class ShortRange(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - -class LongRange(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - -class TargetSystem(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) - - -class AvgPrices(Screen): - - def __init__(self, parent, screen_title, manager) -> None: - super().__init__(parent, screen_title, manager) diff --git a/src/ships.py b/src/ships.py deleted file mode 100644 index 89cb9d9..0000000 --- a/src/ships.py +++ /dev/null @@ -1,190 +0,0 @@ -""" - Space Trader | RPINerd, 2024 - An elite-inspired space trading RPG originally on PalmOS - - Ships Module - This module contains the classes and functions for the game ships, weapons, shields and gadgets. -""" - - -class ShipID: - # ESCAPEPOD = 0 #? Not in source - FLEA = 0 - GNAT = 1 - FIREFLY = 2 - MOSQUITO = 3 - BUMBLEBEE = 4 - BEETLE = 5 - HORNET = 6 - GRASSHOPPER = 7 - TERMITE = 8 - WASP = 9 - SPACEMONSTER = 10 - DRAGONFLY = 11 - MANTIS = 12 - SCARAB = 13 - BOTTLE = 14 - CUSTOM = 15 - SCORPION = 16 - - @staticmethod - def enum() -> list[int]: - return range(17) - - @staticmethod - def lst() -> list[str]: - return [ - "Flea", - "Gnat", - "Firefly", - "Mosquito", - "Bumblebee", - "Beetle", - "Hornet", - "Grasshopper", - "Termite", - "Wasp", - "Space Monster", - "Dragonfly", - "Mantis", - "Scarab", - "Bottle", - "Custom", - "Scorpion", - ] - - @staticmethod - def sale_lst() -> list[str]: - return [ - "Flea", - "Gnat", - "Firefly", - "Mosquito", - "Bumblebee", - "Beetle", - "Hornet", - "Grasshopper", - "Termite", - "Wasp", - ] - - -class EquipmentType: - WEAPON = 0 - SHIELD = 1 - GADGET = 2 - - -class GadgetID: - CARGOBAYS = 0 - AUTOREPAIR = 1 - NAVIGATION = 2 - TARGETING = 3 - CLOAKING = 4 - FUELCOMPACTOR = 5 - SMUGGLERHOLD = 6 - - -class WeaponID: - PULSELASER = 0 - BEAMLASER = 1 - MILITARYLASER = 2 - MORGANSLASER = 3 - PHOTONDISRUPTOR = 4 - QUANTUMDISRUPTOR = 5 - - -class SheildID: - ENERGY = 0 - REFLECTIVE = 1 - LIGHTNING = 2 - - -class Equipment: - - def __init__(self, id, price, tech_level): - self.id = id - self.price = price - self.tech_level = tech_level - - @staticmethod - def sale_list() -> list[str]: - return [ - "Pulse laser", - "Beam laser", - "Military laser", - "Energy shield", - "Reflective shield", - "5 extra cargo bays", - "Auto-repair system", - "Navigation system", - "Targeting system", - "Cloaking device", - ] - - -class Weapon(Equipment): - - def __init__(self, id, damage, unk_bool, price, tech_level, unknown): - super().__init__(id, price, tech_level) - self.damage = damage - self.unk_bool = unk_bool - self.unknown = unknown - - -class Shield(Equipment): - - # TODO what are points and unknown? - def __init__(self, id, points, price, tech_level, unknown): - super().__init__(id, price, tech_level) - self.points = points - self.unknown = unknown - - -class Gadget(Equipment): - - def __init__(self, id, skill, price, tech_level, unknown): - super().__init__(id, price, tech_level) - self.skill = skill - self.unknown = unknown - - -class Ship: - - def __init__( - self, - name: str, - size: int, - cargo: int, - weapon_slots: int, - shield_slots: int, - gadget_slots: int, - crew: int, - fuel: int, - fuel_cost: int, - hull: int, - repair_cost: int, - price: int, - unknown_percent: int, - police_use: int, - pirate_use: int, - trader_use: int, - tech_level: int, - ): - self.name = name - self.size = size - self.cargo = cargo - self.weapon_slots = weapon_slots - self.shield_slots = shield_slots - self.gadget_slots = gadget_slots - self.crew = crew - self.fuel = fuel - self.fuel_cost = fuel_cost - self.hull = hull - self.repair_cost = repair_cost - self.price = price - self.unknown_percent = unknown_percent - self.police_use = police_use - self.pirate_use = pirate_use - self.trader_use = trader_use - self.tech_level = tech_level diff --git a/src/ui_actions.py b/src/ui_actions.py index 7416a64..428c726 100644 --- a/src/ui_actions.py +++ b/src/ui_actions.py @@ -8,6 +8,7 @@ """ import src.constants as c +import src.economy as e # Disordered list of user interactions @@ -82,6 +83,10 @@ def buy_pod(): pass +def get_ware_list() -> list[str]: + return e.Ware.lst() + + def buy_good(): pass diff --git a/src/universe.py b/src/universe.py index 7537e0e..3f73537 100644 --- a/src/universe.py +++ b/src/universe.py @@ -7,12 +7,947 @@ contains all the systems, their respective governments and traits. """ +from math import floor, pow, sqrt from random import choice, randint -from .constants import GALAXYHEIGHT, GALAXYWIDTH, MIN_DISTANCE, SECTOR_DIAMETER, SocietalPressure, SpecialResource -from .game_data import GOVERNMENTS, PLANET_NAMES -from .planet import Planet -from .utils import planet_distance, wormhole_exists +from .constants import ( + GALAXYHEIGHT, + GALAXYWIDTH, + MAX_WORMHOLES, + MIN_DISTANCE, + SECTOR_DIAMETER, + Activity, + Size, + SocietalPressure, + SpecialResource, + TechLevel, +) +from .economy import PoliticalSystem, Ware + +TMPGAMEDIFFICULTY = 1 +PLANET_NAMES = { + 0: "Acamar", + 1: "Adahn", + 2: "Aldea", + 3: "Andevian", + 4: "Antedi", + 5: "Balosnee", + 6: "Baratas", + 7: "Bob", + 8: "Brax", + 9: "Bretel", + 10: "Calondia", + 11: "Campor", + 12: "Capelle", + 13: "Carzon", + 14: "Castor", + 15: "Cestus", + 16: "Cheron", + 17: "Courteney", + 18: "Daled", + 19: "Damast", + 20: "Davlos", + 21: "Deneb", + 22: "Deneva", + 23: "Devidia", + 24: "Draylon", + 25: "Drema", + 26: "Endor", + 27: "Esmee", + 28: "Exo", + 29: "Ferris", + 30: "Festen", + 31: "Fourmi", + 32: "Frolix", + 33: "Gemulon", + 34: "Guinifer", + 35: "Hades", + 36: "Hamlet", + 37: "Helena", + 38: "Hulst", + 39: "Iodine", + 40: "Iralius", + 41: "Janus", + 42: "Japori", + 43: "Jarada", + 44: "Jason", + 45: "Kaylon", + 46: "Khefka", + 47: "Kira", + 48: "Klaatu", + 49: "Klaestron", + 50: "Korma", + 51: "Kravat", + 52: "Krios", + 53: "Laertes", + 54: "Largo", + 55: "Lave", + 56: "Ligon", + 57: "Lowry", + 58: "Magrat", + 59: "Malcoria", + 60: "Melina", + 61: "Mentar", + 62: "Merik", + 63: "Mintaka", + 64: "Montor", + 65: "Mordan", + 66: "Myrthe", + 67: "Nelvana", + 68: "Nix", + 69: "Nyle", + 70: "Odet", + 71: "Og", + 72: "Omega", + 73: "Omphalos", + 74: "Orias", + 75: "Othello", + 76: "Parade", + 77: "Penthara", + 78: "Picard", + 79: "Pollux", + 80: "Quator", + 81: "Rakhar", + 82: "Ran", + 83: "Regulas", + 84: "Relva", + 85: "Rhymus", + 86: "Rochani", + 87: "Rubicum", + 88: "Rutia", + 89: "Sarpeidon", + 90: "Sefalla", + 91: "Seltrice", + 92: "Sigma", + 93: "Sol", + 94: "Somari", + 95: "Stakoron", + 96: "Styris", + 97: "Talani", + 98: "Tamus", + 99: "Tantalos", + 100: "Tanuga", + 101: "Tarchannen", + 102: "Terosa", + 103: "Thera", + 104: "Titan", + 105: "Torin", + 106: "Triacus", + 107: "Turkana", + 108: "Tyrus", + 109: "Umberlee", + 110: "Utopia", + 111: "Vadera", + 112: "Vagra", + 113: "Vandor", + 114: "Ventax", + 115: "Xenon", + 116: "Xerxes", + 117: "Yew", + 118: "Yojimbo", + 119: "Zalkon", + 120: "Zuul", +} +GOVERNMENTS = { + PoliticalSystem.ANARCHY: PoliticalSystem( + "Anarchy", + 0, + Activity.ABSENT, + Activity.SWARMS, + Activity.MINIMAL, + TechLevel.PRE_AGRICULTURAL, + TechLevel.INDUSTRIAL, + 7, + True, + True, + Ware.FOOD, + ), + PoliticalSystem.CAPITALIST: PoliticalSystem( + "Capitalist", + 2, + Activity.SOME, + Activity.FEW, + Activity.SWARMS, + TechLevel.EARLY_INDUSTRIAL, + TechLevel.HI_TECH, + 1, + True, + True, + Ware.ORE, + ), + PoliticalSystem.COMMUNIST: PoliticalSystem( + "Communist", + 6, + Activity.ABUNDANT, + Activity.MODERATE, + Activity.MODERATE, + TechLevel.AGRICULTURAL, + TechLevel.INDUSTRIAL, + 5, + True, + True, + Ware.NONE, + ), + PoliticalSystem.CONFEDERACY: PoliticalSystem( + "Confederacy", + 5, + Activity.MODERATE, + Activity.SOME, + Activity.MANY, + TechLevel.AGRICULTURAL, + TechLevel.POST_INDUSTRIAL, + 3, + True, + True, + Ware.GAMES, + ), + PoliticalSystem.CORPORATE: PoliticalSystem( + "Corporate", + 2, + Activity.ABUNDANT, + Activity.FEW, + Activity.SWARMS, + TechLevel.EARLY_INDUSTRIAL, + TechLevel.HI_TECH, + 2, + True, + True, + Ware.ROBOTS, + ), + PoliticalSystem.CYBERNETIC: PoliticalSystem( + "Cybernetic", + 0, + Activity.SWARMS, + Activity.SWARMS, + Activity.MANY, + TechLevel.POST_INDUSTRIAL, + TechLevel.HI_TECH, + 0, + False, + False, + Ware.ORE, + ), + PoliticalSystem.DEMOCRACY: PoliticalSystem( + "Democracy", + 4, + Activity.SOME, + Activity.FEW, + Activity.MANY, + TechLevel.RENAISSANCE, + TechLevel.HI_TECH, + 2, + True, + True, + Ware.GAMES, + ), + PoliticalSystem.DICTATORSHIP: PoliticalSystem( + "Dictatorship", + 3, + Activity.MODERATE, + Activity.MANY, + Activity.SOME, + TechLevel.PRE_AGRICULTURAL, + TechLevel.HI_TECH, + 2, + True, + True, + Ware.NONE, + ), + PoliticalSystem.FASCIST: PoliticalSystem( + "Fascist", + 7, + Activity.SWARMS, + Activity.SWARMS, + Activity.MINIMAL, + TechLevel.EARLY_INDUSTRIAL, + TechLevel.HI_TECH, + 0, + False, + True, + Ware.MACHINERY, + ), + PoliticalSystem.FEUDAL: PoliticalSystem( + "Feudal", + 1, + Activity.MINIMAL, + Activity.ABUNDANT, + Activity.FEW, + TechLevel.PRE_AGRICULTURAL, + TechLevel.RENAISSANCE, + 6, + True, + True, + Ware.FIREARMS, + ), + PoliticalSystem.MILITARY: PoliticalSystem( + "Military", + 7, + Activity.SWARMS, + Activity.ABSENT, + Activity.ABUNDANT, + TechLevel.MEDIEVAL, + TechLevel.HI_TECH, + 0, + False, + True, + Ware.ROBOTS, + ), + PoliticalSystem.MONARCHY: PoliticalSystem( + "Monarchy", + 3, + Activity.MODERATE, + Activity.SOME, + Activity.MODERATE, + TechLevel.PRE_AGRICULTURAL, + TechLevel.INDUSTRIAL, + 4, + True, + True, + Ware.MEDICINE, + ), + PoliticalSystem.PACIFIST: PoliticalSystem( + "Pacifist", + 7, + Activity.FEW, + Activity.MINIMAL, + Activity.MANY, + TechLevel.PRE_AGRICULTURAL, + TechLevel.RENAISSANCE, + 1, + True, + False, + Ware.NONE, + ), + PoliticalSystem.SOCIALIST: PoliticalSystem( + "Socialist", + 4, + Activity.FEW, + Activity.MANY, + Activity.SOME, + TechLevel.PRE_AGRICULTURAL, + TechLevel.INDUSTRIAL, + 6, + True, + True, + Ware.NONE, + ), + PoliticalSystem.SATORI: PoliticalSystem( + "Satori", + 0, + Activity.MINIMAL, + Activity.MINIMAL, + Activity.MINIMAL, + TechLevel.PRE_AGRICULTURAL, + TechLevel.AGRICULTURAL, + 0, + False, + False, + Ware.NONE, + ), + PoliticalSystem.TECHNOCRACY: PoliticalSystem( + "Technocracy", + 1, + Activity.ABUNDANT, + Activity.SOME, + Activity.ABUNDANT, + TechLevel.EARLY_INDUSTRIAL, + TechLevel.HI_TECH, + 2, + True, + True, + Ware.WATER, + ), + PoliticalSystem.THEOCRACY: PoliticalSystem( + "Theocracy", + 5, + Activity.ABUNDANT, + Activity.MINIMAL, + Activity.MODERATE, + TechLevel.PRE_AGRICULTURAL, + TechLevel.EARLY_INDUSTRIAL, + 0, + True, + True, + Ware.NARCOTICS, + ), +} +TRADEITEMS = { + Ware.WATER: Ware( + "Water", + TechLevel.PRE_AGRICULTURAL, + TechLevel.PRE_AGRICULTURAL, + TechLevel.MEDIEVAL, + 30, + 3, + 4, + SocietalPressure.DROUGHT, + SpecialResource.SWEETOCEANS, + SpecialResource.DESERT, + 30, + 50, + 1, + ), + Ware.FURS: Ware( + "Furs", + TechLevel.PRE_AGRICULTURAL, + TechLevel.PRE_AGRICULTURAL, + TechLevel.PRE_AGRICULTURAL, + 250, + 10, + 10, + SocietalPressure.COLD, + SpecialResource.RICHFAUNA, + SpecialResource.LIFELESS, + 230, + 280, + 5, + ), + Ware.FOOD: Ware( + "Food", + TechLevel.AGRICULTURAL, + TechLevel.PRE_AGRICULTURAL, + TechLevel.AGRICULTURAL, + 100, + 5, + 5, + SocietalPressure.CROPFAILURE, + SpecialResource.RICHSOIL, + SpecialResource.POORSOIL, + 90, + 160, + 5, + ), + Ware.ORE: Ware( + "Ore", + TechLevel.MEDIEVAL, + TechLevel.MEDIEVAL, + TechLevel.RENAISSANCE, + 350, + 20, + 10, + SocietalPressure.WAR, + SpecialResource.MINERAL_RICH, + SpecialResource.MINERAL_POOR, + 350, + 420, + 10, + ), + Ware.GAMES: Ware( + "Games", + TechLevel.RENAISSANCE, + TechLevel.AGRICULTURAL, + TechLevel.POST_INDUSTRIAL, + 250, + -10, + 5, + SocietalPressure.BOREDOM, + SpecialResource.ARTISTIC, + SpecialResource.NOTHING, + 160, + 270, + 5, + ), + Ware.FIREARMS: Ware( + "Firearms", + TechLevel.RENAISSANCE, + TechLevel.AGRICULTURAL, + TechLevel.INDUSTRIAL, + 1250, + -75, + 100, + SocietalPressure.WAR, + SpecialResource.WARLIKE, + SpecialResource.NOTHING, + 600, + 1100, + 25, + ), + Ware.MEDICINE: Ware( + "Medicine", + TechLevel.EARLY_INDUSTRIAL, + TechLevel.AGRICULTURAL, + TechLevel.POST_INDUSTRIAL, + 650, + -20, + 10, + SocietalPressure.PLAGUE, + SpecialResource.SPECIALHERBS, + SpecialResource.NOTHING, + 400, + 700, + 25, + ), + Ware.MACHINERY: Ware( + "Machinery", + TechLevel.EARLY_INDUSTRIAL, + TechLevel.RENAISSANCE, + TechLevel.INDUSTRIAL, + 900, + -30, + 5, + SocietalPressure.EMPLOYMENT, + SpecialResource.NOTHING, + SpecialResource.NOTHING, + 600, + 800, + 25, + ), + Ware.NARCOTICS: Ware( + "Narrcotics", + TechLevel.INDUSTRIAL, + TechLevel.PRE_AGRICULTURAL, + TechLevel.INDUSTRIAL, + 3500, + -125, + 150, + SocietalPressure.BOREDOM, + SpecialResource.WEIRDMUSHROOMS, + SpecialResource.NOTHING, + 2000, + 3000, + 50, + ), + Ware.ROBOTS: Ware( + "Robots", + TechLevel.POST_INDUSTRIAL, + TechLevel.EARLY_INDUSTRIAL, + TechLevel.HI_TECH, + 5000, + -150, + 100, + SocietalPressure.EMPLOYMENT, + SpecialResource.NOTHING, + SpecialResource.NOTHING, + 3500, + 5000, + 100, + ), +} + + +class Planet: + """ + Object representing a single planet in the game world. + + params: name - planet name + params: x - x coordinate of the planet + params: y - y coordinate of the planet + params: size - planet size + params: tech_level - tech level of the planet + params: government - political system type of the planet + params: soci_pressure - current pressure on the planet + params: special_resource - current special resource of the planet + params: quest_system - whether the planet is a quest host + params: trade_items - items available for trade on the planet + #? params: count_down - countdown + params: visited - whether the planet has been visited + #? params: shipyard_id - id of the shipyard in the system + """ + + def __init__( + self, + name, + x: int, + y: int, + size: int, + government: PoliticalSystem, + tech_level: int, + soci_pressure: int, + special_resource: int, + ): + self.name = name + self.x = x + self.y = y + self.size = size + self.government = government + self.tech_level = tech_level + self.soci_pressure = soci_pressure + self.special_resource = special_resource + self.quest_system = False + self.trade_items = [0] * 10 + self.count_down = 0 + self.visited = False + self.shipyard_id = None + + self.initialize_trade_items() + + # Basic Info Interfaces + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + repr_str = f"{self.name} ({self.x}, {self.y}), \ + {Size.name(self.size)}, {self.get_government_name()}, \ + {self.get_tech_level()}, {SpecialResource.name(self.special_resource)}, \ + {self.soci_pressure}, {self.government.law}, {self.government.crime}" + return repr_str + + def pprint(self) -> str: + info = f"""--------------- + Planet: {self.name} at ({self.x}, {self.y})\n \ + Size: {Size.name(self.size)}\n \ + Tech Level: {self.tech_level}\n \ + Government: {self.get_government_name()}\n \ + Resources: {SpecialResource.name(self.special_resource)}\n \ + Police: {self.government.law}\n \ + Pirates: {self.government.crime}\n \ + Pressure: {self.soci_pressure}\n \ + --------------- + """ + return info + + @staticmethod + def system_info_headers() -> list[str]: + """Reference for making window""" + # ? Maybe should be in a "UI" data module? + return [ + "Name:", + "Size:", + "Tech level:", + "Government:", + "Resources:", + "Police:", + "Pirates:", + ] + + def system_info(self) -> list[str]: + return [ + self.name, + Size.name(self.size), + TechLevel.name(self.tech_level), + self.get_government_name(), + SpecialResource.name(self.special_resource), + Activity.name(self.government.law), + Activity.name(self.government.crime), + ] + + def get_location(self) -> tuple[int, int]: + return (self.x, self.y) + + def get_size(self) -> int: + return self.size + + def get_tech_level(self) -> int: + return self.tech_level + + def set_visited(self) -> None: + self.visited = True + + def set_tech_level(self, value) -> None: + self.tech_level = value + + # TODO implement + def dest_is_ok(self) -> bool: + """ + Check if the destination is reachable with the current fuel level + Also account for wormholes + + return: bool - whether the destination is reachable + """ + raise NotImplementedError("Planet.dest_is_ok not implemented") + # comm = Game.current_game.commander + # return self != comm.current_system and ( + # self.get_distance() <= comm.ship.fuel or Functions.wormhole_exists(comm.current_system, self) + # ) + + def get_distance(self, target_planet=None): + return int(floor(sqrt(pow(self.x - target_planet.x, 2) + pow(self.y - target_planet.y, 2)))) + + # Political Interfaces + # TODO maybe change to alter_ and handle political shift logic here + def set_govt_type(self, value) -> None: + self.government = value + + def get_govt_type(self) -> PoliticalSystem: + return self.government + + def get_government_name(self) -> str: + return str(self.government) + + # Economic Interfaces + def get_pressure(self) -> int: + """ + Societal pressures: + + 0 = under no particular pressure; Uneventful + 1 = at war; Ore and Weapons in demand + 2 = ravaged by a plague; Medicine in demand + 3 = suffering from a drought; Water in demand + 4 = suffering from extreme boredom; Games and Narcotics in demand + 5 = suffering from a cold spell; Furs in demand + 6 = suffering from a crop failure; Food in demand + 7 = lacking enough workers; Machinery and Robots in demand + """ + return self.soci_pressure + + def set_pressure(self, value: int) -> None: + self.soci_pressure = value + + def get_special_resource(self) -> int: + """ + Special resources: + + 0 = Nothing Special + 1 = Mineral Rich + 2 = Mineral Poor + 3 = Desert + 4 = Sweetwater Oceans + 5 = Rich Soil + 6 = Poor Soil + 7 = Rich Fauna + 8 = Lifeless + 9 = Weird Mushrooms + 10 = Special Herbs + 11 = Artistic Populace + 12 = Warlike Populace + """ + if self.visited: + return self.special_resource + # TODO maybe not random here? + else: + self.special_resource = SpecialResource.random() + return self.special_resource + + def initialize_trade_items(self): + """ + Set the starting quantity of each trade good for the planet + """ + + for item_id in Ware.enum(): + + # Make sure the item is allowed to be traded + if not self.is_item_traded(item_id): + self.trade_items[item_id] = 0 + else: + # Quantity is dictated by the planet tech level, size, and a bit of randomness + self.trade_items[item_id] = (self.size + 1) * ( + randint(9, 14) - abs(TRADEITEMS[item_id].tech_level_max - self.tech_level) + ) + + # Because of the enormous profitssss possible, + # there shouldn't be too many robots or narcotics available + if item_id >= Ware.NARCOTICS: + self.trade_items[item_id] = ( + (self.trade_items[item_id] * (5 - TMPGAMEDIFFICULTY)) / (6 - TMPGAMEDIFFICULTY) + ) + 1 + + # Adjust for special resources and societal pressures + if self.special_resource == TRADEITEMS[item_id].special_resource_drop: + self.trade_items[item_id] = self.trade_items[item_id] * 4 / 3 + if self.special_resource == TRADEITEMS[item_id].special_resource_hike: + self.trade_items[item_id] = self.trade_items[item_id] * 3 / 4 + if self.soci_pressure == TRADEITEMS[item_id].pressure: + self.trade_items[item_id] = self.trade_items[item_id] / 5 + + # Another small random factor + self.trade_items[item_id] = self.trade_items[item_id] - randint(1, 10) + randint(1, 10) + + # Finally just make sure it's not negative + if self.trade_items[item_id] < 0: + self.trade_items[item_id] = 0 + + def is_item_traded(self, item) -> bool: + """ + Given an item ID, check with the planets political system to see if it can be traded + + params: item - item ID to check + + return: bool - whether the item can be traded + """ + + if item not in [Ware.FIREARMS, Ware.NARCOTICS]: + return True + + if item == Ware.FIREARMS: + return self.government.firearms_ok() + + elif item == Ware.NARCOTICS: + return self.government.drugs_ok() + + else: + raise ValueError(f"Item ID {item} not valid!") + + def item_used(self, item): + raise NotImplementedError("Planet.item_used not implemented") + # return ( + # (item.item_type != d.NARCOTICS or self.get_political_system().is_drugs_ok()) + # and (item.item_type != d.FIREARMS or self.get_political_system().is_firearms_ok()) + # and self.tech_level.cast_to_int() >= item.tech_usage.cast_to_int() + # ) + + def get_inventory(self): + return self.trade_items + + # Misc Interfaces + # TODO implement + def get_mercenaries_for_hire(self) -> list: + """ + Commander cmdr = Game.CurrentGame.Commander; + CrewMember[] mercs = Game.CurrentGame.Mercenaries; + ArrayList forHire = new ArrayList(3); + + for (int i = 1; i < mercs.Length; i++) + { + if (mercs[i].CurrentSystem == cmdr.CurrentSystem && !cmdr.Ship.HasCrew(mercs[i].Id)) + forHire.Add(mercs[i]); + } + + return (CrewMember[])forHire.ToArray(typeof(CrewMember)); + """ + raise NotImplementedError("Planet.get_mercenaries_for_hire not implemented") + # cmdr = Game.current_game.commander + # return [ + # merc + # for merc in Game.current_game.mercenaries.values() + # if merc.is_mercenary() and merc.current_system == cmdr.current_system and not cmdr.ship.has_crew(merc.id) + # ] + + def is_quest_system(self) -> bool: + return self.quest_system + + def set_quest_system(self, value) -> None: + self.quest_system = value + + # TODO implement + def show_quest_button(self): + """ + public bool ShowSpecialButton() + { + Game game = Game.CurrentGame; + bool show = false; + + switch (SpecialEventType) + { + case SpecialEventType.Artifact: + case SpecialEventType.Dragonfly: + case SpecialEventType.Experiment: + case SpecialEventType.Jarek: + show = game.Commander.PoliceRecordScore >= Consts.PoliceRecordScoreDubious; + break; + case SpecialEventType.ArtifactDelivery: + show = game.Commander.Ship.ArtifactOnBoard; + break; + case SpecialEventType.CargoForSale: + show = game.Commander.Ship.FreeCargoBays >= 3; + break; + case SpecialEventType.DragonflyBaratas: + show = game.QuestStatusDragonfly > SpecialEvent.StatusDragonflyNotStarted && + game.QuestStatusDragonfly < SpecialEvent.StatusDragonflyDestroyed; + break; + case SpecialEventType.DragonflyDestroyed: + show = game.QuestStatusDragonfly == SpecialEvent.StatusDragonflyDestroyed; + break; + case SpecialEventType.DragonflyMelina: + show = game.QuestStatusDragonfly > SpecialEvent.StatusDragonflyFlyBaratas && + game.QuestStatusDragonfly < SpecialEvent.StatusDragonflyDestroyed; + break; + case SpecialEventType.DragonflyRegulas: + show = game.QuestStatusDragonfly > SpecialEvent.StatusDragonflyFlyMelina && + game.QuestStatusDragonfly < SpecialEvent.StatusDragonflyDestroyed; + break; + case SpecialEventType.DragonflyShield: + case SpecialEventType.ExperimentFailed: + case SpecialEventType.Gemulon: + case SpecialEventType.GemulonFuel: + case SpecialEventType.GemulonInvaded: + case SpecialEventType.Lottery: + case SpecialEventType.ReactorLaser: + case SpecialEventType.PrincessQuantum: + case SpecialEventType.SculptureHiddenBays: + case SpecialEventType.Skill: + case SpecialEventType.SpaceMonster: + case SpecialEventType.Tribble: + show = true; + break; + case SpecialEventType.EraseRecord: + case SpecialEventType.Wild: + show = game.Commander.PoliceRecordScore < Consts.PoliceRecordScoreDubious; + break; + case SpecialEventType.ExperimentStopped: + show = game.QuestStatusExperiment > SpecialEvent.StatusExperimentNotStarted && + game.QuestStatusExperiment < SpecialEvent.StatusExperimentPerformed; + break; + case SpecialEventType.GemulonRescued: + show = game.QuestStatusGemulon > SpecialEvent.StatusGemulonNotStarted && + game.QuestStatusGemulon < SpecialEvent.StatusGemulonTooLate; + break; + case SpecialEventType.Japori: + show = game.QuestStatusJapori == SpecialEvent.StatusJaporiNotStarted && + game.Commander.PoliceRecordScore >= Consts.PoliceRecordScoreDubious; + break; + case SpecialEventType.JaporiDelivery: + show = game.QuestStatusJapori == SpecialEvent.StatusJaporiInTransit; + break; + case SpecialEventType.JarekGetsOut: + show = game.Commander.Ship.JarekOnBoard; + break; + case SpecialEventType.Moon: + show = game.QuestStatusMoon == SpecialEvent.StatusMoonNotStarted && + game.Commander.Worth > SpecialEvent.MoonCost * .8; + break; + case SpecialEventType.MoonRetirement: + show = game.QuestStatusMoon == SpecialEvent.StatusMoonBought; + break; + case SpecialEventType.Princess: + show = game.Commander.PoliceRecordScore >= Consts.PoliceRecordScoreLawful && + game.Commander.ReputationScore >= Consts.ReputationScoreAverage; + break; + case SpecialEventType.PrincessCentauri: + show = game.QuestStatusPrincess >= SpecialEvent.StatusPrincessFlyCentauri && + game.QuestStatusPrincess <= SpecialEvent.StatusPrincessFlyQonos; + break; + case SpecialEventType.PrincessInthara: + show = game.QuestStatusPrincess >= SpecialEvent.StatusPrincessFlyInthara && + game.QuestStatusPrincess <= SpecialEvent.StatusPrincessFlyQonos; + break; + case SpecialEventType.PrincessQonos: + show = game.QuestStatusPrincess == SpecialEvent.StatusPrincessRescued && + !game.Commander.Ship.PrincessOnBoard; + break; + case SpecialEventType.PrincessReturned: + show = game.Commander.Ship.PrincessOnBoard; + break; + case SpecialEventType.Reactor: + show = game.QuestStatusReactor == SpecialEvent.StatusReactorNotStarted && + game.Commander.PoliceRecordScore < Consts.PoliceRecordScoreDubious && + game.Commander.ReputationScore >= Consts.ReputationScoreAverage; + break; + case SpecialEventType.ReactorDelivered: + show = game.Commander.Ship.ReactorOnBoard; + break; + case SpecialEventType.Scarab: + show = game.QuestStatusScarab == SpecialEvent.StatusScarabNotStarted && + game.Commander.ReputationScore >= Consts.ReputationScoreAverage; + break; + case SpecialEventType.ScarabDestroyed: + case SpecialEventType.ScarabUpgradeHull: + show = game.QuestStatusScarab == SpecialEvent.StatusScarabDestroyed; + break; + case SpecialEventType.Sculpture: + show = game.QuestStatusSculpture == SpecialEvent.StatusSculptureNotStarted && + game.Commander.PoliceRecordScore < Consts.PoliceRecordScoreDubious && + game.Commander.ReputationScore >= Consts.ReputationScoreAverage; + break; + case SpecialEventType.SculptureDelivered: + show = game.QuestStatusSculpture == SpecialEvent.StatusSculptureInTransit; + break; + case SpecialEventType.SpaceMonsterKilled: + show = game.QuestStatusSpaceMonster == SpecialEvent.StatusSpaceMonsterDestroyed; + break; + case SpecialEventType.TribbleBuyer: + show = game.Commander.Ship.Tribbles > 0; + break; + case SpecialEventType.WildGetsOut: + show = game.Commander.Ship.WildOnBoard; + break; + default: + break; + } + + return show; + } + """ + raise NotImplementedError("Planet.show_quest_button not implemented") class Universe: @@ -126,3 +1061,57 @@ def extra_planet_shuffle(self): for wh in self.wormholes: new_index = randint(0, len(self.wormholes) - 1) wh, self.wormholes[new_index] = self.wormholes[new_index], wh + + +def planet_distance(planet: tuple[int, int], x2: int, y2: int) -> float: + """ + Calculate the distance between a planet and a point. + + params: planet - tuple containing the x and y coordinates of the planet + params: x2 - x coordinate of point 2 + params: y2 - y coordinate of point 2 + + returns: distance between the planet and the point + """ + return distance(planet[0], planet[1], x2, y2) + + +def distance(x1: int, y1: int, x2: int, y2: int) -> float: + """ + Calculate the distance between two points. + + params: x1 - x coordinate of point 1 + params: y1 - y coordinate of point 1 + params: x2 - x coordinate of point 2 + params: y2 - y coordinate of point 2 + + returns: distance between the two points + """ + return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5 + + +def wormhole_exists(wormholes: list[int], a: int, b: int) -> bool: + """ + Check if a wormhole exists at the given coordinates. + + params: wormholes - list of wormholes + params: a - first wormhole + params: b - second wormhole, or -1 if only checking for any wormhole at a + + returns: True if wormhole exists, False otherwise + """ + + # TODO bit of a mess, probably should have small separate functions for each check + if a in wormholes: + + if b < 0: + return True + + index = wormholes.index(a) + if index < MAX_WORMHOLES - 1: + if wormholes[index + 1] == b: + return True + elif wormholes[0] == b: + return True + + return False diff --git a/src/utils.py b/src/utils.py index eb0eb9e..e4fd911 100644 --- a/src/utils.py +++ b/src/utils.py @@ -12,62 +12,6 @@ import sys from typing import Union -from .constants import MAX_WORMHOLES - - -def planet_distance(planet: tuple[int, int], x2: int, y2: int) -> float: - """ - Calculate the distance between a planet and a point. - - params: planet - tuple containing the x and y coordinates of the planet - params: x2 - x coordinate of point 2 - params: y2 - y coordinate of point 2 - - returns: distance between the planet and the point - """ - return distance(planet[0], planet[1], x2, y2) - - -def distance(x1: int, y1: int, x2: int, y2: int) -> float: - """ - Calculate the distance between two points. - - params: x1 - x coordinate of point 1 - params: y1 - y coordinate of point 1 - params: x2 - x coordinate of point 2 - params: y2 - y coordinate of point 2 - - returns: distance between the two points - """ - return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5 - - -def wormhole_exists(wormholes: list[int], a: int, b: int) -> bool: - """ - Check if a wormhole exists at the given coordinates. - - params: wormholes - list of wormholes - params: a - first wormhole - params: b - second wormhole, or -1 if only checking for any wormhole at a - - returns: True if wormhole exists, False otherwise - """ - - # TODO bit of a mess, probably should have small separate functions for each check - if a in wormholes: - - if b < 0: - return True - - index = wormholes.index(a) - if index < MAX_WORMHOLES - 1: - if wormholes[index + 1] == b: - return True - elif wormholes[0] == b: - return True - - return False - class FontManager: diff --git a/testing/test_universe.py b/testing/test_universe.py index 91ab6f2..0e2fbe8 100644 --- a/testing/test_universe.py +++ b/testing/test_universe.py @@ -4,8 +4,7 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) import src.constants as c import src.game_data as gd -from src.planet import Planet -from src.universe import Universe +from src.universe import Planet, Universe testverse = Universe()