Skip to content

Commit

Permalink
A python script to generate ship view
Browse files Browse the repository at this point in the history
  • Loading branch information
royfalk committed Oct 27, 2024
1 parent afb3699 commit fdd6f48
Show file tree
Hide file tree
Showing 2 changed files with 325 additions and 0 deletions.
21 changes: 21 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"general": {},

"graphics": {
"resolution_x": 2560,
"resolution_y": 1600,
"screen": 0
},

"components": {
"drive": {
"non_combat_mode_multiplier": 100
}
},

"constants": {
"megajoules_multiplier": 100
},

"advanced": {}
}
304 changes: 304 additions & 0 deletions python/base_computer/ship_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
import locale
import math
import json


newline = "#n#"
red = "#c1:.3:.3#"
green = "#c0:1:.5#"
light_grey = "#c.75:.9:1#"
grey = "#c.6:.7:.8#"
light_yellow = "#c.675:.925:.825#"
end_color = "#-c"

non_combat_speed_multiplier = 1
megajoules_multiplier = 1

llama_begin = {}

with open('config.json', 'r') as file:
data = json.load(file)
non_combat_speed_multiplier = data['components']['drive']['non_combat_mode_multiplier']
megajoules_multiplier = data['constants']['megajoules_multiplier']

with open('units/units.json', 'r') as file:
data = json.load(file)

for ship in data:
if ship['Key'] == 'Llama.begin':
llama_begin = ship
break


# Format large number
def lnum(ship_stats, key, divider = 1.0):
num = float(ship_stats[key])/divider
num = '{:n}'.format(num)
return num

def get(ship_stats, key):
return ship_stats[key]

def get_bool(ship_stats, key):
s = ship_stats[key]
if(s == 'TRUE' or s=='1'):
return True
return False

def get_int(ship_stats, key):
return int(ship_stats[key])

def get_dbl(ship_stats, key, divider = 1.0):
fl = float(ship_stats[key])/divider
#s = f"{key} {fl}"
#print(s)
return fl

def get_fmt_dbl(ship_stats, key, divider = 1.0):
return "{:.2f}".format(float(ship_stats[key]))

def fmt_dbl(dbl):
return "{:.2f}".format(dbl)

def near_equal(a,b):
return a-b < 0.01 and b-a < 0.01

def get_notes(ship_stats):
text = f"{green}[NOTES]{newline}{newline}"
text += f"{grey}#-c{ship_stats['Textual_Description']}{newline}{newline}"
return text

def get_variant(key):
# TODO: refactor with dict and for/each
if key.endswith('blank'):
return ''
if key.endswith('begin'):
return 'Variant: #-cStock (Refurbished)'
if key.endswith('stock'):
return 'Variant: #-cStock'
if key.endswith('civvie'):
return 'Variant: #-cCivilian'
if key.endswith('milspec'):
return 'Variant: #-cMilspec'
return ''

def get_itts(itts):
if(itts=='1'):
return 'yes'
return 'no'

def get_iff(iff):
if iff=='0': return 'none'
if iff=='1': return 'friend/foe'
if iff=='2': return 'object recognition'
return iff

# General
def get_general(ship_stats):
text = f"{green}[GENERAL INFORMATION]{newline}"
text += f"#-c{newline}{light_grey}Model: #-c{ship_stats['Name']}{light_grey} {get_variant(ship_stats['Key'])}{newline}"
text += f"{light_grey}Mass: #-c{lnum(ship_stats,'Mass')} metric tons{newline}"
text += f"{light_grey}Hold volume: #-c{lnum(ship_stats,'Hold_Volume')} cubic meters{newline}"
text += f"{light_grey}Upgrade volume: #-c{lnum(ship_stats,'Upgrade_Storage_Volume')} cubic meters{newline}"
text += f"{light_grey}Fuel capacity: #-c{lnum(ship_stats,'Fuel_Capacity')} metric tons of Lithium-6{newline}{newline}"
return text

# Flight Characteristics
def get_flight(ship_stats):
mass = get_dbl(ship_stats,'Mass')
moment = get_dbl(ship_stats,'Moment_Of_Inertia')
divider = 9.8 * mass
divider_maneuver = moment * 180 / math.pi
yaw = get_dbl(ship_stats,'Maneuver_Yaw', divider_maneuver)
pitch = get_dbl(ship_stats,'Maneuver_Pitch', divider_maneuver)
roll = get_dbl(ship_stats,'Maneuver_Roll', divider_maneuver)

forward = get_dbl(ship_stats,'Forward_Accel', divider)
retro = get_dbl(ship_stats,'Retro_Accel', divider)

lateral = (get_dbl(ship_stats,'Left_Accel', divider) + get_dbl(ship_stats,'Right_Accel', divider))/2
vertical = (get_dbl(ship_stats,'Top_Accel', divider) + get_dbl(ship_stats,'Bottom_Accel', divider))/2

afterburner = get_dbl(ship_stats,'Afterburner_Accel', divider)

text = f"{green}[FLIGHT CHARACTERISTICS]{newline}"

if(yaw == pitch and yaw == roll):
text += f"#-c{newline}{light_grey}Turning response: #-c{fmt_dbl(yaw)} radians/second²{newline}"
text += f"{grey} (yaw, pitch, roll)#-c{newline}"
else:
text += f"#-c{newline}{light_grey} yaw #-c{fmt_dbl(yaw)} radians/second²{newline}"
text += f"#-c{newline}{light_grey} pitch #-c{fmt_dbl(pitch)} radians/second²{newline}"
text += f"#-c{newline}{light_grey} roll #-c{fmt_dbl(roll)} radians/second²{newline}"

text += f"{light_grey}Fore acceleration: #-c{fmt_dbl(forward)} gravities{newline}"
text += f"{light_grey}Aft acceleration: #-c{fmt_dbl(retro)} gravities{newline}"

if(lateral == vertical):
text += f"{light_grey}Orthogonal acceleration: #-c{fmt_dbl(lateral)} gravities{newline}"
text += f"{grey}(vertical and lateral axes)#-c{newline}"
else:
text += f"{light_grey} Lateral acceleration #-c{fmt_dbl(lateral)} gravities{newline}"
text += f"{grey} Vertical acceleration #-c{fmt_dbl(vertical)} gravities{newline}"
text += f"{light_grey}Forward acceleration with overthrust: #-c{fmt_dbl(afterburner)} gravities{newline}{newline}"
return text

def get_governor(ship_stats):
divider = 180 / math.pi
speed = get_int(ship_stats, 'Default_Speed_Governor')
afterburner = get_int(ship_stats, 'Afterburner_Speed_Governor')

yaw = get_dbl(ship_stats, 'Yaw_Governor',divider)
#yaw_right = get_dbl(ship_stats, 'Yaw_Governor_Right')
#yaw_left = get_dbl(ship_stats, 'Yaw_Governor_Left')

pitch = get_dbl(ship_stats, 'Pitch_Governor',divider)
#pitch_down = get_dbl(ship_stats, 'Pitch_Governor_Up')
#pitch_up = get_dbl(ship_stats, 'Pitch_Governor_Down')

roll = get_dbl(ship_stats, 'Roll_Governor',divider)
#roll_right = get_dbl(ship_stats, 'Roll_Governor_Right')
#roll_left = get_dbl(ship_stats, 'Roll_Governor_Left')

text = f"{green}[GOVERNOR SETTINGS]{newline}#-c{newline}"
text += f"{light_grey}Max combat speed: #-c{speed} m/s{newline}"
text += f"{light_grey}Max overdrive combat speed: #-c{afterburner} m/s{newline}"
text += f"{light_grey}Max non-combat speed: #-c{speed * non_combat_speed_multiplier} m/s{newline}"
text += f"{light_grey}Max turn rates:#-c{newline}"
text += f"{light_yellow} - yaw: #-c{fmt_dbl(yaw)} radians/second{newline}"
text += f"{light_yellow} - pitch: #-c{fmt_dbl(pitch)} radians/second{newline}"
text += f"{light_yellow} - roll: #-c{fmt_dbl(roll)} radians/second{newline}{newline}"
return text

def get_radar(ship_stats):
radar_range = lnum(ship_stats,'Radar_Range',1000)
max_cone = get_dbl(ship_stats,'Max_Cone', 180 / math.pi)
tracking_cone = get_dbl(ship_stats,'Tracking_Cone', 180 / math.pi)
lock_cone = get_dbl(ship_stats,'Lock_Cone', 180 / math.pi)
itts = ship_stats['ITTS']
iff = ship_stats['Radar_Color']

text = f"{green}[TARGETTING SUBSYSTEM]{newline}#-c{newline}"
text += f"{light_grey}Tracking range: #-c{radar_range} km{newline}"

if(near_equal(max_cone,math.pi)):
text += f"{light_grey}Tracking cone: #-cOmni-directional{newline}"
else:
text += f"{light_grey}Tracking cone: #-c{fmt_dbl(max_cone * 2)} radians{newline}"
text += f"{light_grey} (planar angle: 2 pi means full space)#-c{newline}"
text += f"{light_grey}Assisted targeting cone: #-c{fmt_dbl(tracking_cone * 2)} radians{newline}"
text += f"{light_grey}Missile locking cone: #-c{fmt_dbl(lock_cone * 2)} radians{newline}"
text += f"{light_grey}ITTS (Intelligent Target Tracking System) support: #-c{get_itts(itts)}{newline}"
text += f"{light_grey}AFHH (Advanced Flag & Hostility Heuristics) support: #-c{get_iff(iff)} {newline}{newline}"
return text

def get_energy_spec_and_jump(ship_stats):
reactor = get_dbl(ship_stats,'Reactor_Recharge',1/megajoules_multiplier)
energy = get_dbl(ship_stats,'Primary_Capacitor',1/megajoules_multiplier)
ftl_energy = get_dbl(ship_stats,'Warp_Capacitor',1/megajoules_multiplier)
spec_cost = get_dbl(ship_stats,'Warp_Usage_Cost',1/megajoules_multiplier)

jump_drive_installed = get_bool(ship_stats,'Jump_Drive_Present')
jump_delay = get_dbl(ship_stats,'Jump_Drive_Delay')
jump_cost = get_dbl(ship_stats,'Outsystem_Jump_Cost',1/megajoules_multiplier)


text = f"{green}[ENERGY SUBSYSTEM]{newline}#-c{newline}"
text += f"{light_grey}Recharge: #-c{reactor} MJ/s{newline}"
text += f"{light_grey}Main capacitor: #-c{energy} MJ{newline}"
text += f"{light_grey}SPEC capacitor: #-c{ftl_energy}0 MJ{newline}{newline}"

text += f"{green}[SPEC SUBSYSTEM]{newline}#-c{newline}"
text += f"{light_grey}Active SPEC Energy Requirements: #-c{spec_cost} MJ/s{newline}{newline}"

text += f"{green}[JUMP SUBSYSTEM]{newline}#-c{newline}"
if(jump_drive_installed):
text += f"{light_grey}Energy cost for jumpnode travel: #-c{jump_cost} MJ{newline}"
text += f"{light_grey}Delay: #-c{jump_delay} seconds{newline}{newline}"
else:
text += f"{red}No outsystem jump drive present{end_color}{newline}{newline}"

return text

def get_durability(ship_stats):
armor = [
('Fore-starboard-high','Armor_Front_Top_Right'),
('Aft-starboard-high','Armor_Back_Top_Right'),
('Fore-port-high','Armor_Front_Top_Left'),
('Aft-port-high','Armor_Back_Top_Left'),
('Fore-starboard-low','Armor_Front_Bottom_Right'),
('Aft-starboard-low','Armor_Back_Bottom_Right'),
('Fore-port-low','Armor_Front_Bottom_Left'),
('Aft-port-low','Armor_Back_Bottom_Left'),
]

shield4 = [
('Port','Shield_Front_Bottom_Left'),('Starboard','Shield_Front_Bottom_Right'),('Fore','Shield_Front_Top_Right'),('Aft','Shield_Back_Top_Left'),
]

shield2 = [
('Fore','Shield_Front_Top_Right'),('Aft','Shield_Back_Top_Left'),
]

# This is a kludge. Should go away when we refactor units.json and unit_csv.cpp
shield_stat = {}
num_emitters = 0
for pair in shield4:
if ship_stats[pair[1]] == '':
continue
value = get_dbl(ship_stats,pair[1])
if value > 0:
num_emitters += 1


hull = lnum(ship_stats,'Hull')
shield_recharge = lnum(ship_stats,'Shield_Recharge')

text = f"{green}[DURABILITY STATISTICS]{newline}#-c{newline}"
text += f"{light_grey}Sustainable Hull Damage: #-c{hull} MJ{newline}{newline}"

text += f"{light_grey}Armor#-c{newline}"
for pair in armor:
armor_stat = lnum(ship_stats, pair[1])
text += f"{light_yellow} - {pair[0]}: #-c{armor_stat} MJ{newline}"

text += f"{newline}{light_grey}Shields#-c{newline}"
text += f"{light_grey}Shield recharge: #-c{shield_recharge} MJ/s{newline}"
if num_emitters == 0:
text += f"{red}No shielding.{end_color}{newline}{newline}"
elif num_emitters == 2:
text += f"{light_grey}Number of shield emitter: 2{end_color}{newline}"
for pair in shield2:
shield_stat = lnum(ship_stats, pair[1])
text += f"{light_yellow} - {pair[0]}: #-c{shield_stat} MJ{newline}"
else:
text += f"{light_grey}Number of shield emitter: 4{end_color}{newline}"
for pair in shield4:
shield_stat = lnum(ship_stats, pair[1])
text += f"{light_yellow} - {pair[0]}: #-c{shield_stat} MJ{newline}"

return text



def get_ship_description(ship_stats):
locale.setlocale(locale.LC_ALL, '')

text = get_notes(ship_stats)
text += get_general(ship_stats)
text += get_flight(ship_stats)
text += get_governor(ship_stats)
text += get_radar(ship_stats)
text += get_energy_spec_and_jump(ship_stats)
text += get_durability(ship_stats)

return text

# Test function
# Useful to check python script for correctness before running VS

t = get_ship_description(llama_begin)
t = t.replace('#n#','\n')
print(t)


0 comments on commit fdd6f48

Please sign in to comment.