Lycanphoenix

MechEngine Beta (0.30.73)

May 23rd, 2018
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 34.87 KB | None | 0 0
  1. print("MechEngine Beta, 0.30.73");
  2. print("Build Date: 2018-05-23. Designed using Python 3.6.4 Stackless Shell");
  3. import math, os, sys, time, datetime, threading, builtins
  4. def gettime():
  5.     now = datetime.datetime.now()
  6.     return print("Current Time and Date, Local:", now.strftime("%A, %Y-%m-%d, %H:%M:%S %z"))
  7. gettime()
  8. print();
  9.  
  10. #Development Goals:
  11.      #Add options to restart program and/or export log upon completion.
  12.      #Add engine descriptions to help the user make an informed decision.
  13.     #Add example mechs to choose from
  14.  
  15. def fib(n):    # write Fibonacci series up to n
  16.      """Print a Fibonacci series up to n."""
  17.      a, b = 0, 1
  18.      while a <= n:
  19.          print(a, end=" ");
  20.          a, b = b, a + b
  21.      print();
  22.  
  23. def mem_fib(n, _cache={}):
  24.     '''efficiently memoized recursive function, returns a Fibonacci number with n iterations.'''
  25.     if n in _cache:
  26.         return _cache[n]
  27.     elif n > 1:
  28.         return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
  29.     return n
  30.  
  31. def printfib(n):
  32.     for i in range(n):
  33.         print(i, mem_fib(i))
  34.  
  35. def RoundUp5(x):
  36.   return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5
  37.  
  38. def RoundUpHalf(x):
  39.   return math.ceil(x*2.0)/2.0
  40.  
  41. def RoundUpQuarter(x):
  42.   return math.ceil(x*4.0)/4.0
  43.  
  44. def RoundUpFractional(x):
  45.   return math.ceil(x*1000.0)/1000.0
  46.  
  47. def RoundDown5(x):
  48.   return math.floor(x / 5.0) * 5
  49.  
  50. def RoundDownHalf(x):
  51.   return math.floor(x*2.0)/2.0
  52.  
  53. def RoundDownQuarter(x):
  54.   return math.floor(x*4.0)/4.0
  55.  
  56. def RoundDownFractional(x):
  57.   return math.floor(x*1000.0)/1000.0
  58.  
  59. def roundNearest(f):
  60.     return round(f + .00000000000001);
  61.  
  62. #Deprecated
  63. def roundHalfUp(f): #deprecated!
  64.     return RoundUpHalf(f) #round(f + 0.00000000000001)
  65.  
  66. def roundEngine(x, base=5): #deprecated!
  67.     return int(base * RoundUpHalf(float(x)/base));
  68.  
  69. def roundTonnage(x, base=5): #deprecated!
  70.     return int(base * RoundUpHalf(float(x)/base));
  71. #End Deprecation
  72.  
  73. #HYN-DRN-5813 Core Input Dictionary:
  74. def clamp(min_value, max_value, x):
  75.   """Returns x, limited to the range min_val to max_val."""
  76.   return max(min(x, max_value), min_value)
  77.  
  78. def RepresentsInt(s):
  79.   try:
  80.     int(s)
  81.     return True
  82.   except ValueError:
  83.     return False
  84.  
  85. def ask(question, min_val, max_val):
  86.   x = ''
  87.   while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
  88.     x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
  89.   return clamp(min_val, max_val, int(x))
  90.  
  91. MechType = ("Biped")
  92. #def PromptMechType()
  93. #NewMechType = PromptMechType()
  94. #MechType = NewMechType
  95. CurrentMechType = MechType
  96.  
  97. Inputs = {"BattleMech’s Tonnage": {"min":2, "max":200, "value": None},
  98.           "desired Walk MP" : {"min":1, "max":30 , "value": None},
  99. #          "desired number of additional Heat Sinks": {"min:":0, "max":100, "value": None},
  100.           }
  101.  
  102. def load_inputs(inputs_dict):
  103.   """Iterate over the given inputs dictionary, asking the user for each
  104.   and setting their values"""
  105.   for name in inputs_dict:
  106.     #name takes each key in the dictionary, which in this case is names of inputs
  107.     inputs_dict[name]["value"] = ask("Please provide your %s"%name,
  108.                                      inputs_dict[name]["min"],
  109.                                      inputs_dict[name]["max"])
  110.  
  111. #"Load inputs"
  112. print ("Hint: One ground hex = 30 meters, one turn = 10 seconds.")
  113. load_inputs(Inputs)
  114.  
  115. SuspFact = 0 #SuspFact = (input("Suspension Factor: "))
  116.  
  117. MechTonnage = (Inputs["BattleMech’s Tonnage"]["value"])
  118.  
  119. if MechTonnage < 10:
  120.     MechClass = ("ProtoMech")
  121.     MechName = ("ProtoMech")
  122. elif 9 < MechTonnage:
  123.     if MechTonnage < 20: MechClass = ("Ultralight")
  124.     elif 19 < MechTonnage < 36: MechClass = ("Light")
  125.     elif 35 < MechTonnage < 56: MechClass = ("Medium")
  126.     elif 55 < MechTonnage < 76: MechClass = ("Heavy")
  127.     elif 75 < MechTonnage < 101: MechClass = ("Assault")
  128.     elif 100 < MechTonnage: MechClass = ("SuperHeavy")
  129.     MechName = (MechClass + " BattleMech")
  130. else:
  131.     MechName = ("Unit")
  132.  
  133. NewMechName = input("Name your BattleMech: ");
  134. if NewMechName != '': MechName = NewMechName
  135. print()
  136. fib(MechTonnage)
  137. print();
  138.  
  139. CruisingSpeed = math.ceil(Inputs["desired Walk MP"]["value"]);
  140. def kph(s):
  141.     return (math.ceil(s*108))/10
  142. def metersec(s):
  143.     return (math.ceil(s*30))/10
  144. def mph(s):
  145.     return (math.ceil(s*671))/100
  146. #UserHeatSinks = (#(Inputs["desired number of additional Heat Sinks"]["value"]);
  147.  
  148. #"Do calculations"
  149. FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
  150. if MechTonnage > 15:
  151.     rating = max(10, RoundUp5((Inputs["BattleMech’s Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact));
  152. else:
  153.     rating = max(2, (Inputs["BattleMech’s Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact);
  154.  
  155. if rating >500:
  156.     print ("WARNING! This engine rating of", rating, "is outside normal parameters, and the weight has been extrapolated through a polynomial function.",
  157.             "Consent among all participating players must be reached before it can be used in an actual game.");
  158.  
  159. TableTuple = False
  160.  
  161. if TableTuple is True:
  162.     #"Master Engine Table:" (Tuple)
  163.     FusionEngineTable = {#See TechManual and Tactical Operations for more details
  164.       (5,10,15,20,25): 0.5, (30,35,40,45): 1.0, (50,55,60): 1.5, (65,70,75): 2.0, (80,85): 2.5, (90,95,100): 3.0,#Standard Gyro: 1 Ton.
  165.       (105,110): 3.5, (115,120,125): 4.0, (130,135): 4.5, (140,145): 5.0, (150,155): 5.5, (160,165,170): 6.0, (175,180): 7.0, (185,190): 7.5, (195,): 8.0, (200,205): 8.5,#Standard Gyro: 2 Tons.
  166.       (210,): 9.0, (215,): 9.5, (220,225): 10.0, (230,): 10.5, (235,): 11.0, (240,): 11.5, (245,): 12.0, (250,): 12.5, (255,): 13.0, (260,): 13.5, (265,): 14.0, (270,): 14.5, (275,): 15.5, (280,): 16.0, (285,): 16.5, (290,): 17.5, (295,): 18.0, (300,): 19.0,#Standard Gyro: 3 Tons.
  167.       (305,): 19.5, (310,): 20.5, (315,): 21.5, (320,): 22.5, (325,): 23.5, (330,): 24.5, (335,): 25.5, (340,): 27.0, (345,): 28.5, (350,): 29.5, (355,): 31.5, (360,): 33.0, (365,): 34.5, (370,): 36.5, (375,): 38.5, (380,): 41.0, (385,): 43.5, (390,): 46.0, (395,): 49.0, (400,): 52.5,#Standard Gyro: 4 Tons.
  168.       (405,): 56.5, (410,): 61.0, (415,): 66.5, (420,): 72.5, (425,): 79.5, (430,): 87.5, (435,): 97.0, (440,): 107.5, (445,): 119.5, (450,): 133.5, (455,): 150.0, (460,): 168.5, (465,): 190.0, (470,): 214.5, (475,): 243.0, (480,): 275.5, (485,): 313.0, (490,): 356.0, (495,): 405.5, (500,): 462.5#Standard Gyro: 5 Tons. XL Gyro: N/A.
  169.       }
  170.  
  171. else:
  172.     #"Master Engine Table:" (Backup)
  173.     FusionEngineTable = {#See TechManual and Tactical Operations for more details
  174.       5: 0.5, 10: 0.5, 15: 0.5, 20: 0.5, 25: 0.5, 30: 1.0, 35: 1.0, 40: 1.0, 45: 1.0, 50: 1.5, 55: 1.5, 60: 1.5, 65: 2.0, 70: 2.0, 75: 2.0, 80: 2.5, 85: 2.5, 90: 3.0, 95: 3.0, 100: 3.0,#Standard Gyro: 1 Ton. Compact Gyro: 1.5 Tons. XL Gyro: 0.5 Tons. Heavy-Duty Gyro: 2 Tons.
  175.       105: 3.5, 110: 3.5, 115: 4.0, 120: 4.0, 125: 4.0, 130: 4.5, 135: 4.5, 140: 5.0, 145: 5.0, 150: 5.5, 155: 5.5, 160: 6.0, 165: 6.0, 170: 6.0, 175: 7.0, 180: 7.0, 185: 7.5, 190: 7.5, 195: 8.0, 200: 8.5,#Standard Gyro: 2 Tons. Compact Gyro: 3 Tons. XL Gyro: 1 Ton. Heavy-Duty/SuperHeavy Gyro: 4 Tons.
  176.       205: 8.5, 210: 9.0, 215: 9.5, 220: 10.0, 225: 10.0, 230: 10.5, 235: 11.0, 240: 11.5, 245: 12.0, 250: 12.5, 255: 13.0, 260: 13.5, 265: 14.0, 270: 14.5, 275: 15.5, 280: 16.0, 285: 16.5, 290: 17.5, 295: 18.0, 300: 19.0,#Standard Gyro: 3 Tons. Compact Gyro: 4.5 Tons. XL Gyro: 1.5 Tons. Heavy-Duty/SuperHeavy Gyro: 6 Tons.
  177.       305: 19.5, 310: 20.5, 315: 21.5, 320: 22.5, 325: 23.5, 330: 24.5, 335: 25.5, 340: 27.0, 345: 28.5, 350: 29.5, 355: 31.5, 360: 33.0, 365: 34.5, 370: 36.5, 375: 38.5, 380: 41.0, 385: 43.5, 390: 46.0, 395: 49.0, 400: 52.5,#Standard Gyro: 4 Tons. Compact Gyro: 6 Tons. XL Gyro: 2 Tons. Heavy-Duty/SuperHeavy Gyro: 8 Tons.
  178.       405: 56.5, 410: 61.0, 415: 66.5, 420: 72.5, 425: 79.5, 430: 87.5, 435: 97.0, 440: 107.5, 445: 119.5, 450: 133.5, 455: 150.0, 460: 168.5, 465: 190.0, 470: 214.5, 475: 243.0, 480: 275.5, 485: 313.0, 490: 356.0, 495: 405.5, 500: 462.5#Standard Gyro: 5 Tons. Compact Gyro: 7.5 Tons. XL Gyro: N/A. Heavy-Duty/SuperHeavy Gyro: 10 Tons.
  179.       }
  180.  
  181.     #ProtoMechEngineTable = {#ProtoMechs, for engine ratings below 40, multiply the engine rating by 0.025 to find the mass. Afterwards, they use Standard Fusion Engine weights.
  182.     #    1: .025, 2: .050, 3: .075, 4: .100, 5: .125, 6: .150, 7: .175, 8: .200, 9: .225, 10: .250,
  183.     #    11: .275, 12: .300, 13: .325, 14: .350, 15: .375, 16: .400, 17: .425, 18: .450, 19: .475, 20: .500,
  184.     #    21: .525, 22: .550, 23: .575, 24: .600, 25: .625, 26: .650, 27: .675, 28: .700, 29: .725, 30: .750,
  185.     #    31: .775, 32: .800, 33: .825, 34: .850, 35: .875, 36: .900, 37: .925, 38: .950, 39: .975, 40: 1.0,}
  186.  
  187. def PromptEngineType():
  188.     """Ask the user for their desired engine type, then return it."""
  189.     #engine list:
  190.     if MechTonnage < 16 and rating < 401:
  191.         el = [#Basic Engine Types:
  192.               "Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
  193.               #Advanced Engine Types:
  194.               "XXL Fusion Engine", "Compact Fusion Engine",
  195.               #Non-Fusion Engines:
  196.               "Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
  197.               #Primitive Engines:
  198.               "Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
  199.               #Special Engine Types:
  200.               "Lithium-Fusion Engine", "ProtoMech Engine",
  201.               ]
  202.     elif MechTonnage < 16 and rating > 400:
  203.         el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine", "XXL Fusion Engine", "Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine", "Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine", "Lithium-Fusion Engine", "ProtoMech Engine"]
  204.     elif 15 < MechTonnage < 101 and rating < 401:
  205.         el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine","XXL Fusion Engine", "Compact Fusion Engine","Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine","Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine", "Lithium-Fusion Engine"]
  206.     elif 15 < MechTonnage < 101 and rating > 400:
  207.         el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine", "XXL Fusion Engine", "Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine", "Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine", "Lithium-Fusion Engine"]
  208.     elif MechTonnage > 100 and rating < 401:
  209.         el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine", "XXL Fusion Engine", "Compact Fusion Engine", "Fission Engine", "Lithium-Fusion Engine"]
  210.     elif MechTonnage > 100 and rating > 400:
  211.         el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine", "XXL Fusion Engine", "Fission Engine", "Lithium-Fusion Engine"]
  212.  
  213.     if rating < 401:
  214.         print("Engine types:");
  215.         for i in range(0, len(el)):
  216.             print("  (%d) %s"%(i, el[i]));
  217.         num = ask("Please select your desired Engine type", 0, len(el)-1);
  218.         print();
  219.         return el[num]
  220.     else:
  221.         print("Large Engine types:");
  222.         for i in range(0, len(el)):
  223.             print("  (%d) %s"%(i, el[i]));
  224.         num = ask("Please select your desired Large Engine type", 0, len(el)-1);
  225.         print();
  226.         return el[num]
  227.  
  228. if MechTonnage < 10:
  229.     EngineType = ("ProtoMech Engine")
  230. else:
  231.     EngineType = PromptEngineType()
  232.  
  233. if EngineType in {"ProtoMech Engine"}:
  234.     rating = (MechTonnage * FlankingSpeed) - SuspFact
  235.     if rating < 41:
  236.         rating = RoundUp5(rating)
  237.     if MechClass in {"Ultralight"}:
  238.         MechClass = ("UltraHeavy ProtoMech")
  239. else:
  240.     rating = RoundUp5((MechTonnage * CruisingSpeed) - SuspFact)
  241.  
  242. if EngineType in {"Lithium-Fusion Engine"}:
  243.     if CruisingSpeed < 2:
  244.         CruisingSpeed = 2
  245.         FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
  246.     elif CruisingSpeed > 1:
  247.         CruisingSpeed = (Inputs["desired Walk MP"]["value"])
  248.         FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
  249.  
  250. def FusionWeight(rating):
  251.     if EngineType in ["ProtoMech Engine"]:
  252.         if rating < 41:
  253.             weight = rating * (25.0/1000.0)
  254.             #print (weight)
  255.             return rating * (25.0/1000.0) #ProtoMechEngineTable[rating]
  256.         else:
  257.             return FusionEngineTable[RoundUp5(rating)]
  258. #            for key in FusionEngineTable:
  259. #                    if rating in key:
  260. #                        weight = FusionEngineTable[key]
  261. #                        #print (weight)
  262. #                        return FusionEngineTable[key]
  263.     elif rating < 501:
  264.         return FusionEngineTable[RoundUp5(rating)]
  265. #        for key in FusionEngineTable:
  266. #                if rating in key:
  267. #                    weight = FusionEngineTable[key]
  268. #                    #print (weight)
  269. #                    return FusionEngineTable[key]
  270.     elif rating > 500: #Uses polynomial curves and floating-point math to extrapolate mass for engine ratings beyond 500. Experimental feature, not recommended for everyday use.
  271.         x = RoundUp5(rating)
  272.         coeff = [7.05283012941420e-23, -1.58264921514316e-19,  1.58814453473840e-16,
  273.                  -9.19203426420176e-14,  3.32942410135420e-11, -7.72438823285226e-09,
  274.                  1.13925338769604e-06, -0.000102985669746005,  0.00538423547801741,
  275.                  -0.112116210954985, 1.24919663674987]
  276.         icoeff = zip(range(0, len(coeff)), reversed(coeff))
  277.         weight = 0.0
  278.         for p,c in icoeff:
  279.             weight += c * (x**p)
  280.         weight = RoundUpFractional(weight*1000.0)/1000.0
  281.         #print (weight)
  282.         return weight
  283.         print ("WARNING! This Engine Rating is outside normal Rating parameters, and its weight has been extrapolated. Player discretion is advised.");
  284.         print();
  285.  
  286. #def FusionWeightPoly(rating): #Uses polynomial curves and floating-point math to extrapolate mass for engine ratings beyond 500. Experimental feature, not recommended for everyday use.
  287. #  x = RoundUp5(rating)
  288. #  coeff = [7.05283012941420e-23, -1.58264921514316e-19,  1.58814453473840e-16,
  289. #          -9.19203426420176e-14,  3.32942410135420e-11, -7.72438823285226e-09,
  290. #           1.13925338769604e-06, -0.000102985669746005,  0.00538423547801741,
  291. #          -0.112116210954985, 1.24919663674987]
  292. #  icoeff = zip(range(0, len(coeff)), reversed(coeff))
  293. #  weight = 0.0
  294. #  for p,c in icoeff:
  295. #    weight += c * (x**p)
  296. #  weight = roundNearest(weight * 2.0)/2.0
  297. #  return weight
  298. #
  299. #for k in FusionEngineTable:
  300. #  t = FusionWeight(k)
  301. #  p = FusionWeightPoly(k)
  302. #  d = t - p
  303. #  if d > .01:
  304. #    print(k, t, p, d)
  305.  
  306. def EngineWeight(engine_type, rating):
  307.    #Using a dictionary to match engine name to a formula
  308.    weight = FusionWeight(rating * 1.0)
  309.    #print (weight)
  310.    primitive = FusionWeight(rating * 1.2)
  311.    lithium = FusionWeight(max(MechTonnage, rating - MechTonnage))
  312.    if rating < 41:
  313.       proto = rating * (25.0/1000.0) #ProtoMechEngineTable[rating]
  314.       lithium_proto = max(MechTonnage, rating - MechTonnage) * (25.0/1000.0)
  315.    else:
  316.       proto = weight * 1.0
  317.       lithium_proto = lithium * 1.0
  318.  
  319.    #print (weight)
  320.    ed = {"Standard Fusion Engine" : max(0.5, weight * 1.0),
  321.          "Light Fusion Engine"    : max(0.5, RoundUpHalf(weight * .75)),
  322.          "XL Fusion Engine"       : max(0.5, RoundUpHalf(weight * .50)),
  323.          "XXL Fusion Engine"      : max(0.5, RoundUpHalf(weight / 3.0)),
  324.          "Compact Fusion Engine"  : max(1.0, RoundUpHalf(weight * 1.5)),
  325.          "Internal Combustion Engine (ICE)"  : max(1.0, RoundUpHalf(weight * 2.0)), #No Heat Sinks at all. Can't use energy weapons or Jump Jets. Don't forget fuel!
  326.          "Fuel Cell"  : max(1.0, RoundUpHalf((weight * 2.0) * 0.5)), #Only 1 Heat Sink. Can't use energy weapons or Jump Jets. Don't forget fuel!
  327.          "Fission Engine"  : max(5.0, RoundUpHalf(weight * float(7.0/4.0))), #Only 5 Heat Sinks. Illegal in the Inner Sphere, and expensive.
  328.          "Lithium-Fusion Engine"  : max(0.5, RoundUpHalf(lithium)), #Non-Canon. 10 Heat Sinks. Increases a mech's Walking Speed by 1.
  329.          "Primitive Fusion Engine"  : max(0.5, RoundUpHalf(primitive)), #Multiplies engine rating by 1.2, but does not increase performance.
  330.          "Primitive Internal Combustion Engine (ICE)"  : max(1.0, RoundUpHalf(primitive * 2.0)), #Multiplies engine rating by 1.2, but does not increase performance.
  331.          "Primitive Fuel Cell"  : max(1.0, RoundUpHalf(primitive * 1.2)), #Multiplies engine rating by 1.2, but does not increase performance.
  332.          "Primitive Fission Engine"  : max(5.0, RoundUpHalf(primitive * (7.0/4.0))), #Multiplies engine rating by 1.2, but does not increase performance.
  333.          "ProtoMech Engine" : RoundUpFractional((proto * 1000.0)/1000.0),
  334.          "ProtoMech XL Lithium-Fusion Engine" : RoundUpFractional(max(0.013, lithium_proto/2)),
  335.          "No Engine" : 0,
  336.          }
  337.    return ed[engine_type]
  338.  
  339. if EngineType in {"Lithium-Fusion Engine"}:
  340.     LithiumBatteryRating = max(MechTonnage, rating - MechTonnage)
  341. elif EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell," "Primitive Fission Engine"}:
  342.     LithiumBatteryRating = RoundUp5(rating * 1.2)
  343. else:
  344.     LithiumBatteryRating = rating
  345.  
  346. #Cockpits
  347. def PromptCockpitType():
  348.     """Ask the user for their desired cockpit type, then return it."""
  349.     #cockpit list:
  350.     if LithiumBatteryRating < 401:
  351.             cl = ["Standard", "Small", "Armored", "Torso", "Interface", "Drone Operating System"]
  352.     elif LithiumBatteryRating > 400:
  353.           cl = ["Standard", "Small", "Armored", "Interface", "Drone Operating System"]
  354.     print("Cockpit types:");
  355.     for i in range(0, len(cl)):
  356.         print("  (%d) %s"%(i, cl[i]));
  357.     num = ask("Please select your desired Cockpit type", 0, len(cl)-1);
  358.     print();
  359.     return cl[num]
  360.  
  361. def CockpitWeight(cockpit_type):
  362.    #Using a dictionary to match cockpit name to a formula
  363.    cd = {
  364.         "ProtoMech": 0.5,
  365.         "UltraHeavy ProtoMech": 0.75,
  366.         "Drone Operating System": max(1.0, RoundUpHalf((MechTonnage/10.0) + 0.5)),
  367.         "Small": 2.0,
  368.         ("Standard", "AutoMech", "Industrial", "Armored Small"): 3.0,
  369.         ("Armored", "Torso", "Tripod", "Interface", "SuperHeavy"): 4.0,
  370.         ("Primitive", "Primitive Industrial", "SuperHeavy Tripod"): 5.0
  371.         }
  372. #   return ed[cockpit_type]
  373.    for key in cd:
  374.         if cockpit_type in key:
  375.              return cd[key]
  376.  
  377. #Skeletons
  378. def PromptInternalType():
  379.    """Ask the user for their desired internal structure type, then return it."""
  380.    #internal structure list:
  381.    if MechTonnage < 101:
  382.         if EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"}:
  383.             il = ["Primitive Standard", "Primitive Industrial"]
  384.         else:
  385.             il = ["Standard", "Endo Steel", "Composite", "Hybrid", "Reinforced", "Industrial"]
  386.    elif MechTonnage > 100:
  387.         il = ["SuperHeavy Standard", "SuperHeavy Hybrid", "SuperHeavy Endo Steel", "SuperHeavy Reinforced", "SuperHeavy Industrial"] #You have balls if you pick that last one.
  388.    print("Internal Structure types:");
  389.    for i in range(0, len(il)):
  390.        print("  (%d) %s"%(i, il[i]))
  391.    num = ask("Please select your desired Internal Structure type", 0, len(il)-1);
  392.    print();
  393.    return il[num]
  394.  
  395. def InternalWeight(internal_type):
  396.     #Using a dictionary to match internal structure name to a formula
  397.     isd = {
  398.          ("Standard", "Primitive Standard", "SuperHeavy Endo Steel", "ProtoMech"): RoundUpHalf(MechTonnage/10.0),
  399.          ("Endo Steel", "Composite"): RoundUpHalf(MechTonnage/20.0),
  400.          "Hybrid": RoundUpHalf(MechTonnage*7.5/100.0),
  401.          ("Reinforced", "Industrial", "Primitive Industrial", "SuperHeavy Standard") : RoundUpHalf(MechTonnage/5.0),
  402.          "SuperHeavy Hybrid": RoundUpHalf(MechTonnage*15.0/100.0),
  403.          ("SuperHeavy Industrial", "SuperHeavy Reinforced"): RoundUpHalf(MechTonnage/2.5),
  404.          }
  405. #   return ed[internal_type] #Trying to select keys from individual items out of a tuple, but the program is instead reading the entire tuple as a key.
  406.     for key in isd:
  407.        if internal_type in key:
  408.            return isd[key]
  409.  
  410. if MechTonnage > 100:
  411.      InternalType = PromptInternalType()
  412.      CockpitType = ("SuperHeavy")
  413.      if MechType in ["Tripod"]:
  414.           MechType = ("SuperHeavy Tripod")
  415.      else:
  416.           Mechtype = ("SuperHeavy" + CurrentMechType)
  417. elif EngineType in ["ProtoMech Engine"]:
  418.      InternalType = ("ProtoMech")
  419.      MechType = ("ProtoMech")
  420.      if MechTonnage < 10:
  421.           CockpitType = ("ProtoMech")
  422.      elif MechTonnage > 9:
  423.           CockpitType = ("UltraHeavy ProtoMech")
  424. else:
  425.      MechType = CurrentMechType
  426.      InternalType = PromptInternalType()
  427.      if EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"}:
  428.          CockpitType = ("Primitive")
  429.      else:
  430.          CockpitType = PromptCockpitType()
  431.  
  432. #Gyros
  433. def PromptGyroType():
  434.     """Ask the user for their desired gyro type, then return it."""
  435.     #gyro list:
  436.     if LithiumBatteryRating < 401 or EngineType in ["Compact Fusion Engine"]:
  437.           gl = ["Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
  438.     elif EngineType in {"Lithium-Fusion Engine"} and rating < 501:
  439.           gl = ["Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
  440.     elif LithiumBatteryRating > 400 or CockpitType in ["Torso"]:
  441.           if EngineType not in ["Compact Fusion Engine"]:
  442.               gl = ["Standard", "Compact", "Heavy-Duty",]
  443.     print("Gyro types:")
  444.     for i in range(0, len(gl)):
  445.         print("  (%d) %s"%(i, gl[i]))
  446.     num = ask("Please select your desired Gyro type", 0, len(gl)-1)
  447.     print();
  448.     return gl[num]
  449.  
  450. if EngineType in ["Lithium-Fusion Engine"]:
  451.     FinalRating = LithiumBatteryRating
  452. elif EngineType in ["Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"]:
  453.     FinalRating = MechTonnage * CruisingSpeed * 1.2
  454. elif EngineType in ["ProtoMech Engine"]:
  455.     FinalRating = MechTonnage * FlankingSpeed
  456. else:
  457.     FinalRating = MechTonnage * CruisingSpeed
  458.  
  459. GyroRating = math.ceil(FinalRating / 100)
  460.  
  461. if MechTonnage > 100:
  462.     GyroType = ("SuperHeavy")
  463. elif EngineType in ["Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"]:
  464.     if MechTonnage < 101:
  465.          GyroType = ("Primitive")
  466.     elif MechTonnage > 100:
  467.          GyroType = ("SuperHeavy Primitive")
  468. elif CockpitType in ["ProtoMech", "UltraHeavy ProtoMech", "Interface"]:
  469.     GyroType = ("None")
  470. else:
  471.     GyroType = PromptGyroType()
  472.  
  473. def GyroWeight(gyro_type):
  474.    #Using a dictionary to match gyro name to a formula
  475.    gmass = GyroRating
  476.    gd = {
  477.         ("Standard", "Primitive") : max(1.0, gmass*1.0),
  478.         "XL (Extra-Light)" : max(1.0, RoundUpHalf(gmass/2.0)),
  479.         "Compact" : max(1.5, RoundUpHalf(gmass*1.5)),
  480.         ("Heavy-Duty", "SuperHeavy", "Primitive SuperHeavy") : max(2.0, math.ceil(gmass * 2.0)),
  481.         "None": (gmass*0.0),
  482.         "Armored" : (gmass + 2.0),
  483.         "Armored Compact" :  1.0 + RoundUpHalf(gmass*1.5),
  484.         "Armored XL" : 3.0 + RoundUpHalf(gmass/2.0),
  485.         "Armored Heavy-Duty" : 2.0 + (gmass*2.0),
  486.         }
  487. #   return ed[gyro_type]
  488.    for key in gd:
  489.         if gyro_type in key:
  490.              return gd[key]
  491.  
  492. #Heat Sinks
  493. def PromptHeatSinkType():
  494.     """Ask the user for their desired heat sink type, then return it."""
  495.     #heat sink list:
  496.     hsl = ["Single", "Double (Inner Sphere)", "Double (Clan)", "Laser", "Compact"]
  497.     print("Heat Sink types:");
  498.     for i in range(0, len(hsl)):
  499.         print("  (%d) %s"%(i, hsl[i]));
  500.     num = ask("Please select your desired Heat Sink type", 0, len(hsl)-1);
  501.     print();
  502.     return hsl[num]
  503.  
  504. if EngineType in {"Fission Engine", "Primitive Fission Engine"}:
  505.     FreeHeatSinks = 5
  506.     HeatSinkType = PromptHeatSinkType()
  507. elif EngineType in {"Fuel Cell", "Primitive Fuel Cell"}:
  508.     FreeHeatSinks = 1
  509.     HeatSinkType = PromptHeatSinkType()
  510. elif EngineType in {"Internal Combustion Engine (ICE)", "Primitive Internal Combustion Engine (ICE)"}:
  511.     FreeHeatSinks = 0
  512.     HeatSinkType = PromptHeatSinkType()
  513. elif EngineType in {"ProtoMech Engine"}:
  514.     FreeHeatSinks = 0
  515.     HeatSinkType = ("ProtoMech")
  516. else:
  517.     FreeHeatSinks = 10
  518.     HeatSinkType = PromptHeatSinkType()
  519.  
  520. if EngineType in ["ProtoMech Engine"]:
  521.      UserHeatSinks = ask("Please provide your desired quantity of ProtoMech Heat Sinks", 0, MechTonnage*4)
  522.      
  523. elif HeatSinkType in ["Compact"]:
  524.      print ("You currently have", int(FreeHeatSinks), HeatSinkType, "Heat Sinks.")
  525.      UserHeatSinks = ask("If you wish to install additional Heat Sinks, enter the quantity you wish to add", 0, math.floor(MechTonnage*2/3))
  526. else:
  527.      print ("You currently have", int(FreeHeatSinks), HeatSinkType, "Heat Sinks.")
  528.      UserHeatSinks = ask("If you wish to install additional Heat Sinks, enter the quantity you wish to add", 0, MechTonnage)
  529.      
  530. TotalHeatSinks = UserHeatSinks + FreeHeatSinks
  531.  
  532. if UserHeatSinks > 0:
  533.      print("You now have", TotalHeatSinks, "total", HeatSinkType, "HeatSinks.")
  534.  
  535. if EngineType in {"ProtoMech Engine"}:
  536.         HeatSinkWeight = RoundUpFractional(UserHeatSinks/4.0)
  537.         IntegralHeatSinks = int(TotalHeatSinks)
  538.         HeatSinkSlots = 0
  539. elif HeatSinkType in {"Compact"}:
  540.         HeatSinkWeight = RoundUpHalf(UserHeatSinks * 1.5)
  541.         IntegralHeatSinks = int(min(TotalHeatSinks, math.floor(LithiumBatteryRating/12.5)))
  542. else:
  543.         HeatSinkWeight = UserHeatSinks * 1.0
  544.         IntegralHeatSinks = int(min(TotalHeatSinks, math.floor(LithiumBatteryRating/25.0)))
  545.  
  546. PodHeatSinks = TotalHeatSinks - IntegralHeatSinks
  547.  
  548. if MechTonnage < 101:
  549.      if HeatSinkType in ["Single", "Liquid Metal"]:
  550.          HeatSinkSlots = PodHeatSinks
  551.      elif HeatSinkType in ["Double (Inner Sphere)", "Double (ProtoType)"]:
  552.          HeatSinkSlots = PodHeatSinks * 3
  553.      elif HeatSinkType in ["Double (Clan)", "Double (Star Empire)", "Laser"]:
  554.          HeatSinkSlots = PodHeatSinks * 2
  555.      elif HeatSinkType in ["Compact"]:
  556.          HeatSinkSlots = math.ceil(PodHeatSinks/2)
  557.      elif HeatSinkType in ["ProtoMech"]:
  558.          HeatSinkSlots = 0
  559.  
  560. elif MechTonnage > 100:
  561.      if HeatSinkType in ["Single"]:
  562.          HeatSinkSlots = math.ceil(PodHeatSinks/2)
  563.      elif HeatSinkType in ["Double (Inner Sphere)"]:
  564.          HeatSinkSlots = math.ceil(PodHeatSinks * 1.5)
  565.      elif HeatSinkType in ["Double (Clan)", "Laser"]:
  566.          HeatSinkSlots = PodHeatSinks
  567.      elif HeatSinkType in ["Compact"]:
  568.          HeatSinkSlots = math.ceil(PodHeatSinks/4)
  569.  
  570. #Podspace
  571. skeleton = InternalWeight(InternalType)
  572. tripod = RoundUpHalf(skeleton * 1.1)
  573. cockpit = CockpitWeight(CockpitType)
  574. gyro = GyroWeight(GyroType)
  575. EngineTonnage = EngineWeight(EngineType, rating)
  576.  
  577. if MechType in ["Combat Vehicle", "Support Vehicle"]:
  578.      if EngineType in ["Internal Combustion Engine (ICE)", "Fuel Cell", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell"]:
  579.           VehicleEngine = EngineTonnage
  580.      else:
  581.           if MechType in ["Combat Vehicle"]:
  582.                VehicleEngine = RoundUpHalf(EngineTonnage * 1.5)
  583.           elif MechType in ["Support Vehicle"]:
  584.                VehicleEngine = RoundUpFractional(EngineTonnage * 1.5)
  585. else:
  586.      VehicleEngine = EngineTonnage
  587.  
  588. print()
  589.  
  590. #DEBUG READOUT - UNCOMMENT IF CRASHES OCCUR
  591. print ("DEBUG READOUUT - RECOMMENT IF CRASHES NO LONGER OCCUR")
  592. print ("MechTonnage =", MechTonnage)
  593. print ("EngineTonnage =", EngineTonnage)
  594. print ("VehicleEngine =", VehicleEngine)
  595. print ("FinalRating =", FinalRating)
  596. print ("skeleton =", skeleton)
  597. print ("tripod =", tripod)
  598. print ("gyro =", gyro)
  599. print ("cockpit =", cockpit)
  600. print ("HeatSinkWeight =", HeatSinkWeight)
  601. input()
  602. if MechType in ["Tripod", "SuperHeavy Tripod"]:
  603.      podspace = RoundDownHalf(MechTonnage - EngineTonnage - tripod - gyro - cockpit - HeatSinkWeight)
  604. elif EngineType in ["ProtoMech Engine", "ProtoMech XL Lithium-Fusion Engine"] or MechType in ["ProtoMech", "Quad ProtoMech", "Glider ProtoMech"]:
  605.      podspace = RoundDownFractional(MechTonnage - EngineTonnage - skeleton - gyro - cockpit - HeatSinkWeight)
  606. elif MechType in ["Combat Vehicle"]:
  607.      podspace = RoundDownHalf(MechTonnage - VehicleEngine - skeleton - gyro - cockpit - HeatSinkWeight)
  608. elif MechType in ["Support Vehicle"]:
  609.      podspace = RoundDownFractional(MechTonnage - VehicleEngine - skeleton - gyro - cockpit - HeatSinkWeight)
  610. else:
  611.      podspace = RoundDownHalf(MechTonnage - EngineTonnage - skeleton - gyro - cockpit - HeatSinkWeight)
  612.  
  613. if VehicleEngine > MechTonnage:
  614.     print ("WARNING! Your engine is heavier than the mech!");
  615.     print ("WARNING! Your mech has negative podspace, and is Overweight!");
  616.     input()
  617. elif podspace < 0.0:
  618.     print ("WARNING! Your mech has negative podspace, and is Overweight!");
  619.     input()
  620. else:
  621.     print("ALL SYSTEMS NOMINAL.")
  622.     input()
  623.  
  624. #Finalize
  625. if MechName in {"BattleMech", "Ultralight BattleMech", "Light BattleMech", "Medium BattleMech", "Heavy BattleMech", "Assault BattleMech", "SuperHeavy BattleMech"}:
  626.      if InternalType in {"Industrial"}:
  627.          if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
  628.               MechName = (MechClass + " IndustrialMech")
  629.      if InternalType in {"Primitive Standard"}:
  630.          if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
  631.               MechName = ("Primitive " + MechClass + " BattleMech")
  632.      if InternalType in {"Primitive Industrial"}:
  633.          if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
  634.               MechName = ("Primitive " + MechClass + " IndustrialMech")
  635.      elif MechClass in {"ProtoMech", "UltraHeavy ProtoMech"}:
  636.           MechName = MechClass
  637.           MechType = ("ProtoMech")
  638.      elif CockpitType in {"AutoMech"}:
  639.           MechName = (MechClass + "AutoMech")
  640.           MechType = ("AutoMech")
  641.  
  642. #Technical Readout
  643. fib(FinalRating)
  644. print()
  645. print ("Your", MechName, "has a Cruising MP of", CruisingSpeed, "hexes per turn, and a Flanking MP of", FlankingSpeed, "hexes per turn.");
  646.  
  647. print ("This speed is provided by a", FinalRating,'rated', EngineType, "weighing", EngineTonnage, "metric tons.");
  648.  
  649. if EngineType in ["ProtoMech Engine", "ProtoMech XL Lithium-Fusion Engine"]:
  650.      print("You have", TotalHeatSinks, HeatSinkType, "Heat Sinks weighing", HeatSinkWeight, "metric tons.")
  651.  
  652. else:
  653.      print("You have", TotalHeatSinks, HeatSinkType, "Heat Sinks weighing", HeatSinkWeight, "metric tons, of which", IntegralHeatSinks, "of them are Integral,")
  654.      print ("and out of those", TotalHeatSinks, HeatSinkType, "Heat Sinks,",FreeHeatSinks, "of them come with the engine.")
  655.      if PodHeatSinks > 0:
  656.           print ("The remaining", HeatSinkType, "Heat Sinks occupy", HeatSinkSlots, "Critical Spaces in total.")    
  657.  
  658. print()
  659.  
  660. if MechType in ["Tripod"]:
  661.      print ("The Mech's weight is supported by a", InternalType, "Internal Structure with a mass of", tripod, "metric tons.");
  662.  
  663. elif MechType in ["AutoMech"]:
  664.      print ("The AutoMech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton, "metric tons.");
  665.      
  666. elif MechType in ["ProtoMech"]:
  667.      print ("The ProtoMech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton*1000, "kilograms.");
  668.  
  669. else:
  670.      print ("The Mech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton, "metric tons.");
  671.  
  672. if GyroType in ["None"] and MechTonnage > 9:
  673.      print("The pilot is cocooned in an", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");
  674.  
  675. elif GyroType in ["None"] and MechTonnage <10:
  676.      print("The pilot is cocooned in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");
  677.  
  678. elif CockpitType in ["Drone Operating System", "AutoMech"]:
  679.      if GyroType in ["XL (Extra-Light)"]:
  680.           print ("and keeping the", MechName, "upright is an", GyroType, "Gyro weighing", gyro, "metric tons.")
  681.      else:
  682.           print ("and keeping the", MechName, "upright is a", GyroType, "Gyro weighing", gyro, "metric tons.")
  683.      
  684.      if CockpitType in ["Drone Operating System"]:
  685.           print ("The brains of this machine consist of a", CockpitType, "weighing", cockpit, "metric tons.")
  686.      
  687.      elif CockpitType in ["AutoMech"]:
  688.           print ("The brains of this machine consist of an", CockpitType, "weighing", cockpit, "metric tons.")
  689.  
  690. elif GyroType in ["SuperHeavy"]:
  691.      print ("and the only thing stopping your", MechName, "from toppling over is a monstrous", GyroType, "Gyro weighing", gyro, "metric tons.");
  692.      print ("The pilots are 'efficiently' huddled together in a", CockpitType, "Cockpit, weighing a massive", cockpit, "metric tons.");
  693.  
  694. elif GyroType in ["XL (Extra-Light)"]:
  695.      print ("and keeping the", MechName, "upright is an", GyroType, "Gyro weighing", gyro, "metric tons.");
  696.      print ("The pilot sits ’comfortably’ in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");
  697.  
  698. else:
  699.      print ("and keeping the", MechName, "upright is a", GyroType, "Gyro weighing", gyro, "metric tons.");
  700.      print ("The pilot sits 'comfortably' in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");
  701.  
  702. print()
  703. print ("The", MechName, "has an average walking speed of", kph(CruisingSpeed), "km/h, and a maximum running speed of", kph(FlankingSpeed), "km/h.");
  704.  
  705. if podspace > 0.0:
  706.    print ("The", MechName, "has", podspace, "tons of Pod Space available to mount weapons, armor and equipment.");
  707.    print();
  708.    fib(podspace)
  709.    print();
  710. else:
  711.    print ("Oh, stravag! It would seem that your engineers left your", MechName, "with only", podspace, "tons of Pod Space,")
  712.    print ("and now thanks to them, it cannot mount any weapons, armor or equipment!");
  713.    print();
  714.    print("+++ MELON. MELON. MELON. Out-of-Cheese Error. +++")
  715.    print("Redo from Start.")
  716.    input()
  717.  
  718. ## Closing sequence.
  719. print ("Please visit http://www.sarna.net for more information on these terms and components.");
  720. print ("If you have any questions or feedback about the software, such as feature requests or bug reports,");
  721. print ("if you need technical support, or would simply like to contribute to development, then please visit:");
  722. print ("https://tinyurl.com/Sarna-Forums-MechEngine");
  723. print();
  724. gettime()
  725. input("Shutdown Sequence: Initiated.") #Change this line to a menu option once Restart has been implemented.
  726. print ("Shutting Down.")
  727.  
  728. ## End of Line.
  729.  
  730. #Contribution Links:
  731. #     https://pastebin.com/dpMnWPjp
  732. #     https://docs.google.com/document/d/1A6Y79pelpzdRg00DHcZNO3tyrdvthFSaU4tihSvGkE8/edit?usp=sharing
Add Comment
Please, Sign In to add comment