Vanilla Freelancer weapon stats patterns
-
I just replayed Freelancer for the first time in years (I am seriously impressed with the HD Edition). It inspired me and I’m looking back over work that I did back in 2008 on weapons stats . My goal was/is to make it easy to generate an arbitrary new weapon that is completely consistent with the original framework.
Example: using what is clear about stats progression within weapon_equip.ini, the Starkiller is a level 5 torpedo. Using the stats progression, a level 1 baby torpedo launcher that is “consistent” with vanilla Freelancer torpedoes (I’ll call it the Cometkiller) would have 400 hit points for the launcher. The torpedoes would cause 936 damage and have a range (this bit is still a guess) of 980 meters.
Has anyone else posted details on progressions before? I thought I might have posted what I found on TLR, but didn’t. I also seem to recall emailing some details to Tooth for possible use in Asgard 3, but don’t have any of my email archived from that long ago.
If someone else HAS done this kind of thing, I’d love to know; it will save me a lot of time tearing out my hair (which is already much thinner than it was in 2004-2008 ).
If someone hasn’t, I can post what I have as a framework for other people to use and to get feedback. With the possible exception of the theoretical Level 10 cruise disruptor, I don’t think any of it would excessively alter vanilla game balance.
-
I think most mods have tried to move away from the tiered approach vanilla takes! I’ve not heard of this being done before and it seems like a really neat idea to make interesting gear available at all stages of the game.
If you’re looking at generating INI files to do this, might I recommend using Python for it? Our mod takes a very different approach, but creating hundreds of weapon ini entries by hand is pretty miserable, and if you can take a formulaic approach you’ll save yourself a great deal of time
-
@IrateRedKite said in Vanilla Freelancer weapon stats patterns:
If you’re looking at generating INI files to do this, might I recommend using Python for it?
Yes, you may. Last time I used PowerShell for parsing the files since I could use stream processing cmdlets. I’m lazy and this time around I’ve been using ChatGPT to handle parsing; since it defaults to using Python for processing, I’ve already got some basic INI processing. It will need guardrails and error handling to be good Python, but it’s a start.
, creating hundreds of weapon ini entries by hand is pretty miserable
Oh, yes.
-
Is there a more appropriate place to post questions and results? I’m finding old community knowledge in the archived posts and FL data (thanks to everyone who made that possible!) from TLR, but I’m not seeing a lot of general FL mod discussions here. Likely it will be boring commentary and code snippets.
-
IrateRedKite Administrators Historic Supporter Wiki Contributorreplied to WatercoolerWarrior on global:last_edited_by,
@WatercoolerWarrior There’s the wiki, which can be found here: https://the-starport.com/wiki/ and is all handled through GitHub, but this is more for established Knowledge and less for discussion. There’s a lot that goes on in the #modding channel of the TSP Discord, but honestly, post results here and folks will probably come along to discuss them/answer questions if you’re patient!
-
Rough notes on this. In-progress spreadsheets are shared from my Google Drive; the tables below are space-justified for display purposes.
I’d like to know about potentials issues/errors anyone finds. I’m disclaiming intellectual property rights; if anyone finds it useful (or any code or generated weapons I may post related to this) feel free to reuse. I’m also curious about whether anyone has gone through this material before; I find it hard to believe I’m the first to try systematizing the vanilla weaponry.
==================
I’ve found this to be consistent across guns in weapon_equip, as long as we’re comparing apples to apples and oranges to oranges - e.g., comparing li_gun01 marks to each other rh_gun02 marks to each other, etc.
Data is rounded to 3 decimal places.
Headings are abbreviated so I can make it viewable in fixed width here.UNIVERSAL TABLE - applies to every player weapon family in vanilla FL.
Level Gun HP HP Ratio Tough Dmg Ratio Dmg rel 1 Damage rel 5 Shield Ratio Shield rel 1 1 400 N/A N/A N/A 1.000 0.404 N/A 1.000 2 548 1.370 1.252 1.252 1.252 0.506 1.369 1.369 3 750 1.369 1.219 1.219 1.526 0.617 1.369 1.874 4 1026 1.368 1.269 1.269 1.937 0.783 1.369 2.566 5 1405 1.369 1.278 1.278 2.475 1.000 1.369 3.512 6 1923 1.369 1.305 1.305 3.230 1.305 1.369 4.809 7 2632 1.369 1.322 1.322 4.270 1.725 1.369 6.583 8 4215 1.601 1.521 1.521 6.495 2.624 1.369 9.012 9 6752 1.602 1.538 1.538 9.989 4.036 1.369 12.338 10 6752 1.000 1.2 1.2 11.987 4.843 1.369 16.890
Level - this is the weapon mount level, of course.
Gun HP - hit points of the gun itself, meaning the damage it can take before being destroyed if someone targets it on an unshielded ship. ALL user weapons in vanilla Freelancer use these HP values (including minedroppers, CDs, and torpedoes, allowing us to neatly assign “levels” to them).
HP ratio - Gun HP ratio compared to the preceding level.
Tough - weapon toughness ratio compared to preceding level toughness.
Dmg ratio - same growth as toughness, this is the way damage increases within a weapon family for increases in level.
Dmg rel 1 - scaled damage compared to level 1. For example, a theoretical level 10 version of liberty gun 1 would cause 11.987 times as much damage as the level 1 version.
Dmg rel 5 - Same thing as rel 1, but with everything scaled to a level 5 version.
Shield ratio - level to level shield strength increase.
Shield rel 1 - shield strength compared to level 1. If a level 1 Nerf shield has a strength of 1000, level 10 would be 16,980.OTHER FACTORS
Energy use: damage caused per unit of energy expended varies across family, but within each family is a constant ratio. Here’s the table for that. The data did not precisely match this, but it was within 1% and appeared to be due to rounding in weapon_equip.ini values, and yields a difference of less than 1 point of damage everywhere I spot checked.
The shield killer cases are at bottom, and show hull/shield damage efficiency.Family D/E br_gun01 3.333 br_gun02 4.00 co_gun01 3.20 fc_b_gun01 4.00 fc_bd_gun01 3.20 fc_c_gun01 5.00 fc_fa_gun01 6.00 fc_g_gun01 4.167 fc_gc_gun01 3.333 fc_h_gun01 4.80 fc_j_gun01 3.333 fc_lh_gun01 3.333 fc_lr_gun01 3.20 fc_lwb_gun01 4.167 fc_m_gun01 5.00 fc_or_gun01 3.20 fc_or_gun02 5.00 fc_ou_gun01 4.00 fc_ou_gun02 4.80 fc_rh_gun01 3.20 fc_u_gun01 5.00 fc_x_gun01 4.80 gd_bh_gun01 2.667 gd_bh_gun02 3.20 gd_gm_gun01 4.00 gd_im_gun01 3.33 gd_z_gun01 3.33 ku_gun01 5.00 ku_gun02 3.33 li_gun01 3.20 li_gun02 4.80 rh_gun01 2.67 rh_gun02 4.80 co_gun02 0.5/16.91 fc_c_gun02 0.417/12.71
NOT DONE/CHECKED AT THIS POINT
- I haven’t checked any turret families.
- For torpedos/CDs, I haven’t tried to come up with ratios for things like range yet - harder to do with only 2 data points each.
- Likewise code weapons, they’re supposed to be unique.
- muzzle velocity and lifetime are the same within each family, but I have’t bothered tabulating.
- haven’t touched effects.
-
Python Code to Generate SQL table from Freelancer INI
Here’s a rough Python script to generate SQL from an INI . I tried alternatives to get the data, but have trouble running Data Storm. DB Browser for SQL Lite breaks data from the FLStat (the one written by Dan Tascau and “hacked” by Jason Hood).
Script has NO guard rails and is all hard-coded at this point. For simple specific reuse, what you need to change is at top.
The root of the Freelancer install you want to query is specified in FlDataRoot, and the relative path to the INI of interest should be in CurrentDataFile. (With single quotes ’ ’ around the paths, Python won’t choke if you do forget to change ‘’ to ‘/’).I’ve only used it on weapon_equip and weapon_good, but parsing is OK there.
Note that the script will create the SQL export file in the same location as the INI, just changing the suffix to SQL. Also, it WILL overwrite an existing “.SQL” file without prompting.
# Hardcoded Configuration variables/constants for testing FlDataRoot = 'c:/Apps/Freelancer-0/DATA/' CurrentDataFile = 'EQUIPMENT/weapon_equip.ini' # Generate SQLOutputFile by replacing the extension with ".sql" SQLOutputFile = os.path.splitext(CurrentDataFile)[0] + ".sql" import os, re def infer_data_type(value): """Infer SQL data type from a string value.""" if re.match(r'^\d+$', value): return 'INT' elif re.match(r'^\d+\.\d+$', value): return 'FLOAT' else: return 'VARCHAR(255)' def parse_file(file_contents): tables = {} current_table = None new_record = True # Flag to indicate when to start a new record for line in file_contents: if line.startswith('['): current_table = line.strip().strip('[]') if current_table not in tables: tables[current_table] = {'fields': {}, 'records': []} new_record = True # New table, so start a new record elif '=' in line and current_table: field, value = line.strip().split(' = ') if field not in tables[current_table]['fields']: tables[current_table]['fields'][field] = infer_data_type(value) if not new_record and field in tables[current_table]['records'][-1]: new_record = True if new_record: tables[current_table]['records'].append({}) new_record = False tables[current_table]['records'][-1][field] = value return tables def generate_sql(tables): """Generate SQL CREATE TABLE and INSERT INTO statements.""" create_statements = [] insert_statements = [] for table, data in tables.items(): field_defs = [f'"{name}" {type}' for name, type in data['fields'].items()] create_statement = 'CREATE TABLE "{}" (\n {}\n);'.format(table, ",\n ".join(field_defs)) create_statements.append(create_statement) for record in data['records']: if record: # Ensure the record is not empty fields = ', '.join([f'"{f}"' for f in record]) values = ', '.join(['\'{}\''.format(v) for v in record.values()]) insert_statement = 'INSERT INTO "{}" ({}) VALUES ({});'.format(table, fields, values) insert_statements.append(insert_statement) return create_statements, insert_statements # Usage example: # file_contents = <read the file contents into a list of lines> # tables = parse_file(file_contents) # create_statements, insert_statements = generate_sql(tables) # combined_sql_statements = '\n\n'.join(create_statements + insert_statements) # Write combined_sql_statements to an output file # Construct full paths input_file_path = os.path.join(FlDataRoot, CurrentDataFile) output_file_path = os.path.join(FlDataRoot, SQLOutputFile) # Read the input file with open(input_file_path, 'r') as file: file_contents = file.readlines() # Process the file contents tables = parse_file(file_contents) create_statements, insert_statements = generate_sql(tables) # Combine all CREATE TABLE and INSERT INTO statements combined_sql_statements = '\n\n'.join(create_statements + insert_statements) # Write the SQL statements to the output file with open(output_file_path, 'w') as output_file: output_file.write(combined_sql_statements) print(f"SQL statements have been written to {output_file_path}")
-
@WatercoolerWarrior said in Vanilla Freelancer weapon stats patterns:
DB Browser for SQL Lite breaks data from the FLStat
Use
sqlite3
to generate the database:>sqlite3 -init FLStat.sql sqlite> .save FLStat.db sqlite> .quit
Now DB Browser will load
FLStat.db
. (Funnily enough it will export it, but still won’t import it.) -
@adoxa said in Vanilla Freelancer weapon stats patterns:
Use sqlite3 to generate the database
That made it easy.
I’ve finished most of the gun-only analysis, and most of it is on the Freelancer Vanilla Weapon Analysis worksheets.
It does turn out that with a couple of minor exceptions, there’s at least one gun of each technology for levels 3-9. With the limited time people spend at lower levels even in SP, that makes extending the guns much less useful. Some possibilities:
Level 3 neutron/4 pulse Corsair weapons via loot drops if someone wants to dawdle in Bretonia early on (I do, it’s where I had the most fun initially playing FL).
Other possibles would be higher level. A level 9 Liberty Laser since the Reaver MK II is an energy hog; a level 9 Netterturn for Rheinland RP; possibly level 10 versions of a few of the standard guns. Here’s a few I came up with . The nicknames are family name they are based on, followed by _wxNN : wx for Weapon Extension and NN is the hp_gun level.
- fc_c_gun01_wx03, “Nina”
- fc_c_gun02_wx04, “Cochillito”
- li_gun01_wx09 “Retribution”
- li_gun01_wx10 “Redemption”
- fc_rh_gun01_wx09 Feuerlanze
- fc_rh_gun01_wx10 Drachenfeuer
- gd_gm_gun01_wx10 Kami no Ikari (神の怒り)
- fc_c_gun01_wx10 Durandal
- fc_ou_gun02_wx10 Kraken IV, Cthulhu
- rh_gun02_wx10 Liebesglut
- fc_c_gun02_wx10 El Cid Campeador
- gd_im_gun01_wx10 Neutralizer
Level 10 damage will only increase by about 20%, but it might be worth messing around with toughness/explosion resistance, and damage per fire to keep them from being uber.
That leaves turrets, missiles, and mines still. It may be a few days before I hit those.
EDIT: I’m going to try to get some closure on the basics for guns. Since it’s only a handful and they’re all closely related to existing vanilla weapons, I can punt on effects and reuse what’s there, while refamiliarizing myself with FLMM. To make it fully usable without a lot of initial headaches, I’ll try doing a mini-mod with availability on specific wrecks, and at least a couple of rumors.
-
UPDATED
I’m going to have another project taking up some time for the next week or two. I’ve confirmed that six vanilla extended weapons work, and have basic infocards done.
There are no bases selling at the moment.Added appropriate bases for weapons, with rep and level consistent with standard Freelancer. Since no level 10 weapons are sold in-game, I set those to 0.7 rep and level 34.
The one thing I have misgivings about is that the level 10 Corsair weapons wind up being a bit uberish for unmodded enemies - damage is in code weapon range, but with 4 refire and high efficiency.I’m a fan of Creative Commons type licenses, but rather than add a license that’s longer than the mod:
Feel free to reuse, modify, fold, spindle, or mutilate the data to your heart’s content. It’s pretty basic. If anyone wants to do a vanilla feel overhaul, what’s most useful is the information it’s based on.Automating weapons generation was overkill for this. When I’m free again, per IrateRedKite’s suggestion, I may put together some code to automate creating complete vanilla-based weapons lines (and in Python, yes - I’ll leave my preferred PowerShell toys at home, even if they do work great for blowing through data streams :} ).
A major caveat is that as-is, it may not be useful for many people since using the level-based hardpoints isn’t as much of a thing. Other issues:
- major overlap in weapons families means the effect is minor.
- there are max about 4 levels of effect for each family of weapon, which means, depending on weapon, 3-4 levels will share the same effect. (This could be mitigated by rearranging the weapon effects a bit, so every faction’s neutron weapon effects look alike, for example?).
- and the biggest impediment: the weapons should get reasonable in-game presence: names, infocards, possible rumors and wreck distribution, etc. That’s the real significant issue. Creating the weapons lines is pretty mechanical, but making them into interesting game elements is where the real effort is.
EDIT EDIT: I’ve changed naming scheme to make names more rational for what may be a somewhat sparse matrix of new weapons: the names are simply family-name_ level_ nn where nn is 2-digit level number.