def BringWeaponsUpAfterPutDown(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.MyWillowPC != unrealsdk.GetEngine().GamePlayers[0].Actor: return True weapon = caller.MyWillowPawn.InvManager.InventoryChain while weapon is not None: if weapon.QuickSelectSlot == params.MainHandWeaponSlot: break weapon = weapon.Inventory # If you dropped the equiped slot default to the start of the list - not sure if other # behaviour might be better? if weapon is None: weapon = caller.MyWillowPawn.InvManager.InventoryChain # If you dropped all weapons just let the game handle it if weapon is None: return True caller.ForceRefreshSkills() caller.ClientBringWeaponsUpAfterPutDown(weapon, self.DupeWeapon(weapon)) return False
def _OnDownloadableContentListRead(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ This function is called to fill in the dlc menu, we overwrite it with our mods instead. """ global _current_mod_list _load_favourite_mods() caller.ClearFilters() caller.SetFilterFromString("compatibility", "Utility Mods", "isCompatibility:1") caller.SetFilterFromString("addon", "Content Mods", "isAddOn:1") caller.SetFilterFromString("seasonpass", "Gameplay Mods", "isSeasonPass:1") caller.SetFilterFromString("misc", "Libraries", "isMisc:1") caller.SetFilterFromStringAndSortNew("all", "All Mods", "") caller.SetStoreHeader("Mods", False, "By Abahbob", "Mod Manager") _current_mod_list = [_general_instance] + GetOrderedModList() # type: ignore translation_context = unrealsdk.GetEngine().GamePlayers[0].GetTranslationContext() for idx, mod in enumerate(_current_mod_list): # This is weird and crashes if you don't have the second arg, but also crashes most the time # when you try to access something on it - seems like a garbage pointer item, _ = caller.CreateMarketplaceItem() item.SetString(caller.Prop_offeringId, str(idx), translation_context) _update_mod_list_item(mod, item, caller, translation_context) caller.AddContentData(item) caller.PostContentLoaded(True) return False
def attribute_definition_helper(new_obj: unrealsdk.UObject) -> None: if new_obj.ValueResolverChain: counter = 0 temp = [] for value in new_obj.ValueResolverChain: new_value = unrealsdk.ConstructObject(Class=value.Class, Outer=new_obj, Name=f"{value.Name}_{counter}", Template=value) unrealsdk.KeepAlive(new_value) new_value.ObjectFlags.B |= 4 temp.append(new_value) counter += 1 new_obj.ValueResolverChain = temp if new_obj.ContextResolverChain: counter = 0 temp = [] for context in new_obj.ContextResolverChain: new_context = unrealsdk.ConstructObject(Class=context.Class, Outer=new_obj, Name=f"{context.Name}_{counter}", Template=context) unrealsdk.KeepAlive(new_context) new_context.ObjectFlags.B |= 4 temp.append(new_context) counter += 1 new_obj.ContextResolverChain = temp
def HandleInputKey(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller != self._TrainingBox: return True self._HandleInput(params.ukey, params.uevent) self.OnInput(params.ukey, params.uevent) # Decode when we exit from keypresses if params.uevent == 1: if params.ukey in self._SubmitKeys: unrealsdk.RemoveHook( "WillowGame.WillowGFxTrainingDialogBox.HandleInputKey", "CustomTextInputBox") self._TrainingBox = None self.OnSubmit("".join(self._Message)) elif params.ukey in self._ExitKeys: unrealsdk.RemoveHook( "WillowGame.WillowGFxTrainingDialogBox.HandleInputKey", "CustomTextInputBox") self._TrainingBox = None self.OnSubmit("") # Normally the use key causes exits too, block it useKey = "FAKE" if caller.GetPC().PlayerInput is not None: useKey = caller.GetPC().PlayerInput.GetKeyForAction( "Use", True) return str(params.ukey) != useKey
def ApplyItemSaveGameData(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: inv_manager = caller.GetPawnInventoryManager() is_local = caller.IsLocalPlayerController() for idx, saved_item in enumerate(params.SaveGame.ItemData): if saved_item.bEquipped: if caller.Role == 3: # ROLE_Authority ServerSetItemSaveGameData(caller, idx, saved_item.DefinitionData, saved_item.Quantity, saved_item.bEquipped, saved_item.Mark) continue if is_local: inv_manager.ClientAddItemToBackpack( expand_item_definition_data(saved_item.DefinitionData), saved_item.Quantity, saved_item.Mark, False, 14) if is_local: caller.UnloadableDlcItemData = list( params.SaveGame.UnloadableDlcItemData) caller.ServerItemSaveGameDataCompleted() return False
def EquipInitialWeapons(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: PC = unrealsdk.GetEngine().GamePlayers[0].Actor if PC.Pawn is None: return False weap = PC.Pawn.Weapon if weap is None: return False # This is the only real bit of the function we overwrite weapAlt = self.DupeWeapon(weap) PC.Pawn.OffHandWeapon = weapAlt PC.Pawn.InvManager.SetCurrentWeapon(weap, False) PC.Pawn.InvManager.SetCurrentWeapon(weapAlt, True) weap.RefillClip() weapAlt.RefillClip() if PC.bInSprintState: caller.SetTimer( min(weap.GetEquipTime(), weapAlt.GetEquipTime()), False, "SprintTransition") caller.SetLeftSideControl() return False
def GenerateInventory(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: # Whenever a vendor inventory is generated, update our cached costs # Unfortuantly ShopInventory is a fixed array, which we can't iterate though, so we have # to do a findall to find the items unrealsdk.DoInjectedCallNext() caller.GenerateInventory() PC = unrealsdk.GetEngine().GamePlayers[0].Actor if caller.ShopType == 1: self.AmmoCosts[caller] = {} for item in unrealsdk.FindAll("WillowUsableItem"): if item.Owner != caller: continue if item.DefinitionData is None or item.DefinitionData.ItemDefinition is None: continue if caller.ShopType == 2: if item.DefinitionData.ItemDefinition.Name == "BuffDrink_HealingInstant": self.VialCosts[caller] = caller.GetSellingPriceForInventory(item, PC, 1) break elif caller.ShopType == 1: name = item.DefinitionData.ItemDefinition.Name if name not in self.AMMO_COUNTS: continue info = self.AMMO_COUNTS[name] price = caller.GetSellingPriceForInventory(item, PC, 1) / info.BulletsPerItem self.AmmoCosts[caller][info.ResourcePoolName] = price return False
def ApplyDLCInventorySaveGameData(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ It doesn't seem like this is actually called anywhere, but better safe than sorry. """ if not caller.IsLocalPlayerController(): caller.ServerItemSaveGameDataCompleted() return False inv_manager = caller.GetPawnInventoryManager() for idx, saved_item in enumerate(params.ItemData): if saved_item.bEquipped: ServerSetItemSaveGameData(caller, idx, saved_item.DefinitionData, saved_item.Quantity, saved_item.bEquipped, saved_item.Mark) continue inv_manager.ClientAddItemToBackpack( expand_item_definition_data(saved_item.DefinitionData), saved_item.Quantity, saved_item.Mark, False, 14) for idx, saved_weap in enumerate(params.WeaponData): if saved_weap.QuickSlot != 0: ServerSetWeaponSaveGameData(caller, idx, saved_weap.DefinitionData, saved_weap.QuickSlot, saved_weap.Mark) continue inv_manager.ClientAddWeaponToBackpack( expand_weapon_definition_data(saved_weap.DefinitionData), saved_weap.Mark, False, 14) inv_manager.UpdateBackpackInventoryCount() caller.ServerItemSaveGameDataCompleted() return False
def bank_on_open(self, caller: unrealsdk.UObject) -> bool: if caller.MaxSlots == 4: caller.ChestSlots = self.stash_size # we opened the stash read_f = open(self.STASH_PATH, "r") bank = json.load(read_f) elif caller.MaxSlots == 3: # the grinder in TPS return True else: read_f = open(self.LOAD_PATH, "r") bank = json.load(read_f).get("Bank", dict()) read_f.close() owner = bl2tools.get_player_controller().Pawn static_wweapon: unrealsdk.UObject = unrealsdk.FindAll("WillowWeapon")[0] static_witem: unrealsdk.UObject = unrealsdk.FindAll("WillowItem")[0] bank_things: list = [] for weapon in bank.get("Weapons", list()): wpn_data, mark = load_weapon_data(weapon) new_weapon: unrealsdk.UObject = static_wweapon.CreateWeaponFromDef(wpn_data, owner, True) new_weapon.Mark = mark bank_things.append((new_weapon.Class, tuple(), new_weapon)) for item in bank.get("Items", list()): item_data, mark = load_item_data(item) new_item: unrealsdk.UObject = static_witem.CreateItemFromDef(item_data, owner, 1, True) new_item.Mark = mark bank_things.append((new_item.Class, tuple(), new_item)) caller.TheChest = bank_things caller.ChestIsOpen = True return False
def apply_save_game_data(self, save_game: unrealsdk.UObject) -> None: weapon_data = [] item_data = [] with open(self.LOAD_PATH, "r") as file: logging.logger.debug(f"Successfully opened file {self.LOAD_PATH}") try: json_save_file = json.load(file) for slot, weapons in enumerate(json_save_file["Wpn_Equipped"]): my_weap_def, mark = load_weapon_data(weapons) weapon_data.append((my_weap_def, 1 + slot, mark)) for weapons in json_save_file["Weapons"]: my_weap_def, mark = load_weapon_data(weapons) weapon_data.append((my_weap_def, 0, mark)) for items in json_save_file["Itm_Equipped"]: my_item_def, mark = load_item_data(items) item_data.append((my_item_def, 1, True, mark)) for items in json_save_file["Items"]: my_item_def, mark = load_item_data(items) item_data.append((my_item_def, 1, False, mark)) save_game.WeaponData = weapon_data save_game.ItemData = item_data logging.logger.debug(f"Successfully loaded the .json!") except Exception as e: logging.logger.debug(e) logging.logger.debug(f"{file} is empty or not a .json!")
def GetItemStatus(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if params.WPC != unrealsdk.GetEngine().GamePlayers[0].Actor: return True if not self.IsOn: return True unrealsdk.DoInjectedCallNext() status = caller.GetItemStatus(params.Item, params.WPC, params.ItemPrice) # If we get back SIS_ItemCanBePurchased (0) we don't have to do anything if status == 0: return True # Otherwise temporarily give all the money you'd need to purcahse it and check again PRI = params.WPC.PlayerReplicationInfo currency = caller.GetCurrencyTypeInventoryIsSoldIn(params.Item) wallet = PRI.GetCurrencyOnHand(currency) PRI.SetCurrencyOnHand(currency, params.ItemPrice) unrealsdk.DoInjectedCallNext() status = caller.GetItemStatus(params.Item, params.WPC, params.ItemPrice) # Revert your money back PRI.SetCurrencyOnHand(currency, wallet) # If the status now is SIS_ItemCanBePurchased (0) then we were just missing money, and # we want the actual status to be ignore that # We can't directly change the return value of the function, only if it executes # However, if the function doesn't execute then it's return value is None # As luck would have it this ends up casting to 0 - the exact value we want to set return bool(status != 0)
def _update_mod_list_item( mod: ModObjects.SDKMod, item: unrealsdk.UObject, movie: unrealsdk.UObject, translation_context: unrealsdk.UObject ) -> None: """ Updates a mod GFxObject to use all the latest fields from it's SDKMod. """ item.SetString(movie.Prop_contentTitleText, mod.Name, translation_context) item.SetString(movie.Prop_costText, "By " + mod.Author, translation_context) item.SetString(movie.Prop_descriptionText, mod.Description, translation_context) item.SetString( movie.Prop_statusText, f"<font color=\"#A1E4EF\">{mod.Version}</font>", # Make this the same colour as author translation_context ) status = mod.Status if mod.Status == "Enabled": status = "<font color=\"#00FF00\">Enabled</font>" elif mod.Status == "Disabled": status = "<font color=\"#FF0000\">Disabled</font>" item.SetString(movie.Prop_messageText, status, translation_context) if isinstance(mod.Types, list): dh.PrintWarning( "Using lists for mod types is deprecated, combine types with bitwise or instead." ) # For some odd reason these take in floats, but treat them as bools item.SetFloat(movie.Prop_isCompatibility, float(ModObjects.ModTypes.Utility in mod.Types)) item.SetFloat(movie.Prop_isAddOn, float(ModObjects.ModTypes.Content in mod.Types)) item.SetFloat(movie.Prop_isSeasonPass, float(ModObjects.ModTypes.Gameplay in mod.Types)) item.SetFloat(movie.Prop_isMisc, float(ModObjects.ModTypes.Library in mod.Types)) item.SetFloat(movie.Prop_isNewOffer, float(mod.Name in _favourite_mods or mod == _general_instance))
def TakeDamage(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: PC = unrealsdk.GetEngine().GamePlayers[0].Actor if params.InstigatedBy != PC: return True if not self.IsOn: return True game = unrealsdk.FindAll("WillowCoopGameInfo")[-1] if game.IsFriendlyFire(caller, params.InstigatedBy.Pawn): return True caller.SetShieldStrength(0) # Try set the health to 1 so that your shot kills them, giving xp # Only do it if they have more than 1 health though, so that you don't get stuck in a # loop if you somehow deal less than 1 damage if caller.GetHealth() > 1: caller.SetHealth(1) else: caller.SetHealth(0) return True
def PostBeginPlay(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: # Re-run the function so we can modify it after it's done unrealsdk.DoInjectedCallNext() caller.PostBeginPlay() caller.bShowUndiscoveredMissions = False return False
def MultiplyDenIfAble(self, den: unrealsdk.UObject, amount: float) -> None: if self.CanDenBeMultiplied(den): den.SpawnData.MaxActiveActors = round( den.SpawnData.MaxActiveActors * amount) den.MaxActiveActorsIsNormal = round(den.MaxActiveActorsIsNormal * amount) den.MaxActiveActorsThreatened = round( den.MaxActiveActorsThreatened * amount) den.MaxTotalActors = round(den.MaxTotalActors * amount)
def set_location( sm_component: unrealsdk.UObject, position: Union[List[float], Tuple[float, float, float]]) -> None: x, y, z = position sm_component.CachedParentToWorld.WPlane.X = x sm_component.CachedParentToWorld.WPlane.Y = y sm_component.CachedParentToWorld.WPlane.Z = z sm_component.ForceUpdate(False) sm_component.SetComponentRBFixed(True)
def PawnDamageHook(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if BBInstance.boss_pawn is None: if caller.IsChampion() or caller.IsBoss(): BBInstance.boss_pawn = caller BBInstance.InitBar() # elif BBInstance.bar_active: # GetEngine().GetCurrentWorldInfo().GRI.UpdateBossBarInfo() return True
def _SharedHandleInputKey(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ This function is called on pretty much all key input events on the main menu. We use it to open the dlc menu when you press "M". """ if params.ukey == "M" and params.uevent == KeybindManager.InputEvent.Released: if not caller.IsOverlayMenuOpen(): caller.CheckDownloadableContentListCompleted(caller.WPCOwner.GetMyControllerId(), True) return True
def _setItemCardEx(self, caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ Handles the item info cards descriptions in the inventory screen. Appends our custom text to the end of the original text so it still can be localized. Credits: apple """ # only change the text if the item is a valid DT shield item: unrealsdk.UObject = params.InventoryItem.ObjectPointer if self._isValidShield(item) is False or item.GetMark() != 3: return True """ Since this is called quite often, we can use this to reset the shield if someone has the shield who is not a Mechromancer. Also we can reset the status of equipped shields. This shouldn't happen since the status is lost when it's being thrown away but just in case. """ playerController: unrealsdk.UObject = params.WPC className: str = getVaultHunterClassName(playerController) self._resetShield(item, True, className) self._resetEquippedShield(playerController.MyWillowPawn) # prevent showing DT shield status if no Mechromancer if className != "Mechromancer": return True # append our status to the original text text = item.GenerateFunStatsText() if text is None: text = "" text += f'<font color="{self._RarityColorHex}">' text += "• Current Deathtrap Shield" text += "</font>" """ The hooked function is pretty complex so before replicating its logic, we pass our modified text to it but block it from overwriting. We also overwrite the rarity color here and also block the overwrite. Color format is BGRA in a tuple. """ caller.SetFunStats(text) self._BlockFunStats = True caller.SetTitle( item.GetManufacturer().FlashLabelName, item.GetShortHumanReadableName(), self._RarityColorTuple, item.GetZippyFrame(), item.GetElementalFrame(), item.IsReadied(), ) self._BlockTitle = True return True
def _resetShield(self, shield: unrealsdk.UObject, checkClassName: bool, className: Optional[str] = "") -> None: """ Resets a DT shield of someone who is not a Mechromancer. """ if checkClassName is True and className == "Mechromancer": return if shield.GetMark() == 3: shield.SetMark(1)
def InitializeFromDefinition(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller.Class.Name != "WillowVendingMachine": return True if caller.ShopType == 2: params.Definition.HUDIconDefSecondary = self.HealthIcon caller.SetUsability(True, 1) elif caller.ShopType == 1: params.Definition.HUDIconDefSecondary = self.AmmoIcon caller.SetUsability(True, 1) return True
def AddChatMessage(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if unrealsdk.GetEngine( ).SparkInterface.ObjectPointer.IsSparkEnabled(): return True time = caller.GetTimestampString( unrealsdk.FindAll("WillowSaveGameManager")[-1].TimeFormat) caller.AddChatMessageInternal(params.PRI.PlayerName + time, params.msg) return False
def GetHealthCost(self, pawn: unrealsdk.UObject, vendor: unrealsdk.UObject) -> int: if pawn.GetHealth() == pawn.GetMaxHealth(): return 0 # Not sure how this'd happen but just in case if vendor not in self.VialCosts: return 0 # Again going to assume you haven't modded how much a vial heals full_heal_cost = 4 * self.VialCosts[vendor] missing_health = 1 - (pawn.GetHealth() / pawn.GetMaxHealth()) return max(1, int(full_heal_cost * missing_health))
def inv_partlist_helper(obj: unrealsdk.UObject, new_balance: unrealsdk.UObject) -> None: if obj.PartListCollection: part_list = obj.PartListCollection if obj.PathName(part_list).rsplit(".", 1)[0] == obj.PathName(obj).rsplit(".", 1)[0]: new_name = f"Parts_{new_balance.Name}" else: new_name = new_balance.Name new_part_list = unrealsdk.ConstructObject(Class="ItemPartListCollectionDefinition", Outer=part_list.Outer, Name=new_name, Template=part_list) unrealsdk.KeepAlive(new_part_list) new_part_list.ObjectFlags.B |= 4 new_balance.PartListCollection = new_part_list
def _extOnPopulateKeys(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ This function is called to load the list of keybinds. We add our own binds onto the end of the list after it's called. """ global _modded_keybind_map unrealsdk.DoInjectedCallNext() caller.extOnPopulateKeys() _modded_keybind_map = {} for mod in MenuManager.GetOrderedModList(): if not mod.IsEnabled: continue if all(isinstance(k, Keybind) and k.IsHidden for k in mod.Keybinds): continue tag = f"{_TAG_SEPERATOR}.{mod.Name}" idx = caller.AddKeyBindEntry(tag, tag, mod.Name) caller.KeyBinds[idx].CurrentKey = "None" for input in mod.Keybinds: name: str key: str rebindable: bool if isinstance(input, Keybind): if input.IsHidden: continue name = input.Name key = input.Key rebindable = input.IsRebindable else: dh.PrintWarning(Keybind._list_deprecation_warning) name = input[0] key = input[1] rebindable = True tag = (_TAG_INPUT if rebindable else _TAG_UNREBINDABLE) + f".{mod.Name}.{name}" idx = caller.AddKeyBindEntry(tag, tag, " " * _INDENT + name) _modded_keybind_map[idx] = input if not rebindable: key = "[ ]" if key == "None" else f"[ {key} ]" caller.KeyBinds[idx].CurrentKey = key return False
def _KeyboardMouseOptionsPopulate(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ This function is called to create the kb/m settings menu. We use it to inject our own "MODDED KEYBINDS" menu. """ # If we have no modded binds, disable the menu disabled = True for mod in ModObjects.Mods: if not mod.IsEnabled: continue for input in mod.Keybinds: if isinstance(input, Keybind) and input.IsHidden: continue disabled = False break if not disabled: break def AddListItem(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ This function is called every time an item is added to *any* menu list - we obviously can't use a generic hook. Using it cause it simplifies the code to add our own entry. """ if params.Caption != "$WillowMenu.MenuOptionDisplayNames.KeyBinds": return True # Want ours to display after the normal keybinds option unrealsdk.DoInjectedCallNext() caller.AddListItem(params.EventID, params.Caption, params.bDisabled, params.bNew) caller.AddListItem(_MODDED_EVENT_ID, _MODDED_KEYBINDS_CAPTION, disabled, False) return False unrealsdk.RunHook("WillowGame.WillowScrollingList.AddListItem", "ModMenu.KeybindManager", AddListItem) unrealsdk.DoInjectedCallNext() caller.Populate(params.TheList) caller.AddDescription(_MODDED_EVENT_ID, "$WillowMenu.MenuOptionDisplayNames.KeyBindsDesc") unrealsdk.RemoveHook("WillowGame.WillowScrollingList.AddListItem", "ModMenu.KeybindManager") return False
def AddListItem(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: """ This function is called every time an item is added to *any* menu list - we obviously can't use a generic hook. Using it cause it simplifies the code to add our own entry. """ if params.Caption != "$WillowMenu.MenuOptionDisplayNames.KeyBinds": return True # Want ours to display after the normal keybinds option unrealsdk.DoInjectedCallNext() caller.AddListItem(params.EventID, params.Caption, params.bDisabled, params.bNew) caller.AddListItem(_MODDED_EVENT_ID, _MODDED_KEYBINDS_CAPTION, disabled, False) return False
def evaluator_expression_helper(evaluator: unrealsdk.UObject) -> None: if evaluator.Expression1: new_expression = unrealsdk.ConstructObject(Class=evaluator.Expression1.Class, Outer=evaluator, Name=f"{evaluator.Expression1.Name}_1", Template=evaluator.Expression1) unrealsdk.KeepAlive(new_expression) new_expression.ObjectFlags.B |= 4 evaluator.Expression1 = new_expression if evaluator.Expression2: new_expression = unrealsdk.ConstructObject(Class=evaluator.Expression1.Class, Outer=evaluator, Name=f"{evaluator.Expression1.Name}_2", Template=evaluator.Expression1) unrealsdk.KeepAlive(new_expression) new_expression.ObjectFlags.B |= 4 evaluator.Expression1 = new_expression
def HandleInputKey(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if caller == self._TrainingBox: self.OnInput(params.ukey, params.uevent) # We don't have a good function to hook for when this exits so we have to decode it # from the key presses if self._TrainingBox is not None and self._TrainingBox.DelayUntilShowOk < 0 and params.uevent == 1: use_key = "FAKE" if caller.GetPC().PlayerInput is not None: use_key = caller.GetPC().PlayerInput.GetKeyForAction("Use", True) if params.ukey in self._ExitKeys or params.ukey == use_key: unrealsdk.RemoveHook("WillowGame.WillowGFxTrainingDialogBox.HandleInputKey", "CustomTrainingBox") self._TrainingBox = None self.OnExit() return True
def SetItemCardEx(caller: unrealsdk.UObject, function: unrealsdk.UFunction, params: unrealsdk.FStruct) -> bool: if params.InventoryItem.ObjectPointer is None: return True if self.CanItemBeEquipped(params.InventoryItem.ObjectPointer): return True caller.SetItemCardEx(params.WPC, params.InventoryItem.ObjectPointer, params.CompareAgainstInventoryItem, params.CurrencyType, params.OverrideValue) caller.SetLevelRequirement(True, False, False, self.UnableToEquipMessage) return False