BattleTech Engine Calculator, Pre-Alpha

Pages: 1
AmaroqStarwind
04/28/18 05:14 PM
13.84.155.127

Edit Reply Quote Quick Reply
Well, here's the complete and unabridged source code of my command-line Engine Calculator. I plan to later include an actual Engine Table, including weights and ratings for XL Fusion, Light Fusion, Compact Fusion, XXL Fusion, Fission, Fuel Cell, Internal Combustion, Primitive Engines, ProtoMech Engines (ratings under 40), and perhaps even Lithium-Fusion Engines (despite those not being canon).

I also plan to include different unit types, such as Ground Vehicles (which multiply Fusion/Fission engine weights, and which also have a suspension factor) and ProtoMechs (which calculate their top speed very differently).
_ _ _ _ _
Code:
print ("Welcome to MechEngine, an Engine Calculator for BattleTech, written in Python 3.6.5.")
print ("Currently, only standard Fusion Engines and standard BattleMechs are available,")
print ("and engine weight has also not yet been implemented.")
print (" ")
tonnage = int(input("Please provide the your 'Mech's Tonnage: "))
cruise = int(input("Please provide your desired Walk MP: "))
flank = int(cruise * 1.5)
print ("Calculating...")
rating = (tonnage * cruise)
print (" ")
print ("Your calculated Engine Rating is:", rating)
print ("Your cruising speed is", int(cruise * 3), "m/s")
print ("Your top speed is", int(flank * 3), "m/s")
print (" ")
print ("To find your engine weight, please look up your engine type and engine rating on")
print ("the Master Engine Table, as shown on Page 49 of TechManual, and for")
print ("XXL Engines, divide the mass of a standard engine by 3 and round to the next half-ton.")
print (" ")
print ("Thank you for testing MechEngine. Please be sure to send feedback. More features coming soon!")

_ _ _ _ _

It has an unfortunate bug... it does not round up Run MP correctly, and I'm not sure how to fix that yet. You see, it is supposed to round up, but Python is rounding down.

I'm also using Meters per Second, instead of Kilometers per Hour, because trying to use Floating Points gives me this:
_ _ _ _ _
Please provide the your 'Mech's Tonnage: 55
Please provide your desired Walk MP: 5
Engine Rating: 275
Your cruising speed is 54.0 km/h
Your top speed is 75.60000000000001 km/h

_ _ _ _ _

Oops.

If anybody could help out with this, and any other oversights, please let me know.

Known problems with this version:
- No minimum or maximum tonnage
- No support for alternate engine/unit types
- Engine weight and Master Engine Table not yet imlemented
- No minimum or maximum engine rating
- Incorrect Run/Flank MP rounding
- No rounding of 'Mech tonnage to 5 ton increments
- No rounding of engine rating to increments of 5
- Command-line only.

The attachment is a text file containing the current version of the source code, as of this post. Attachment (213 downloads)


Edited by AmaroqStarwind (04/28/18 07:18 PM)
AmaroqStarwind
04/28/18 07:42 PM
13.84.155.127

Edit Reply Quote Quick Reply
Latest version of the program.
_ _ _ _ _
Code:
print ("Establishing construction rules, please wait...")
#Establishing Rounding rules at startup
def roundHalfUp(f):
return round(f + 0.00000000000001)
#Establishing Tonnage rules at startup
def limit(tonnage, minimum=10, maximum=200):
return max(min(tonnage, maximum), minimum)
def roundTonnage(x, base=5):
return int(base * roundHalfUp(float(x)/base))
#Establishing Engine rules
def limit(rating, minimum=10, maximum=500):
return max(min(rating, maximum), minimum)
def limit(cruise, minimum=1, maximum=50):
return max(min(cruise, maximum), minimum)
def roundEngine(x, base=5):
return int(base * roundHalfUp(float(x)/base))
#Construction Rules verified
print ("Construction Rules verified! Initializing interface.")
print ()
#The actual program follows below
print ("Welcome to MechEngine, an Engine Calculator for BattleTech, written in Python 3.6.5.")
print ("Currently, only standard Fusion Engines and standard BattleMechs are available,")
print ("and engine weight has also not yet been implemented.")
print ()
tonnage = int(input("Please provide your 'Mech's Tonnage: "))
print ("Your 'Mech weighs", tonnage, "tons.")
print ()
cruise = int(input("Please provide your desired Walk MP: "))
flank = int(roundHalfUp(cruise * 1.5))
print ("Your 'Mech has a Walk MP of", cruise, "hexes, and a Run MP of", flank, "hexes.")
print ()
print ("Provide any input to begin calculations.")
input (">>> ")
print ("Calculating Engine Rating...")
rating = roundEngine(tonnage * cruise)
print ()
print ("Your calculated Engine Rating is:", rating)
print ("Your cruising/walking speed is", int(cruise * 3), "m/s")
print ("Your maximum speed is", int(flank * 3), "m/s")
print ()
print ("To find your engine weight, please look up your engine type and engine rating on")
print ("the Master Engine Table, as shown on Page 49 of TechManual, and for")
print ("XXL Engines, divide the mass of a standard engine by 3 and round to")
print ("the next half-ton.")
print ()
print ("Thank you for testing MechEngine. Please be sure to send feedback.")
print ("More features coming soon!")
print ()
print ("This program will now exit.")

_ _ _ _ _

Verified, it works in both Visual Studio and the Python 3.6.5 shell.

However, while I have the Minimum/Maximum Tonnage rules, Minimum/Maximum speed rules, Oddball Tonnage rules and Engine Rounding rules all defined, I have not actually implemented them yet. I don't really know how to apply limiters to inputs at the moment.
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/01/18 04:39 PM
13.84.155.127

Edit Reply Quote Quick Reply
Current design goals:

Code:
 (not really, just formatting)

00: Include example units for new users to choose from, to demonstrate how things work ("XX means it cannot be implemented yet.)
- Bushwacker, used in all of my test runs, has a tonnage of 55, a Walk MP of 5, a Run MP of 8, and an engine rating of 275.
XX - It uses an XL Fusion Engine.

- Atlas has a tonnage of 100, a Walk MP of 3, a Run MP of 5, and an Engine Rating of 300.
- It uses a standard Fusion Engine.

- Timber Wolf (Mad Cat) has a tonnage of 75, a Walk MP of 5, a Run MP of 8, and an Engine Rating of 375.
XX - It uses an XL Fusion Engine.

- The Dire Wolf (Daishi) has a tonnage of 100, a Walk MP of 4, a Run MP of 6, and an Engine Rating of 400.
XX - It uses an XL Fusion Engine.

XX - The Sprite ProtoMech has a tonnage of 15, a Walk MP of 3, a Run MP of 5, and carries a 75-rated Engine.
- ProtoMechs calculate Engine Rating differently than BattleMechs, and thusly are slower.
- The Sprite carries 5 Extended Jump Jets, each weighing .30 tons.

XX - The Prodigal Son BattleMech has a tonnage of 60, a Walk MP of 4, a Run MP of 6, and carries a 300-rated engine.
- The Prodigal Son, ordinarily, would use a 360-rated engine, but carries a Lithium Fusion Engine.
- Damage to the batteries in the Lithium Fusion Engine will produce extra heat and reduce its movement speed.
- Lithium Fusion Engines are a non-canon invention, but operate similarly to a Hybrid Car.

XX - The Mackie has a tonnage of 100, a Walk MP of 3, a Run MP of 5, and carries a 360-rated Engine.
- Because it is a Primitive BattleMech, it uses a Primitive Fusion Engine.
- A 360 Primitive Engine has the same performance as a lighter, modern 300-rated Engine.
- Primitive Engines can be used in modern units, but do not perform any better than they would in a Primitive unit.
- Primitive units cannot use modern engines.

- The UrbanMech has a tonnage of 30, a Walk MP of 2, a Run MP of 3, and carries a 60-rated engine.
- The UrbanMech carries a standard Fusion engine, and 2 Jump Jets.

01: Enforce universal minimums and maximums:
- Limit maximum (mech) tonnage to 200
- Limit minimim (mech) tonnage to 10
- Limit minimum (protomech) tonnage to 2
- Limit maximum (protomech) tonnage to 15
- Limit (mech) tonnage to increments of 5
- Limit engine ratings above 40 to increments of 5
- No engine can exist above rating 500
- ProtoMechs cannot have an engine rating less than 2
- All other units cannot have an engine rating less than 10
- A unit has a minimum Engine Rating and a maximum Engine Rating both equal to a multiple of its tonnage, and then subtracting any Suspension Factor it might have. It still cannot have an engine rating below 10, even after subtracting Suspension Factor.

02: Incorporate Master Engine Table for determining (engine) tonnage.
- May need to create a separate file and import it.
- Preferably being able to import external XML, Excel, CSV or SQL databases
- Python version is most likely

03: Incorporate different types of engines;
- XL Fusion Engines weigh half as much as standard Fusion engines, to a minimum of 0.5 tons
- XXL Fusion Engines weigh one third as much as standard Fusion engines, to a minimum of 0.5 tons
- Compact Fusion Engines weigh 1.5 times as much as standard Fusion engines
- Except for ProtoMech engines under rating 40, all engine weights are rounded up to the next 0.5 tons
- ProtoMech engines under rating 40 multiply their engine rating by 0.025 to find their tonnage
- Don't forget Fission Engine, Internal Combustion Engine and Fuel Cell weights
- Incorporate Primitive Engines, which have 1.2x the rating of equally powerful newer engines
- Incorporate Lithium Fusion Engines, which provide a suspension factor equal to 1x your mech's tonnage.
- Engine ratings greater than 400 occupy 2 additional spaces inside the center torso
- XL and XXL engines occupy space in the side torsos. XXL engines also produce more heat.
- Compact Engines occupy half as much space as a standard engine. They cannot exist in ratings above 400.
- Fuel Cells and Internal Combustion Engines cannot power Gauss Rifles or most energy weapons

04: Incorporate Heat Sinks
- Internal Combustion, Fuel Cell, and Fission engines provide 0, 1 and 5 "weight free" heat sinks respectively.
- Fusion Engines and their derivatives provide 10 "weight free" heat sinks.
- A certain number of heat sinks (including but not limited to the "weight free" heat sinks) can be mounted inside the engine
- The formula for in-engine heat sinks is equal to Engine Rating / 25, rounded down.
- If the engine rating is less than 250, then not all of the weight free heat sinks can be put inside the engine.
- Compact Heat Sinks double the number of heat sinks that can be mounted inside the engine.
- ProtoMechs do not receive free heat sinks.
- Ground vehicles and ProtoMechs cannot carry most energy weapons unless they have enough heat sinks to dissipate the heat.
- Double Heat Sinks and Laser Heat Sinks dissipate heat twice as efficiently as standard Heat Sinks, but are bulkier.
- Two Compact Heat Sinks can fit in the space of one standard Heat Sink, but a single Compact Heat Sink is 50% heavier than a standard Heat Sink
- ProtoMechs can only use ProtoMech Heat Sinks, which weigh 25% as much as a standard HeatSink.
- Only ProtoMechs can use ProtoMech Heat Sinks. Double/Laser versions of ProtoMech Heat Sinks do not exist.
- Laser Heat Sinks do not perform more efficiently underwater or in cold environments, but do not perform less efficiently in hot environments or in vacuum.
- Laser Heat Sinks cannot benefit from coolant trucks, but do not suffer from coolant degredation.
- Laser Heat Sinks reduce the chances of an ammunition explosion, but make a mech more visisble at night.
- Different Heat Sinks cannot be mixed inside a mech.
- The "Weight-Free' heat sinks provided by an engine can be any type of heat sink, as long as all other heat sinks on the mech are the same type.

05: Incorporate different unit types:
- ProtoMechs calculate engine rating based on their Run/Flank MP * their tonnage, instead of their Cruise/Walk MP
- Ground vehicles have a suspension factor, which is subtracted from their final engine rating
- Ground vehicles multiply the engine weight by 1.5 for Fission Engines, Fusion Engines, and their derivatives
- HoverCraft have a minimum engine weight equal to 20% their total tonnage. They cannot be constructed heavier than 50 tons, but they have the highest Suspension Factor of any known vehicle.
- ProtoMechs cannot carry special engine types, only standard Fusion engines.
- Land Air 'Mechs cannot carry special engine types, only standard (or compact) Fusion Engines. They also cannot be constructed heavier than 55 tons.
- Hover Tank 'Mechs can use special engine types, but are a non-canon unit type. They also cannot be constructed heavier than 50 tons. When in Hover Tank mode, they have the same Suspension Factor as a Hovercraft of the same mass. However, because they must still be able to operate in other modes, this Suspension Factor does not reduce their engine rating, and merely increases their top speed while in Hover Tank mode.
- SuperHeavy Mechs cannot use Fuel Cells, Fission Engines or Internal Combustion Engines.

06: Incorporate Gyros:
- Standard Gyros have a weight equal to the Engine Rating divided by 100, rounded up to the next full ton.
- XL Gyros halve the Standard Gyro weight, but occupy 50% more space. They cannot be used on engine ratings greater than 400.
- Compact Gyros multiply the Standard Gyro weight by 1.5
- Heavy-Duty and SuperHeavy Gyros double the Standard Gyro weight.
- ProtoMechs, and mechs using Interface Cockpits, do not need gyros.
- Because Land Air 'Mechs have Gyros, they ignore the rule that Aerospace fighters must carry their weight symmetrically.
- SuperHeavy mechs can only use SuperHeavy Gyros. SuperHeavy mechs cannot use Interface Cockpits.

07: Incorporate Jump Jets:
- No more standard Jump Jets can be installed than a unit's Walk/Cruise MP.
- No more Improved Jump Jets or Extended Jump Jets can be installed than a unit's Run/Flank MP. They weigh twice as much as standard Jump Jets, but produce half as much heat.
- Vehicles need to use Vehicular Jump Jets. Aside from not producing heat, they are identical to standard Jump Jets.
- No more Underwater Maneuvering Units can be installed than a unit's Walk MP. They weigh the same as standard Jump Jets.
- Different types of Jump Jets cannot be used on the same mech.
- Land Air 'Mechs need a minimum of 3 Jump Jets installed.
- ProtoMechs have access Extended Jump Jets, instead of Improved Jump Jets.
- Standard Jump Jets weigh varyingly depending on the class of mech:
- 0.5 Tons for mechs in the 10-ton to 55-ton range.
- 1.0 Tons for mechs in the 60-ton to 80-ton range.
- 2.0 Tons for mechs in the 85-ton to 100-ton range.
- Mechs greater than 100 tons cannot mount any kind of Jump Jet, not even Mechanical Jump Boosters.
- ProtoMechs have much lighter Jump Jets, but I do not remember their weights.
- Each Jump Jet provides a jumping distance of 30 meters, or 1 hex. A mech carrying the maximum number of standard Jump Jets can therefor jump as far as it can walk in the same span of time.
- Jump Jets produce 1 point of heat per Hex traveled, to a minimum of 3 heat, even if fewer than 3 hexes are traveled.
- Mechanical Jump Boosters enable a mech to jump without producing heat, even when underwater, but they cannot be combined with Partial Wings, and weigh 5% of a mech's total weight for every 30 meters of jumping distance desired. They can be combined with Jump Jets, but cannot be used in the same turn, and they also cannot allow a mech to change direction while in mid-air (or to land on enemy mechs).

08: Incorporate Physical Enhancements:
- MASC enables a mech to run at twice its Walking speed for short periods, but can cause severe (and permanent) damage to its leg actuators.
- Triple Strength Myomers (TSM), when the mech reaches 9 points of overheat, increase its Walking Speed by 2. Running speed is recalculated normally. They cannot be combined with MASC.
- The Actuator Enhancement System makes piloting rolls easier, but it cannot be combined with TSM or with MASC.
- Superchargers enable a mech to run at twice its Walking speed for short periods, but can cause severe damage to the engines. They are compatible with both MASC and TSM, and when MASC and Superchargers are used at the same time, a mech can run at 2.5 times its Walking speed. The chance of catastrophic failure while doing so increases significantly, however.
- Partial Wings can be installed on a mech, which enable it to jump further and dissipate more heat while it is in an atmosphere. However, the bonuses must be calculated differently depending on both gravity and atmospheric density. It weighs 7% of the mech's total weight for Inner Sphere mechs, 5% of the mech's total weight for Clan mechs, and 20% of the ProtoMech's total weight for ProtoMechs. Land Air 'Mechs and Hover Tank Mechs cannot mount Partial Wings.
- Mechs greater than 100 tons cannot use any physical enhancements.

09: Make the tool cross-platform.
- Windows, OS-X and Linux (Portable)
- Android
- iOS
- Entirely open-source.

10: Give the tool a proper GUI.
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.


Edited by AmaroqStarwind (05/01/18 06:11 PM)
AmaroqStarwind
05/01/18 08:44 PM
13.84.155.127

Edit Reply Quote Quick Reply
New Version
- 'Mech Names have been implemented.
- Minimum/Maximum 'Mech Tonnages have been implemented.
- Minimum/Maximum Walk MP have been implemented.
- Run MP rounding error has been fixed.

Source Code
Code:

# MechEngine, HYN-DRN-5813 build

def roundHalfUp(f):
return round(f + 0.00000000000001)

#HYN-DRN-5813 Input Dictionary:
Inputs = {"BattleMech's Tonnage": {"min":10, "max":200, "value": None},
"desired Walk MP" : {"min":1, "max":50 , "value": None}}
def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)
def ask(question, min_val, max_val):
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

def roundEngine(x, base=5):
return int(base * roundHalfUp(float(x)/base))

#Load inputs
load_inputs(Inputs)
MechName = (input("Name your BattleMech: "))
EngineType = ("Fusion Engine")

#Do calculations
flank = int(roundHalfUp(Inputs["desired Walk MP"]["value"] * 1.5))

rating = roundEngine(Inputs["BattleMech's Tonnage"]["value"] * Inputs["desired Walk MP"]["value"])
print()
print ("Your", MechName, "has a Walk MP of", (Inputs["desired Walk MP"]["value"]), "hexes, and a Run MP of", flank, "hexes.")
print ("This speed is provided by a", rating,"rated", EngineType)
print()
print ("The", MechName, "has an average walking speed of", int((Inputs["desired Walk MP"]["value"]) * 3), "m/s.")
print ("The", MechName, "also has a maximum running speed of", int(flank * 3), "m/s.")
print()
print("Press ENTER to exit.")
input(">>> ")


Special Thanks to HYN-DRN-5813 for helping me with defining input ranges.
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/02/18 07:47 PM
13.84.155.127

Edit Reply Quote Quick Reply
I have discovered a bug where the program would crash if the user enters a blank input in response to either question. The program also seems to crash in response to any input on some mobile interpreters, such as Sololearner.

If somebody could help me fix this, that would be much appreciated.
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.


Edited by AmaroqStarwind (05/02/18 07:58 PM)
AmaroqStarwind
05/04/18 09:14 PM
13.84.155.127

Edit Reply Quote Quick Reply
BETA RELEASE
I have finally implemented engine weight and multiple engine types. Still a few bugs to fix and features to add, but the most important things have all been done now!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Code:

# MechEngine, HYN-DRN-5813 build
# Build Date: 2018-05-04

import math

def RoundUp5(x):
return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def roundHalfUp(f):
return round(f + 0.00000000000001)

def roundEngine(x, base=5):
return int(base * roundHalfUp(float(x)/base))

#def roundTonnage(x, base=5):
# return int(base * roundHalfUp(float(x)/base))

#HYN-DRN-5813 Input Dictionary:
Inputs = {"BattleMech's Tonnage": {"min":10, "max":200, "value": None},
"desired Walk MP" : {"min":1, "max":29 , "value": None}}
def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)
def ask(question, min_val, max_val):
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#Load inputs
load_inputs(Inputs)
MechName = (input("Name your BattleMech: "))

#Do calculations
flank = int(roundHalfUp(Inputs["desired Walk MP"]["value"] * 1.5))
rating = roundEngine(Inputs["BattleMech's Tonnage"]["value"] * Inputs["desired Walk MP"]["value"])

#Engines:
FusionEngineTable = {
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,
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,
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,
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,
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}

def RoundUpHalf(x):
return math.ceil(x*2)/2

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
"XXL Fusion Engine", "Compact Fusion Engine"]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
return el[num]

EngineType = PromptEngineType()

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
rating = FusionEngineTable[RoundUp5(rating)]
ed = {"Standard Fusion Engine" : rating,
"Light Fusion Engine" : RoundUpHalf(rating * .75),
"XL Fusion Engine" : RoundUpHalf(rating * .50),
"XXL Fusion Engine" : RoundUpHalf(rating * .33),
"Compact Fusion Engine" : RoundUpHalf(rating * 1.5)}
return ed[engine_type]

print()
print ("Your", MechName, "has a Walk MP of", (Inputs["desired Walk MP"]["value"]), "hexes, and a Run MP of", flank, "hexes.")
print ("This speed is provided by a", rating,"rated", EngineType, "weighing", EngineWeight(EngineType, rating), "metric tons.")
print()
print ("The", MechName, "has an average walking speed of", int((Inputs["desired Walk MP"]["value"]) * 3), "m/s.")
print ("The", MechName, "also has a maximum running speed of", int(flank * 3), "m/s.")
print()
print("Press ENTER to exit.")
input(">>> ")
Attachment (245 downloads)
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/07/18 06:27 PM
13.84.155.127

Edit Reply Quote Quick Reply
Does anybody have any interest in seeing new features, or in helping me fix bugs?

If so, then what new features would you like to see, and/or bugs you would like to report?

- - - - - - - - - - - - - - - - - - - -

NEW VERSION, PODSPACE!
You must install Python 3.6.5 to run this program.

Code:
# MechEngine, "Examples" build
# Build Date: 2018-05-07

#Objectives of this build:
#Fix crash on receiving blank input for tonnage or movement speed
#Set default mech name if user enters blank value
#Reset input calls when outside specified ranges, such as Walk MP of 45 or tonnage of 1
#Remove SuperHeavy Mechs (for now)
#Add Gyro Weight (standard only)
#Add Internal Structure Weight (standard only)
#Add Cockpit Weight (standard cockpits only)
#Calculate remaining Pod Space
#Add more engine types

import math

def RoundUp5(x):
return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def RoundUpHalf(x):
return math.ceil(x*2)/2

def roundHalfUp(f): #deprecated!
return RoundUpHalf(f) #round(f + 0.00000000000001)

def roundEngine(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))

def roundTonnage(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))

#HYN-DRN-5813 Core Input Dictionary:
Inputs = {"BattleMech's Tonnage": {"min":10, "max":100, "value": None},
"desired Walk MP" : {"min":1, "max":29 , "value": None}}

def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)

def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False

def ask(question, min_val, max_val):
x = ''
while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#"Load inputs"
load_inputs(Inputs)

SuspFact = 0 #SuspFact = (input("Suspension Factor: "))
MechName = ("BattleMech")
NewMechName = input("Name your BattleMech: ")
if NewMechName != '': MechName = NewMechName

#"Do calculations"
flank = int(math.ceil(Inputs["desired Walk MP"]["value"] * 1.5))
rating = max(10, RoundUp5((Inputs["BattleMech's Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact))
gyro = max(1.0, ((2 * (math.ceil(rating/100))) * 0.5)) #Standard Gyros only
skeleton = max(0.5, (2 * ((math.ceil((Inputs["BattleMech's Tonnage"]["value"])/10)) * 0.50))) #Standard Internal Skeleton only
cockpit = 3.0 #Standard Cockpit only

InternalType = ("Standard Internal Structure")
GyroType = ("Standard")
CockpitType = ("Standard")

#"Master Engine Table:"
FusionEngineTable = {
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,
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,
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,
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,
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}

ProtoMechEngineTable = {
1: 0.025,
2: 0.050,
3: 0.075,
4: 0.100,
5: 0.125,
6: 0.150,
7: 0.175,
8: 0.200,
9: 0.225,
10: 0.250,
11: 0.275,
12: 0.300,
13: 0.325,
14: 0.350,
15: 0.375,
16: 0.400,
17: 0.425,
18: 0.450,
19: 0.475,
20: 0.500,
21: 0.525,
22: 0.550,
23: 0.575,
24: 0.600,
25: 0.625,
26: 0.650,
27: 0.675,
28: 0.700,
29: 0.725,
30: 0.750,
31: 0.775,
32: 0.800,
33: 0.825,
34: 0.850,
35: 0.875,
36: 0.900,
37: 0.925,
38: 0.950,
39: 0.975,
40: 1.000}

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
"XXL Fusion Engine", "Compact Fusion Engine", "Internal Combustion Engine", "Fuel Cell Engine", "Fission Engine"]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
return el[num]

EngineType = PromptEngineType()

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
rating = FusionEngineTable[RoundUp5(rating)]
#primitive = FusionEngineTable[RoundUp5(rating * 1.2)]
#lithium = max((Inputs["BattleMech's Tonnage"]["value"]), (FusionEngineTable[RoundUp5(rating - Inputs["BattleMech's Tonnage"]["value"])]))
ed = {"Standard Fusion Engine" : max(0.5, rating),
"Light Fusion Engine" : max(0.5, RoundUpHalf(rating * .75)),
"XL Fusion Engine" : max(0.5, RoundUpHalf(rating * .50)),
"XXL Fusion Engine" : max(0.5, RoundUpHalf(rating / 3)),
"Compact Fusion Engine" : max(1.0, RoundUpHalf(rating * 1.5)),
"Internal Combustion Engine" : max(1.0, RoundUpHalf(rating * 2.0)),
"Fuel Cell Engine" : max(1.0, RoundUpHalf((rating * 2) * 0.5)),
"Fission Engine" : max(5.0, RoundUpHalf(rating * 1.75))#,
#"Lithium-Fusion Engine" : max(0.5, RoundUpHalf(lithium)),
#"Primitive Fusion Engine" : max(0.5, RoundUpHalf(primitive)),
#"Primitive Internal Combustion Engine" :max(1, RoundUpHalf(primitive * 2.0)),
#"Primitive Fuel Cell Engine" : max(1, RoundUpHalf(primitive * 1.2)),
#"Primitive Fission Engine" : max(5.0, RoundUpHalf(primitive * 1.75))
}
return ed[engine_type]

podspace = ((Inputs["BattleMech's Tonnage"]["value"]) - (EngineWeight(EngineType, rating)) - skeleton - gyro - cockpit)

print()
print ("Your", MechName, "has a Walk MP of", (Inputs["desired Walk MP"]["value"]), "hexes, and a Run MP of", flank, "hexes.")
print ("This speed is provided by a", rating,"rated", EngineType, "weighing", EngineWeight(EngineType, rating), "metric tons.")
print ("The mech's weight is supported by a", InternalType, "with a mass of", skeleton, "metric tons,")
print ("and keeping the", MechName, "upright is a", GyroType, "Gyro, weighing", gyro, "metric tons.")
print ("The pilot sits 'comfortably' in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.")
print()
print ("The", MechName, "has an average walking speed of", int((Inputs["desired Walk MP"]["value"]) * 3), "m/s, and a maximum running speed of", int(flank * 3), "m/s.")
print ("The", MechName, "has", podspace, "tons of Pod Space available to mount weapons, armor and equipment.")
print()
print("Press ENTER to exit the program.")
input('')


- - - - - - - - - - - - - - - - - - - -

Remember to report any and all bugs that you run into. It is important to make the continued development of this software go as smoothly as possible.

Also don't forget to share with me any features you want to see! Attachment (183 downloads)
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.


Edited by AmaroqStarwind (05/07/18 10:50 PM)
AmaroqStarwind
05/08/18 08:24 PM
13.84.155.127

Edit Reply Quote Quick Reply
Made some further changes. Enjoy.

Code:
# MechEngine, "Podspace" build, revision 2
# Build Date: 2018-05-08

#Development Goals:
#Reset input calls if calculated engine rating exceeds 500
#Add warning with Overweight Engines
#Add options to restart program and/or export log upon completions
#Add descriptions for each engine type
#Add engine descriptions to help the user make an informed decision.

#Add example mechs to choose from
#Flea:
#Tonnage: 20
#Movement: 6/9/0
#Endo Steel Chassis and 120 Standard Engine.
#UrbanMech:
#Tonnage: 30
#Movement: 2/3/2
#Standard Chassis and 60 Standard Engine.
#Raven:
#Tonnage: 35
#Movement: 6/9/0
#Standard Chassis and 210 XL Engine.
#Shadow Cat:
#Tonnage: 45
#Movement: 6/9/6
#Endo Steel Chassis and 270 XL Engine.
#Raider:
#Tonnage: 50
#Movement: 4/6/0
#Standard Chassis and 200 ICE.
#Bushwacker:
#Tonnage: 55
#Movement: 5/8/0
#Standard Chassis and 275 XL Engine.
#Ebon Jaguar (Cauldron Born):
#Tonnage: 65
#Movement: 5/8/0
#Endo Steel Chassis and 325 XL Engine.
#Timber Wolf (Mad Cat):
#Tonnage: 75
#Movement: 5/8/0
#Endo Steel Chassis and 375 XL Engine.
#Atlas:
#Tonnage: 100
#Movement: 3/5/0
#Standard Chassis and 300 Standard Engine.
#Dire Wolf:
#Tonnage: 100
#Movement: 3/5/0
#Standard Chassis and 300 XL Engine.


import math

def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()

def RoundUp5(x):
return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def RoundUpHalf(x):
return math.ceil(x*2)/2

def roundHalfUp(f): #deprecated!
return RoundUpHalf(f) #round(f + 0.00000000000001)

def roundEngine(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))

def roundTonnage(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))

#HYN-DRN-5813 Core Input Dictionary:
Inputs = {"BattleMech's Tonnage": {"min":10, "max":100, "value": None},
"desired Walk MP" : {"min":1, "max":29 , "value": None}}

def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)

def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False

def ask(question, min_val, max_val):
x = ''
while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#"Load inputs"
load_inputs(Inputs)

SuspFact = 0 #SuspFact = (input("Suspension Factor: "))
MechName = ("BattleMech")
NewMechName = input("Name your BattleMech: ")
if NewMechName != '': MechName = NewMechName

#"Do calculations"
flank = int(math.ceil(Inputs["desired Walk MP"]["value"] * 1.5))
rating = max(10, RoundUp5((Inputs["BattleMech's Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact))
gyro = max(1.0, ((2 * (math.ceil(rating/100))) * 0.5)) #Standard Gyros only
skeleton = max(0.5, (2 * ((math.ceil((Inputs["BattleMech's Tonnage"]["value"])/10)) * 0.50))) #Standard Internal Skeleton only
cockpit = 3.0 #Standard Cockpit only

InternalType = ("Standard Internal Structure")
#Standard: 10% Total BattleMech Tonnage (biped/quad), 11% (tripod)
#Double for SuperHeavy Mechs
#Endo Steel / Composite: 5% Total BattleMech Tonnage (biped/quad), 5.5% (tripod)
#Double for SuperHeavy Mechs
#Hybrid (aka "Endo-Composite"): 7.5% Total BattleMech Tonnage (biped/quad), 8.25% (tripod)
#Double for SuperHeavy Mechs
#Reinforced: 20% Total BattleMech Tonnage (biped/quad), 22% (tripod)
#Not available for SuperHeavy Mechs
#Industrial: 20% Total IndustrialMech Tonnage (biped/quad), 22% (Tripod)
#Double for SuperHeavy Mechs

GyroType = ("Standard")
#Standard Gyro: Engine Rating / 100, rounded up to next ton
#XL Gyro: Standard Gyro weight divided by 2
#Not available for engine ratings above 400.
#Compact Gyro: Standard Gyro weight multiplied by 1.5
#Heavy-Duty Gyro: Standard Gyro weight multiplied by 2
#SuperHeavy Gyro: Standard Gyro weight multiplied by 2
#No Gyro: Doesn't weigh anything or take up space, for obvious reasons.
#Only available on ProtoMechs or with Interface Cockpits.
#Primitive Gyro: Uses Primitive Engine rating.

CockpitType = ("Standard")
#Standard: 3 Tons.
#Small: 2 Tons.
#Halves oxygen supply and is very cramped.
#Interface: 4 Tons.
#Pilot is impervious to ammo explosions, and the mech doesn't need a gyro.
#Industral: 3 Tons.
#No ejection mechanism (usually) and has poor targeting systems.
#Tripod: 4 Tons.
#Two pilots!
#Dual: 4 Tons.
#Two pilots!
#Torso: 4 Tons.
#Pilot is protected by the torso armor, but is more susceptible to heat and cannot eject.
#SuperHeavy: 4 Tons.
#Two pilots!
#Cockpit Command Console: 5 Tons.
#Two pilots!
#Turns mech into a mobile command center.
#Primitive: 5 Tons.
#Primitive Industrial: 5 Tons.
#No targeting systems at all.
#SuperHeavy Tripod: 5 Tons.
#Three pilots!
#Turns mech into a mobile command center.

#"Master Engine Table:"

FusionEngineTable = {
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,
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,
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,
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,
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}

#Warning: ProtoMechs have not yet been implemented! Do not use this table!
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.
1: 0.025,
2: 0.050,
3: 0.075,
4: 0.100,
5: 0.125,
6: 0.150,
7: 0.175,
8: 0.200,
9: 0.225,
10: 0.250,
11: 0.275,
12: 0.300,
13: 0.325,
14: 0.350,
15: 0.375,
16: 0.400,
17: 0.425,
18: 0.450,
19: 0.475,
20: 0.500,
21: 0.525,
22: 0.550,
23: 0.575,
24: 0.600,
25: 0.625,
26: 0.650,
27: 0.675,
28: 0.700,
29: 0.725,
30: 0.750,
31: 0.775,
32: 0.800,
33: 0.825,
34: 0.850,
35: 0.875,
36: 0.900,
37: 0.925,
38: 0.950,
39: 0.975,
40: 1.000}

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine"#,
#Primitive Engines:
#"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"#,
#Special Engine Types:
#"Lithium-Fusion Engine"#, #ProtoMech Engine"#,

]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
return el[num]

EngineType = PromptEngineType()

def FusionWeight(x):
return FusionEngineTable[RoundUp5(x)]

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
weight = FusionWeight(rating)
primitive = FusionWeight(rating * 1.2)
lithium = FusionWeight(max((Inputs["BattleMech's Tonnage"]["value"]), (rating - (Inputs["BattleMech's Tonnage"]["value"]))))
ed = {"Standard Fusion Engine" : max(0.5, weight),
"Light Fusion Engine" : max(0.5, RoundUpHalf(weight * .75)),
"XL Fusion Engine" : max(0.5, RoundUpHalf(weight * .50)),
"XXL Fusion Engine" : max(0.5, RoundUpHalf(weight / 3)),
"Compact Fusion Engine" : max(1.0, RoundUpHalf(weight * 1.5)),
"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!
"Fuel Cell" : max(1.0, RoundUpHalf((weight * 2) * 0.5)), #Only 1 Heat Sink. Can't use energy weapons or Jump Jets. Don't forget fuel!
"Fission Engine" : max(5.0, RoundUpHalf(weight * 1.75)), #Only 5 Heat Sinks. Illegal and expensive.
"Lithium-Fusion Engine" : max(0.5, RoundUpHalf(lithium)), #Non-Canon. 10 Heat Sinks. Increases a mech's Walking Speed by 1.
"Primitive Fusion Engine" : max(0.5, RoundUpHalf(primitive)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Internal Combustion Engine (ICE)" : max(1, RoundUpHalf(primitive * 2.0)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fuel Cell" : max(1.0, RoundUpHalf(primitive * 1.2)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fission Engine" : max(5.0, RoundUpHalf(primitive * 1.75)) #Multiplies engine rating by 1.2, but does not increase performance.
}
return ed[engine_type]

podspace = ((Inputs["BattleMech's Tonnage"]["value"]) - (EngineWeight(EngineType, rating)) - skeleton - gyro - cockpit)

print()
print ("Your", MechName, "has a Walk MP of", (Inputs["desired Walk MP"]["value"]), "hexes, and a Run MP of", flank, "hexes.")
print ("This speed is provided by a", rating, "rated", EngineType, "weighing", EngineWeight(EngineType, rating), "metric tons.")
print ("The mech's weight is supported by a", InternalType, "with a mass of", skeleton, "metric tons,")
print ("and keeping the", MechName, "upright is a", GyroType, "Gyro, weighing", gyro, "metric tons.")
print ("The pilot sits 'comfortably' in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.")
print()
print ("The", MechName, "has an average walking speed of", ((Inputs["desired Walk MP"]["value"]) * 10.8), "km/h, and a maximum running speed of", (flank * 10.8), "km/h.")
print ("The", MechName, "has", podspace, "tons of Pod Space available to mount weapons, armor and equipment.")
print()
print ("Please visit www.sarna.net for more information on these terms and components.")
print ("If you have any questions or feedback about the software, please visit https://tinyurl.com/Sarna-Forums-MechEngine")
print()
print("Press ENTER to exit the program.")
input('')

~~~~
I colored that all by hand, by the way. Attachment (190 downloads)
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/09/18 08:56 PM
13.84.155.127

Edit Reply Quote Quick Reply
Bugfixes and New Features:
1. I fixed a crash that occurs if the user tries to get an engine rating above 500
2. I added a warning that will display if you end up with an engine rating higher than 500
3. I added warnings which display if your mech has negative podspace, or if the engine tonnage exceeds the mech's tonnage.
4. Engine Ratings above 500 are now extrapolated via a polynomial function.

- - - - - - - - - - - -

Google Drive: https://docs.google.com/document/d/1QmiJ3oWpNFptCU7t4uIFGPpbgR6yi9OW-FHyNg9omds

- - - - - - - - - - - -

Raw Code:
print("MechEngine, ''Podspace'' build, revision 3")
print ("Build Date: 2018-05-09. Designed using Python 3.6.5 Shell")
import math, os, sys, time
print()

#Development Goals:
#Reset input calls if calculated engine rating exceeds 500
#Add warning with Overweight Engines
#Add options to restart program and/or export log upon completions
#Add descriptions for each engine type
#Add engine descriptions to help the user make an informed decision.

#Add example mechs to choose from
#Flea:
#Tonnage: 20
#Movement: 6/9/0
#Endo Steel Chassis and 120 Standard Engine.
#UrbanMech:
#Tonnage: 30
#Movement: 2/3/2
#Standard Chassis and 60 Standard Engine.
#Raven:
#Tonnage: 35
#Movement: 6/9/0
#Standard Chassis and 210 XL Engine.
#Shadow Cat:
#Tonnage: 45
#Movement: 6/9/6
#Endo Steel Chassis and 270 XL Engine.
#Raider:
#Tonnage: 50
#Movement: 4/6/0
#Standard Chassis and 200 ICE.
#Bushwacker:
#Tonnage: 55
#Movement: 5/8/0
#Standard Chassis and 275 XL Engine.
#Ebon Jaguar (Cauldron Born):
#Tonnage: 65
#Movement: 5/8/0
#Endo Steel Chassis and 325 XL Engine.
#Timber Wolf (Mad Cat):
#Tonnage: 75
#Movement: 5/8/0
#Endo Steel Chassis and 375 XL Engine.
#Atlas:
#Tonnage: 100
#Movement: 3/5/0
#Standard Chassis and 300 Standard Engine.
#Dire Wolf:
#Tonnage: 100
#Movement: 3/5/0
#Standard Chassis and 300 XL Engine.

def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()

def RoundUp5(x):
return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def RoundUpHalf(x):
return math.ceil(x*2)/2

def RoundUpQuarter(x):
return math.ceil(x*4)/4

def RoundUpFractional(x):
return math.ceil(x*1000)/1000

def roundNearest(f):
return round(f + 0.00000000000001)

#Deprecated
def roundHalfUp(f): #deprecated!
return RoundUpHalf(f) #round(f + 0.00000000000001)

def roundEngine(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))

def roundTonnage(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))
#End Deprecation

#HYN-DRN-5813 Core Input Dictionary:
Inputs = {"BattleMech's Tonnage": {"min":10, "max":100, "value": None},
"desired Walk MP" : {"min":1, "max":29 , "value": None}}

def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)

def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False

def ask(question, min_val, max_val):
x = ''
while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#"Load inputs"
load_inputs(Inputs)

SuspFact = 0 #SuspFact = (input("Suspension Factor: "))
MechName = ("BattleMech")
NewMechName = input("Name your BattleMech: ")
if NewMechName != '': MechName = NewMechName
MechTonnage = (Inputs["BattleMech's Tonnage"]["value"])
CruisingSpeed = (Inputs["desired Walk MP"]["value"])
def kph(s):
return round((s*10.8)*100)/100

#"Do calculations"
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
rating = max(10, RoundUp5((Inputs["BattleMech's Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact))
if rating >500:
print ("WARNING! This engine rating is outside normal parameters, and has been extrapolated. Do not use it in an actual game.")
gyro = max(1.0, math.ceil(rating/100)) #Standard Gyros only
skeleton = max(0.5, (2 * ((math.ceil((Inputs["BattleMech's Tonnage"]["value"])/10)) * 0.50))) #Standard Internal Skeleton only
cockpit = 3.0 #Standard Cockpit only

InternalType = ("Standard Internal Structure")
#Standard: 10% Total BattleMech Tonnage (biped/quad), 11% (tripod)
#Double for SuperHeavy Mechs
#Endo Steel / Composite: 5% Total BattleMech Tonnage (biped/quad), 5.5% (tripod)
#Double for SuperHeavy Mechs
#Hybrid (aka "Endo-Composite"): 7.5% Total BattleMech Tonnage (biped/quad), 8.25% (tripod)
#Double for SuperHeavy Mechs
#Reinforced: 20% Total BattleMech Tonnage (biped/quad), 22% (tripod)
#Not available for SuperHeavy Mechs
#Industrial: 20% Total IndustrialMech Tonnage (biped/quad), 22% (Tripod)
#Double for SuperHeavy Mechs
GyroType = ("Standard")
#Standard Gyro: Engine Rating / 100, rounded up to next ton
#XL Gyro: Standard Gyro weight divided by 2
#Not available for engine ratings above 400.
#Compact Gyro: Standard Gyro weight multiplied by 1.5
#Heavy-Duty Gyro: Standard Gyro weight multiplied by 2
#SuperHeavy Gyro: Standard Gyro weight multiplied by 2
#No Gyro: Doesn't weigh anything or take up space, for obvious reasons.
#Only available on ProtoMechs or with Interface Cockpits.
#Primitive Gyro: Uses Primitive Engine rating.
CockpitType = ("Standard")
#Standard: 3 Tons.
#Small: 2 Tons.
#Halves oxygen supply and is very cramped.
#Interface: 4 Tons.
#Pilot is impervious to ammo explosions, and the mech doesn't need a gyro.
#Industral: 3 Tons.
#No ejection mechanism (usually) and has poor targeting systems.
#Tripod: 4 Tons.
#Two pilots!
#Dual: 4 Tons.
#Two pilots!
#Torso: 4 Tons.
#Pilot is protected by the torso armor, but is more susceptible to heat and cannot eject.
#SuperHeavy: 4 Tons.
#Two pilots!
#Cockpit Command Console: 5 Tons.
#Two pilots!
#Turns mech into a mobile command center.
#Primitive: 5 Tons.
#Primitive Industrial: 5 Tons.
#No targeting systems at all.
#SuperHeavy Tripod: 5 Tons.
#Three pilots!
#Turns mech into a mobile command center.

#"Master Engine Table:"
FusionEngineTable = {#See TechManual and Tactical Operations for more details
110: 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.
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.
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.
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.
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.
}

#Warning: ProtoMechs have not yet been implemented! Do not use this table!
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.
1: 0.025, 2: 0.050, 3: 0.075, 4: 0.100, 5: 0.125, 6: 0.150, 7: 0.175, 8: 0.200, 9: 0.225, 10: 0.250, 11: 0.275, 12: 0.300, 13: 0.325,
14: 0.350, 15: 0.375, 16: 0.400, 17: 0.425, 18: 0.450, 19: 0.475,
20: 0.500, 21: 0.525, 22: 0.550, 23: 0.575, 24: 0.600, 25: 0.625,
26: 0.650, 27: 0.675, 28: 0.700, 29: 0.725, 30: 0.750, 31: 0.775, 32: 0.800, 33: 0.825, 34: 0.850, 35: 0.875, 36: 0.900, 37: 0.925, 38: 0.950, 39: 0.975, 40: 1.000}

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
#"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
#"Lithium-Fusion Engine"#, #ProtoMech Engine"#,
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
return el[num]

EngineType = PromptEngineType()

def FusionWeight(rating):
if rating <501:
return FusionEngineTable[RoundUp5(rating)]
else:
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = roundNearest(weight * 1000)/1000
return weight
print ("WARNING! This Engine Rating is outside normal Rating parameters, and its weight has been extrapolated. Do not use it in an actual game.")
print()

def FusionWeightPoly(rating): #Uses polynomial curves and floating-point math to extrapolate mass for engine ratings beyond 500. Experimental feature, not recommended for use.
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = roundNearest(weight * 2)/2
return weight

#for k in FusionEngineTable:
# t = FusionWeight(k)
# p = FusionWeightPoly(k)
# d = t - p
# if d > .01:
# print(k, t, p, d)

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
weight = FusionWeight(rating)
# primitive = FusionWeight(rating * 1.2)
# lithium = FusionWeight(max(MechTonnage, (rating - MechTonnage)))
#505plus = FusionWeightPoly(rating)
#505plusLithium = FusionWeightPoly(max((Inputs["BattleMech's Tonnage"]["value"]), (rating - (Inputs["BattleMech's Tonnage"]["value"]))))
ed = {"Standard Fusion Engine" : max(0.5, weight),
"Light Fusion Engine" : max(0.5, RoundUpHalf(weight * .75)),
"XL Fusion Engine" : max(0.5, RoundUpHalf(weight * .50)),
"XXL Fusion Engine" : max(0.5, RoundUpHalf(weight / 3)),
"Compact Fusion Engine" : max(1.0, RoundUpHalf(weight * 1.5)),
"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!
"Fuel Cell" : max(1.0, RoundUpHalf((weight * 2) * 0.5)), #Only 1 Heat Sink. Can't use energy weapons or Jump Jets. Don't forget fuel!
"Fission Engine" : max(5.0, RoundUpHalf(weight * 1.75)), #Only 5 Heat Sinks. Illegal in the Inner Sphere, and expensive.
# "Lithium-Fusion Engine" : max(0.5, RoundUpHalf(lithium)), #Non-Canon. 10 Heat Sinks. Increases a mech's Walking Speed by 1.
# "Primitive Fusion Engine" : max(0.5, RoundUpHalf(primitive)), #Multiplies engine rating by 1.2, but does not increase performance.
# "Primitive Internal Combustion Engine (ICE)" : max(1, RoundUpHalf(primitive * 2.0)), #Multiplies engine rating by 1.2, but does not increase performance.
# "Primitive Fuel Cell" : max(1.0, RoundUpHalf(primitive * 1.2)), #Multiplies engine rating by 1.2, but does not increase performance.
# "Primitive Fission Engine" : max(5.0, RoundUpHalf(primitive * 1.75)) #Multiplies engine rating by 1.2, but does not increase performance.
}
return ed[engine_type]

#Messy, should clean up later
FinalRating = rating
#def Gyrofy(FinalRating):
#return math.ceil(FinalRating /100)
GyroRating = math.ceil(FinalRating / 100)#Gyrofy(FinalRating)

#if EngineType is "Lithium-Fusion Engine":
# FinalRating = max(MechTonnage, (rating - MechTonnage)),
# GyroRating = math.ceil(FinalRating / 100)#Gyrofy(FinalRating)
# GyroType = ("Standard")#Change this line once alternate Gyro types have been implemented
#else:
# FinalRating = rating
# math.ceil(FinalRating / 100)#Gyrofy(FinalRating)
# GyroType = ("Standard")#Change this line once alternate Gyro types have been implemented
#if EngineType is "Primitive Fusion Engine" or "Primitive Internal Combustion Engine (ICE)" or "Primitive Fuel Cell" or "Primitive Fission Engine":
# FinalRating = RoundUp5(rating * 1.2),
# GyroRating = math.ceil(FinalRating / 100)#Gyrofy(FinalRating)
# GyroType = ("Primitive")
#else:
# FinalRating = rating,
# math.ceil(FinalRating / 100)#Gyrofy(FinalRating)
# GyroType = ("Standard")#Change this line once alternate Gyro types have been implemented

GyroWeight = GyroRating #Change this line once alternate Gyro types have been implemented
podspace = (MechTonnage - (EngineWeight(EngineType, rating)) - skeleton - GyroWeight - cockpit)

if (EngineWeight(EngineType, rating)) > MechTonnage:
print ("WARNING! Your engine is heavier than the mech!")
if podspace <0:
print ("WARNING! Your mech has negative podspace, and is Overweight!")

print()
print ("Your", MechName, "has a Walk MP of", CruisingSpeed, "hexes, and a Run MP of", FlankingSpeed, "hexes.")
print ("This speed is provided by a", FinalRating, "rated", EngineType, "weighing", EngineWeight(EngineType, rating), "metric tons.")
print ("The mech's weight is supported by a", InternalType, "with a mass of", skeleton, "metric tons,")
print ("and keeping the", MechName, "upright is a", GyroType, "Gyro, weighing", GyroRating, "metric tons.")
print ("The pilot sits 'comfortably' in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.")
print()
print ("The", MechName, "has an average walking speed of", kph(CruisingSpeed), "km/h, and a maximum running speed of", kph(FlankingSpeed), "km/h.")
print ("The", MechName, "has", podspace, "tons of Pod Space available to mount weapons, armor and equipment.")
print()
print ("Please visit www.sarna.net for more information on these terms and components.")
print ("If you have any questions or feedback about the software, please visit https://tinyurl.com/Sarna-Forums-MechEngine")
print()
input("Press ENTER to exit the program.") #Change this line to a menu option once Restart has been implemented.
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.


Edited by AmaroqStarwind (05/10/18 07:48 PM)
AmaroqStarwind
05/10/18 10:03 PM
99.203.154.41

Edit Reply Quote Quick Reply
Latest version is out, and I'm pretty sure that it's far too big to put the raw code for it in this post, but I'm going to try.

In the meantime, here's a list of some new features and bugfixes.
- Primitive Engine rating now displays correctly, and only when Primitive Engines are used.
- Primitive Gyros and Primitive Cockpits now calculate correctly, and are only used when Primitive Engines are used.
- ProtoMech engines are now available if your Tonnage is 15 or less.
- Speed now displays in Kilometers Per Hour, instead of Meters Per Second.
- If a ProtoMech engine is selected, the correct formula is used to determine its weight if the rating is below 40. If the rating is 40 or above, then it will instead use the Master Engine Table.
- ProtoMech Engines do not use Gyros and will use an appropriately weighted cockpit.
- Primitive Engines and Lithium-Fusion Engines are now available, and will calculate the Engine Rating correctly.
- If the calculated Podspace is either 0 or a negative value, then the readout message for Podspace will change to indicate that you cannot carry any weapons, armor or equipment.
- SuperHeavy units are back! What's more, they calculate their Cockpit, Internal Structure and Gyro weights correctly, and the available engine types are restricted to Fission Engines, Fusion Engines and their derivatives.
- Alternate Gyro types are now available, except for SuperHeavy Mechs (which use SuperHeavy Gyros) and ProtoMechs (which do not have Gyros).
- If the Engine Rating exceeds 400, then Compact Engines and XL Gyros are not available. It also tells you to select a Large Engine type, instead of just an Engine type.
- If the Engine Rating exceeds 400, and then drops back into the 400 range if you select a Lithium-Fusion Engine, XL Gyros become available again.

I have successfully constructed a Mackie, an Atlas, an Atlas Lithium (Lithium Fusion test run), a Dire Wolf, a Bushwacker, and the UrbanMech UM-WTF IIC with the help of this tool. I have also published the code on Google Drive.

https://docs.google.com/document/d/1A6Y79pelpzdRg00DHcZNO3tyrdvthFSaU4tihSvGkE8

- = + = - = + = - = + = - = + = - = + = -

Code:
print("MechEngine, ''Podspace'' build, revision 5")
print ("Build Date: 2018-05-10. Designed using Python 3.6.4 Stackless Shell")
import math, os, sys, time
print()

#Development Goals:
#Add options to restart program and/or export log upon completion.
#Add engine descriptions to help the user make an informed decision.
#Implement selectable alternate Cockpit and Internal Structure types.
#Add example mechs to choose from:
#Moved below

def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()

def RoundUp5(x):
return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def RoundUpHalf(x):
return math.ceil(x*2)/2

def RoundUpQuarter(x):
return math.ceil(x*4)/4

def RoundUpFractional(x):
return math.ceil(x*1000)/1000

def roundNearest(f):
return round(f + 0.00000000000001)

#Deprecated
def roundHalfUp(f): #deprecated!
return RoundUpHalf(f) #round(f + 0.00000000000001)

def roundEngine(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))

def roundTonnage(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))
#End Deprecation

#HYN-DRN-5813 Core Input Dictionary:
Inputs = {"BattleMech's Tonnage": {"min":10, "max":200, "value": None},
"desired Walk MP" : {"min":1, "max":30 , "value": None}}

def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)

def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False

def ask(question, min_val, max_val):
x = ''
while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#"Load inputs"
load_inputs(Inputs)

SuspFact = 0 #SuspFact = (input("Suspension Factor: "))
MechName = ("BattleMech")
NewMechName = input("Name your BattleMech: ")
if NewMechName != '': MechName = NewMechName
MechTonnage = (Inputs["BattleMech's Tonnage"]["value"])
CruisingSpeed = (Inputs["desired Walk MP"]["value"])
def kph(s):
return round((s*10.8)*100)/100
def metersec(s):
return round((s*3)*100)/100
def mph(s):
return round((s*6.71)*100)/100

#"Do calculations"
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
rating = max(10, RoundUp5((Inputs["BattleMech's Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact))
if rating >500:
print ("WARNING! This engine rating is outside normal parameters, and has been extrapolated. Do not use it in an actual game.")

#def PromptCockpitType()
#Standard: 3 Tons.
#Small: 2 Tons.
#Interface: 4 Tons. No Gyro.
#Industral: 3 Tons.
#Tripod/Dual/SuperHeavy: 4 Tons.
#Two pilots!
#Torso: 4 Tons.
#Primitive: 5 Tons.
#Primitive Industrial: 5 Tons.
#Cockpit Command Console: 5 Tons.
#Two pilots!
#Turns mech into a mobile command center.
#SuperHeavy Tripod: 5 Tons.
#Three pilots!
#Turns mech into a mobile command center.

#def PromptInternalType()
#Standard: 10% Total BattleMech Tonnage (biped/quad), 11% (tripod)
#Double for SuperHeavy Mechs
#Endo Steel / Composite: 5% Total BattleMech Tonnage (biped/quad), 5.5% (tripod)
#Double for SuperHeavy Mechs
#Hybrid (aka "Endo-Composite"): 7.5% Total BattleMech Tonnage (biped/quad), 8.25% (tripod)
#Double for SuperHeavy Mechs
#Reinforced: 20% Total BattleMech Tonnage (biped/quad), 22% (tripod)
#Not available for SuperHeavy Mechs
#Industrial: 20% Total IndustrialMech Tonnage (biped/quad), 22% (Tripod)
#Double for SuperHeavy Mechs

if MechTonnage > 100:
InternalType = ("SuperHeavy Internal Structure") #Change once alternate structure types have been implemented
skeleton = max(0.5, RoundUpHalf(MechTonnage/5))
CockpitType = ("SuperHeavy")
cockpit = 5.0
else:
InternalType = ("Standard Internal Structure") #PromptInternalType()
skeleton = max(0.5, RoundUpHalf(MechTonnage/10)) #Standard Internal Skeleton only
CockpitType = ("Standard") #PromptCockpitType()
cockpit = 3.0

#"Master Engine Table:"
FusionEngineTable = {#See TechManual and Tactical Operations for more details
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.
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.
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.
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.
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.
}

#Warning: ProtoMechs have not yet been implemented! Do not use this table!
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.
1: 0.025, 2: 0.050, 3: 0.075, 4: 0.100, 5: 0.125, 6: 0.150, 7: 0.175, 8: 0.200, 9: 0.225, 10: 0.250,
11: 0.275, 12: 0.300, 13: 0.325, 14: 0.350, 15: 0.375, 16: 0.400, 17: 0.425, 18: 0.450, 19: 0.475, 20: 0.500,
21: 0.525, 22: 0.550, 23: 0.575, 24: 0.600, 25: 0.625, 26: 0.650, 27: 0.675, 28: 0.700, 29: 0.725, 30: 0.750,
31: 0.775, 32: 0.800, 33: 0.825, 34: 0.850, 35: 0.875, 36: 0.900, 37: 0.925, 38: 0.950, 39: 0.975, 40: 1.000,}

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
if 15 < MechTonnage < 101:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", #ProtoMech Engine",
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", #ProtoMech Engine",
]
print("Large Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
elif MechTonnage < 16:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", "ProtoMech Engine",
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", "ProtoMech Engine",
]
print("Large Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Fuel Cell", "Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine",
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
"Fuel Cell", "Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine",
]
print("Large Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]

EngineType = PromptEngineType()
if EngineType in {"ProtoMech Engine"}:
rating = MechTonnage * FlankingSpeed
else:
rating = MechTonnage * CruisingSpeed - SuspFact

def FusionWeight(rating):
if rating <501:
return FusionEngineTable[RoundUp5(rating)]
elif EngineType in {"ProtoMech Engine"}:
if rating <40:
return ProtoMechEngineTable[rating]
else:
return FusionEngineTable[RoundUp5(rating)]
else:
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = roundNearest(weight * 1000)/1000
return weight
print ("WARNING! This Engine Rating is outside normal Rating parameters, and its weight has been extrapolated. Do not use it in an actual game.")
print()

def FusionWeightPoly(rating): #Uses polynomial curves and floating-point math to extrapolate mass for engine ratings beyond 500. Experimental feature, not recommended for use.
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = roundNearest(weight * 2)/2
return weight

#for k in FusionEngineTable:
# t = FusionWeight(k)
# p = FusionWeightPoly(k)
# d = t - p
# if d > .01:
# print(k, t, p, d)

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
weight = FusionWeight(rating)
primitive = FusionWeight(rating * 1.2)
lithium = FusionWeight(max(MechTonnage, (rating - MechTonnage)))
if rating < 40:
proto = ProtoMechEngineTable[rating]
else:
proto = FusionWeight(rating)
#505plus = FusionWeightPoly(rating)
#505plusLithium = FusionWeightPoly(max((Inputs["BattleMech's Tonnage"]["value"]), (rating - (Inputs["BattleMech's Tonnage"]["value"]))))
ed = {"Standard Fusion Engine" : max(0.5, weight),
"Light Fusion Engine" : max(0.5, RoundUpHalf(weight * .75)),
"XL Fusion Engine" : max(0.5, RoundUpHalf(weight * .50)),
"XXL Fusion Engine" : max(0.5, RoundUpHalf(weight / 3)),
"Compact Fusion Engine" : max(1.0, RoundUpHalf(weight * 1.5)),
"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!
"Fuel Cell" : max(1.0, RoundUpHalf((weight * 2) * 0.5)), #Only 1 Heat Sink. Can't use energy weapons or Jump Jets. Don't forget fuel!
"Fission Engine" : max(5.0, RoundUpHalf(weight * 1.75)), #Only 5 Heat Sinks. Illegal in the Inner Sphere, and expensive.
"Lithium-Fusion Engine" : max(0.5, RoundUpHalf(lithium)), #Non-Canon. 10 Heat Sinks. Increases a mech's Walking Speed by 1.
"Primitive Fusion Engine" : max(0.5, RoundUpHalf(primitive)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Internal Combustion Engine (ICE)" : max(1, RoundUpHalf(primitive * 2.0)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fuel Cell" : max(1.0, RoundUpHalf(primitive * 1.2)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fission Engine" : max(5.0, RoundUpHalf(primitive * 1.75)), #Multiplies engine rating by 1.2, but does not increase performance.
"ProtoMech Engine" : (proto * 1.000),
}
return ed[engine_type]

#Messy, should clean up later
def PromptGyroType():
"""Ask the user for their desired gyro type, then return it."""
#gyro list:
if rating <401:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
else:
if EngineType in {"Lithium-Fusion Engine"}:
if rating - MechTonnage < 401:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
else:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "Compact", "Heavy-Duty",]
else:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "Compact", "Heavy-Duty",]
print("Gyro types:")
for i in range(0, len(gl)):
print(" (%d) %s"%(i, gl[i]))
num = ask("Please enter number of your desired Gyro type", 0, len(gl)-1)
print()
return gl[num]

FinalRating = rating
GyroRating = math.ceil(FinalRating / 100)

if EngineType in {"Lithium-Fusion Engine"}:
FinalRating = max(MechTonnage, (rating - MechTonnage))
GyroRating = math.ceil(FinalRating / 100)
if MechTonnage <101:
GyroType = PromptGyroType()
else:
GyroType = ("SuperHeavy")
elif EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"}:
FinalRating = RoundUp5(rating * 1.2)
GyroRating = math.ceil(FinalRating / 100)
CockpitType = ("Primitive")
cockpit = 5.0
GyroType = ("Primitive")
#InternalType = ("Primitive Internal Structure")
elif EngineType in {"ProtoMech Engine"}:
FinalRating = rating
GyroType = ("None")
#InternalType = ("ProtoMech Internal Structure")
if MechTonnage < 10:
CockpitType = ("ProtoMech")
cockpit = 0.500
else:
CockpitType = ("UltraHeavy ProtoMech")
cockpit = 0.750
else:
FinalRating = rating
GyroRating = math.ceil(FinalRating / 100)
if MechTonnage < 101:
GyroType = PromptGyroType()
#elif CockpitType in {"Interface Cockpit"}:
#GyroType = ("None")
else:
GyroType = ("SuperHeavy")

def GyroWeight(gyro_type):
#Using a dictionary to match engine name to a formula
gmass = GyroRating
ed = {
"Standard" : max(1, gmass*1.0),
"XL (Extra-Light)" : max(1, RoundUpHalf(gmass/2.0)),
"Compact" : max(1.5, RoundUpHalf(gmass*1.5)),
"Heavy-Duty" : max(2, math.ceil(gmass*2.0)),
"SuperHeavy" : max(2, math.ceil(gmass*2.0)),
"Primitive" : max(1, (gmass*1.0)),
"Primitive SuperHeavy" : max(2, math.ceil(gmass*2.0)),
"None": (gmass*0.0),
}
return ed[gyro_type]

podspace = (MechTonnage - (EngineWeight(EngineType, rating)) - skeleton - GyroWeight(GyroType) - cockpit)

if (EngineWeight(EngineType, rating)) > MechTonnage:
print ("WARNING! Your engine is heavier than the mech!")
if podspace <0:
print ("WARNING! Your mech has negative podspace, and is Overweight!")

print ("Your", MechName, "has a Walk MP of", CruisingSpeed, "hexes, and a Run MP of", FlankingSpeed, "hexes.")
print ("This speed is provided by a", FinalRating, "rated", EngineType, "weighing", EngineWeight(EngineType, rating), "metric tons.")
print ("The mech's weight is supported by a", InternalType, "with a mass of", skeleton, "metric tons,")
if GyroType in {"None"}:
print("The pilot is cocooned in a(n)", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.")
print()
elif GyroType in {"SuperHeavy"}:
print ("and keeping the", MechName, "upright is a(n)", GyroType, "Gyro, weighing", GyroWeight(GyroType), "metric tons.")
print ("The pilots are huddled together in a", CockpitType, "Cockpit, weighing a massive", cockpit, "metric tons.")
print()
else:
print ("and keeping the", MechName, "upright is a(n)", GyroType, "Gyro, weighing", GyroWeight(GyroType), "metric tons.")
print ("The pilot sits 'comfortably' in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.")
print()

print ("The", MechName, "has an average walking speed of", kph(CruisingSpeed), "km/h, and a maximum running speed of", kph(FlankingSpeed), "km/h.")
if podspace > 0:
print ("The", MechName, "has", podspace, "tons of Pod Space available to mount weapons, armor and equipment.")
print()
else:
print ("The", MechName, "has", podspace, "tons of Pod Space left, and cannot mount any weapons, armor or equipment.")
print()

print ("Please visit www.sarna.net for more information on these terms and components.")
print ("If you have any questions or feedback about the software, please visit https://tinyurl.com/Sarna-Forums-MechEngine")
print()
input("Press ENTER to exit the program.") #Change this line to a menu option once Restart has been implemented.

#Example Mechs roadmap, WIP:
#Flea:
#Tonnage: 20
#Class: Light (Biped)
#Tech: Inner Sphere
#Movement: 6/9/0
#Endo Steel Chassis: 1.0 Tons
#120 Standard Engine.
#
#UrbanMech:
#Tonnage: 30
#Class: Light (Biped)
#Tech: Inner Sphere
#Movement: 2/3/2
#Standard Chassis: 3.0 Tons
#60 Standard Engine.
#11 Standard Heat Sinks: 1.0 Tons
#Raven:
#Tonnage: 35
#Movement: 6/9/0
#Standard Chassis: 3.5 Tons
#210 XL Engine.
#Ostscout IIC (Fixed):
#Tonnage: 30
#Class: Light (Biped)
#Movement: 11/17/11
#Endo Steel Chassis: 1.5 Tons
#330 XL Engine: 12.5 Tons
#Ostscout IIC (Original):
#Tonnage: 35
#Class: Light (Biped)
#Movement: 11/17/11
#Tech: Clan
#Endo Steel Chassis: 2.0 Tons
#385 XXL Fusion Engine: 14.5 Tons
#10 Standard Heat Sinks: 0.0 Tons
#Standard Gyro: 4 Tons
#Small Cockpit: 2 Tons
#Shadow Cat:
#Tonnage: 45
#Movement: 6/9/6
#Endo Steel Chassis: 2.5 Tons
#270 XL Engine.
#
#Raider:
#Tonnage: 50
#Movement: 4/6/0
#Standard Chassis: 5.0 Tons
#200 Internal Combustion Engine
#2 Standard Heat Sinks: 2.0 Tons
#Bushwacker:
#Tonnage: 55
#Movement: 5/8/0
#Standard Chassis: 5.5 Tons
#275 XL Engine: 8.0 Tons
#11 Double Heat Sinks: 1.0 Tons
#Standard Gyro: 3 Tons
#Standard Cockpit: 3 Tons
#Mad Dog (Vulture):
#Tonnage: 60
#Ebon Jaguar (Cauldron Born):
#Tonnage: 65
#Movement: 5/8/0
#Endo Steel Chassis
#325 XL Engine
#Standard Gyro: 4 Tons
#Standard Cockpit: 3 Tons
#Timber Wolf (Mad Cat):
#Tonnage: 75
#Movement: 5/8/0
#Endo Steel Chassis: 4.0 Tons
#375 XL Engine:
#15 Double Heat Sinks: 0.0 Tons
#Atlas:
#Tonnage: 100
#Movement: 3/5/0
#Standard Chassis: 10 Tons
#300 Standard Engine
#Dire Wolf (Daishi):
#Tonnage: 100
#Movement: 3/5/0
#Standard Chassis: 10 Tons
#300 XL Engine
#Standard Gyro: 3 Tons
#Standard Cockpit: 3 Tons
#Mackie:
#Tonnage: 100
#Class: Assault (Biped)
#Tech: Primitive
#Movement: 3/5/0
#Primitive Chassis: 10 Tons
#360 Primitive Fusion Engine
#Primitive Gyro: 4 Tons
#Primitive Cockpit: 5 Tons
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/11/18 08:08 PM
174.235.12.17

Edit Reply Quote Quick Reply
Quick bugs found:
- I forgot to prohibit SuperHeavy mechs from carrying Fuel Cells.
- I accidentally set the weight of a SuperHeavy Cockpit to 5 tons instead of 4
- I forgot to change the internal structure type of ProtoMechs from Standard Internal Structure to ProtoMech Internal Structure.

I intend to fix all of these issues before the next release. That is all~!
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/14/18 08:27 PM
13.84.155.127

Edit Reply Quote Quick Reply
Future development of the software has been cancelled. It has reached a point that most of the important features have all been implemented (besides cockpits and internal structures), and I cannot actually work on it any further because of unrelated outside factors.

I am sorry if anyone was actually looking forward to the next version release, but as I had stated before in previous posts, it is Open-Source. You will still need a Python 3 interpreter and editor to run it and make any changes, and if you have any questions regarding the code itself, do not be afraid to contact me on Discord. (My Discord tag is "Amaroq Starwind#1092")

Here is the latest code release.

- - - - - - - - - - - - - - - - - -
Code:
print("MechEngine Beta, 0.30.63")
print ("Build Date: 2018-05-14. Designed using Python 3.6.4 Stackless Shell")
import math, os, sys, time
print()

#Development Goals:
#Add options to restart program and/or export log upon completion.
#Add engine descriptions to help the user make an informed decision.
#Implement selectable alternate Cockpit and Internal Structure types.
#Add example mechs to choose from:
#Moved below

def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()

def RoundUp5(x):
return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def RoundUpHalf(x):
return math.ceil(x*2)/2

def RoundUpQuarter(x):
return math.ceil(x*4)/4

def RoundUpFractional(x):
return math.ceil(x*1000)/1000

def roundNearest(f):
return round(f + 0.00000000000001)

#Deprecated
def roundHalfUp(f): #deprecated!
return RoundUpHalf(f) #round(f + 0.00000000000001)

def roundEngine(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))

def roundTonnage(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base))
#End Deprecation

#HYN-DRN-5813 Core Input Dictionary:
Inputs = {"BattleMech's Tonnage": {"min":2, "max":200, "value": None},
"desired Walk MP" : {"min":1, "max":30 , "value": None}}

def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)

def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False

def ask(question, min_val, max_val):
x = ''
while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#"Load inputs"
load_inputs(Inputs)

SuspFact = 0 #SuspFact = (input("Suspension Factor: "))
MechName = ("BattleMech")
NewMechName = input("Name your BattleMech: ")
if NewMechName != '': MechName = NewMechName
print()
MechTonnage = (Inputs["BattleMech's Tonnage"]["value"])
CruisingSpeed = (Inputs["desired Walk MP"]["value"])
def kph(s):
return round((s*10.8)*100)/100
def metersec(s):
return round((s*3)*100)/100
def mph(s):
return round((s*6.71)*100)/100

#"Do calculations"
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
rating = max(10, RoundUp5((Inputs["BattleMech's Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact))
if rating >500:
print ("WARNING! This engine rating is outside normal parameters, and has been extrapolated. Do not use it in an actual game.")

#def PromptCockpitType()
#Standard: 3 Tons.
#Small: 2 Tons.
#Interface: 4 Tons. No Gyro.
#Industral: 3 Tons.
#Tripod/Dual/SuperHeavy: 4 Tons.
#Two pilots!
#Torso: 4 Tons.
#Primitive: 5 Tons.
#Primitive Industrial: 5 Tons.
#Cockpit Command Console: 5 Tons.
#Two pilots!
#Turns mech into a mobile command center.
#SuperHeavy Tripod: 5 Tons.
#Three pilots!
#Turns mech into a mobile command center.

#def PromptInternalType()
#Standard: 10% Total BattleMech Tonnage (biped/quad), 11% (tripod)
#Double for SuperHeavy Mechs
#Endo Steel / Composite: 5% Total BattleMech Tonnage (biped/quad), 5.5% (tripod)
#Double for SuperHeavy Mechs
#Hybrid (aka "Endo-Composite"): 7.5% Total BattleMech Tonnage (biped/quad), 8.25% (tripod)
#Double for SuperHeavy Mechs
#Reinforced: 20% Total BattleMech Tonnage (biped/quad), 22% (tripod)
#Not available for SuperHeavy Mechs
#Industrial: 20% Total IndustrialMech Tonnage (biped/quad), 22% (Tripod)
#Double for SuperHeavy Mechs

if MechTonnage > 100:
InternalType = ("SuperHeavy Internal Structure") #Change once alternate structure types have been implemented
skeleton = max(0.5, RoundUpHalf(MechTonnage/5))
CockpitType = ("SuperHeavy")
cockpit = 4.0
else:
InternalType = ("Standard Internal Structure") #PromptInternalType()
skeleton = max(0.5, RoundUpHalf(MechTonnage/10)) #Standard Internal Skeleton only
CockpitType = ("Standard") #PromptCockpitType()
cockpit = 3.0

#"Master Engine Table:"
FusionEngineTable = {#See TechManual and Tactical Operations for more details
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.
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.
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.
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.
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.
}

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.
1: 0.025, 2: 0.050, 3: 0.075, 4: 0.100, 5: 0.125, 6: 0.150, 7: 0.175, 8: 0.200, 9: 0.225, 10: 0.250,
11: 0.275, 12: 0.300, 13: 0.325, 14: 0.350, 15: 0.375, 16: 0.400, 17: 0.425, 18: 0.450, 19: 0.475, 20: 0.500,
21: 0.525, 22: 0.550, 23: 0.575, 24: 0.600, 25: 0.625, 26: 0.650, 27: 0.675, 28: 0.700, 29: 0.725, 30: 0.750,
31: 0.775, 32: 0.800, 33: 0.825, 34: 0.850, 35: 0.875, 36: 0.900, 37: 0.925, 38: 0.950, 39: 0.975, 40: 1.000,}

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
if 15 < MechTonnage < 101:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", #ProtoMech Engine",
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", #ProtoMech Engine",
]
print("Large Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
elif MechTonnage < 16:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", "ProtoMech Engine",
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", "ProtoMech Engine",
]
print("Large Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
#"Fuel Cell",
"Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine",
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
#"Fuel Cell",
"Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine",
]
print("Large Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]))
num = ask("Please enter number of your desired engine type", 0, len(el)-1)
print()
return el[num]
if MechTonnage < 10:
EngineType = ("ProtoMech Engine")
else:
EngineType = PromptEngineType()

if EngineType in {"ProtoMech Engine"}:
rating = (MechTonnage * FlankingSpeed)
else:
rating = (MechTonnage * CruisingSpeed) - SuspFact

if EngineType in {"Lithium-Fusion Engine"}:
if CruisingSpeed < 2:
CruisingSpeed = 2
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
elif CruisingSpeed > 1:
CruisingSpeed = (Inputs["desired Walk MP"]["value"])
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)

def FusionWeight(rating):
if rating <501:
return FusionEngineTable[RoundUp5(rating)]
elif EngineType in {"ProtoMech Engine"}:
if rating <41:
return Rating * 0.025 #ProtoMechEngineTable[rating]
else:
return FusionEngineTable[RoundUp5(rating)]
else:
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = roundNearest(weight * 1000)/1000
return weight
print ("WARNING! This Engine Rating is outside normal Rating parameters, and its weight has been extrapolated. Do not use it in an actual game.")
print()

def FusionWeightPoly(rating): #Uses polynomial curves and floating-point math to extrapolate mass for engine ratings beyond 500. Experimental feature, not recommended for use.
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = roundNearest(weight * 2)/2
return weight

#for k in FusionEngineTable:
# t = FusionWeight(k)
# p = FusionWeightPoly(k)
# d = t - p
# if d > .01:
# print(k, t, p, d)

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
weight = FusionWeight(rating)
primitive = FusionWeight(rating * 1.2)
lithium = FusionWeight(max(MechTonnage, rating - MechTonnage))
if rating < 40:
proto = ProtoMechEngineTable[rating]
else:
proto = FusionWeight(rating)
#505plus = FusionWeightPoly(rating)
#505plusLithium = FusionWeightPoly(max((Inputs["BattleMech's Tonnage"]["value"]), (rating - (Inputs["BattleMech's Tonnage"]["value"]))))
ed = {"Standard Fusion Engine" : max(0.5, weight),
"Light Fusion Engine" : max(0.5, RoundUpHalf(weight * .75)),
"XL Fusion Engine" : max(0.5, RoundUpHalf(weight * .50)),
"XXL Fusion Engine" : max(0.5, RoundUpHalf(weight / 3)),
"Compact Fusion Engine" : max(1.0, RoundUpHalf(weight * 1.5)),
"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!
"Fuel Cell" : max(1.0, RoundUpHalf((weight * 2) * 0.5)), #Only 1 Heat Sink. Can't use energy weapons or Jump Jets. Don't forget fuel!
"Fission Engine" : max(5.0, RoundUpHalf(weight * 1.75)), #Only 5 Heat Sinks. Illegal in the Inner Sphere, and expensive.
"Lithium-Fusion Engine" : max(0.5, RoundUpHalf(lithium)), #Non-Canon. 10 Heat Sinks. Increases a mech's Walking Speed by 1.
"Primitive Fusion Engine" : max(0.5, RoundUpHalf(primitive)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Internal Combustion Engine (ICE)" : max(1, RoundUpHalf(primitive * 2.0)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fuel Cell" : max(1.0, RoundUpHalf(primitive * 1.2)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fission Engine" : max(5.0, RoundUpHalf(primitive * 1.75)), #Multiplies engine rating by 1.2, but does not increase performance.
"ProtoMech Engine" : (proto * 1.000),
}
return ed[engine_type]

#Messy, should clean up later
def PromptGyroType():
"""Ask the user for their desired gyro type, then return it."""
#gyro list:
if rating <401:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
else:
if EngineType in {"Lithium-Fusion Engine"}:
if rating - MechTonnage < 401:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
else:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "Compact", "Heavy-Duty",]
else:
gl = [#Gyro Types; ignore if using Interface Cockpit
"Standard", "Compact", "Heavy-Duty",]
print("Gyro types:")
for i in range(0, len(gl)):
print(" (%d) %s"%(i, gl[i]))
num = ask("Please enter number of your desired Gyro type", 0, len(gl)-1)
print()
return gl[num]

FinalRating = rating
GyroRating = math.ceil(FinalRating / 100)

if EngineType in {"Lithium-Fusion Engine"}:
FinalRating = max(MechTonnage, (rating - MechTonnage))
GyroRating = math.ceil(FinalRating / 100)
if MechTonnage <101:
GyroType = PromptGyroType()
else:
GyroType = ("SuperHeavy")
elif EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"}:
FinalRating = RoundUp5(rating * 1.2)
GyroRating = math.ceil(FinalRating / 100)
CockpitType = ("Primitive")
cockpit = 5.0
GyroType = ("Primitive")
#InternalType = ("Primitive Internal Structure")
elif EngineType in {"ProtoMech Engine"}:
FinalRating = rating
GyroType = ("None")
InternalType = ("ProtoMech Internal Structure")
#InternalType = ("ProtoMech Internal Structure")
if MechTonnage < 10:
CockpitType = ("ProtoMech")
cockpit = 0.500
else:
CockpitType = ("UltraHeavy ProtoMech")
cockpit = 0.750
else:
FinalRating = rating
GyroRating = math.ceil(FinalRating / 100)
if MechTonnage < 101:
GyroType = PromptGyroType()
#elif CockpitType in {"Interface Cockpit"}:
#GyroType = ("None")
else:
GyroType = ("SuperHeavy")

def GyroWeight(gyro_type):
#Using a dictionary to match engine name to a formula
gmass = GyroRating
ed = {
"Standard" : max(1, gmass*1.0),
"XL (Extra-Light)" : max(1, RoundUpHalf(gmass/2.0)),
"Compact" : max(1.5, RoundUpHalf(gmass*1.5)),
"Heavy-Duty" : max(2, math.ceil(gmass*2.0)),
"SuperHeavy" : max(2, math.ceil(gmass*2.0)),
"Primitive" : max(1, (gmass*1.0)),
"Primitive SuperHeavy" : max(2, math.ceil(gmass*2.0)),
"None": (gmass*0.0),
}
return ed[gyro_type]

podspace = (MechTonnage - (EngineWeight(EngineType, rating)) - skeleton - GyroWeight(GyroType) - cockpit)

if (EngineWeight(EngineType, rating)) > MechTonnage:
print ("WARNING! Your engine is heavier than the mech!")
if podspace <0:
print ("WARNING! Your mech has negative podspace, and is Overweight!")

print ("Your", MechName, "has a Walk MP of", CruisingSpeed, "hexes, and a Run MP of", FlankingSpeed, "hexes.")
print ("This speed is provided by a", FinalRating, "rated", EngineType, "weighing", EngineWeight(EngineType, rating), "metric tons.")
print ("The mech's weight is supported by a", InternalType, "with a mass of", skeleton, "metric tons,")
if GyroType in {"None"}:
print("The pilot is cocooned in a(n)", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.")
print()
elif GyroType in {"SuperHeavy"}:
print ("and keeping the", MechName, "upright is a(n)", GyroType, "Gyro, weighing", GyroWeight(GyroType), "metric tons.")
print ("The pilots are huddled together in a", CockpitType, "Cockpit, weighing a massive", cockpit, "metric tons.")
print()
else:
print ("and keeping the", MechName, "upright is a(n)", GyroType, "Gyro, weighing", GyroWeight(GyroType), "metric tons.")
print ("The pilot sits 'comfortably' in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.")
print()

print ("The", MechName, "has an average walking speed of", kph(CruisingSpeed), "km/h, and a maximum running speed of", kph(FlankingSpeed), "km/h.")
if podspace > 0:
print ("The", MechName, "has", podspace, "tons of Pod Space available to mount weapons, armor and equipment.")
print()
else:
print ("The", MechName, "has", podspace, "tons of Pod Space left, and cannot mount any weapons, armor or equipment.")
print()

print ("Please visit http://www.sarna.net for more information on these terms and components.")
print ("If you have any questions or feedback about the software, such as feature requests or bug reports,")
print ("if you need technical support, or would simply like to contribute to development, then please visit:")
print ("https://tinyurl.com/Sarna-Forums-MechEngine")
print()
input("Press ENTER to exit the program.") #Change this line to a menu option once Restart has been implemented.
Attachment (184 downloads)
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/16/18 05:26 PM
13.84.155.127

Edit Reply Quote Quick Reply
Correction and Status Update:
- Development is not completely cancelled, but it is still on hiatus. Official development will eventually resume, I will keep you posted.
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/21/18 09:44 PM
13.84.155.127

Edit Reply Quote Quick Reply
Fixed a lot of bugs and added a lot of features.
- Program now displays time and date
- ProtoMech support and SuperHeavy mechs has been improved
- SuperHeavy IndustrialMechs are a thing now.
- Internal Structure and Cockpit types can now be selected.
- IndustrialMechs can now be selected.
- Heat Sinks have been implemented.
- Many bug fixes, big and small.
- Groundwork laid out for alternate unit types.
- Hidden cockpit and gyro options.

=-=-=-=-=-=-=-=-=-=-=-=-=

Code:

print("MechEngine Beta, 0.30.67");
print("Build Date: 2018-05-21. Designed using Python 3.6.4 Stackless Shell");
import math, os, sys, time, datetime, threading
now = datetime.datetime.now()
while now != datetime.datetime.now():
now = datetime.datetime.now()
print("Current Date:", now.strftime("%A, %Y-%m-%d, %H:%M:%S (local)"))
print();

#Development Goals:
#Add options to restart program and/or export log upon completion.
#Add engine descriptions to help the user make an informed decision.
#Add example mechs to choose from

def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a != n:
print(a, end="");
a, b = b, a+b
print();

def RoundUp5(x):
return math.ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def RoundUpHalf(x):
return math.ceil(x*2.0)/2.0

def RoundUpQuarter(x):
return math.ceil(x*4.0)/4.0

def RoundUpFractional(x):
return math.ceil(x*1000.0)/1000.0

def RoundDown5(x):
return math.floor(x / 5.0) * 5

def RoundDownHalf(x):
return math.floor(x*2.0)/2.0

def RoundDownQuarter(x):
return math.floor(x*4.0)/4.0

def RoundDownFractional(x):
return math.floor(x*1000.0)/1000.0

def roundNearest(f):
return round(f + .00000000000001);

#Deprecated
def roundHalfUp(f): #deprecated!
return RoundUpHalf(f) #round(f + 0.00000000000001)

def roundEngine(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base));

def roundTonnage(x, base=5): #deprecated!
return int(base * RoundUpHalf(float(x)/base));
#End Deprecation

#HYN-DRN-5813 Core Input Dictionary:
def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)

def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False

def ask(question, min_val, max_val):
x = ''
while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

MechType = ("Biped")
#def PromptMechType()
#NewMechType = PromptMechType()
#MechType = NewMechType
CurrentMechType = MechType

Inputs = {"BattleMech’s Tonnage": {"min":2, "max":200, "value": None},
"desired Walk MP" : {"min":1, "max":30 , "value": None},
# "desired number of additional Heat Sinks": {"min:":0, "max":100, "value": None},
}

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#"Load inputs"
print ("Hint: One ground hex = 30 meters, one turn = 10 seconds.")
load_inputs(Inputs)

SuspFact = 0 #SuspFact = (input("Suspension Factor: "))

MechTonnage = (Inputs["BattleMech’s Tonnage"]["value"])
if MechTonnage < 10:
MechClass = ("ProtoMech")
MechName = ("ProtoMech")
elif 9 < MechTonnage < 20:
MechClass = ("Ultralight")
MechName = ("Ultralight BattleMech")
elif 19 < MechTonnage < 36:
MechClass = ("Light")
MechName = ("Light BattleMech")
elif 35 < MechTonnage < 56:
MechClass = ("Medium")
MechName = ("Medium BattleMech")
elif 55 < MechTonnage < 76:
MechClass = ("Heavy")
MechName = ("Heavy BattleMech")
elif 75 < MechTonnage < 101:
MechClass = ("Assault")
MechName = ("Assault BattleMech")
elif 100 < MechTonnage:
MechClass = ("SuperHeavy")
MechName = ("SuperHeavy BattleMech")

NewMechName = input("Name your BattleMech: ");
if NewMechName != '': MechName = NewMechName
print();

CruisingSpeed = math.ceil(Inputs["desired Walk MP"]["value"]);
def kph(s):
return (math.ceil(s*108))/10
def metersec(s):
return (math.ceil(s*30))/10
def mph(s):
return (math.ceil(s*671))/100
#UserHeatSinks = (#(Inputs["desired number of additional Heat Sinks"]["value"]);

#"Do calculations"
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
if MechTonnage > 9:
rating = max(10, RoundUp5((Inputs["BattleMech’s Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact));
else:
rating = max(2, (Inputs["BattleMech’s Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact);

if rating >500:
print ("WARNING! This engine rating is outside normal parameters, and the weight has been extrapolated through a polynomial function.",
"Consent among all participating players must be reached before it can be used in an actual game.");

#"Master Engine Table:"
FusionEngineTable = {#See TechManual and Tactical Operations for more details
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.
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.
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.
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.
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.
}

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.
1: .025, 2: .050, 3: .075, 4: .100, 5: .125, 6: .150, 7: .175, 8: .200, 9: .225, 10: .250,
11: .275, 12: .300, 13: .325, 14: .350, 15: .375, 16: .400, 17: .425, 18: .450, 19: .475, 20: .500,
21: .525, 22: .550, 23: .575, 24: .600, 25: .625, 26: .650, 27: .675, 28: .700, 29: .725, 30: .750,
31: .775, 32: .800, 33: .825, 34: .850, 35: .875, 36: .900, 37: .925, 38: .950, 39: .975, 40: 1.0,}

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
if 15 < MechTonnage < 101:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", #ProtoMech Engine",
]
print("Engine types:");
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask("Please select your desired Engine type", 0, len(el)-1);
print();
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", #ProtoMech Engine",
]
print("Large Engine types:");
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask("Please select your Large Engine type", 0, len(el)-1);
print();
return el[num]
elif MechTonnage < 16:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", "ProtoMech Engine",
]
print("Engine types:");
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask("Please select your desired Engine type", 0, len(el)-1);
print();
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", "ProtoMech Engine",
]
print("Large Engine types:");
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask("Please select your desired Large Engine type", 0, len(el)-1);
print();
return el[num]
else:
if rating < 401:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
#"Fuel Cell",
"Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine",
]
print("Engine types:")
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask("Please select your desired Engine type", 0, len(el)-1);
print();
return el[num]
else:
el = [#Basic Engine Types: 10 Heat Sinks each.
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types: 10 Heat Sinks each, but XXL will produce double heat from all types of movement.
"XXL Fusion Engine",# "Compact Fusion Engine",
#Non-Fusion Engines:
#"Fuel Cell",
"Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine",
]
print("Large Engine types:");
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask("Please select your desired Large Engine type", 0, len(el)-1);
print();
return el[num]

if MechTonnage < 10:
EngineType = ("ProtoMech Engine")
else:
EngineType = PromptEngineType()

if EngineType in {"ProtoMech Engine"}:
rating = (MechTonnage * FlankingSpeed)
if MechClass in {"Ultralight"}:
MechClass = ("UltraHeavy ProtoMech")
else:
rating = (MechTonnage * CruisingSpeed) - SuspFact

if EngineType in {"Lithium-Fusion Engine"}:
if CruisingSpeed < 2:
CruisingSpeed = 2
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)
elif CruisingSpeed > 1:
CruisingSpeed = (Inputs["desired Walk MP"]["value"])
FlankingSpeed = math.ceil(CruisingSpeed * 1.5)

def FusionWeight(rating):
if rating <501:
return FusionEngineTable[RoundUp5(rating)]
elif EngineType in {"ProtoMech Engine"}:
if rating <41:
return rating * (25.0/1000.0) #ProtoMechEngineTable[rating]
else:
return FusionEngineTable[RoundUp5(rating)]
else: #Uses polynomial curves and floating-point math to extrapolate mass for engine ratings beyond 500. Experimental feature, not recommended for everyday use.
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = RoundUpFractional(roundNearest(weight * 1000.0)/1000.0)
return weight
print ("WARNING! This Engine Rating is outside normal Rating parameters, and its weight has been extrapolated. Do not use it in an actual game.");
print();

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.
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = roundNearest(weight * 2.0)/2.0
return weight

#for k in FusionEngineTable:
# t = FusionWeight(k)
# p = FusionWeightPoly(k)
# d = t - p
# if d > .01:
# print(k, t, p, d)

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
weight = FusionWeight(rating)
primitive = FusionWeight(rating * 1.2)
lithium = FusionWeight(max(MechTonnage, rating - MechTonnage))
if rating < 40:
proto = rating * (25.0/1000.0) #ProtoMechEngineTable[rating]
lithium_proto = max(MechTonnage, rating - MechTonnage) * (25.0/1000.0)
else:
proto = weight
lithium_proto = lithium
ed = {"Standard Fusion Engine" : max(0.5, weight),
"Light Fusion Engine" : max(0.5, RoundUpHalf(weight * .75)),
"XL Fusion Engine" : max(0.5, RoundUpHalf(weight * .50)),
"XXL Fusion Engine" : max(0.5, RoundUpHalf(weight / 3.0)),
"Compact Fusion Engine" : max(1.0, RoundUpHalf(weight * 1.5)),
"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!
"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!
"Fission Engine" : max(5.0, RoundUpHalf(weight * float(7.0/4.0))), #Only 5 Heat Sinks. Illegal in the Inner Sphere, and expensive.
"Lithium-Fusion Engine" : max(0.5, RoundUpHalf(lithium)), #Non-Canon. 10 Heat Sinks. Increases a mech's Walking Speed by 1.
"Primitive Fusion Engine" : max(0.5, RoundUpHalf(primitive)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Internal Combustion Engine (ICE)" : max(1.0, RoundUpHalf(primitive * 2.0)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fuel Cell" : max(1.0, RoundUpHalf(primitive * 1.2)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fission Engine" : max(5.0, RoundUpHalf(primitive * (7.0/4.0))), #Multiplies engine rating by 1.2, but does not increase performance.
"ProtoMech Engine" : RoundUpFractional((proto * 1000.0)/1000.0),
"ProtoMech XL Lithium-Fusion Engine" : RoundUpFractional(max(0.017, lithium_proto/3)),
"No Engine" : 0.00,
}
return ed[engine_type]

if EngineType in {"Lithium-Fusion Engine"}:
LithiumBatteryRating = max(MechTonnage, rating - MechTonnage)
elif EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell," "Primitive Fission Engine"}:
LithiumBatteryRating = RoundUp5(rating * 1.2)
else:
LithiumBatteryRating = rating

#Cockpits
def PromptCockpitType():
"""Ask the user for their desired cockpit type, then return it."""
#cockpit list:
if LithiumBatteryRating < 401:
cl = ["Standard", "Small", "Armored", "Torso", "Interface", "Drone Operating System"]
elif LithiumBatteryRating > 400:
cl = ["Standard", "Small", "Armored", "Interface", "Drone Operating System"]
print("Cockpit types:");
for i in range(0, len(cl)):
print(" (%d) %s"%(i, cl[i]));
num = ask("Please select your desired Cockpit type", 0, len(cl)-1);
print();
return cl[num]

def CockpitWeight(cockpit_type):
#Using a dictionary to match cockpit name to a formula
cd = {
"ProtoMech": 0.5,
"UltraHeavy ProtoMech": 0.75,
"Drone Operating System": max(1.0, RoundUpHalf((MechTonnage/10.0) + 0.5)),
"Small": 2.0,
("Standard", "AutoMech", "Industrial", "Armored Small"): 3.0,
#"AutoMech": 3.0,
("Armored", "Torso", "Tripod", "Interface", "SuperHeavy"): 4.0,
#"Torso": 4.0,
#"Tripod": 4.0,
#"Interface": 4.0,
#"SuperHeavy": 4.0,
("Primitive", "Primitive Industrial", "SuperHeavy Tripod"): 5.0
}
# return ed[cockpit_type]
for key in cd:
if cockpit_type in key:
return cd[key]

#Skeletons
def PromptInternalType():
"""Ask the user for their desired internal structure type, then return it."""
#internal structure list:
if MechTonnage < 101:
il = ["Standard", "Endo Steel", "Composite", "Hybrid", "Reinforced", "Industrial"]
elif MechTonnage > 100:
il = ["SuperHeavy Standard", "SuperHeavy Hybrid", "SuperHeavy Endo Steel", "SuperHeavy Reinforced", "SuperHeavy Industrial"] #You have balls if you pick that last one.
elif EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"}:
il = ["Primitive Standard", "Primitive Industrial"]
print("Internal Structure types:");
for i in range(0, len(il)):
print(" (%d) %s"%(i, il[i]))
num = ask("Please select your desired Internal Structure type", 0, len(il)-1);
print();
return il[num]

def InternalWeight(internal_type):
#Using a dictionary to match internal structure name to a formula
isd = {
("Standard", "Primitive Standard", "SuperHeavy Endo Steel", "ProtoMech"): RoundUpHalf(MechTonnage/10.0),
("Endo Steel", "Composite"): RoundUpHalf(MechTonnage/20.0),
#"Composite": RoundUpHalf(MechTonnage/20.0),
"Hybrid": RoundUpHalf(MechTonnage*7.5/100.0),
#"Reinforced": RoundUpHalf(MechTonnage/5.0),
#"Industrial": RoundUpHalf(MechTonnage/5.0),
#"Primitive Standard": RoundUpHalf(MechTonnage/10.0),
("Reinforced", "Industrial", "Primitive Industrial", "SuperHeavy Standard") : RoundUpHalf(MechTonnage/5.0),
#"SuperHeavy Standard": RoundUpHalf(MechTonnage/5.0),
"SuperHeavy Hybrid": RoundUpHalf(MechTonnage*15.0/100.0),
#"SuperHeavy Endo Steel": RoundUpHalf(MechTonnage/10.0),
("SuperHeavy Industrial", "SuperHeavy Reinforced"): RoundUpHalf(MechTonnage/2.5),
#"SuperHeavy Reinforced": RoundUpHalf(MechTonnage/2.5),
#"ProtoMech": RoundUpFractional(MechTonnage/10.0)}
}
# 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.
for key in isd:
if internal_type in key:
return isd[key]

if MechTonnage > 100:
InternalType = PromptInternalType()
CockpitType = ("SuperHeavy")
if MechType in ["Tripod"]:
MechType = ("SuperHeavy Tripod")
else:
Mechtype = ("SuperHeavy" + CurrentMechType)
elif EngineType in ["ProtoMech Engine"]:
InternalType = ("ProtoMech")
MechType = ("ProtoMech")
if MechTonnage < 10:
CockpitType = ("ProtoMech")
elif MechTonnage > 9:
CockpitType = ("UltraHeavy ProtoMech")
else:
InternalType = PromptInternalType()
CockpitType = PromptCockpitType()
MechType = CurrentMechType

#Gyros
def PromptGyroType():
"""Ask the user for their desired gyro type, then return it."""
#gyro list:
if LithiumBatteryRating < 401 or EngineType in ["Compact Fusion Engine"]:
gl = ["Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
elif EngineType in {"Lithium-Fusion Engine"} and rating < 501:
gl = ["Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
elif LithiumBatteryRating > 400 or CockpitType in ["Torso"]:
if EngineType not in ["Compact Fusion Engine"]:
gl = ["Standard", "Compact", "Heavy-Duty",]
print("Gyro types:")
for i in range(0, len(gl)):
print(" (%d) %s"%(i, gl[i]))
num = ask("Please select your desired Gyro type", 0, len(gl)-1)
print();
return gl[num]

FinalRating = LithiumBatteryRating
GyroRating = math.ceil(LithiumBatteryRating / 100)

if MechTonnage > 100:
GyroType = ("SuperHeavy")
elif EngineType in ["Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"]:
if MechTonnage < 101:
GyroType = ("Primitive")
elif MechTonnage > 100:
GyroType = ("SuperHeavy Primitive")
elif CockpitType in ["ProtoMech", "UltraHeavy ProtoMech", "Interface"]:
GyroType = ("None")
else:
GyroType = PromptGyroType()

def GyroWeight(gyro_type):
#Using a dictionary to match gyro name to a formula
gmass = GyroRating
gd = {
("Standard", "Primitive Standard") : max(1.0, gmass*1.0),
"XL (Extra-Light)" : max(1.0, RoundUpHalf(gmass/2.0)),
"Compact" : max(1.5, RoundUpHalf(gmass*1.5)),
("Heavy-Duty", "SuperHeavy", "Primitive SuperHeavy") : max(2.0, math.ceil(gmass * 2.0)),
#"SuperHeavy" : max(2.0, math.ceil(gmass*2.0)),
#"Primitive" : max(1.0, gmass*1.0),
#"Primitive SuperHeavy" : max(2.0, math.ceil(gmass*2.0)), #unused
"None": (gmass*0.0),
"Armored" : (gmass + 2.0),
"Armored Compact" : 1.0 + RoundUpHalf(gmass*1.5),
"Armored XL" : 3.0 + RoundUpHalf(gmass/2.0),
"Armored Heavy-Duty" : 2.0 + (gmass*2.0),
}
# return ed[gyro_type]
for key in gd:
if gyro_type in key:
return gd[key]

#Heat Sinks
def PromptHeatSinkType():
"""Ask the user for their desired heat sink type, then return it."""
#heat sink list:
hsl = ["Single", "Double (Inner Sphere)", "Double (Clan)", "Laser", "Compact"]
print("Heat Sink types:");
for i in range(0, len(hsl)):
print(" (%d) %s"%(i, hsl[i]));
num = ask("Please select your desired Heat Sink type", 0, len(hsl)-1);
print();
return hsl[num]

if EngineType in {"Fission Engine", "Primitive Fission Engine"}:
FreeHeatSinks = 5
HeatSinkType = PromptHeatSinkType()
elif EngineType in {"Fuel Cell", "Primitive Fuel Cell"}:
FreeHeatSinks = 1
HeatSinkType = PromptHeatSinkType()
elif EngineType in {"Internal Combustion Engine (ICE)", "Primitive Internal Combustion Engine (ICE)"}:
FreeHeatSinks = 0
HeatSinkType = PromptHeatSinkType()
elif EngineType in {"ProtoMech Engine"}:
FreeHeatSinks = 0
HeatSinkType = ("ProtoMech")
else:
FreeHeatSinks = 10
HeatSinkType = PromptHeatSinkType()

if EngineType in ["ProtoMech Engine"]:
UserHeatSinks = ask("Please provide your desired quantity of ProtoMech Heat Sinks", 0, MechTonnage*4)

else:
print ("You currently have", int(FreeHeatSinks), HeatSinkType, "Heat Sinks.")
UserHeatSinks = ask("If you wish to install additional Heat Sinks, enter the quantity you wish to add", 0, MechTonnage)

TotalHeatSinks = UserHeatSinks + FreeHeatSinks

if TotalHeatSinks > 0:
print()

if EngineType in {"ProtoMech Engine"}:
HeatSinkWeight = RoundUpFractional(UserHeatSinks/4.0)
IntegralHeatSinks = int(TotalHeatSinks)
HeatSinkSlots = 0
elif HeatSinkType in {"Compact"}:
HeatSinkWeight = RoundUpHalf(UserHeatSinks * 1.5)
IntegralHeatSinks = int(min(TotalHeatSinks, math.floor(LithiumBatteryRating/12.5)))
else:
HeatSinkWeight = UserHeatSinks * 1.0
IntegralHeatSinks = int(min(TotalHeatSinks, math.floor(LithiumBatteryRating/25.0)))

PodHeatSinks = TotalHeatSinks - IntegralHeatSinks

if MechTonnage < 101:
if HeatSinkType in ["Single", "Liquid Metal"]:
HeatSinkSlots = PodHeatSinks
elif HeatSinkType in ["Double (Inner Sphere)", "Double (ProtoType)"]:
HeatSinkSlots = PodHeatSinks * 3
elif HeatSinkType in ["Double (Clan)", "Double (Star Empire)", "Laser"]:
HeatSinkSlots = PodHeatSinks * 2
elif HeatSinkType in ["Compact"]:
HeatSinkSlots = math.ceil(PodHeatSinks/2)
elif HeatSinkType in ["ProtoMech"]:
HeatSinkSlots = 0

elif MechTonnage > 100:
if HeatSinkType in ["Single"]:
HeatSinkSlots = math.ceil(PodHeatSinks/2)
elif HeatSinkType in ["Double (Inner Sphere)"]:
HeatSinkSlots = math.ceil(PodHeatSinks * 1.5)
elif HeatSinkType in ["Double (Clan)", "Laser"]:
HeatSinkSlots = PodHeatSinks
elif HeatSinkType in ["Compact"]:
HeatSinkSlots = math.ceil(PodHeatSinks/4)

#Podspace
skeleton = InternalWeight(InternalType)
tripod = RoundUpHalf(skeleton * 1.1)
cockpit = CockpitWeight(CockpitType)
gyro = GyroWeight(GyroType)
EngineTonnage = EngineWeight(EngineType, rating)

if MechType in ["Combat Vehicle", "Support Vehicle"]:
if EngineType in ["Internal Combustion Engine (ICE)", "Fuel Cell", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell"]:
VehicleEngine = EngineTonnage
else:
if MechType in ["Combat Vehicle"]:
VehicleEngine = RoundUpHalf(EngineTonnage * 1.5)
elif MechType in ["Support Vehicle"]:
VehicleEngine = RoundUpFractional(EngineTonnage * 1.5)
else:
VehicleEngine = EngineTonnage

print()
if MechType in ["Tripod", "SuperHeavy Tripod"]:
podspace = RoundDownHalf(MechTonnage - EngineTonnage - tripod - gyro - cockpit - HeatSinkWeight)
elif EngineType in ["ProtoMech Engine", "ProtoMech XL Lithium-Fusion Engine"] or MechType in ["ProtoMech", "Quad ProtoMech", "Glider ProtoMech"]:
podspace = RoundDownFractional(MechTonnage - EngineTonnage - skeleton - gyro - cockpit - HeatSinkWeight)
elif MechType in ["Combat Vehicle"]:
podspace = RoundDownHalf(MechTonnage - VehicleEngine - skeleton - gyro - cockpit - HeatSinkWeight)
elif MechType in ["Support Vehicle"]:
podspace = RoundDownFractional(MechTonnage - VehicleEngine - skeleton - gyro - cockpit - HeatSinkWeight)
else:
podspace = RoundDownHalf(MechTonnage - EngineTonnage - skeleton - gyro - cockpit - HeatSinkWeight)

if VehicleEngine > MechTonnage:
print ("WARNING! Your engine is heavier than the mech!");
if podspace < 0.0:
print ("WARNING! Your mech has negative podspace, and is Overweight!");

#Finalize
if MechName in {"BattleMech", "Ultralight BattleMech", "Light BattleMech", "Medium BattleMech", "Heavy BattleMech", "Assault BattleMech", "SuperHeavy BattleMech"}:
if InternalType in {"Industrial"}:
if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
MechName = (MechClass + "IndustrialMech")
if InternalType in {"Primitive Standard"}:
if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
MechName = ("Primitive" + MechClass + "BattleMech")
if InternalType in {"Primitive Industrial"}:
if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
MechName = ("Primitive" + MechClass + "Industrial")
elif MechClass in {"ProtoMech", "UltraHeavy ProtoMech"}:
MechName = MechClass
elif CockpitType in {"AutoMech"}:
MechName = (MechClass + "AutoMech")

#Technical Readout
print ("Your", MechName, "has a Cruising MP of", CruisingSpeed, "hexes per turn, and a Flanking MP of", FlankingSpeed, "hexes per turn.");

print ("This speed is provided by a", FinalRating, "rated", EngineType, "weighing", EngineTonnage, "metric tons.");

if EngineType in ["ProtoMech Engine", "ProtoMech XL Lithium-Fusion Engine"]:
print("You have", TotalHeatSinks, HeatSinkType, "Heat Sinks weighing", HeatSinkWeight, "metric tons.")

else:
print("You have", TotalHeatSinks, HeatSinkType, "Heat Sinks weighing", HeatSinkWeight, "metric tons, of which", IntegralHeatSinks, "of them are Integral,")
print ("and out of those", TotalHeatSinks, HeatSinkType, "Heat Sinks," + FreeHeatSinks, "of them come with the engine.")
if PodHeatSinks > 0:
print ("The remaining", HeatSinkType, "Heat Sinks occupy", HeatSinkSlots, "Critical Spaces in total.")

print()

if MechType in ["Tripod"]:
print ("The Mech's weight is supported by a", InternalType, "Internal Structure with a mass of", tripod, "metric tons.");

elif MechType in ["AutoMech"]:
print ("The AutoMech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton, "metric tons.");

elif MechType in ["ProtoMech"]:
print ("The ProtoMech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton, "metric tons.");

else:
print ("The Mech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton, "metric tons.");

if GyroType in ["None"] and MechTonnage > 9:
print("The pilot is cocooned in an", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

elif GyroType in ["None"] and MechTonnage <10:
print("The pilot is cocooned in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

elif GyroType in ["SuperHeavy"]:
print ("and stopping your", MechName, "from toppling over is a monstrous", GyroType, "Gyro weighing", gyro, "metric tons.");
print ("The pilots are huddled together in a", CockpitType, "Cockpit, weighing a massive", cockpit, "metric tons.");

elif GyroType in ["XL (Extra-Light)"]:
print ("and keeping the", MechName, "upright is an", GyroType, "Gyro weighing", gyro, "metric tons.");
print ("The pilot sits ’comfortably’ in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

elif CockpitType in ["Drone Operating System", "AutoMech"]:
if GyroType in ["XL (Extra-Light)"]:
print ("and keeping the", MechName, "upright is an", GyroType, "Gyro weighing", gyro, "metric tons.")
else:
print ("and keeping the", MechName, "upright is a", GyroType, "Gyro weighing", gyro, "metric tons.")

if CockpitType in ["Drone Operating System"]:
print ("The brains of this machine consist of a", CockpitType, "weighing", cockpit, "metric tons.")

elif CockpitType in ["AutoMech"]:
print ("The brains of this machine consist of an", CockpitType, "weighing", cockpit, "metric tons.")

else:
print ("and keeping the", MechName, "upright is an", GyroType, "Gyro weighing", gyro, "metric tons.");
print ("The pilot sits 'comfortably' in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

print()
print ("The", MechName, "has an average walking speed of", kph(CruisingSpeed), "km/h, and a maximum running speed of", kph(FlankingSpeed), "km/h.");

if podspace > 0.0:
print ("The", MechName, "has", podspace, "tons of Pod Space available to mount weapons, armor and equipment.");
print();
else:
print ("Oh, stravag! It would seem that the", MechName, "has", podspace, "tons of Pod Space left, and now it cannot mount any weapons, armor or equipment!");
print();

## Closing sequence.
print ("Please visit http://www.sarna.net for more information on these terms and components.");
print ("If you have any questions or feedback about the software, such as feature requests or bug reports,");
print ("if you need technical support, or would simply like to contribute to development, then please visit:");
print ("https://tinyurl.com/Sarna-Forums-MechEngine");
print();
now = datetime.datetime.now()
print("The current time and date is", now.strftime("%A, %Y-%m-%d, %H:%M:%S (local)"))
input("Shutdown Sequence: Initiated.") #Change this line to a menu option once Restart has been implemented.
print ("Shutting Down.")

## End of Line.

#Contribution Links:
# https://pastebin.com/dpMnWPjp
# https://docs.google.com/document/d/1A6Y79pelpzdRg00DHcZNO3tyrdvthFSaU4tihSvGkE8/edit?usp=sharing


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Enjoy!
And as always, don't forget to provide feedback.
https://pastebin.com/dpMnWPjp
https://docs.google.com/document/d/1A6Y79pelpzdRg00DHcZNO3tyrdvthFSaU4tihSvGkE8/edit?usp=sharing
_____ Attachment (166 downloads)
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/23/18 09:39 PM
13.84.155.127

Edit Reply Quote Quick Reply
Mech Engine: Beta (Build 0.30.73)
- Fixed some crashes and other minor bugs, and added some easter eggs.
- Moved over primarily to pastebin, for neatness:
https://pastebin.com/9KrvkKgv
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
05/29/18 05:39 PM
13.84.155.127

Edit Reply Quote Quick Reply
MechEngine: Beta (Build: 0.30.92)
Today, we have two new releases. The first is a general bugfixes build, and the second was developed concurrently by one of my friends, which adds the ability to restart the program.

I also added some example mechs. Feel free to check them out!

https://pastebin.com/FyZMY15V
Both builds and the examples I made are available in an attached ZIP archive. Attachment (166 downloads)
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
AmaroqStarwind
06/12/18 03:01 PM
13.84.155.127

Edit Reply Quote Quick Reply
I apologize for development having stalled for a bit. Here's the latest version, still looking to get some important things implemented before I move on to 1.0.

MechEngine Beta (0.31.32)
https://pastebin.com/VfJ5Sz7Y
https://docs.google.com/document/d/1A6Y79pelpzdRg00DHcZNO3tyrdvthFSaU4tihSvGkE8/edit?usp=sharing

Python 3 to Python 2 Backwards Compatibility Routine
https://pastebin.com/S8wEAVda

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Code:
import math, os, sys, time, datetime, threading, builtins, lib2to3

print('''MechEngine - BattleMech design aid by New Avalon Institute of Science.
Build Version: 0.31.32 (Beta, Python Interpreter)
Build Date: Monday, 2018-06-04.
Designed using Python 3.6 Shell.''')

#Python 3 Backwards Compatibility Wrapper (Alpha)
"""This wrapper is intended to reduce compatibility issues when running Python 3 code in Python 2.
However, it is far from perfect, and is meant primarily for idiot-proofing.
Either rewriting your code, or switching to a newer version of Python, is strongly recommended."""

if sys.version_info[0] > 2:
"""Executes the following code if the user is running Python 3."""
def raw_input(*args, **kwargs):
"""This definition is included so that the version check below doesn't kill the program."""
return input(*args, **kwargs)
def failUnlessEqual(a, b):
return assertEqual(a, b)
def assertEquals(a, b):
return assertEqual(a, b)
def failIfEqual(a, b):
return assertNotEqual(a, b)
def assertNotEquals(a, b):
return failIfEqual(a, b)
def assert_(a):
return assertTrue(a)
def failUnless(a):
return assert_(a)
def failIf(a):
return assertFalse(a)
def failUnlessRaises(exc, cal):
return assertRaises(esc, cal)
def failUnlessAlmostEqual(a, b):
return assertAlmostEqual(a, b)
def assertAlmostEquals(a, b):
return assertAlmostEqual(a, b)
def failIfAlmostEqual(a, b):
return assertNotAlmostEqual(a, b)
def assertNotAlmostEquals(a, b):
return failIfAlmostEqual(a, b)
"""MISC"""
def intern():
return sys.intern()
def long():
"""This definition is included so that Long Integers from Python 2 will just be treated as Python 3 Integers."""
return int
def apply(function, *args, **kwargs):
return function(*args, **kwargs)
def basestring():
return str
def unicode():
return str
def buffer():
return memoryview()
def xrange():
return range()
def __nonzero__():
return __bool__()

if sys.version_info[0] < 3:
"""Executes the following code if the user is running Python 2."""
raw_input("Incompatible Python version detected. Please switch to Python 3.6 before running this program, or crashes may occur.")
def int():
"""This definition is included to automatically treat all Integers as Long Integers, as in Python 3."""
return long()

def floor(x):
"""Always rounds down."""
return math.floor(x)

def ceil(x):
"""Always rounds up."""
return math.ceil(x)

def gettime():
"""Updates and prints the current time and date."""
now = datetime.datetime.now()
return print("Current Time and Date, Local:", now.strftime("%A, %Y-%m-%d, %H:%M:%S %z"))
gettime()
print();

print("""Development Goals:
01. Add option to restart the program upon completion.
02. Add option to export a created unit for sharing, record keeping and analysis.
03. Add component descriptions to help the user make informed decisions.
04. Fully implement Critical Spaces and alternate unit types.
05. Add ability to open and edit existing units, excluding hard-coded examples.
06. Add example units to choose from.
07. Create compiled versions of the program for various platforms.
08. Optimize for stability, compatibility and portability.
09. Make program easier to understand for people not familiar with BattleTech.
10. Create webtool version(?)
11. Clean up code however possible to reduce filesize, fix bugs and making the code easier to understand.
12. Develop graphical user interface.
""")

def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to a final value of n.
Purely for style and is not necessary for program use."""
a, b = 0, 1
while a <= n:
print(a, end=" ");
a, b = b, a + b
print();

def mem_fib(n, _cache={}):
'''Efficiently memoized recursive function, returns a Fibonacci number with n iterations.
Again, entirely optional.'''
if n in _cache:
return _cache[n]
elif n > 1:
return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
return n

def printfib(n):
for i in range(n):
print(i, mem_fib(i))

def RoundUp5(x):
return ceil(x / 5.0) * 5 #Round up to nearest multiple of 5

def RoundUpHalf(x):
return ceil(x*2.0)/2.0

def RoundUpQuarter(x):
return ceil(x*4.0)/4.0

def RoundUpFractional(x):
return ceil(x*1000.0)/1000.0

def RoundDown5(x):
return floor(x / 5.0) * 5

def RoundDownHalf(x):
return floor(x*2.0)/2.0

def RoundDownQuarter(x):
return floor(x*4.0)/4.0

def RoundDownFractional(x):
return floor(x*1000.0)/1000.0

def roundNearest(f):
return int(round(f + .00000000000001));

###Deprecated
##def roundHalfUp(f): #deprecated!
## return RoundUpHalf(f) #round(f + 0.00000000000001)
##
##def roundEngine(x, base=5): #deprecated!
## return int(base * RoundUpHalf(float(x)/base));
##
##def roundTonnage(x, base=5): #deprecated!
## return int(base * RoundUpHalf(float(x)/base));

#HYN-DRN-5813 Core Input Dictionary:
def clamp(min_value, max_value, x):
"""Returns x, limited to the range min_val to max_val."""
return max(min(x, max_value), min_value)

def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
try:
ceil(float(s))
return True
except ValueError:
return False
## return False

def ask(question, min_val, max_val):
x = ''
while not RepresentsInt(x) or int(x) < min_val or int(x) > max_val:
if x != '':
print ("This is not a number. Please enter a valid input.")
x = input(question + " (min %d, max %d)"%(min_val, max_val) + ": ")
return clamp(min_val, max_val, int(x))

MechType = ("Biped")
def PromptMechType():
"""Ask the user for their desired Unit type, then return it. These options do not do anything yet, though."""
#unit list:
ml = ["Biped", "Quad", "Tripod", "Land-Air Mech", "HoverTank Mech",
"ProtoMech", "Glider ProtoMech", "Quad ProtoMech",
"Combat Vehicle - Wheeled", "Support Vehicle - Wheeled", "Combat Vehicle - Tracked", "Support Vehicle - Tracked",
"Combat Vehicle - Hovercraft", "Support Vehicle - Hovercraft", "Combat Vehicle - VTOL", "Support Vehicle - VTOL",
"Combat Vehicle - WiGE", "Support Vehicle - WiGE", "Aerospace Fighter", "Conventional Fighter"]
print("Unit types - These do nothing yet:");
for i in range(0, len(ml)):
print(" (%d) %s"%(i, ml[i]));
num = ask('''
Please select your desired Unit type''', 0, len(ml)-1);
print();
return ml[num]
NewMechType = PromptMechType()
#MechType = NewMechType

if NewMechType in {"Combat Vehicle - Wheeled", "Support Vehicle - Wheeled", "Combat Vehicle - Tracked", "Support Vehicle - Tracked",
"Combat Vehicle - Hovercraft", "Support Vehicle - Hovercraft", "Combat Vehicle - VTOL", "Support Vehicle - VTOL",
"Combat Vehicle - WiGE", "Support Vehicle - WiGE"}:
IsVehicle = True
else:
IsVehicle = False

print ("IsVehicle =", IsVehicle, '''
''')

CurrentMechType = MechType

MinTon = 2
MaxTon = 200
"""Minimum and Maximum unit tonnage will vary with unit type, as will many other options."""

Inputs = {"BattleMech’s Tonnage": {"min":MinTon, "max":MaxTon, "value": None},
"desired Walk MP" : {"min":1, "max":30 , "value": None},
}

def load_inputs(inputs_dict):
"""Iterate over the given inputs dictionary, asking the user for each
and setting their values"""
for name in inputs_dict:
#name takes each key in the dictionary, which in this case is names of inputs
inputs_dict[name]["value"] = ask("Please provide your %s"%name,
inputs_dict[name]["min"],
inputs_dict[name]["max"])

#"Load inputs"
print ("Hint: One ground hex = 30 meters, one turn = 10 seconds.")
load_inputs(Inputs)

SuspFact = 0 #SuspFact = (input("Suspension Factor: "))

MechTonnage = (Inputs["BattleMech’s Tonnage"]["value"])

if MechTonnage < 10:
MechClass = ("ProtoMech")
MechName = ("ProtoMech")
elif 9 < MechTonnage:
if MechTonnage < 20: MechClass = ("Ultralight")
elif 19 < MechTonnage < 36: MechClass = ("Light")
elif 35 < MechTonnage < 56: MechClass = ("Medium")
elif 55 < MechTonnage < 76: MechClass = ("Heavy")
elif 75 < MechTonnage < 101: MechClass = ("Assault")
elif 100 < MechTonnage: MechClass = ("SuperHeavy")
MechName = (MechClass + " BattleMech")
else:
MechName = ("Unit")

NewMechName = input("Name your BattleMech: ");
if NewMechName != '': MechName = NewMechName
print()

CruisingSpeed = ceil(Inputs["desired Walk MP"]["value"]);
def kph(s):
return (ceil(s*108))/10
def metersec(s):
return (ceil(s*30))/10
def mph(s):
return (ceil(s*671))/100

print('''Press ENTER to confirm Unit Statistics:
Unit Name:''', MechName,'''
Unit Type:''', MechType,'''
Tonnage:''', MechTonnage, '''Metric Tons.
Weightclass:''', MechClass,'''
Cruising Speed:''', CruisingSpeed, "Hexes per Turn.")
input()

fib(MechTonnage)
print()

#"Do calculations"
FlankingSpeed = ceil(CruisingSpeed * 1.5)
if MechTonnage > 15:
rating = max(10, RoundUp5((Inputs["BattleMech’s Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact));
else:
rating = max(2, (Inputs["BattleMech’s Tonnage"]["value"] * Inputs["desired Walk MP"]["value"]) - SuspFact);

if rating >500:
print ("WARNING! This engine rating of", rating, '''is outside normal parameters, and the weight will be extrapolated through a polynomial function.
Consent among all participating players must be reached before it can be used for an actual game.''')


#"Master Engine Table:"
FusionEngineTable = {#See TechManual and Tactical Operations for more details
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,#Gyro: 1 Ton
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,#Gyro: 2 Tons
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,#Gyro: 3 Tons
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,#Gyro: 4 Tons
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#Gyro: 5 Tons
}

def PromptEngineType():
"""Ask the user for their desired engine type, then return it."""
#engine list:
if MechTonnage < 16 and rating < 401:
el = [#Basic Engine Types:
"Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine",
#Advanced Engine Types:
"XXL Fusion Engine", "Compact Fusion Engine",
#Non-Fusion Engines:
"Internal Combustion Engine (ICE)", "Fuel Cell", "Fission Engine",
#Primitive Engines:
"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine",
#Special Engine Types:
"Lithium-Fusion Engine", "ProtoMech Engine",
]
elif MechTonnage < 16 and rating > 400:
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"]
elif 15 < MechTonnage < 101 and rating < 401:
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"]
elif 15 < MechTonnage < 101 and rating > 400:
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"]
elif MechTonnage > 100 and rating < 401:
el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine", "XXL Fusion Engine", "Compact Fusion Engine", "Fission Engine", "Lithium-Fusion Engine"]
elif MechTonnage > 100 and rating > 400:
el = ["Standard Fusion Engine", "Light Fusion Engine", "XL Fusion Engine", "XXL Fusion Engine", "Fission Engine", "Lithium-Fusion Engine"]

if rating < 401:
print('''Engine types:
(Rule of thumb: XL is lighter, but bulkier, than Standard.)''')
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask('''
Please select your desired Engine type''', 0, len(el)-1);
print();
return el[num]
else:
print('''Large Engine types:
(Rule of thumb: XL is lighter, but bulkier, than Standard.)''');
for i in range(0, len(el)):
print(" (%d) %s"%(i, el[i]));
num = ask('''
Please select your desired Large Engine type''', 0, len(el)-1);
print();
return el[num]

if MechTonnage < 10:
EngineType = ("ProtoMech Engine")
else:
EngineType = PromptEngineType()

if EngineType in {"ProtoMech Engine"}:
rating = (MechTonnage * FlankingSpeed) - SuspFact
if rating < 41:
rating = RoundUp5(rating)
if MechClass in {"Ultralight"}:
MechClass = ("UltraHeavy ProtoMech")
else:
rating = RoundUp5((MechTonnage * CruisingSpeed) - SuspFact)

if EngineType in {"Lithium-Fusion Engine"}:
if CruisingSpeed < 2:
CruisingSpeed = 2
FlankingSpeed = ceil(CruisingSpeed * 1.5)
elif CruisingSpeed > 1:
CruisingSpeed = (Inputs["desired Walk MP"]["value"])
FlankingSpeed = ceil(CruisingSpeed * 1.5)

def FusionWeight(rating):
if EngineType in ["ProtoMech Engine"]:
"""ProtoMechs, for engine ratings below 40, multiply the engine rating by 0.025 to find the mass.
Afterwards, they use Standard Fusion Engine weights."""
if rating < 41:
weight = rating * (25.0/1000.0)
#print (weight)
return rating * (25.0/1000.0)
else:
return FusionEngineTable[RoundUp5(rating)]

elif rating < 501:
return FusionEngineTable[RoundUp5(rating)]

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.
x = RoundUp5(rating)
coeff = [7.05283012941420e-23, -1.58264921514316e-19, 1.58814453473840e-16,
-9.19203426420176e-14, 3.32942410135420e-11, -7.72438823285226e-09,
1.13925338769604e-06, -0.000102985669746005, 0.00538423547801741,
-0.112116210954985, 1.24919663674987]
icoeff = zip(range(0, len(coeff)), reversed(coeff))
weight = 0.0
for p,c in icoeff:
weight += c * (x**p)
weight = RoundUpFractional(weight*1000.0)/1000.0

## for k in FusionEngineTable:
## t = FusionWeight(k)
## p = FusionWeightPoly(k)
## d = t - p
## if d > .01:
## print(k, t, p, d)

#print (weight)
return weight
print('''WARNING! This Engine Rating is outside normal Rating parameters, and its weight has been extrapolated. Player discretion is advised.
''')

def EngineWeight(engine_type, rating):
#Using a dictionary to match engine name to a formula
weight = FusionWeight(rating * 1.0)
#print (weight)
primitive = FusionWeight(rating * 1.2)
lithium = FusionWeight(max(MechTonnage, rating - MechTonnage))
if rating < 41:
proto = rating * (25.0/1000.0)
lithium_proto = max(MechTonnage, rating - MechTonnage) * (25.0/1000.0)
else:
proto = weight * 1.0
lithium_proto = lithium * 1.0

#print (weight)
ed = {"Standard Fusion Engine" : max(0.5, weight * 1.0),
"Light Fusion Engine" : max(0.5, RoundUpHalf(weight * .75)),
"XL Fusion Engine" : max(0.5, RoundUpHalf(weight * .50)),
"XXL Fusion Engine" : max(0.5, RoundUpHalf(weight / 3.0)),
"Compact Fusion Engine" : max(1.0, RoundUpHalf(weight * 1.5)),
"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!
"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!
"Fission Engine" : max(5.0, RoundUpHalf(weight * float(7.0/4.0))), #Only 5 Heat Sinks. Illegal in the Inner Sphere, and expensive.
"Lithium-Fusion Engine" : max(0.5, RoundUpHalf(lithium)), #Non-Canon. 10 Heat Sinks. Increases a mech's Walking Speed by 1.
"Primitive Fusion Engine" : max(0.5, RoundUpHalf(primitive)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Internal Combustion Engine (ICE)" : max(1.0, RoundUpHalf(primitive * 2.0)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fuel Cell" : max(1.0, RoundUpHalf(primitive * 1.2)), #Multiplies engine rating by 1.2, but does not increase performance.
"Primitive Fission Engine" : max(5.0, RoundUpHalf(primitive * (7.0/4.0))), #Multiplies engine rating by 1.2, but does not increase performance.
"ProtoMech Engine" : RoundUpFractional((proto * 1000.0)/1000.0),
"ProtoMech XL Lithium-Fusion Engine" : RoundUpFractional(max(0.013, lithium_proto/2)),
"Battery (Tech Level C)" : RoundUpFractional(weight * 1.5),
"Battery (Tech Level D)" : RoundUpFractional(weight * 1.2),
"Battery (Tech Level E)" : weight,
"Battery (Tech Level F)" : RoundUpFractional(weight * 0.8),
"Solar (Tech Level C)" : RoundUpFractional(weight * 5),
"Solar (Tech Level D)" : RoundUpFractional(weight * 4.5),
"Solar (Tech Level E)" : RoundUpFractional(weight * 4),
"Solar (Tech Level F)" : RoundUpFractional(weight * 3.5),
"No Engine" : 0,
}
return ed[engine_type]

if EngineType in {"Lithium-Fusion Engine"}:
LithiumBatteryRating = max(MechTonnage, rating - MechTonnage)
elif EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell," "Primitive Fission Engine"}:
LithiumBatteryRating = RoundUp5(rating * 1.2)
else:
LithiumBatteryRating = rating

#Cockpits
def PromptCockpitType():
"""Ask the user for their desired cockpit type, then return it."""
#cockpit list:
if LithiumBatteryRating < 401:
cl = ["Standard", "Small", "Armored", "Torso", "Interface", "Drone Operating System"]
elif LithiumBatteryRating > 400:
cl = ["Standard", "Small", "Armored", "Interface", "Drone Operating System"]
print("Cockpit types:");
for i in range(0, len(cl)):
print(" (%d) %s"%(i, cl[i]));
num = ask('''
Please select your desired Cockpit type''', 0, len(cl)-1);
print();
return cl[num]

def CockpitWeight(cockpit_type):
#Using a dictionary to match cockpit name to a formula
cd = {
"ProtoMech": 0.5,
"UltraHeavy ProtoMech": 0.75,
"Drone Operating System": max(1.0, RoundUpHalf((MechTonnage/10.0) + 0.5)),
"Small": 2.0,
("Standard", "AutoMech", "Industrial", "Armored Small"): 3.0,
("Armored", "Torso", "Tripod", "Interface", "SuperHeavy"): 4.0,
("Primitive", "Primitive Industrial", "SuperHeavy Tripod"): 5.0
}
# return ed[cockpit_type]
for key in cd:
if cockpit_type in key:
return cd[key]

#Skeletons
def PromptInternalType():
"""Ask the user for their desired internal structure type, then return it."""
#internal structure list:
if MechTonnage < 101:
if EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"}:
il = ["Primitive Standard", "Primitive Industrial"]
else:
il = ["Standard", "Endo Steel", "Composite", "Hybrid", "Reinforced", "Industrial"]
elif MechTonnage > 100:
il = ["SuperHeavy Standard", "SuperHeavy Hybrid", "SuperHeavy Endo Steel", "SuperHeavy Reinforced", "SuperHeavy Industrial"] #You have balls if you pick that last one.
print('''Internal Structure types:
(Rule of thumb: Endo Steel is lighter, but bulkier, than Standard.)''')
for i in range(0, len(il)):
print(" (%d) %s"%(i, il[i]))
num = ask('''
Please select your desired Internal Structure type''', 0, len(il)-1);
print();
return il[num]

def InternalWeight(internal_type):
#Using a dictionary to match internal structure name to a formula
isd = {
("Standard", "Primitive Standard", "SuperHeavy Endo Steel", "ProtoMech"): RoundUpHalf(MechTonnage/10.0),
("Endo Steel", "Composite"): RoundUpHalf(MechTonnage/20.0),
"Hybrid": RoundUpHalf(MechTonnage*7.5/100.0),
("Reinforced", "Industrial", "Primitive Industrial", "SuperHeavy Standard") : RoundUpHalf(MechTonnage/5.0),
"SuperHeavy Hybrid": RoundUpHalf(MechTonnage*15.0/100.0),
("SuperHeavy Industrial", "SuperHeavy Reinforced"): RoundUpHalf(MechTonnage/2.5),
}
# 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.
for key in isd:
if internal_type in key:
return isd[key]

if MechTonnage > 100:
InternalType = PromptInternalType()
CockpitType = ("SuperHeavy")
if MechType in ["Tripod"]:
MechType = ("SuperHeavy Tripod")
else:
Mechtype = ("SuperHeavy" + CurrentMechType)
elif EngineType in ["ProtoMech Engine"]:
InternalType = ("ProtoMech")
MechType = ("ProtoMech")
if MechTonnage < 10:
CockpitType = ("ProtoMech")
elif MechTonnage > 9:
CockpitType = ("UltraHeavy ProtoMech")
else:
MechType = CurrentMechType
InternalType = PromptInternalType()
if EngineType in {"Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"}:
CockpitType = ("Primitive")
else:
CockpitType = PromptCockpitType()

#Gyros
def PromptGyroType():
"""Ask the user for their desired gyro type, then return it."""
#gyro list:
if LithiumBatteryRating < 401 or EngineType in ["Compact Fusion Engine"]:
gl = ["Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
elif EngineType in {"Lithium-Fusion Engine"} and rating < 501:
gl = ["Standard", "XL (Extra-Light)", "Compact", "Heavy-Duty",]
elif LithiumBatteryRating > 400 or CockpitType in ["Torso"]:
if EngineType not in ["Compact Fusion Engine"]:
gl = ["Standard", "Compact", "Heavy-Duty",]
print("Gyro types:")
for i in range(0, len(gl)):
print(" (%d) %s"%(i, gl[i]))
num = ask("Please select your desired Gyro type", 0, len(gl)-1)
print();
return gl[num]

if EngineType in ["Lithium-Fusion Engine"]:
FinalRating = LithiumBatteryRating
elif EngineType in ["Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"]:
FinalRating = MechTonnage * CruisingSpeed * 1.2
elif EngineType in ["ProtoMech Engine"]:
FinalRating = MechTonnage * FlankingSpeed
else:
FinalRating = MechTonnage * CruisingSpeed

GyroRating = ceil(FinalRating / 100)

if MechTonnage > 100:
GyroType = ("SuperHeavy")
elif EngineType in ["Primitive Fusion Engine", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell", "Primitive Fission Engine"]:
if MechTonnage < 101:
GyroType = ("Primitive")
elif MechTonnage > 100:
GyroType = ("SuperHeavy Primitive")
elif CockpitType in ["ProtoMech", "UltraHeavy ProtoMech", "Interface"]:
GyroType = ("None")
else:
GyroType = PromptGyroType()

def GyroWeight(gyro_type):
#Using a dictionary to match gyro name to a formula
gmass = GyroRating
gd = {
("Standard", "Primitive") : max(1.0, gmass*1.0),
"XL (Extra-Light)" : max(1.0, RoundUpHalf(gmass/2.0)),
"Compact" : max(1.5, RoundUpHalf(gmass*1.5)),
("Heavy-Duty", "SuperHeavy", "Primitive SuperHeavy") : max(2.0, ceil(gmass * 2.0)),
"None": (gmass*0.0),
"Armored" : (gmass + 2.0),
"Armored Compact" : 1.0 + RoundUpHalf(gmass*1.5),
"Armored XL" : 3.0 + RoundUpHalf(gmass/2.0),
"Armored Heavy-Duty" : 2.0 + (gmass*2.0),
}
# return ed[gyro_type]
for key in gd:
if gyro_type in key:
return gd[key]

#Heat Sinks
def PromptHeatSinkType():
"""Ask the user for their desired heat sink type, then return it."""
#heat sink list:
hsl = ["Single", "Double (Inner Sphere)", "Double (Clan)", "Laser", "Compact"]
print("Heat Sink types:");
for i in range(0, len(hsl)):
print(" (%d) %s"%(i, hsl[i]));
num = ask('''
Please select your desired Heat Sink type''', 0, len(hsl)-1);
print();
return hsl[num]

if EngineType in {"Fission Engine", "Primitive Fission Engine"}:
FreeHeatSinks = 5
HeatSinkType = PromptHeatSinkType()
elif EngineType in {"Fuel Cell", "Primitive Fuel Cell"}:
FreeHeatSinks = 1
HeatSinkType = PromptHeatSinkType()
elif EngineType in {"Internal Combustion Engine (ICE)", "Primitive Internal Combustion Engine (ICE)"}:
FreeHeatSinks = 0
HeatSinkType = PromptHeatSinkType()
elif EngineType in {"ProtoMech Engine"}:
FreeHeatSinks = 0
HeatSinkType = ("ProtoMech")
else:
FreeHeatSinks = 10
HeatSinkType = PromptHeatSinkType()

if EngineType in ["ProtoMech Engine"]:
UserHeatSinks = ask("Please provide your desired quantity of ProtoMech Heat Sinks", 0, MechTonnage*4)

elif HeatSinkType in ["Compact"]:
print ("You currently have", int(FreeHeatSinks), HeatSinkType, "Heat Sinks.")
UserHeatSinks = ask("If you wish to install additional Heat Sinks, enter the quantity you wish to add", 0, floor(MechTonnage*2/3))
else:
print ("You currently have", int(FreeHeatSinks), HeatSinkType, "Heat Sinks.")
UserHeatSinks = ask("If you wish to install additional Heat Sinks, enter the quantity you wish to add", 0, MechTonnage)

TotalHeatSinks = UserHeatSinks + FreeHeatSinks

if UserHeatSinks > 0:
print("You now have", TotalHeatSinks, "total", HeatSinkType, "HeatSinks.")

if EngineType in {"ProtoMech Engine"}:
HeatSinkWeight = RoundUpFractional(UserHeatSinks/4.0)
IntegralHeatSinks = int(TotalHeatSinks)
HeatSinkSlots = 0
elif HeatSinkType in {"Compact"}:
HeatSinkWeight = RoundUpHalf(UserHeatSinks * 1.5)
IntegralHeatSinks = int(min(TotalHeatSinks, floor(LithiumBatteryRating/12.5)))
else:
HeatSinkWeight = UserHeatSinks * 1.0
IntegralHeatSinks = int(min(TotalHeatSinks, floor(LithiumBatteryRating/25.0)))

PodHeatSinks = TotalHeatSinks - IntegralHeatSinks

if MechTonnage < 101:
if HeatSinkType in ["Single", "Liquid Metal"]:
HeatSinkSlots = PodHeatSinks
elif HeatSinkType in ["Double (Inner Sphere)", "Double (ProtoType)"]:
HeatSinkSlots = PodHeatSinks * 3
elif HeatSinkType in ["Double (Clan)", "Double (Star Empire)", "Laser"]:
HeatSinkSlots = PodHeatSinks * 2
elif HeatSinkType in ["Compact"]:
HeatSinkSlots = ceil(PodHeatSinks/2)
elif HeatSinkType in ["ProtoMech"]:
HeatSinkSlots = 0

elif MechTonnage > 100:
if HeatSinkType in ["Single"]:
HeatSinkSlots = ceil(PodHeatSinks/2)
elif HeatSinkType in ["Double (Inner Sphere)"]:
HeatSinkSlots = ceil(PodHeatSinks * 1.5)
elif HeatSinkType in ["Double (Clan)", "Laser"]:
HeatSinkSlots = PodHeatSinks
elif HeatSinkType in ["Compact"]:
HeatSinkSlots = ceil(PodHeatSinks/4)

#Podspace
skeleton = InternalWeight(InternalType)
tripod = RoundUpHalf(skeleton * 1.1)
cockpit = CockpitWeight(CockpitType)
gyro = GyroWeight(GyroType)
EngineTonnage = EngineWeight(EngineType, rating)

##if MechType in ["Combat Vehicle", "Support Vehicle"]:
## if EngineType in ["Internal Combustion Engine (ICE)", "Fuel Cell", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell"]:
## VehicleEngine = EngineTonnage
## else:
## if MechType in ["Combat Vehicle"]:
## VehicleEngine = RoundUpHalf(EngineTonnage * 1.5)
## elif MechType in ["Support Vehicle"]:
## VehicleEngine = RoundUpFractional(EngineTonnage * 1.5)
##else:
## if EngineType in ["Internal Combustion Engine (ICE)", "Fuel Cell", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell"]:
## VehicleEngine = EngineTonnage
## else:
## VehicleEngine = RoundUpHalf(EngineTonnage * 1.5)

if IsVehicle is True:
if EngineType not in ["Internal Combustion Engine (ICE)", "Fuel Cell", "Primitive Internal Combustion Engine (ICE)", "Primitive Fuel Cell"]:
VehicleEngine = EngineTonnage * 1.5
else:
VehicleEngine = EngineTonnage

print()

#DEBUG READOUT - UNCOMMENT IF CRASHES OCCUR
print('''DEBUG READOUT - RECOMMENT IF CRASHES NO LONGER OCCUR:
MechTonnage =''', MechTonnage,'''
EngineTonnage =''', EngineTonnage,'''
VehicleEngine =''', VehicleEngine,'''
FinalRating =''', FinalRating,'''
skeleton =''', skeleton,'''
tripod =''', tripod,'''
gyro =''', gyro,'''
cockpit =''', cockpit,'''
HeatSinkWeight =''', HeatSinkWeight,'''

Press ENTER to confirm, or Ctrl+C to abort.''')
input()
#^^^^^^^^^^^^^

if MechType in ["Tripod", "SuperHeavy Tripod"]:
podspace = RoundDownHalf(MechTonnage - EngineTonnage - tripod - gyro - cockpit - HeatSinkWeight)
elif EngineType in ["ProtoMech Engine", "ProtoMech XL Lithium-Fusion Engine"] or MechType in ["ProtoMech", "Quad ProtoMech", "Glider ProtoMech"]:
podspace = RoundDownFractional(MechTonnage - EngineTonnage - skeleton - gyro - cockpit - HeatSinkWeight)
elif MechType in ["Combat Vehicle"]:
podspace = RoundDownHalf(MechTonnage - VehicleEngine - skeleton - gyro - cockpit - HeatSinkWeight)
elif MechType in ["Support Vehicle"]:
podspace = RoundDownFractional(MechTonnage - VehicleEngine - skeleton - gyro - cockpit - HeatSinkWeight)
else:
podspace = RoundDownHalf(MechTonnage - EngineTonnage - skeleton - gyro - cockpit - HeatSinkWeight)

if VehicleEngine > MechTonnage:
print('''WARNING! Your engine is heavier than the mech!
WARNING! Your mech has negative podspace, and is Overweight!''')
input()
elif podspace < 0.0:
print("WARNING! Your mech has negative podspace, and is Overweight!")
input()
else:
print("ALL SYSTEMS NOMINAL.")
input()

#Finalize
if MechName in {"BattleMech", "Ultralight BattleMech", "Light BattleMech", "Medium BattleMech", "Heavy BattleMech", "Assault BattleMech", "SuperHeavy BattleMech"}:
if InternalType in {"Industrial"}:
if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
MechName = (MechClass + " IndustrialMech")
if InternalType in {"Primitive Standard"}:
if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
MechName = ("Primitive " + MechClass + " BattleMech")
if InternalType in {"Primitive Industrial"}:
if MechClass in {"Ultralight", "Light", "Medium", "Heavy", "Assault", "SuperHeavy"}:
MechName = ("Primitive " + MechClass + " IndustrialMech")
elif MechClass in {"ProtoMech", "UltraHeavy ProtoMech"}:
MechName = MechClass
MechType = ("ProtoMech")
elif CockpitType in {"AutoMech"}:
MechName = (MechClass + " AutoMech")
MechType = ("AutoMech")

#Technical Readout
fib(FinalRating)
print('''
Your''', MechName, "has a Cruising MP of", CruisingSpeed, "hexes per turn, and a Flanking MP of", FlankingSpeed, '''hexes per turn.
This speed is provided by a''', FinalRating,'rated', EngineType, "weighing", EngineTonnage, "metric tons.");

if EngineType in ["ProtoMech Engine", "ProtoMech XL Lithium-Fusion Engine"]:
print("You have", TotalHeatSinks, HeatSinkType, "Heat Sinks weighing", HeatSinkWeight, "metric tons.")

else:
print("You have", TotalHeatSinks, HeatSinkType, "Heat Sinks weighing", HeatSinkWeight, "metric tons, of which", IntegralHeatSinks, '''of them are Integral,
and out of those''', TotalHeatSinks, HeatSinkType, "Heat Sinks,",FreeHeatSinks, "of them come with the engine.")
if PodHeatSinks > 0:
print ("The remaining", HeatSinkType, "Heat Sinks occupy", HeatSinkSlots, "Critical Spaces in total.")

print()

if MechType in ["Tripod"]:
print("The Mech's weight is supported by a", InternalType, "Internal Structure with a mass of", tripod, "metric tons.");

elif MechType in ["AutoMech"]:
print ("The AutoMech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton, "metric tons.");

elif MechType in ["ProtoMech"]:
print ("The ProtoMech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton*1000, "kilograms.");

else:
print ("The Mech’s weight is supported by a", InternalType, "Internal Structure with a mass of", skeleton, "metric tons.");

if GyroType in ["None"] and MechTonnage > 9:
print("The pilot is cocooned in an", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

elif GyroType in ["None"] and MechTonnage <10:
print("The pilot is cocooned in a", CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

elif CockpitType in ["Drone Operating System", "AutoMech"]:
if GyroType in ["XL (Extra-Light)"]:
print ("and keeping the", MechName, "upright is an", GyroType, "Gyro weighing", gyro, "metric tons.")
else:
print ("and keeping the", MechName, "upright is a", GyroType, "Gyro weighing", gyro, "metric tons.")

if CockpitType in ["Drone Operating System"]:
print ("The brains of this machine consist of a", CockpitType, "weighing", cockpit, "metric tons.")

elif CockpitType in ["AutoMech"]:
print ("The brains of this machine consist of an", CockpitType, "computer weighing", cockpit, "metric tons.")

elif GyroType in ["SuperHeavy"]:
print ("and the only thing stopping your", MechName, "from toppling over is a monstrous", GyroType, "Gyro weighing", gyro, '''metric tons.
The pilots are 'efficiently' huddled together in a''', CockpitType, "Cockpit, weighing a massive", cockpit, "metric tons.");

elif GyroType in ["XL (Extra-Light)"]:
print ("and keeping the", MechName, "upright is an", GyroType, "Gyro weighing", gyro, '''metric tons.
The pilot sits ’comfortably’ in a''', CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

else:
print("and keeping the", MechName, "upright is a", GyroType, "Gyro weighing", gyro, '''metric tons.
The pilot sits 'comfortably' in a''', CockpitType, "Cockpit, which weighs", cockpit, "metric tons.");

print('''
The''', MechName, "has an average walking speed of", kph(CruisingSpeed), "km/h, and a maximum running speed of", kph(FlankingSpeed), "km/h.");

if podspace > 0.0:
print("The", MechName, "has", podspace, '''tons of Pod Space available to mount weapons, armor and equipment.
''')
fib(podspace)
print();
else:
print("Oh, stravag! It would seem that your engineers left your", MechName, "with only", podspace, '''tons of Pod Space,
and thanks to their incompetence, the mech cannot mount any weapons, armor or equipment!

+++ MELON MELON MELON. OUT-OF-CHEESE ERROR. REDO FROM START. +++''')
input()

## Closing sequence.
print('''Please visit http://www.sarna.net for more information on these terms and components.
If you have any questions or feedback about the software, such as feature requests or bug reports,
if you need technical support, or if you would simply like to contribute to development, then please visit:
https://tinyurl.com/Sarna-Forums-MechEngine
''')
gettime()
input("Shutdown Sequence: Initiated.") #Change this line to a menu option once Restart has been implemented.
print ("Shutting Down.")

## End of Line.

#Contribution Links:
# https://pastebin.com/VfJ5Sz7Y
# https://docs.google.com/document/d/1A6Y79pelpzdRg00DHcZNO3tyrdvthFSaU4tihSvGkE8/edit?usp=sharing
Discord: Amaroq the Kitsune#1092
Telegram: @Lycanphoenix
MechEngine (Alpha) -- On Hiatus

The Scientist Caste has determined that time travel is dishonorable.
Pages: 1
Extra information
0 registered and 136 anonymous users are browsing this forum.

Moderator:  Nic Jansma, Cray, Frabby, BobTheZombie 

Print Topic

Forum Permissions
      You cannot start new topics
      You cannot reply to topics
      HTML is disabled
      UBBCode is enabled

Topic views: 13942


Contact Admins Sarna.net