A generator for *Star Wars* interstellar shipping and passenger jobs, based loosely on the missions you can take on in *Escape Velocity* and *Endless Space*.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import argparse, re
  2. from string import Template
  3. from typing import NamedTuple
  4. from jinja2 import Environment, PackageLoader, select_autoescape
  5. # global variables
  6. env = Environment(
  7. loader=PackageLoader("swjg"),
  8. autoescape=select_autoescape
  9. )
  10. parser = argparse.ArgumentParser()
  11. # helper functions
  12. def get_identifiers_from_template(template):
  13. # Template.get_identifiers() doesn't appear until Python 3.11
  14. # Don't substitute anything; get the raw string
  15. template_str = Template.safe_substitute()
  16. matches = re.findall("\$[a-z0-9_\.]+", template_str)
  17. matches = [x[1:] for x in matches]
  18. return matches
  19. # classes and such
  20. class Destination(NamedTuple):
  21. world: str
  22. system: str|None
  23. sector: str|None
  24. class Mission:
  25. output_destination_template = Template("to $world in the $system system")
  26. output_sector_template = Template(", part of the $sector,")
  27. value_template = Template("for $value credits")
  28. error_template = Template("You haven't given this mission some of the values it needs. Please check: $potential_values")
  29. def __init__(self, destination:Destination, value:int, *args, **kwargs):
  30. # destination: Destination (see above)
  31. self.world = destination.world if destination.world is not None else None
  32. self.system = destination.system if destination.system is not None else destination.world
  33. self.sector = destination.sector if destination.sector is not None else None
  34. self.value = value
  35. # for arg, val in kwargs.items():
  36. # setattr(self, arg, val)
  37. def assemble_templates(self) -> list:
  38. # Override this in children
  39. template_list = []
  40. if self.world != None:
  41. template_list.append(self.output_destination_template)
  42. if self.sector != None:
  43. template_list.append(self.output_sector_template)
  44. template_list.append(self.value_template)
  45. return template_list
  46. def get_current_values(self) -> dict:
  47. return {
  48. "world": self.world,
  49. "system": self.system,
  50. "sector": self.sector,
  51. "value": self.value
  52. }
  53. def missing_values(self) -> list:
  54. object_vars = vars(self)
  55. missing = []
  56. for key, val in object_vars.items():
  57. if val == None:
  58. missing.append(key)
  59. return missing
  60. def assemble_text(self) -> str:
  61. missing_vals = self.missing_values()
  62. templates = self.assemble_templates()
  63. if len(templates) == 0 or len(missing_vals) != 0: # either both of these should be true or neither should
  64. raise ValueError(self.error_template.substitute(potential_values=missing_vals))
  65. current_values = self.get_current_values()
  66. output = []
  67. for template in templates:
  68. output.append(template.substitute(**current_values))
  69. out_text = " ".join(output)
  70. out_text = out_text.replace(" ,", ",")
  71. out_text += "."
  72. return out_text
  73. class PassengerMission(Mission):
  74. output_initial_template = Template("Bring $number passengers")
  75. def __init__(self, number:int, *args, **kwargs):
  76. super(PassengerMission, self).__init__(*args, **kwargs)
  77. self.number = number
  78. def get_current_values(self) -> dict:
  79. base_dict = super(PassengerMission, self).get_current_values()
  80. new_dict = {
  81. "number": self.number
  82. }
  83. base_dict.update(new_dict)
  84. return base_dict
  85. def assemble_templates(self):
  86. template_list = [self.output_initial_template]
  87. template_list.extend(super(PassengerMission, self).assemble_templates())
  88. return template_list
  89. def assemble_text(self) -> str:
  90. return super(PassengerMission, self).assemble_text()
  91. class CargoMission(Mission):
  92. output_initial_template = Template("Deliver $tons tons of $item")
  93. output_time_timeplate = Template("in the next $time days")
  94. def __init__(self, tons:int, item:str, time:int, *args, **kwargs):
  95. # tons: integer
  96. # item: string (this will not be pluralized in the text)
  97. # time: integer (number of days the crew have to complete delivery)
  98. # value: integer (value in credits)
  99. super(CargoMission, self).__init__(*args, **kwargs)
  100. self.tons = tons
  101. self.item = item
  102. self.time = time
  103. def get_current_values(self) -> dict:
  104. base_dict = super(CargoMission, self).get_current_values()
  105. new_dict = {
  106. "tons": self.tons,
  107. "item": self.item,
  108. "time": self.time
  109. }
  110. base_dict.update(new_dict)
  111. return base_dict
  112. def assemble_templates(self):
  113. template_list = [self.output_initial_template]
  114. if self.time is not None:
  115. template_list.append(self.output_time_timeplate)
  116. template_list.extend(super(CargoMission, self).assemble_templates())
  117. return template_list
  118. def assemble_text(self) -> str:
  119. return super(CargoMission, self).assemble_text()
  120. class GroupMission(Mission):
  121. output_initial_template = Template("Bring $number members of a $group")
  122. def __init__(self, number:int, group:str, *args, **kwargs):
  123. super(GroupMission, self).__init__(*args, **kwargs)
  124. self.number = number
  125. self.group = group
  126. def get_current_values(self) -> dict:
  127. base_dict = super(GroupMission, self).get_current_values()
  128. new_dict = {
  129. "number": self.number,
  130. "group": self.group
  131. }
  132. base_dict.update(new_dict)
  133. return base_dict
  134. def assemble_templates(self):
  135. template_list = [self.output_initial_template]
  136. template_list.extend(super(GroupMission, self).assemble_templates())
  137. return template_list
  138. def assemble_text(self) -> str:
  139. return super(GroupMission, self).assemble_text()
  140. # the function that does the thing
  141. def main():
  142. import random
  143. mission_types = [PassengerMission, CargoMission, GroupMission]
  144. missions = []
  145. for _ in range(5):
  146. current_mission = random.choice(mission_types)
  147. destination = Destination("Alderaan", None, "Core Worlds")
  148. number = random.randint(1,8)
  149. tons = random.randint(4, 12)
  150. item = random.choice(["gravel", "computer chips", "spice", "live ysalamiri", "empty shipping containers"])
  151. time = random.randint(7, 31)
  152. value = random.randint(20, 120) * 1000
  153. group = None
  154. if current_mission == GroupMission:
  155. group = random.choice(["family", "performing troupe", "acrobatic troupe"])
  156. missions.append(current_mission(destination=destination, number=number, tons=tons, item=item, time=time, value=value, group=group))
  157. for mission in missions:
  158. # print(mission, mission.__dict__)
  159. print(mission.assemble_text())
  160. # Don't do anything if the module is loaded wholesale into something else
  161. if __name__ == "__main__":
  162. main()