def write_mod(self): mod = Mod( f'money_grenade_changes_{self.mod_filename}.bl3hotfix', f'Money Grenade Changes: {self.mod_label}', 'Apocalyptech', [ f"Changes the 'Money' grenade part to drop {self.desc_text} instead of money.", ], contact='https://apocalyptech.com/contact.php', lic=Mod.CC_BY_SA_40, v='1.0.0', cats='joke, gear-grenade, cheat', ss= f'https://raw.githubusercontent.com/BLCM/bl3mods/master/Apocalyptech/gear_changes/money_grenade_changes/screenshot_{self.mod_filename}.png', ) mod.header('Update item prefixes') mod.reg_hotfix( Mod.PATCH, '', '/Game/Gear/GrenadeMods/_Design/Naming/GrenadeModNamingStrategy', 'SingleNames.SingleNames[20].NamePart.Object..PartName', self.single_name) mod.reg_hotfix( Mod.PATCH, '', '/Game/Gear/GrenadeMods/_Design/Naming/GrenadeModNamingStrategy', 'TripleNames.TripleNames[11].NamePart.Object..PartName', self.triple_name) self._combo_name(mod, 19, self.combo_name_mirv) self._combo_name(mod, 36, self.combo_name_rain) self._combo_name(mod, 52, self.combo_name_nuke) self._combo_name(mod, 67, self.combo_name_large) self._combo_name(mod, 81, self.combo_name_bouncy) self._combo_name(mod, 94, self.combo_name_spring) self._combo_name(mod, 106, self.combo_name_sticky) self._combo_name(mod, 117, self.combo_name_artillery) self._combo_name(mod, 127, self.combo_name_lingering) self._combo_name(mod, 136, self.combo_name_divide) self._combo_name(mod, 144, self.combo_name_singularity) self._combo_name(mod, 151, self.combo_name_roider) self._combo_name(mod, 157, self.combo_name_link) self._combo_name(mod, 162, self.combo_name_transfusion) self._combo_name(mod, 166, self.combo_name_generator) self._combo_name(mod, 169, self.combo_name_elemental) self._combo_name(mod, 171, self.combo_name_force) self._combo_name(mod, 172, self.combo_name_money) mod.newline() mod.header('Update part name') mod.reg_hotfix( Mod.PATCH, '', '/Game/Gear/GrenadeMods/_Design/PartSets/Part_Behavior/Money/UIStat_Grenade_Money_Icon', 'Text', self.part_text.upper()) mod.newline() mod.header('Update drop pools and card descriptions') for pool_label, rewards, (uistat_name, uistat_text) in [ ('Single-part grenade', self.rewards1, self.uistat1), ('Double-part grenade', self.rewards2, self.uistat2), ('Triple-part grenade', self.rewards3, self.uistat3), ]: mod.comment(pool_label) mod.reg_hotfix(Mod.PATCH, '', rewards.pool_name, 'BalancedItems', str(rewards)) mod.reg_hotfix(Mod.PATCH, '', uistat_name, 'FormatText', uistat_text.format(self.card_text)) mod.newline() # Special-case hardcodes for some mod types if self.mod_label == 'Diamond Keys': # Fix up the diamond key item so that it looks better when dropped # (by default it just looks like eridium, and also doesn't auto-pickup) mod.header_lines([ "Fixing up droppable Diamond Key object", "", "We're making a few changes here which affect the item card specifically,", "though the item card will basically never be seen since we're enabling", "auto-pickup as well. If you *do* get a glimpse of the card (using Photo", "Mode or the like) you'll see a bit of weirdness still -- the card might", "inherit the visual price of whatever card was last looked at, and the", "loot beam icon might inherit the last-looked-at item as well. In the", "end I'm not bothering to track that down, though, since you've gotta", "work hard to see the card anyway.", ]) mod.comment('Use an actual key mesh') mod.reg_hotfix( Mod.PATCH, '', '/Game/PatchDLC/VaultCard/Data/Currency/BP_DiamondKey_Single.Default__BP_DiamondKey_Single_C', 'ItemMeshComponent.Object..StaticMesh', # Tried lots of various meshes here; I'm tempted to go with one of the keyring ones, # but in the end I just went with one of the smaller single-key ones. Would be nice # if I could get that Geranium Key-to-City ones to interact with physics, though # that might cause weird problems with the key during the plot (or on Decoration), # so eh. We'll just stick with the tiny key for now. # A bit much, though it's a nice big size. Is definitely a keyring, though. #Mod.get_full_cond('/Dandelion/Missions/Plot/Ep04_Trashtown/Janitor_Keyring/Model/Meshes/SM_Janitor_Keyring', 'StaticMesh'), # Definitely a keyring; probably better than SM_Janitor_Keyring if I feel okay with that... #Mod.get_full_cond('/Ixora2/Missions/02_Eden6/Keyring/Model/Meshes/SM_Key_Ring', 'StaticMesh'), # Hah, just a rusty sphere basically #Mod.get_full_cond('/Geranium/LevelArt/Lodge/Props/Model/Meshes/SM_Apple_Key', 'StaticMesh'), # Very nice (and rightly-sized!) key, but it weirdly doesn't seem to actually interact with physics # at all? Just hangs there in midair. #Mod.get_full_cond('/Geranium/InteractiveObjects/MissionAssets/Plot_5/Model/Meshes/SM_Key_to_City', 'StaticMesh'), # Same story here; and seemingly identical to the other one. Almost certainly a copied object. #Mod.get_full_cond('/Game/PatchDLC/Geranium/InteractiveObjects/PlayerQuarters/RoomDecoMeshes/Meshes/SM_Key_to_City_RoomDeco', 'StaticMesh'), # Perfectly serviceable key, but quite small #Mod.get_full_cond('/Hibiscus/InteractiveObjects/MissionSpecific/Plot/EP03/Pickups/SM_Key_GateKey', 'StaticMesh'), # Perfectly serviceable key, but quite small Mod.get_full_cond( '/Game/LevelArt/Environments/_Global/Props/Keys/Key_Scooters/Model/Meshes/SM_Key_Scooters', 'StaticMesh'), ) mod.newline() mod.comment('Set a different item card type') mod.reg_hotfix( Mod.PATCH, '', '/Game/PatchDLC/VaultCard/Data/Currency/InvData_DiamondKey', 'ItemCardTypeFrameName', #'currencyEridium', # Mission is nice; has a diamondy icon, even! 'Mission', # Cash works well #'Cash', ) mod.newline() mod.comment( 'Set monetary value to 1; might prevent currency from inheriting from previously-viewed items' ) mod.reg_hotfix( Mod.PATCH, '', '/Game/PatchDLC/VaultCard/Data/Currency/InvData_DiamondKey', 'MonetaryValue', BVCF(bvc=1)) mod.newline() mod.comment( 'Assign Legendary rarity (instead of Eridium), for loot bar + frame color' ) mod.reg_hotfix( Mod.PATCH, '', '/Game/PatchDLC/VaultCard/Data/Currency/InventoryBalance_DiamondKey', 'RarityData', Mod.get_full_cond( '/Game/GameData/Loot/RarityData/RarityData_05_Legendary', 'RarityData')) mod.newline() mod.comment('Auto-pickup Diamond Keys') mod.reg_hotfix( Mod.PATCH, '', '/Game/Gear/_Shared/_Design/InventoryCategories/InventoryCategory_DiamondKey', 'PickupActionType', #'OnUseOnly', 'OnUseOrTouch', ) mod.newline() mod.close()
'Mayhem 2.0', '/Game/PatchDLC/Mayhem2/Gear/Weapon/DataTable_WeaponBalance_Mayhem2', [ ('The Monarch', 'AR_TheMonarch', 1.6, 0.7), ('Plaguebearer', 'HW_Plague', 1.1, 0.9), ('Backburner', 'HW_Backburner', 2, 1.7), # TODO: GBX nerfed Kaoson from 2.25 to 1.6, but also buffed most other legendary SMGs. # Should re-test all the SMGs in here to see how they fare now. ('Kaoson', 'Kaoson', 1.6, 1), ('Sand Hawk', 'SR_SandHawk', 1.5, 0.5), ('Reflux', 'SG_Reflux', 1.75, 1.5), ]), ]: mod.header(cat_name) for weap_label, row, default_scale, new_scale in sorted(weapons): mod.comment('{} (default: {})'.format(weap_label, default_scale)) mod.table_hotfix(Mod.PATCH, '', balance_obj, row, 'DamageScale_2_4F6EF14648BA8F2AE9217DAFEA60EE53', new_scale) mod.newline() readme_reports.append('{}: `{}` -> `{}`'.format( weap_label, default_scale, new_scale)) mod.close() print('Info for pasting into README:') print('') for line in sorted(readme_reports): print(' - {}'.format(line)) print('')
def save_mod(save_filename): """ Save out a mod file. This actually relies on an awful lot of global variables. Apologies. """ mod = Mod(save_filename, 'Arbitrary Partlocks: {}'.format(bal_last), 'Apocalyptech', [ 'Auto-generated partlocks, chosen with an interactive CLI app.', ], lic=Mod.CC_BY_SA_40, ) for cat_idx, cat_actions in enumerate(actions): cur_cat = categories[cat_idx] always_vals = set() never_vals = set() for action in cat_actions.values(): if action.action == Action.ALWAYS: always_vals.add(action.list_idx) else: never_vals.add(action.list_idx) # Now, loop through each category and assign new weights if len(always_vals) > 0 or len(never_vals) > 0: if cat_idx == 0: # We could try to generalize, but whatever. Just process anoints separately cur_idx = 0 if cur_cat.cat.partlist: cur_source = cur_cat.cat.partlist[0].anoint_source for num, part in enumerate(cur_cat.cat.partlist): # Reset our array index if needed if part.anoint_source != cur_source: cur_idx = 0 cur_source = part.anoint_source # If we have any "always" entries, we effectively assume everything else # is a "never", so we process a bit differently if len(always_vals) > 0: if num not in always_vals: never_vals.add(num) # Now write out if part.anoint_source != balance_name: extra_txt = ' (affects anything using this anoint)' attr_ref = 'GenericParts.Parts' else: extra_txt = '' attr_ref = 'RuntimeGenericPartList.PartList' if num in always_vals: mod.comment('Anointments: Always choose {}{}'.format(part.short_name, extra_txt)) mod.reg_hotfix(Mod.PATCH, '', part.anoint_source, '{}[{}].Weight'.format(attr_ref, cur_idx), BVCF(bvc=1)) mod.newline() elif num in never_vals: mod.comment('Anointments: Never choose {}{}'.format(part.short_name, extra_txt)) mod.reg_hotfix(Mod.PATCH, '', part.anoint_source, '{}[{}].Weight'.format(attr_ref, cur_idx), BVCF(bvc=0)) mod.newline() # Increment our index cur_idx += 1 else: # Make sure this is set to use weights if not cur_cat.cat.use_weight_with_mult: mod.comment('Category {}: Enable weight-based part picking'.format(cat_idx)) mod.reg_hotfix(Mod.PATCH, '', balance.partset_name, 'ActorPartLists.ActorPartLists[{}].bUseWeightWithMultiplePartSelection'.format(cat_idx-1), 'True') mod.newline() # Regular parts # TODO: If we ever get GPartExpansion objects which do more than add expansions, # well have to support it here, too. cur_idx = cur_cat.start_part_idx for num, part in enumerate(cur_cat.cat.partlist): # If we have any "always" entries, we effectively assume everything else # is a "never", so we process a bit differently if len(always_vals) > 0: if num not in always_vals: never_vals.add(num) # Now write out if num in always_vals: mod.comment('Category {}: Always choose {}'.format(cat_idx, part.short_name)) mod.reg_hotfix(Mod.PATCH, '', balance_name, 'RuntimePartList.AllParts[{}].Weight'.format(cur_idx), BVCF(bvc=1)) mod.newline() elif num in never_vals: mod.comment('Category {}: Never choose {}'.format(cat_idx, part.short_name)) mod.reg_hotfix(Mod.PATCH, '', balance_name, 'RuntimePartList.AllParts[{}].Weight'.format(cur_idx), BVCF(bvc=0)) mod.newline() # Increment index cur_idx += 1 print('') print(color_success + '='*80) mod.close() print(color_success + '='*80) print(color_reset) input('Hit Enter to Continue...') print('')