A save state/password generator for the original Metroid.
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.

metroidgen.py 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import random
  2. class MetroidState:
  3. def __init__(self):
  4. self.itemsCollected = {
  5. "Maru Mari": False,
  6. "Bombs": False,
  7. "Long Beam": False,
  8. "Ice Beam": False,
  9. "Wave Beam": False,
  10. "High Jump Boots": False,
  11. "Varia": False,
  12. "Screw Attack": False
  13. }
  14. self.samusHas = {
  15. "Maru Mari": False,
  16. "Bombs": False,
  17. "Long Beam": False,
  18. "Ice Beam": False,
  19. "Wave Beam": False,
  20. "High Jump Boots": False,
  21. "Varia": False,
  22. "Screw Attack": False
  23. }
  24. self.missileTanks = {
  25. 1: False,
  26. 2: False,
  27. 3: False,
  28. 4: False,
  29. 5: False,
  30. 6: False,
  31. 7: False,
  32. 8: False,
  33. 9: False,
  34. 10: False,
  35. 11: False,
  36. 12: False,
  37. 13: False,
  38. 14: False,
  39. 15: False,
  40. 16: False,
  41. 17: False,
  42. 18: False,
  43. 19: False,
  44. 20: False,
  45. 21: False
  46. }
  47. self.energyTanks = {
  48. 1: False,
  49. 2: False,
  50. 3: False,
  51. 4: False,
  52. 5: False,
  53. 6: False,
  54. 7: False,
  55. 8: False
  56. }
  57. self.zebetitesDestroyed = {
  58. 1: False,
  59. 2: False,
  60. 3: False,
  61. 4: False,
  62. 5: False
  63. }
  64. self.doors = {
  65. "Brinstar": {
  66. 1: False,
  67. 2: False,
  68. 3: False,
  69. 4: False,
  70. 5: False
  71. }, "Norfair": {
  72. 1: False,
  73. 2: False,
  74. 3: False,
  75. 4: False
  76. }, "Kraid": {
  77. 1: False,
  78. 2: False,
  79. 3: False,
  80. 4: False,
  81. 5: False
  82. }, "Ridley": {
  83. 1: False,
  84. 2: False
  85. }, "Tourian": {
  86. 1: False,
  87. 2: False,
  88. 3: False
  89. }
  90. }
  91. self.kraidKilled = False
  92. self.ridleyKilled = False
  93. self.motherBrainKilled = False
  94. self.kraidStatue = False
  95. self.ridleyStatue = False
  96. self.swimsuit = False
  97. self.missileCount = 0
  98. self.gameAge = 0
  99. self.locations = ["Brinstar", "Norfair", "Kraid's Lair", "Ridley's Lair", "Tourian"]
  100. self.startLocation = 0
  101. def toggleItem(self, itm):
  102. if itm in self.itemsCollected.keys():
  103. self.itemsCollected[itm] = not self.itemsCollected[itm]
  104. self.samusHas[itm] = not self.samusHas[itm]
  105. else:
  106. print("Couldn't find item: {}".format(str(itm)))
  107. def toggleMissileTank(self, num):
  108. try:
  109. num = int(num)
  110. except:
  111. print("{} is not a number".format(num))
  112. return
  113. if num in self.missileTanks.keys():
  114. self.missileTanks[num] = not self.missileTanks[num]
  115. else:
  116. print("Couldn't find missile tank: {}".format(num))
  117. def toggleEnergyTank(self, num):
  118. try:
  119. num = int(num)
  120. except:
  121. print("{} is not a number".format(num))
  122. return
  123. if num in self.energyTanks.keys():
  124. self.energyTanks[num] = not self.energyTanks[num]
  125. else:
  126. print("Couldn't find energy tank: {}".format(num))
  127. def toggleZebetite(self, num):
  128. try:
  129. num = int(num)
  130. except:
  131. print("{} is not a number".format(num))
  132. return
  133. if num in self.zebetitesDestroyed.keys():
  134. self.zebetitesDestroyed[num] = not self.zebetitesDestroyed[num]
  135. else:
  136. print("Couldn't find Zebetite: {}".format(num))
  137. def toggleKraid(self):
  138. self.kraidKilled = not self.kraidKilled
  139. self.kraidStatue = self.kraidKilled
  140. def toggleKraidStatue(self):
  141. self.kraidStatue = not self.kraidStatue
  142. if self.kraidKilled and not self.kraidStatue:
  143. print("WARNING: Kraid has been killed but his statue has not been raised.")
  144. def toggleRidley(self):
  145. self.ridleyKilled = not self.ridleyKilled
  146. self.ridleyStatue = self.ridleyKilled
  147. def toggleRidleyStatue(self):
  148. self.ridleyStatue = not self.ridleyStatue
  149. if self.ridleyKilled and not self.ridleyStatue:
  150. print("WARNING: Ridley has been killed but his statue has not been raised.")
  151. def toggleMotherBrain(self):
  152. self.motherBrainKilled = not self.motherBrainKilled
  153. def toggleDoor(self, area, door):
  154. try:
  155. area = str(area)
  156. door = int(door)
  157. except:
  158. print("Area must be string, door must be a positive integer")
  159. return
  160. if area in self.doors.keys() and int(door) in self.doors[area].keys():
  161. self.doors[area][door] = not self.doors[area][door]
  162. else:
  163. print("Couldn't find door {} in area {}".format(door, area))
  164. def toggleSwimsuit(self):
  165. self.swimsuit = not self.swimsuit
  166. def newLocation(self, loc):
  167. try:
  168. loc = str(loc)
  169. except:
  170. print("Location must be a string")
  171. return
  172. if loc in self.locations:
  173. self.startLocation = self.locations.index(loc)
  174. else:
  175. print("Couldn't find location: {}".format(loc))
  176. def collectedItems(self):
  177. o = []
  178. for k,v in self.itemsCollected.items():
  179. if v == True:
  180. o.append(k)
  181. if len(o) == 0:
  182. return "None"
  183. else:
  184. return ", ".join(o)
  185. def collectedMissiles(self):
  186. o = []
  187. for k, v in self.missileTanks.items():
  188. if v == True:
  189. o.append(k)
  190. if len(o) == 0:
  191. return "None"
  192. else:
  193. return ", ".join([str(b) for b in o])
  194. def collectedEtanks(self):
  195. o = []
  196. for k, v in self.energyTanks.items():
  197. if v == True:
  198. o.append(k)
  199. if len(o) == 0:
  200. return "None"
  201. else:
  202. return ", ".join([str(b) for b in o])
  203. def killedZebetites(self):
  204. o = []
  205. for k, v in self.zebetitesDestroyed.items():
  206. if v == True:
  207. o.append(k)
  208. if len(o) == 0:
  209. return "None"
  210. else:
  211. return ", ".join([str(b) for b in o])
  212. def killedBosses(self):
  213. o = []
  214. if self.kraidKilled:
  215. o.append("Kraid")
  216. if self.ridleyKilled:
  217. o.append("Ridley")
  218. if self.motherBrainKilled:
  219. o.append("Mother Brain")
  220. if len(o) == 0:
  221. return "None"
  222. else:
  223. return ", ".join(o)
  224. def raisedStatues(self):
  225. o = []
  226. if self.kraidStatue:
  227. o.append("Kraid")
  228. if self.ridleyStatue:
  229. o.append("Ridley")
  230. if len(o) == 0:
  231. return "None"
  232. else:
  233. return ", ".join(o)
  234. def inBailey(self):
  235. if self.swimsuit:
  236. return "Yes"
  237. else:
  238. return "No"
  239. def toString(self):
  240. ic = "Items Collected: {}".format(self.collectedItems())
  241. mt = "Missile Tanks Collected: {}".format(self.collectedMissiles())
  242. et = "Energy Tanks Collected: {}".format(self.collectedEtanks())
  243. zb = "Zebetites Killed: {}".format(self.killedZebetites())
  244. kb = "Bosses Killed: {}".format(self.killedBosses())
  245. rs = "Statues Raised: {}".format(self.raisedStatues())
  246. sw = "Swimsuit?: {}".format(self.inBailey())
  247. sl = "Start Location: {}".format(self.locations[self.startLocation])
  248. dr = ""
  249. return "\n".join([ic, mt, et, zb, kb, rs, sw, sl, dr])
  250. def randomize(self):
  251. # Items
  252. if random.randint(0,1) == 1:
  253. self.toggleItem("Maru Mari")
  254. if random.randint(0,1) == 1:
  255. self.toggleItem("Bombs")
  256. if random.randint(0,1) == 1:
  257. self.toggleItem("Varia")
  258. if random.randint(0,1) == 1:
  259. self.toggleItem("High Jump Boots")
  260. if random.randint(0,1) == 1:
  261. self.toggleItem("Screw Attack")
  262. if random.randint(0,1) == 1:
  263. self.toggleItem("Long Beam")
  264. beam = random.randint(0,2)
  265. if beam == 1:
  266. self.toggleItem("Ice Beam")
  267. elif beam == 2:
  268. self.toggleItem("Wave Beam")
  269. # Missile Tanks
  270. for i in range(21):
  271. if random.randint(0,1) == 1:
  272. self.toggleMissileTank(i+1)
  273. # Energy Tanks
  274. for i in range(8):
  275. if random.randint(0,1) == 1:
  276. self.toggleEnergyTank(i+1)
  277. # Zebetites
  278. for i in range(5):
  279. if random.randint(0,1) == 1:
  280. self.toggleZebetite(i+1)
  281. # Bosses killed
  282. if random.randint(0,1) == 1:
  283. self.toggleKraid()
  284. if random.randint(0,1) == 1:
  285. self.toggleRidley()
  286. if random.randint(0,1) == 1:
  287. self.toggleMotherBrain()
  288. # Statues raised
  289. if not self.kraidKilled and random.randint(0,1) == 1:
  290. self.toggleKraidStatue()
  291. if not self.ridleyKilled and random.randint(0,1) == 1:
  292. self.toggleRidleyStatue()
  293. # Swimsuit
  294. if random.randint(0,2) == 2:
  295. self.toggleSwimsuit()
  296. # Start Location
  297. self.startLocation = random.randint(0,4)
  298. def main():
  299. gs = MetroidState()
  300. gs.randomize()
  301. print(gs.toString())
  302. if __name__ == "__main__":
  303. main()