-
-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A python script to generate ship view #130
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
fdd6f48
A python script to generate ship view
royfalk 1a458e5
Merge branch 'master' into task_ship_view
royfalk 1270946
Add missing change to cmake
royfalk 5a79352
Merge remote-tracking branch 'origin/task_ship_view' into task_ship_view
royfalk d8cf1f7
Modify python script
royfalk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,309 @@ | ||
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 | ||
|
||
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'] | ||
|
||
|
||
|
||
# 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' | ||
if key.endswith('rg'): | ||
return 'Variant: #-cRegional Guard' | ||
if key.endswith('rgspec'): | ||
return 'Variant: #-cRegional Guard Spec' | ||
|
||
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 | ||
|
||
if __name__ == "__main__": | ||
# Test function | ||
# Useful to check python script for correctness before running VS | ||
|
||
with open('units/units.json', 'r') as file: | ||
data = json.load(file) | ||
|
||
for ship in data: | ||
if ship['Key'] == 'Llama.begin': | ||
t = get_ship_description(ship) | ||
t = t.replace('#n#','\n') | ||
print(t) | ||
break | ||
|
||
|
||
|
||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since
config.json
would have to be in a specific place we need to either:(a) define a working directory for the active "game"
(b) expose these as Python Objects instead of making each script load it if it wants access. This would eliminate the
open
andjson.load
steps; and we'd have to define the interface - either as a pure Python Dictionary/Object or as something else. A first step might be just having aload
method that would load the contents and return thedata
object like you have above.I'd rather
b
between the two.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking more about this...option
a
might actually be a better solution for game asset data. But let's evolve the conversation on this beyond just this PR.