UE4SS has a very powerful debugger live feature where you can search blueprints, etc. and edit them in real time. This is a great way of searching the game and figuring out what you need to manipulate to write your Lua script. Below for example is the value to change the camera’s X, Y, Z offset.
Useful Tip: In the UE4SS settings, make sure to enable hot reloading. You can then reload your script with CTRL + R
to quickly test your changes without needing to restart the game.
Also, here is a dumped Hogwarts Legacy SDK that can be helpful to search through to find things
I also highly recommend using FMODEL to dump parsed JSON for anything related to what you're working on (in FMODEL, right click on the top folder and click Save Folder's Packages Properties .JSON"
). You can then open up the whole project with a text editor like Visual Studio Code and use powerful Regular Expressions to search for things (like something within a blueprint) rather than manually hunting for them only by blueprint names within FMODEL.
A helpful Regular Expression is to search multiple words like Broom AND Camera
. Use the regular expression (?=.*broom)(?=.*camera)
and it'll help pinpoint what you're looking for. Or (?=.*broom)(?=.*camera)(?=.*_C)
etc.
local BipedPlayer = nil
local GearManager = nil
local EGearSlotIDEnum = {
HEAD = 0,
OUTFIT = 1,
BACK = 2,
NECK = 3,
HAND = 4,
FACE = 5,
Num = 6,
EGearSlotIDEnum_MAX = 7
}
local EGearSavedItemIDEnum = {
HEAD = nil,
OUTFIT = nil,
BACK = nil,
NECK = nil,
HAND = nil,
FACE = nil,
Num = nil,
EGearSlotIDEnum_MAX = nil`
}
function Init()
BipedPlayer = FindFirstOf("Biped_Player")
GearManager = FindFirstOf("GearManager")
IsInitialized = true
end
function HoodToggle()
if(GearManager:IsValid() and BipedPlayer:IsValid())
then
local GearItemID = GearManager:GetEquippedGearItemID(BipedPlayer, EGearSlotIDEnum.OUTFIT)
if GearManager:IsHoodUp(BipedPlayer)
then
GearManager:SetHoodPosition(BipedPlayer, GearItemID, false, true)
else
GearManager:SetHoodPosition(BipedPlayer, GearItemID, true, true)
end
else
print("No instance of class 'GearManager' was found.")
end
end
function PlayerUnEquipWand()
if(BipedPlayer:IsValid())
then
local eGetRightArmState = BipedPlayer.GetRightArmState(15)
BipedPlayer.SetRightArmState(2, 15, true);
BipedPlayer.UnEquipWand()
BipedPlayer.SetRightArmState(eGetRightArmState, 15, true);
else
print("No instance of class 'Biped_Player' was found.")
end
end
function TogglePlayerGear(SlotID)
if (GearManager:IsValid() and BipedPlayer:IsValid())
then
if (GearManager:CanUnequipActorSlotID(BipedPlayer, SlotID))
then
EGearSavedItemIDEnum[SlotID] = GearManager:GetActorEquippedGearItemID(BipedPlayer, SlotID)
GearManager:UnequipActorSlotID(BipedPlayer, SlotID, true)
elseif EGearSavedItemIDEnum[SlotID] ~= nil
then
GearManager:SetActorEquippedGearItemID(BipedPlayer, EGearSavedItemIDEnum[SlotID], true)
end
end
end
RegisterKeyBind(Key.F6, function()
ExecuteInGameThread(function()
Init()
PlayerUnEquipWand()
end)
end)
RegisterKeyBind(Key.F6, {ModifierKey.SHIFT}, function()
ExecuteInGameThread(function()
Init()
PlayerUnEquipWand()
end)
end)
RegisterKeyBind(Key.F7, function()
ExecuteInGameThread(function()
Init()
HoodToggle()
end)
end)
RegisterKeyBind(Key.F1, { ModifierKey.CONTROL }, function()
ExecuteInGameThread(function()
Init()
TogglePlayerGear(EGearSlotIDEnum.HEAD)
end)
end)
RegisterKeyBind(Key.F2, { ModifierKey.CONTROL }, function()
ExecuteInGameThread(function()
Init()
TogglePlayerGear(EGearSlotIDEnum.OUTFIT)
end)
end)
RegisterKeyBind(Key.F3, { ModifierKey.CONTROL }, function()
ExecuteInGameThread(function()
Init()
TogglePlayerGear(EGearSlotIDEnum.BACK)
end)
end)
RegisterKeyBind(Key.F4, { ModifierKey.CONTROL }, function()
ExecuteInGameThread(function()
Init()
TogglePlayerGear(EGearSlotIDEnum.NECK)
end)
end)
RegisterKeyBind(Key.F5, { ModifierKey.CONTROL }, function()
ExecuteInGameThread(function()
Init()
TogglePlayerGear(EGearSlotIDEnum.HAND)
end)
end)
RegisterKeyBind(Key.F6, { ModifierKey.CONTROL }, function()
ExecuteInGameThread(function()
Init()
TogglePlayerGear(EGearSlotIDEnum.FACE)
end)
end)
Toggle Gear Mod (Uniquip Wand, etc.)
-- Author: VTLI#9513 (Discord: Hogwarts Legacy Modding)
-- ##############################
-- Please remove after doing the quest, otherwise this script may impact your performance!
-- This unofficial fix is a quick and dirty solution till the devs release an official fix!
-- ##############################
-- ##############################
-- Local Vars
-- ##############################
local cage = nil
local fixed = false;
-- ##############################
-- Hooks
-- ##############################
function OpenCage()
cage = FindFirstOf("BP_BeastCages_C")
if cage
then
cage:OnUnlocked(true,true,true,true)
fixed = true
else
end
end
RegisterHook("/Script/Phoenix.SpellTool:Start", function(Context, loc, muzzleloc)
if not fixed then
spell = Context:get():GetClass():GetFullName()
if spell == "BlueprintGeneratedClass /Game/Gameplay/ToolSet/Spells/Reparo/BP_ReparoSpell.BP_ReparoSpell_C" then
print("Unlock")
OpenCage()
else end
else end
end)
local HogwartsHudTogglerDisabled = false
RegisterKeyBind(Key.F9, {}, function()
local UIManager = FindFirstOf("UIManager")
if not UIManager:IsValid() then
print("[Hogwarts HUD Toggler] Couldn't get UIManager instance, therefore, could't toggle the HUD\n")
return
end
if HogwartsHudTogglerDisabled then
UIManager:ToggleHUD(true, true)
HogwartsHudTogglerDisabled = false
else
UIManager:ToggleHUD(false, false)
HogwartsHudTogglerDisabled = true
end
end)
-- Author: Rysel#4780 (discord Hogwarts Legacy Modding)
-- #######################################################################################
-- ###################################.C.O.N.F.I.G.#######################################
-- #######################################################################################
--
-- ### Tempus Imperium ### Day/Night Cycle speed modifications ###
--
-- Edit "clockRate" value to multiply the in-game time of the day/night cycle.
--
-- example: clockRate = 1 | 1 game day = 1 real hour (Default)
-- example: clockRate = 0.5 | 1 game day = 2 real hours
-- example: clockRate = 0.25 | 1 game day = 4 real hours
-- example: clockRate = 2 | 1 game day = 30 real minutes
--
-- EDIT HERE ↓↓↓
local clockRate = 0,0417 -- The rate of the day/night cycle clock (Safe values: 0.05-50)
local rateMultiplier = 2 -- The multiplayer to increase/decrease your clockRate
--
-- If you want to speedup/down the clock on the fly, you can
-- bind the following hotkeys. Find every key listed here:
-- https://github.com/UE4SS/UE4SS/wiki/Table-Key
--
local IncrementRateKey = Key.ADD -- Key to speed up the day/night cycle
local DecrementRateKey = Key.SUBTRACT -- Key to speed dn the day/night cycle
local ResetRateKey = Key.MULTIPLY -- Key to reset the speed to your rate
--
-- #######################################################################################
-- ####################################################################.rysel.############
-- #######################################################################################
-- Begin code
local modInitialized = false
local toggle = false
local dayNightMasterPath = "/Game/Levels/Overland/Overland_Global_Sky.Overland_Global_Sky:PersistentLevel.BP_DayNightSky_Overland_2.DayNightMaster"
local timeSourceSchedulerPath = dayNightMasterPath .. ".TimeSourceScheduler_0"
local timeSourceFromDateTimePath = dayNightMasterPath .. ".TimeSourceFromDateTime_1"
local currentModTimePath = "/Game/Environment/DayNightSky/Overland/BP_DayNightSky_Overland.Default__BP_DayNightSky_Overland_C:DayNightMaster.TimeSourceFromDateTime_1"
local dayNightMaster = nil
local currentModTime = nil
local timeSourceScheduler = nil
local timeSourceFromDateTime = nil
local gameScheduler = nil
userClockRate = clockRate
function SetClockRate(thisClockRate)
gameScheduler = FindFirstOf("Scheduler")
gameScheduler.SetSimulationTimeFactorOverride(thisClockRate)
print("Set simulation factor to: " .. thisClockRate)
end
function ToggleMod()
toggle = not toggle
timeSourceScheduler.bDisable = toggle
print("Scheduler Disabled? " .. tostring(toggle))
end
function SyncWithGameTime()
print("Syncing...")
timeSourceScheduler.bDisable = true
local currentDayMinute = gameScheduler.GetMinuteOfTheDay() -- dayNightMaster.LastNormalizedTime
local currentYear = gameScheduler.GetCalendarYear() -- currentModTime.DateTime.Year
local currentMonth = gameScheduler.GetMonthOfTheYear() -- currentModTime.DateTime.Month
local currentDay = gameScheduler.GetDayOfTheMonth() -- currentModTime.DateTime.Day
local currentHour = gameScheduler.GetHourOfTheDay() -- math.floor(currentTime)
local currentMinute = math.floor(((currentDayMinute / 60) - currentHour) * 60)
local currentAmPm = currentHour < 12 and 0 or 1
timeSourceFromDateTime.isEnabled = false
timeSourceFromDateTime.Rate = (clockRate + .0) * 1.333333
timeSourceFromDateTime.bUseRate = true
timeSourceFromDateTime.DateTime.Year = currentYear
timeSourceFromDateTime.DateTime.Month = currentMonth
timeSourceFromDateTime.DateTime.Day = currentDay
timeSourceFromDateTime.DateTime.Hour = currentHour
timeSourceFromDateTime.DateTime.Minute = currentMinute
timeSourceFromDateTime.DateTime.AmPm = currentAmPm
SetClockRate(clockRate)
timeSourceScheduler.bDisable = false
timeSourceFromDateTime.isEnabled = true
end
function IncreaseRate()
clockRate = clockRate * rateMultiplier
SetClockRate(clockRate)
Init()
print("++ClockRate = " .. clockRate)
end
function DecreaseRate()
clockRate = clockRate / rateMultiplier
SetClockRate(clockRate)
Init()
print("--ClockRate = " .. clockRate)
end
function ResetRate()
clockRate = userClockRate
SetClockRate(clockRate)
Init()
print("Reset ClockRate = " .. clockRate)
end
function Init()
print("Initializing...")
dayNightMaster = StaticFindObject(dayNightMasterPath)
currentModTime = StaticFindObject(currentModTimePath)
timeSourceScheduler = StaticFindObject(timeSourceSchedulerPath)
timeSourceFromDateTime = StaticFindObject(timeSourceFromDateTimePath)
gameScheduler = FindFirstOf("Scheduler")
if not (dayNightMaster == nil
and currentModTime == nil
and timeSourceScheduler == nil
and timeSourceFromDateTime == nil) then
timeSourceScheduler.bDisable = true
ExecuteWithDelay(50, SyncWithGameTime)
if not modInitialized then
ExecuteWithDelay(100, function()
SetClockRate(clockRate)
end)
end
toggle = true
modInitialized = true
-- RegisterKeyBind(Key.F2, ToggleMod) -- for debug only, dont do this
print("Initialized!")
end
end
print("## Aliquamriu ## Waiting for the player controller\n")
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function()
print("Load level detected, resetting...")
SetClockRate(1)
print("Set simulation factor to: " .. 1)
print("Fire Init")
ExecuteWithDelay(5000, Init)
end)
RegisterKeyBind(IncrementRateKey, IncreaseRate)
RegisterKeyBind(DecrementRateKey, DecreaseRate)
RegisterKeyBind(ResetRateKey, ResetRate)
Tempus Imperium - Day Night Cycle Speed Modifications
local Json = require("jsonStorage")
KismetSystemLibrary = nil
KismetMathLibrary = nil
IsInitialized = false
IsApplied = false
IsSpecialApplied = false
cameraConfig = 1
currentCam = "internal"
currentIX = 0
currentIY = 0
currentIZ = 0
currentEX = 0
currentEY = 0
currentEZ = 0
function fif(condition, if_true, if_false)
if condition then return if_true else return if_false end
end
function Init()
KismetSystemLibrary = StaticFindObject("/Script/Engine.Default__KismetSystemLibrary")
if not KismetSystemLibrary:IsValid() then error("KismetSystemLibrary(For Camera Offset) not valid\n") end
print(string.format("KismetSystemLibrary(For Camera Offset): %s\n", KismetSystemLibrary:GetFullName()))
KismetMathLibrary = StaticFindObject("/Script/Engine.Default__KismetMathLibrary")
if not KismetMathLibrary:IsValid() then error("KismetMathLibrary(For Camera Offset) not valid\n") end
print(string.format("KismetMathLibrary (For Camera Offset): %s\n", KismetMathLibrary:GetFullName()))
IsInitialized = true
end
Init()
function GetPlayerController()
local PlayerControllers = FindAllOf("PlayerController")
local PlayerController = nil
for Index,Controller in pairs(PlayerControllers) do
if Controller.Pawn:IsValid() and Controller.Pawn:IsPlayerControlled() then
PlayerController = Controller
else
print("Not valid or not player controlled\n")
end
end
if PlayerController and PlayerController:IsValid() then
return PlayerController
else
error("No PlayerController found\n")
end
end
function SepcialFPSTest(addValue, doYorX, doZ)
if currentCam == "internal" then
currentIX = currentIX + fif(doYorX == false and doZ == false, addValue, 0)
currentIY = currentIY + fif(doYorX and doZ == false, addValue, 0)
currentIZ = currentIZ + fif(doZ, addValue, 0)
elseif currentCam == "external" then
currentEX = currentEX + fif(doYorX == false and doZ == false, addValue, 0)
currentEY = currentEY + fif(doYorX and doZ == false, addValue, 0)
currentEZ = currentEZ + fif(doZ, addValue, 0)
end
local InsideCameraStacks = FindAllOf("BP_AddCameraSpaceTranslation_Default_C")
for Index,Stack in pairs(InsideCameraStacks) do
if Stack:IsValid() then
Stack:SetPropertyValue("CameraSpaceTranslation", {
["X"] = currentIX,
["Y"] = currentIY,
["Z"] = currentIZ,
})
else
print("Not valid CameraStack\n")
end
end
local OpenSpaceCameraStacks = FindAllOf("BP_AddCameraSpaceTranslation_OpenSpace_C")
for Index,Stack in pairs(OpenSpaceCameraStacks) do
if Stack:IsValid() then
Stack:SetPropertyValue("CameraSpaceTranslation", {
["X"] = (-95 + (currentIX * -1)) + currentEX,
["Y"] = (20 + (currentIY * -1)) + currentEY,
["Z"] = (-35 + (currentIZ * -1)) + currentEZ,
})
else
print("Not valid CameraStack\n")
end
end
end
function Reset()
local InsideCameraStacks = FindAllOf("BP_AddCameraSpaceTranslation_Default_C")
for Index,Stack in pairs(InsideCameraStacks) do
if Stack:IsValid() then
Stack:SetPropertyValue("CameraSpaceTranslation", {
["X"] = 0,
["Y"] = 0,
["Z"] = 0,
})
else
print("Not valid CameraStack\n")
end
end
local OpenSpaceCameraStacks = FindAllOf("BP_AddCameraSpaceTranslation_OpenSpace_C")
for Index,Stack in pairs(OpenSpaceCameraStacks) do
if Stack:IsValid() then
Stack:SetPropertyValue("CameraSpaceTranslation", {
["X"] = -95,
["Y"] = 20,
["Z"] = -35,
})
else
print("Not valid CameraStack\n")
end
end
currentIX = 0
currentIY = 0
currentIZ = 0
saveSettings()
end
function switchBetweenCameras()
if cameraConfig == 4 then
cameraConfig = 1
else
cameraConfig = cameraConfig + 1
end
loadCameraSettings()
end
function switchBetweenIandE()
if currentCam == "internal" then
currentCam = "external"
else
currentCam = "internal"
end
end
function setCameraStack()
local InsideCameraStacks = FindAllOf("BP_AddCameraSpaceTranslation_Default_C")
for Index,Stack in pairs(InsideCameraStacks) do
if Stack:IsValid() then
Stack:SetPropertyValue("CameraSpaceTranslation", {
["X"] = currentIX,
["Y"] = currentIY,
["Z"] = currentIZ,
})
else
print("Not valid CameraStack\n")
end
end
local OpenSpaceCameraStacks = FindAllOf("BP_AddCameraSpaceTranslation_OpenSpace_C")
for Index,Stack in pairs(OpenSpaceCameraStacks) do
if Stack:IsValid() then
Stack:SetPropertyValue("CameraSpaceTranslation", {
["X"] = (-95 + (currentIX * -1)) + currentEX,
["Y"] = (20 + (currentIY * -1)) + currentEY,
["Z"] = (-35 + (currentIZ * -1)) + currentEZ,
})
else
print("Not valid CameraStack\n")
end
end
end
function saveSettings()
Json.saveTable({["X"] = fif(currentCam == "internal", currentIX, currentEX), ["Y"] = fif(currentCam == "internal", currentIY, currentEY), ["Z"] = fif(currentCam == "internal", currentIZ, currentEZ)}, "CameraSettings.json", string.format("%s_config %s", currentCam, cameraConfig))
Json.saveTable(cameraConfig, "Settings.json", "lastUsedConfig")
Json.saveTable(currentCam, "Settings.json", "lastEditedCamera")
end
function loadCameraSettings()
local internalCamSettings = Json.loadTable("CameraSettings.json", string.format("internal_config %s", cameraConfig))
currentIX = internalCamSettings.X
currentIY = internalCamSettings.Y
currentIZ = internalCamSettings.Z
local externalCamSettings = Json.loadTable("CameraSettings.json", string.format("external_config %s", cameraConfig))
currentEX = externalCamSettings.X
currentEY = externalCamSettings.Y
currentEZ = externalCamSettings.Z
setCameraStack()
end
function loadSettings()
cameraConfig = Json.loadTable("Settings.json", "lastUsedConfig")
currentCam = Json.loadTable("Settings.json", "lastEditedCamera")
loadCameraSettings()
end
function tryFPS()
local playerController = GetPlayerController()
local playerPawn = playerController.Pawn
local characterMesh = playerPawn.Mesh
characterMesh:setHiddenInGame(true, false)
characterMesh.Mesh:setHiddenInGame(true, false)
end
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context)
loadSettings()
end)
RegisterKeyBind(Key.NUM_EIGHT, function()
SepcialFPSTest(5, false, false)
end)
RegisterKeyBind(Key.NUM_EIGHT, {ModifierKey.ALT}, function()
SepcialFPSTest(5, false, true)
end)
RegisterKeyBind(Key.NUM_TWO, function()
SepcialFPSTest(-5, false, false)
end)
RegisterKeyBind(Key.NUM_TWO, {ModifierKey.ALT}, function()
SepcialFPSTest(-5, false, true)
end)
RegisterKeyBind(Key.NUM_FOUR, function()
SepcialFPSTest(-5, true, false)
end)
RegisterKeyBind(Key.NUM_SIX, function()
SepcialFPSTest(5, true, false)
end)
RegisterKeyBind(Key.NUM_ONE, function()
Reset()
end)
RegisterKeyBind(Key.F7, function()
saveSettings()
end)
RegisterKeyBind(Key.F6, function()
switchBetweenCameras()
end)
RegisterKeyBind(Key.F6, {ModifierKey.ALT}, function()
switchBetweenIandE()
end)
RegisterKeyBind(Key.F5, {ModifierKey.ALT}, function()
tryFPS()
end)
-- Authors: (discord Hogwarts Legacy Modding)
-- winterelfeas#7101
-- Rysel#4780
-- VTLI#9513
-- Luffy#4000
-- ##############################
-- Local vars
-- ##############################
local BipedPlayer = nil
local BipedAnimInstance = nil
local HUDManager = nil
-- If user uses Hotkey to enable HUD, it will stay permanently enabled
local permanentHUD = false
-- How long before HUD disappears
local showHudLast = 5
local startShowHudTime = os.time()
local hudVisible = false
-- Used to reduce possible performance impact and tick less often
local pastFrames = 0
local triggerLogicAfterFrames = 30
-- ############################################
-- Init Biped player (only used by keypress)
-- ############################################
function Init()
print("Init..\n")
BipedPlayer = FindFirstOf("Biped_Player")
if not BipedPlayer:IsValid()
then
error("No BipedPlayer found ...\n")
else
print(string.format("BipedPlayer %s..\n", BipedPlayer:GetFullName()))
IsInitialized = true
end
end
-- ##############################
-- Hook on load / reload
-- ##############################
function EnableHUD()
if not hudVisible then
print("Enable HUD")
HUDManager:ToggleHUD(true, true, true)
hudVisible = true
startShowHudTime = os.time()
end
end
function DisableHUD()
if hudVisible then
print("Disable HUD")
HUDManager:ToggleHUD(false, false, true)
hudVisible = false
end
end
function TickImpact(bCombatReady)
if not permanentHUD then
-- Used to reduce possible performance impact and tick less often
pastFrames = pastFrames + 1
if pastFrames > triggerLogicAfterFrames then
pastFrames = 0
local combatMode = false
if not HUDManager or not HUDManager:IsValid() then
print("No HUD Manager available")
return
else
-- ENABLE HUD If on a combat ready tick
if not combatMode and bCombatReady then
-- print("Tick combat mode")
combatMode = true
startShowHudTime = os.time()
EnableHUD()
end
if not combatMode then
-- CHECK Combat mode for idle / move anims
if BipedPlayer.bInCombatMode then
-- print("Biped in combat mode")
combatMode = true
EnableHUD()
else
-- print("Biped NOT in combat mode")
combatMode = false
end
end
end
-- print(string.format("Combat mode: %s", tostring(combatMode)))
-- print(string.format("HUD Visible: %s", tostring(hudVisible)))
-- Manage Tool Wheel and Speel Menu UI pop
if HUDManager.bShowHUD and not hudVisible then
print(string.format("HUD Visible uncatched: %s", tostring(HUDManager.bShowHUD)))
hudVisible = true
startShowHudTime = os.time()
end
-- HIDE HUD After X seconds if no more in combat
if hudVisible and not combatMode then
local currentTickTime = os.time()
local pastSecondsSinceHudShowAndNoMoreCombat = currentTickTime - startShowHudTime
if pastSecondsSinceHudShowAndNoMoreCombat > showHudLast then
--print(string.format("Auto disable HUD after %s seconds", tostring(pastSecondsSinceHudShowAndNoMoreCombat)))
DisableHUD()
end
end
end
end
end
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully")
BipedPlayer = Context:get().Pawn
HUDManager = FindFirstOf("PhoenixHud_C")
RegisterHook("/Game/Pawn/Shared/StateTree/BTT_Biped_Protego.BTT_Biped_Protego_C:ReceiveTick", function(Context, DeltaSeconds)
TickImpact(true, false)
end)
RegisterHook("/Game/Pawn/Shared/StateTree/BTT_Biped_WandCast.BTT_Biped_WandCast_C:ReceiveTick", function(Context, DeltaSeconds)
TickImpact(true, false)
end)
RegisterHook("/Game/Pawn/Shared/StateTree/BTT_HoverBroom.BTT_HoverBroom_C:ReceiveTick", function(Context, DeltaSeconds)
TickImpact(false, true)
end)
RegisterHook("/Game/Pawn/Shared/StateTree/BTS_Biped_MoveAndIdle.BTS_Biped_MoveAndIdle_C:ReceiveTick", function(Context, DeltaSeconds)
TickImpact(false, false)
end)
hudVisible = true
startShowHudTime = os.time()
end)
-- ##############################
-- Trigger by Key press
-- ##############################
local hudEnabledSettings = false;
RegisterKeyBind(Key.F6, function()
ExecuteInGameThread(function()
print("Key pressed, running code")
-- hudVisible = false
if hudEnabledSettings == true then
hudEnabledSettings = false
permanentHUD = false
else
hudEnabledSettings = true
permanentHUD = true
end
HUDManager:ToggleHUD(hudEnabledSettings, hudEnabledSettings, true)
end)
end)
-- BlockingVolume
-- Script by Narknon
local UEHelpers = require("UEHelpers")
local GetWorld = UEHelpers.GetWorld
function DestroyVolumes()
BlockingVolumes = FindAllOf("NoMountZoneVolume")
if BlockingVolumes then
for Index,Volume in pairs(BlockingVolumes) do
print(string.format("Volume: %s\n", Volume:GetFullName()))
Volume:K2_DestroyActor()
end
end
DismountVolumes = FindAllOf("NoDismountZoneVolume")
if DismountVolumes then
for Index,DismountVolume in pairs(DismountVolumes) do
print(string.format("Volume: %s\n", DismountVolume:GetFullName()))
DismountVolume:K2_DestroyActor()
end
end
HeightVolumes = FindAllOf("MountHeightLimitVolume")
if HeightVolumes then
for Index,HeightVolume in pairs(HeightVolumes) do
print(string.format("Volume: %s\n", HeightVolume:GetFullName()))
HeightVolume:K2_DestroyActor()
end
end
SpeedLimitVolumes = FindAllOf("MountSpeedLimitVolume")
if SpeedLimitVolumes then
for Index,SpeedLimitVolume in pairs(SpeedLimitVolumes) do
print(string.format("Volume: %s\n", SpeedLimitVolume:GetFullName()))
SpeedLimitVolume:K2_DestroyActor()
end
end
end
RegisterKeyBind(Key.F6, {ModifierKey.CONTROL}, function()
DestroyVolumes()
end)
-- Author: Newt#4780 (Hogwarts Legacy Discord)
-- Idea: winterelfeas#7101
RegisterHook("/Script/Phoenix.UIManager:GetToMapFromBackButton", function()
-- Disable by default until Async is executed
-- local FastTravelManager = FindFirstOf("FastTravelManager")
-- FastTravelManager.SetFastTravelDisabled(true)
-- Async to not cause too long freeze on menu open
ExecuteAsync(function()
-- Need to reget every time to reload distance
local FlooNetworks = FindAllOf("BP_FastTravel_PillarPlaque_C")
local BipedPlayer = FindFirstOf("Biped_Player")
local DisableFastTravel = true
local MaxDistance = 500.0
for Index, Floo in pairs(FlooNetworks) do
if Floo:IsValid() and BipedPlayer:GetDistanceTo(Floo) < MaxDistance and string.match(Floo:GetFullName(), "FastTravel") then
DisableFastTravel = false
break
end
end
local FastTravelManager = FindFirstOf("FastTravelManager")
FastTravelManager.SetFastTravelDisabled(DisableFastTravel)
end)
end)
-- Author: VTLI#9513 (Discord: Hogwarts Legacy Modding)
-- ##############################
-- Local Vars
-- ##############################
local Player = nil
local Lock = nil
-- ##############################
-- Hooks
-- ##############################
RegisterHook("/Script/Phoenix.LockableComponent:CanPlayerUseAlohomoraOnLock", function(Context)
if Lock then
Lock.FadeBlackDuration = 0
Lock.PuzzleComplete = true
Lock:Exit()
Lock = nil
else
end
end)
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
Player = Context:get().Pawn
RegisterHook("/Game/RiggedObjects/Environments/AlohomoraLock/BP_AlohomoraLock.BP_AlohomoraLock_C:ReceiveBeginPlay", function(Context)
Lock = Context:get()
end)
end)
AUTOHOMORA - Auto Skip Alohomora Minigame
-- Authors: (discord Hogwarts Legacy Modding)
-- winterelfeas#7101
-- Credit: Rysel for his Tempus Imperium mod for Scheduler example
-- ############################################
-- Init Biped player (only used by keypress)
-- ############################################
local delayTrigger = 10000
local canTrigger = false
NotifyOnNewObject("/Script/Phoenix.Loadingcreen", function(self)
print("LOADING screen created")
canTrigger = true
end)
function getmonth(index)
local months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }
return months[index]
end
function getday(index)
local days = { "Sunday", "Monday", "Tuesday", "Wednesdary", "Thursday", "Friday", "Saturday" }
return days[index + 1]
end
function DisplayDateTime()
local UIManager = FindFirstOf("UIManager")
local TimeScheduler = FindFirstOf("Scheduler")
local currentHour = TimeScheduler:GetHourOfTheDay()
local currentYear = TimeScheduler.GetCalendarYear()
local currentMonth = getmonth(TimeScheduler.GetMonthOfTheYear())
local currentDay = TimeScheduler.GetDayOfTheMonth()
local currentDayOfWeek = TimeScheduler.GetDayOfTheWeek()
local currentDayStr = getday(currentDayOfWeek)
local currentHour = TimeScheduler.GetHourOfTheDay()
local isPM = currentHour < 12 and 0 or 1
local timeT = "AM"
if isPM == 1 then
timeT = "PM"
end
-- print(tostring(currentHour))
-- print(tostring(currentYear))
-- print(tostring(getmonth(currentMonth)))
-- print(tostring(currentDay))
-- os.time not working sadly to get a direct os.date convertion to nice string
-- local osTime = os.time{year=currentYear, month=currentMonth, day=currentDay, hour=currentHour}
local finalString = string.format("%s:00, %s %s, %s. %s", currentHour, currentDayStr, currentDay, currentMonth, currentYear)
-- Position does nothing sadly
local FTutorialLayoutData= {
["Position"] = {
["X"] = 500,
["Y"] = 500
},
["Alignment"] = {
["X"] = 500,
["Y"] = 500
}
}
UIManager:SetAndShowHintMessage(finalString, FTutorialLayoutData, true, 5)
end
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully -show time after loading screen")
if canTrigger then
canTrigger = false
ExecuteWithDelay(delayTrigger, function()
DisplayDateTime()
end)
RegisterHook("/Script/Phoenix.FastTravelManager:FinishWait", function(context)
print("Waiting")
nextMessageIsTime = true
ExecuteWithDelay(2000, function()
DisplayDateTime()
end)
end)
end
end)
-- ##############################
-- Trigger by Key press
-- ##############################
RegisterKeyBind(Key.F6, function()
ExecuteInGameThread(function()
-- Uncomment below to enable
-- ExecuteAsync(function()
-- nextMessageIsTime = true
-- DisplayDateTime()
-- end)
end)
end)
-- Vanisho is a mod that makes the player invisble whenver they get on a broom
-- The mod can be toggled on or off using [ALT+R]
--
--
-- Author: dooZyz#4822 (Hogwarts Legacy Discord)
-- Idea: HastyBasher#6046
-- Intended to be used with: Tommie#0887 UFO mod
local GearScreen = nil
local BipedPlayer = nil
local Enabled = true
function Init()
BipedPlayer = FindFirstOf("Biped_Player")
GearScreen = StaticFindObject("/Script/Phoenix.Default__GearScreen")
end
-- This will hide the PlayerController's mesh, or show it depending on [IsHidden]
function Vanish(isHidden)
local playerPawn = BipedPlayer
local characterMesh = playerPawn.Mesh
characterMesh:setHiddenInGame(isHidden, true)
end
-- This will check the GearScreen instance to see if our player is mounted or not
function IsMounted()
return GearScreen:IsPlayerOnBroom()
end
-- Toggle enabled state with the [ALT+R] keys
RegisterKeyBind(Key.R, {ModifierKey.ALT}, function()
Enabled = not Enabled
-- Make the player instantly be revealed if they are disabling it
if not Enabled then
print("Disabled Vanish!")
else
print("Enabled Vanish!")
end
end)
-- Checks to see if we have initailized our bipedplayer and gearscreen yet. This will break if reloaded (must go back to main menu, then load game again)
function IsInitialized()
if BipedPlayer == nil or GearScreen == nil then Init() end
return BipedPlayer:IsValid() and GearScreen:IsValid()
end
function DoVanish(Context, Delta)
if IsInitialized() then
if not Enabled then
Vanish(false)
else
Vanish(IsMounted())
end
end
end
--Register our tick callbacks so that we can update our mounted state
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
RegisterHook("/Game/Pawn/Shared/StateTree/BTT_HoverBroom.BTT_HoverBroom_C:ReceiveTick", DoVanish)
RegisterHook("/Game/Pawn/Shared/StateTree/BTS_Biped_MoveAndIdle.BTS_Biped_MoveAndIdle_C:ReceiveTick", DoVanish)
end)
-- Authors: (discord Hogwarts Legacy Modding)
-- winterelfeas#7101
-- Credits: Darkstar#7383, Doudoulix#5078
-- ##############################
-- Local vars
-- ##############################
local BipedPlayer = nil
local GameplayStatics = nil
local GearScreen = nil
-- ##############################
-- Hook on load / reload
-- ##############################
local delayForHook = 5000
local allowHook = true
local bulletTimeStarted = false
local wandLowered = false
local lastWandUpdate = os.clock()
NotifyOnNewObject("/Script/Phoenix.Loadingcreen", function(self)
-- print("LOADING screen created")
-- delayForHook = 10000
allowHook = true
end)
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully - Slow mo")
BipedPlayer = Context:get().Pawn
GameplayStatics = StaticFindObject("/Script/Engine.Default__GameplayStatics")
GearScreen = StaticFindObject("/Script/Phoenix.Default__GearScreen")
if BipedPlayer:IsValid() then
if allowHook then
allowHook = false
-- Wand Up
RegisterHook("/Game/Pawn/Shared/StateTree/BTS_Biped_TopLevel.BTS_Biped_TopLevel_C:InpActEvt_SpellModifierButton_K2Node_CustomInputActionEvent_86", function(context)
--print("Wand Up")
wandLowered = false
lastWandUpdate = os.clock()
-- Os Time is in seconds :(
ExecuteWithDelay(500, function()
local timePushed = os.clock() - lastWandUpdate
--print(tostring(timePushed))
-- Make sure player held button for more than 1 second, otherwise would trigger on basic attack
if not wandLowered and timePushed >= 0.5 and BipedPlayer.bInCombatMode and not GearScreen.IsPlayerOnBroom() then
--print("start bullet time")
GameplayStatics:SetGlobalTimeDilation(BipedPlayer, 0.1)
bulletTimeStarted = true
end
end)
end)
-- Wand Down
RegisterHook("/Game/Pawn/Shared/StateTree/BTS_Biped_TopLevel.BTS_Biped_TopLevel_C:InpActEvt_SpellModifierButton_K2Node_CustomInputActionEvent_87", function(context)
--print("Wand Down")
wandLowered = true
lastWandUpdate = os.clock()
if bulletTimeStarted then
GameplayStatics:SetGlobalTimeDilation(BipedPlayer, 1)
bulletTimeStarted = false
end
end)
end
end
end)
Mod = "SpellHotkeys 1.0" -- by olegbl
LoggingLevel = "None" -- Debug | Info | Warning | Error | None
require("log")
require("spells")
require("keybindings")
-- because we're forced to run in the game's thread, we're going to be
-- introducing quite a bit of lag every time we handle a hotkey activation
-- in order to mitigate this as much as possible, we can try to aggressively
-- cache entities that should not change in order to minimize the number
-- of round-trips we make between LUA and the C# runtime
local WandTool = nil
local SpellToolRecords = {}
function CastSpell(SpellToolRecordName)
Log.Info("CastSpell %s", SpellToolRecordName)
if not WandTool then -- or not WandTool:IsValid() then
Log.Error("Could not find WandTool")
return
end
local SpellToolRecord = SpellToolRecords[SpellToolRecordName]
if not SpellToolRecord then -- or not SpellToolRecord:IsValid() then
Log.Error("Could not find SpellToolRecord")
return
end
local SpellTool = WandTool:GetSpellTool(SpellToolRecord)
local IsSpellToolAvailable = WandTool:IsSpellToolAvailable(SpellToolRecord, false)
if not IsSpellToolAvailable then
Log.Error("SpellTool is not available")
return
end
-- if casting Lumos
if SpellToolRecordName == Spells.CC.Lumos then
-- if Lumos is already active
if SpellTool:IsLumosActive() then
WandTool:CancelCurrentSpell()
return
end
end
-- local SpellName = SpellTool.DatabaseName:ToString()
-- local SpellCategory = SpellCategories[SpellTool:GetSpellCategory()]
-- Log.Info("CastSpell %s (%s)", SpellName, SpellCategory)
Log.Debug("WandTool:CancelCurrentSpell")
WandTool:CancelCurrentSpell()
Log.Debug("WandTool:ActivateSpellTool")
WandTool:ActivateSpellTool(SpellToolRecord, false)
Log.Debug("WandTool:CastActiveSpell")
WandTool:CastActiveSpell()
-- if CastActiveSpell is executed outside of the game thread
-- then the game will crash during the next loading screen
-- ExecuteInGameThread(function()
-- FindFirstOf("WandTool"):CastActiveSpell()
-- end)
end
function InitializeSpellTools()
local WandTool = FindFirstOf("WandTool")
if not WandTool or not WandTool:IsValid() then return end
local function InitializeSpellTool(SpellToolRecordName)
local SpellToolRecord = StaticFindObject(SpellToolRecordName)
if not SpellToolRecord or not SpellToolRecord:IsValid() then return end
SpellToolRecords[SpellToolRecordName] = SpellToolRecord
-- checking if the spell tool is available causes the spell tool to become available shortly thereafter
WandTool:IsSpellToolAvailable(SpellToolRecord, false)
-- local SpellTool = WandTool:GetSpellTool(SpellToolRecord)
-- if not SpellTool or not SpellTool:IsValid() then return end
-- local SpellName = SpellTool.DatabaseName:ToString()
-- WandTool:LoadSpellByName(WandTool.Owner, SpellName, true, true)
end
for SpellCategoryName, SpellCategory in pairs(Spells) do
for SpellName, SpellRecordName in pairs(SpellCategory) do
InitializeSpellTool(SpellRecordName)
end
end
end
NotifyOnNewObject("/Script/Phoenix.WandTool", function(CreatedObject)
WandTool = CreatedObject
InitializeSpellTools()
end)
for Index, KeyBinding in ipairs(KeyBindings) do
RegisterKeyBind(KeyBinding.Key, KeyBinding.Modifiers, function()
-- ExecuteInGameThread makes the call really laggy
-- ideally we'd only run the CastActiveSpell method in the game thread
-- but if we do that, we get random crashes :(
-- maybe https://github.com/UE4SS-RE/RE-UE4SS/commit/5faf0f9f637a61e2b46c47f7bba42e63f1429533 will help?
ExecuteInGameThread(function()
CastSpell(KeyBinding.Spell)
end)
end)
end
Log.Info("Initialized")
-- Author: winterelfeas#7101 (discord Hogwarts Legacy Modding)
-- ##############################
-- Local vars
-- ##############################
local BipedPlayer = nil -- Only used by Keypress
local IsInitialized = false
-- ##############################
-- No Health Regen
-- ##############################
function DisableHealthRegen(Player)
print("Health Regen Percentage BEFORE")
print(tostring(Player.PercentHealthRecoverdPerSecond))
Player.PercentHealthRecoverdPerSecond = 0.000000
print("Health Regen Percentage AFTER")
print(tostring(Player.PercentHealthRecoverdPerSecond))
end
-- ############################################
-- Init Biped player (only used by keypress)
-- ############################################
function Init()
print("Init..\n")
BipedPlayer = FindFirstOf("Biped_Player")
if not BipedPlayer:IsValid()
then
error("No BipedPlayer found ...\n")
else
print(string.format("BipedPlayer %s..\n", BipedPlayer:GetFullName()))
IsInitialized = true
end
end
-- ##############################
-- Hook on load / reload
-- ##############################
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully")
Player = Context:get().Pawn
DisableHealthRegen(Player)
end)
-- ##############################
-- Trigger by Key press
-- ##############################
RegisterKeyBind(Key.F6, function()
ExecuteInGameThread(function()
print("Key pressed, running code")
Init()
DisableHealthRegen(BipedPlayer)
end)
end)
local BipedPlayer = nil
function Init()
BipedPlayer = FindFirstOf("Biped_Player")
if not BipedPlayer:IsValid()
then
error("No BipedPlayer found ...\n")
else
IsInitialized = true
end
end
function SetSlowJog()
BipedPlayer.JogModeSpeedCurve = BipedPlayer.WalkModeSpeedCurve
end
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
Init()
ExecuteInGameThread(function()
SetSlowJog()
end)
end)
-- Author: winterelfeas#7101 (discord Hogwarts Legacy Modding)
-- ##############################
-- Local vars
-- ##############################
local BipedPlayer = nil
local IsInitialized = false
-- #######################################
-- Reduce Ancient Magic finisher damange
-- #######################################
function ReduceAncientMagicFinisherDamage()
print("Finisher damange")
BipedPlayer.FinisherDamage = 150.000000 -- Original value 250
print(tostring(BipedPlayer.FinisherDamage))
-- Other options for the mod:
-- Player.MaxFocus = 1000.000000 -- 1000 should mean only 1 Ancient Magic bar (untested)
-- Player.FinisherFocusCost = 1000.000000 -- it costs one bar, you could increase it but no real necessity
end
-- ############################################
-- Init Biped player (only used by keypress)
-- ############################################
function Init()
print("Init..\n")
BipedPlayer = FindFirstOf("Biped_Player")
if not BipedPlayer:IsValid()
then
error("No BipedPlayer found ...\n")
else
print(string.format("BipedPlayer %s..\n", BipedPlayer:GetFullName()))
IsInitialized = true
end
end
-- ##############################
-- Hook on load / reload
-- ##############################
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully")
BipedPlayer = Context:get().Pawn
ReduceAncientMagicFinisherDamage()
end)
-- ##############################
-- Trigger by Key press
-- ##############################
RegisterKeyBind(Key.F6, function()
ExecuteInGameThread(function()
print("Key pressed, running code")
Init()
ReduceAncientMagicFinisherDamage()
end)
end)
Less OP Ancient Magic Finisher
-- Author: winterelfeas#7101 (discord Hogwarts Legacy Modding)
-- #######################################
-- Smooth / lower out animations
-- #######################################
-- To be less fast in stairs / slope
-- To smooth jogging start animation
function SmoothAnimations()
local stairsUp = StaticFindObject("/Game/Pawn/Student/Abilities/Locomotion/ABL_MoveFwdStairsUp_Loop.Default__ABL_MoveFwdStairsUp_Loop_C:AblPlayAnimationArchitectTask_0")
local stairsDown = StaticFindObject("/Game/Pawn/Student/Abilities/Locomotion/ABL_MoveFwdStairsDown_Loop.Default__ABL_MoveFwdStairsDown_Loop_C:AblPlayAnimationArchitectTask_0")
local turnMove = StaticFindObject("/Game/Pawn/Student/Abilities/Locomotion/ABL_TurnMove_Start.Default__ABL_TurnMove_Start_C:AblPlayAnimationArchitectTask_0")
local walk2jog = StaticFindObject("/Game/Pawn/Student/Abilities/Locomotion/ABL_Walk2Jog.Default__ABL_Walk2Jog_C:AblPlayAnimationArchitectTask_0")
-- Up is slower than going down
stairsUp.m_PlayRate = 0.920000
-- Cannot go less fast for going down otherwise in slops player is SLOWER which makes no sense
stairsDown.m_PlayRate = 0.920000
-- Idle to Jog
turnMove.m_PlayRate = 0.750000
-- Walkt to jog
walk2jog.m_PlayRate = 0.82000
end
-- ##############################
-- Set better speed curve
-- ##############################
function SetBetterSpeedCurve()
-- VALUES edited
--(Keys=(
--[1](Value=95.000000),
--[2](Time=0.150000,Value=156.000000),
--[3](Time=0.200000,Value=156.000000,ArriveTangent=0.396483,LeaveTangent=0.396483),
--[4](InterpMode=RCIM_Constant,Time=0.300000,Value=300.000000),
--[5](Time=0.999100,Value=390.000000)),DefaultValue=340282346638528859811704183484516925440.000000,PreInfinityExtrap=RCCE_Constant,PostInfinityExtrap=RCCE_Constant)
local jogCurve = StaticFindObject("/Game/Pawn/Player/C_JogModeSpeedCurve.C_JogModeSpeedCurve")
local walkCurve = StaticFindObject("/Game/Pawn/Player/C_WalkModeSpeedCurve.C_WalkModeSpeedCurve")
local sprintCurve = StaticFindObject("/Game/Pawn/Player/C_SprintModeSpeedCurve.C_SprintModeSpeedCurve")
print("Jog")
print(tostring(jogCurve:IsValid()))
if jogCurve:IsValid() then
jogCurve.FloatCurve.Keys[1].Value = 95.000000
jogCurve.FloatCurve.Keys[2].Value = 156.000000
jogCurve.FloatCurve.Keys[2].Time = 0.150000
jogCurve.FloatCurve.Keys[3].Value = 200.000000
jogCurve.FloatCurve.Keys[3].Time = 0.200000
jogCurve.FloatCurve.Keys[4].Value = 300.000000
jogCurve.FloatCurve.Keys[4].Time = 0.700000
jogCurve.FloatCurve.Keys[5].Value = 390
jogCurve.FloatCurve.Keys[5].Time = 0.999100
end
print("Walk")
print(tostring(walkCurve:IsValid()))
if walkCurve:IsValid() then
walkCurve.FloatCurve.Keys[1].Value = 95.000000
walkCurve.FloatCurve.Keys[2].Value = 156.000000
walkCurve.FloatCurve.Keys[2].Time = 0.300000
walkCurve.FloatCurve.Keys[3].Value = 300.000000
walkCurve.FloatCurve.Keys[3].Time = 0.800000
end
print("Sprint")
print(tostring(sprintCurve:IsValid()))
-- =========================================================
-- SPRINT CURVE ACTUALLY DOES NOT CHANGE SPRINT SPEED
-- IF LOW ENOUGH IT CAN BECOME A JOG > SOMEHOW
-- =========================================================
if sprintCurve:IsValid() then
sprintCurve.FloatCurve.Keys[1].Value = 450
sprintCurve.FloatCurve.Keys[2].Value = 450
end
end
-- ##############################
-- Hook on load / reload
-- ##############################
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully")
SmoothAnimations()
SetBetterSpeedCurve()
end)
-- ##############################
-- Trigger by Key press
-- ##############################
RegisterKeyBind(Key.F6, function()
ExecuteInGameThread(function()
print("Key pressed, running code")
SetBetterSpeedCurve()
SmoothAnimations()
end)
end)
-- ##############################
-- Local vars
-- ##############################
local Biped_Player = nil
-- ##############################
-- Hook on load / reload
-- ##############################
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully\n")
Biped_Player = FindFirstOf("Biped_Player")
end)
RegisterHook("/Script/Phoenix.Biped_Player:SetInvulnerableTime", function(Context)
if Biped_Player then
ExecuteInGameThread(function()
Biped_Player:ClearInvulnerable()
end)
else
print("No player reference stored. Reload save to attempt correction.\n")
end
end)
-- Author: VTLI#9513 (Discord: Hogwarts Legacy Modding)
-- ##############################
-- Hooks
-- ##############################
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
CheckIfLoaded()
end)
function CheckIfLoaded()
local Function = StaticFindObject("/Game/Gameplay/SphinxPuzzles/Blueprints/BP_Merlin_Gazebo.BP_Merlin_Gazebo_C:ActivationSRFinished")
if not Function:IsValid() then ExecuteWithDelay(2000, CheckIfLoaded) return end
RegisterHook("/Game/Gameplay/SphinxPuzzles/Blueprints/BP_Merlin_Gazebo.BP_Merlin_Gazebo_C:ActivationSRFinished", function(Context)
gazebo = Context:get()
gazebo.GazeboSR.bInstantlySkippable = true
end)
end
ExecuteWithDelay(2000, CheckIfLoaded)
-- ##############################
-- This is just a preview/early version of hopefully a script that will completely avoid the cinematic
-- Current issues:
-- Some Gazebos wont be fully built in the world if you skip the cinematic - though just for the current session. Reloading a save fixes it!
-- ##############################
-- Author: winterelfeas#7101 (discord Hogwarts Legacy Modding)
-- ##############################
-- Local vars
-- ##############################
local BipedPlayer = nil -- Only used by Keypress
local IsInitialized = false
local maxplayerHealth = 1
local expectedplayerhealth = 1
local healthReduce = 1
-- ##############################
-- Functions
-- ##############################
function split(s, sep)
local fields = {}
local sep = sep or " "
local pattern = string.format("([^%s]+)", sep)
string.gsub(s, pattern, function(c) fields[#fields + 1] = c end)
return fields
end
local yearInfo = {}
yearInfo[1] = 31
yearInfo[2] = 28
yearInfo[3] = 31
yearInfo[4] = 30
yearInfo[5] = 31
yearInfo[6] = 30
yearInfo[7] = 31
yearInfo[8] = 31
yearInfo[9] = 30
yearInfo[10] = 31
yearInfo[11] = 30
yearInfo[12] = 31
-- Because with UE4SS Lua we cannot convert old date using os.time
-- need to make our own days comparison
function ProgrammedDaysPassed(month,day,currentMonth,currentDay)
local totalDaysPast = 0
if tonumber(currentMonth) == tonumber(month) then
totalDaysPast = tonumber(currentDay) - tonumber(day)
else
local monthDays = yearInfo[tonumber(month)]
local daysToEnd = monthDays - tonumber(day)
totalDaysPast = daysToEnd + tonumber(currentDay)
end
return totalDaysPast
end
function CheckFileExists()
local file,err = io.open(".\\Mods\\DrinkEatOrDie\\lastdrinkeat.txt",'r')
if file then
return true
else
return false
end
end
-- Keep it simple, if day is not the same, one day passed
function SaveLastTimeEat()
local gameScheduler = FindFirstOf("Scheduler")
local currentHour = gameScheduler:GetHourOfTheDay()
local currentYear = gameScheduler.GetCalendarYear()
local currentMonth = gameScheduler.GetMonthOfTheYear()
local currentDay = gameScheduler.GetDayOfTheMonth()
local currentDate = string.format("%s-%s-%s %s:00", currentYear, currentMonth, currentDay, currentHour)
print("Date: "..currentDate)
local file,err = io.open(".\\Mods\\DrinkEatOrDie\\lastdrinkeat.txt",'w')
if file then
file:write(currentDate)
file:close()
else
print("Error while saving date to file:", err)
end
end
function GetLastTimeEat()
print("Reading file")
local dateLoaded = nil
local file,err = io.open(".\\Mods\\DrinkEatOrDie\\lastdrinkeat.txt",'r')
if file then
dateLoaded = file:read()
file:close()
else
print("Error loading time:", err)
end
print("Date load: "..dateLoaded)
return dateLoaded
end
function GetDaysPast()
print("Get days passed")
local loadedDate = GetLastTimeEat()
-- Ugly solution because of os.time bug with old dates
local loadedDateSplit = split(loadedDate, "-")
local loadedMonth = loadedDateSplit[2]
local loadedDateSplitSpace = split(loadedDateSplit[3]," ")
local loadedDay = loadedDateSplitSpace[1]
print("Split day:"..tostring(loadedDay))
print("Split month:"..tostring(loadedMonth))
--local loadedDate = "1890-10-01 23:00"
local gameScheduler = FindFirstOf("Scheduler")
local currentHour = gameScheduler:GetHourOfTheDay()
local currentYear = gameScheduler.GetCalendarYear()
local currentMonth = gameScheduler.GetMonthOfTheYear()
local currentDay = gameScheduler.GetDayOfTheMonth()
print("Current Day:"..tostring(currentDay))
print("Current Month:"..tostring(currentMonth))
-- Os.time in UE4SS is unable to parse old dates
-- time result cannot be represented in this installation
-- local currentGameDateTime = os.time({year = currentYear, month = currentMonth, day = currentDay, hour = currentHour, min = 0, sec = 0})
-- local pattern = "(%d+)-(%d+)-(%d+) (%d+):(%d+)"
-- local timeToConvert = loadedDate
-- local runyear, runmonth, runday, runhour, runminute = timeToConvert:match(pattern)
-- local daysfrom = os.difftime(loadedDate, currentGameDateTime) / (24 * 60 * 60) -- seconds in a day
local daysfrom = ProgrammedDaysPassed(loadedMonth,loadedDay, currentMonth,currentDay)
print("Days from: "..daysfrom)
return tonumber(daysfrom)
end
function CheckTimeSince()
print("Checking last time eat drink")
ExecuteAsync(function()
if not CheckFileExists() then
SaveLastTimeEat()
else
local daysPast = GetDaysPast()
if daysPast > 0 then
ReduceMaxHealth(daysPast)
end
end
end)
end
function ResetTimeSince()
ExecuteAsync(function()
SaveLastTimeEat()
ExecuteInGameThread(function()
print("Restore health")
BipedPlayer:RestoreHealth()
end)
end)
end
function ReduceMaxHealth(fDaysPast)
if BipedPlayer
then
ExecuteInGameThread(function()
if maxplayerHealth == 1 or maxplayerHealth == 100 then
-- Need to reget here to ensure we get the most up-to-date max health
BipedPlayer = FindFirstOf("Biped_Player")
maxplayerHealth = BipedPlayer:GetObjectStateInfo():GetMaxHealth()
expectedplayerhealth = maxplayerHealth
healthReduce = maxplayerHealth * 0.10
print("Max player health: "..tostring(maxplayerHealth))
print("Reduce tick: "..tostring(healthReduce))
end
local healthToReduce = healthReduce * fDaysPast
expectedplayerhealth = maxplayerHealth - healthToReduce
print("health to reduce: "..tostring(healthToReduce))
print("expectedhealth:"..tostring(expectedplayerhealth))
if expectedplayerhealth == 0 then
expectedplayerhealth = 10
end
print("Set health"..tostring(expectedplayerhealth))
BipedPlayer:GetObjectStateInfo():SetHealth(expectedplayerhealth, true)
--SetPotionMaxHealth(expectedplayerhealth)
end)
end
end
function DisableHealthRegen(Player)
if Player
then
print("Health Regen Percentage BEFORE")
print(tostring(Player.PercentHealthRecoverdPerSecond))
Player.PercentHealthRecoverdPerSecond = 0.000000
print("Health Regen Percentage AFTER")
print(tostring(Player.PercentHealthRecoverdPerSecond))
end
end
-- Not doing anything
function SetPotionMaxHealth(maxHealthPotion)
print("Set max potion health")
local quickHealth = StaticFindObject("/Script/Phoenix.Default__QuickHealthActions")
quickHealth:SetMaxHealth(math.floor(maxHealthPotion))
end
-- ##############################
-- Hook on load / reload
-- ##############################
local canTrigger = false
NotifyOnNewObject("/Script/Phoenix.Loadingcreen", function(self)
print("LOADING screen created")
canTrigger = true
end)
local drinkHooked = false
local foodHooked = false
local foodSmallHooked = false
local foodLargeHooked = false
-- In case player did not go near food or drink, do not cause re-hook at next load
local drinkHookedWaiting = false
local foodHookedWaiting = false
local foodSmallHookedWaiting = false
local foodLargeHookedWaiting = false
function LoadDrink()
print("Wait drink hook")
drinkHookedWaiting = true
local Function = StaticFindObject("/Game/Pawn/Student/Abilities/Interactions/PartialBody/ABL_DrinkBeer.ABL_DrinkBeer_C:OnAbilityStart")
if not Function:IsValid() then ExecuteWithDelay(10000, LoadDrink) return end
print("Hook Drink Beer")
RegisterHook("/Game/Pawn/Student/Abilities/Interactions/PartialBody/ABL_DrinkBeer.ABL_DrinkBeer_C:OnAbilityStart", function(context)
print("Drink Beer")
ResetTimeSince()
end)
drinkHookedWaiting = false
drinkHooked = true
end
function LoadEatFood()
print("Wait eat hook")
foodHookedWaiting = true
local Function = StaticFindObject("/Game/Pawn/Student/Abilities/PartialBody/UseInventoryItem/Food/ABL_EatFood.ABL_EatFood_C:OnAbilityStart")
if not Function:IsValid() then ExecuteWithDelay(10000, LoadEatFood) return end
RegisterHook("/Game/Pawn/Student/Abilities/PartialBody/UseInventoryItem/Food/ABL_EatFood.ABL_EatFood_C:OnAbilityStart", function(context)
print("Eat food")
ResetTimeSince()
end)
foodHookedWaiting = false
foodHooked = true
end
function LoadEatFoodSmall()
print("Wait eat small hook")
foodSmallHookedWaiting = true
local Function = StaticFindObject("/Game/Pawn/Student/Abilities/Interactions/PartialBody/ABL_EatFoodSmall.ABL_EatFoodSmall_C:OnAbilityStart")
if not Function:IsValid() then ExecuteWithDelay(10000, LoadEatFoodSmall) return end
RegisterHook("/Game/Pawn/Student/Abilities/Interactions/PartialBody/ABL_EatFoodSmall.ABL_EatFoodSmall_C:OnAbilityStart", function(context)
print("Eat food small")
ResetTimeSince()
end)
foodSmallHookedWaiting = false
foodSmallHooked = true
end
function LoadEatFoodBig()
print("Wait eat big hook")
foodLargeHookedWaiting = true
local Function = StaticFindObject("/Game/Pawn/Student/Abilities/Interactions/PartialBody/ABL_EatFoodLarge.ABL_EatFoodLarge_C:OnAbilityStart")
if not Function:IsValid() then ExecuteWithDelay(10000, LoadEatFoodBig) return end
RegisterHook("/Game/Pawn/Student/Abilities/Interactions/PartialBody/ABL_EatFoodLarge.ABL_EatFoodLarge_C:OnAbilityStart", function(context)
print("Eat food large")
ResetTimeSince()
end)
foodLargeHooked = true
foodLargeHookedWaiting = false
end
function LoadHooks()
if not drinkHookedWaiting then
ExecuteAsync(function()
LoadDrink()
end)
end
if not foodHookedWaiting then
ExecuteAsync(function()
LoadEatFood()
end)
end
if not foodLargeHookedWaiting then
ExecuteAsync(function()
LoadEatFoodBig()
end)
end
if not foodSmallHookedWaiting then
ExecuteAsync(function()
LoadEatFoodSmall()
end)
end
print("Hooks for DrinkEat")
CheckTimeSince()
RegisterHook("/Script/Phoenix.FastTravelManager:FinishWait", function(context)
print("Waiting food")
CheckTimeSince()
end)
end
-- Register Hook to interpret keypresses
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("Hooked on load / reload succesfully - Drink Eat")
BipedPlayer = Context:get().Pawn
DisableHealthRegen(BipedPlayer)
if canTrigger then
canTrigger = false
LoadHooks()
end
end)
RegisterKeyBind(Key.F6, function()
ExecuteInGameThread(function()
-- Uncomment to enable
local actor = FindFirstOf("Biped_Player")
print("health: "..tostring(actor:GetHealth()))
print("max health: "..tostring(actor:GetObjectStateInfo():GetMaxHealth()))
end)
end)
-- ==========================================================================
-- Seasons Manager Mod ------------------------------------------------------
--
-- Description:
-- After the main story, the seasons stop progressing which is unfortunate.
-- Why miss out on the beautiful seasonal scenery and decorations?
-- This mod aims to address this.
--
-- The time will now progress through the game year and seasons will change
-- accordingly.
-- Authors:
-- Lecernawx (Little Mac)
-- winterelfeas#7101
-- Credits:
-- Darkstar
-- Narknon
-- Rysel
-- Modders in the Hogwarts Legacy Modding Discord
-- ==========================================================================
-- User Variables (feel free to change them to your liking)
local useRealTime = false -- When true, seasons will change according to which day it is in real-life.
local dateSetEnabled = false -- Whether changing the date manually is enabled. Useful if the game gets stuck or game progression is affected.
local dateSetKey = Key.F12 -- Key to activate a date change manually.
local dateSetMonth = 1 -- Month to set. JAN = 1, FEB = 2, MAR = 3, etc.
local dateSetDay = 1 -- Day to set. Can be from 1-31 depending on the month.
local dateSetHour = 0 -- Hour to set. Can be from 0-23.
local dateSetMinute = 0 -- Minute to set. Can be from 0-59.
local manualModifierKey = ModifierKey.CONTROL -- Key used in combination with 1, 2, 3, etc. to manually change the month in-game.
local clockDisplayAutomatic = true -- When true, the clock will automatically display at the set interval defined below.
local clockDisplayKey = Key.F5 -- Key to force display the clock to screen manually.
local clockDisplayFrequency = 60 -- The clock will be displayed each time this number of minutes have passed.
-- Ex. 15 would display the clock every 15 in-game minutes (12:00, 12:15, 12:30, 12:45, etc.)
-- This value should be from 1 - 60.
-- --------------------------------------------------------------------------
-- Mod Variables (only change things below this point if you know what you're doing)
local tickDelay = 10 -- How many milliseconds between ticks of the world timer
local timerStarted = false -- Flag to check whether the world timer is active
local clockDisplayDelay = 10000 -- Amount of time to wait before showing the clock message to the screen in some circumstances
local worldInitialized = false -- Flag to check whether the world has initialized after a loading screen
local allowClockDisplay = false -- Flag to prevent duplicate printing of the clock to the screen
local clockLastMinuteDisplayed = 0 -- Variable to keep track of the last minute displayed to the screen
local clockLastHourDisplayed = 0 -- Variable to keep track of the last hour displayed to the screen
local clockLastMinuteRecorded = 0 -- Variable to keep track of the last minute read from the game.
local clockLastHourRecorded = 0 -- Variable to keep track of the last hour read from the game.
local clockLastDayRecorded = 0 -- Variable to keep track of the last day read from the game.
-- --------------------------------------------------------------------------
-- Custom println implementation for cleaner logs
function println(str)
print("\n[SEASONS MANAGER] " .. str .. "\n")
end
-- World timer start/stop and tick function ---------------------------------
function StopTimer()
timerStarted = false
end
function StartTimer()
ExecuteInGameThread(function()
LoopAsync(tickDelay, function()
DoTick()
-- LoopAsync quits when the callback function returns true
return (not timerStarted)
end)
end)
end
function DoTick()
DisplayClock(false)
end
-- Season Change Logic -----------------------------------------------------
-- Season Values:
----- Season_Fall = 1
----- Season_Winter = 2
----- Season_Spring = 3
----- Season_Summer = 4
-- Decor Values:
----- Off = 0
----- On = 2
function CheckForSeasonUpdate(month, day)
-- Set Default Values
local season = 1
local christmasDecor = 0
local halloweenDecor = 0
-- Fetch week day
local time = os.date("*t")
-- Set Season
if useRealTime then
season = math.ceil((time.day / 31) * 4)
else
if month >= 9 and month <= 11 then season = 1 end -- Fall: September to November
if month == 12 or month <= 2 then season = 2 end -- Winter: December to February
if month >= 3 and month <= 5 then season = 3 end -- Spring: March to May
if month >= 6 and month <= 8 then season = 4 end -- Summer: June to August
end
ExecuteInGameThread(function()
ChangeSeason(season)
end)
-- Set Decorations
if useRealTime then
-- Christmas
if season == 2 then
if math.ceil((time.day / 31) * 8) == 4 then
christmasDecor = 2
end
end
-- Halloween
if season == 1 then
if math.ceil((time.day / 31) * 8) == 2 then
halloweenDecor = 2
end
end
else
-- Christmas
if season == 2 then
if month == 12 and day >= 1 then
christmasDecor = 2
end
end
-- Halloween
if season == 1 then
if month == 10 and day >= 1 then
halloweenDecor = 2
end
end
end
ExecuteInGameThread(function()
ChangeDecorations(christmasDecor, halloweenDecor)
end)
end
function ChangeSeason(season)
-- Get Game object
local PhoenixGameInstance = FindFirstOf("PhoenixGameInstance")
-- Change the season
-- This crashes when run Async
if PhoenixGameInstance:IsValid() then
PhoenixGameInstance:ForceSeasonUpdate(season)
end
end
function ChangeDecorations(christmasDecor, halloweenDecor)
-- Get Game objects
local StatsManager = FindFirstOf("StatsManager")
local Obj_Christmas = FName("Seasons_ChistmasDecor")
local Obj_Halloween = FName("Seasons_HalloweenDecor")
-- Change the decorations
if StatsManager:IsValid() then
StatsManager:SetStat(Obj_Christmas, christmasDecor)
StatsManager:SetStat(Obj_Halloween, halloweenDecor)
end
end
-- Display Clock Function and Helpers --------------------------------------
function GetMonth(index)
local months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }
return months[index]
end
function GetDay(index)
local days = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }
return days[index + 1]
end
function CalculateMinute(minute, hour)
return math.floor(minute % 60)
end
-- force: display the clock to screen regardless of flags or interval checks that might otherwise prevent it
function DisplayClock(force)
-- Load Game Objects
PhoenixHUD = FindFirstOf("PhoenixHUD")
TimeScheduler = FindFirstOf("Scheduler")
-- Error Check
if not PhoenixHUD:IsValid() or not TimeScheduler:IsValid() then
return
end
-- Get the game's hour and minute
local currentHour = TimeScheduler.GetHourOfTheDay()
local currentMinuteRaw = TimeScheduler.GetMinuteOfTheDay()
local currentMinute = CalculateMinute(currentMinuteRaw, currentHour)
-- Because time is continuous, there can be a delay between when GetHourOfTheDay and GetMinuteOfTheDay get executed.
-- This can cause the hour to be read at a certain point in time, and then the minutes to be read after the hour has passed.
-- To mitigate this, check whether the hour has changed if the minutes are smaller than their previous value.
-- This doesn't make sense on manual time changes, so ignore forced changes, as time will jump forward/backwards.
if not force and ((currentMinute < clockLastMinuteRecorded) and (currentHour == clockLastHourRecorded)) then
currentHour = currentHour + 1
if currentHour >= 24 then
currentHour = currentHour - 24
end
-- Recalculate the minute with the correct hour
currentMinute = CalculateMinute(currentMinuteRaw, currentHour)
end
-- Save the current hour and minute as read from the game
clockLastHourRecorded = currentHour
clockLastMinuteRecorded = currentMinute
-- Fetch the remaining variables
-- There may very well be an issue with values being read at different times at precisely midnight,
-- but I don't want to bother covering each case... some error margin here is acceptable.
local currentDay = TimeScheduler.GetDayOfTheMonth()
local currentDayOfWeek = GetDay(TimeScheduler.GetDayOfTheWeek())
local currentMonthRaw = TimeScheduler.GetMonthOfTheYear()
local currentMonth = GetMonth(currentMonthRaw)
-- If we hit a new day, or change the time manually/at loading - perform season updates
if force or (currentDay ~= clockLastDayRecorded) then
CheckForSeasonUpdate(currentMonthRaw, currentDay)
end
-- Save the current day as read from the game
clockLastDayRecorded = currentDay
-- Check that the game clock has elapsed enough time to hit our defined interval
-- Check if we have already displayed this timestamp to the screen:
-- If we did - skip until enough time has passed
-- If we did not - store the value and set the flag to allow the clock to display to the screen
if (currentMinute % clockDisplayFrequency) == 0 and (currentMinute ~= clockLastMinuteDisplayed or currentHour ~= clockLastHourDisplayed) then
allowClockDisplay = true
clockLastHourDisplayed = currentHour
clockLastMinuteDisplayed = currentMinute
end
-- If this is not a forced display (if this is called by the timer)
-- Check if the mod is set to display automatic clock messages
-- Check if we already printed this timestamp to screen, and return if we did
if not force then
if not clockDisplayAutomatic or not allowClockDisplay then
return
end
end
-- Reset the flag once it's checked for the next ticks
allowClockDisplay = false
-- At this point, we are displaying the message to screen
-- Manipulate the hours and minute for display
local displayHour = currentHour
local displayMinute = currentMinute
local timeSuffix = "AM"
if displayHour >= 12 then
displayHour = displayHour - 12
timeSuffix = "PM"
end
if displayHour == 0 then
displayHour = displayHour + 12
end
if displayMinute >= 60 then
displayMinute = displayMinute - 60
end
-- Build the output string
local finalString = ""
-- Skip the month part if real time is being used (months and days become irrelevant)
if useRealTime then
finalString = string.format("%s - %s:%02d %s", currentDayOfWeek, displayHour, displayMinute, timeSuffix)
else
finalString = string.format("%s, %s. %s - %s:%02d %s", currentDayOfWeek, currentMonth, currentDay, displayHour, displayMinute, timeSuffix)
end
-- Display the string to screen
PhoenixHUD.HUDWidgetRef.TextNotificationPanel:AddNotification(finalString)
end
-- Manually change the date
function ChangeDate(month, day, hour, minute)
println(string.format("DATE CHANGE: Changing the date to: %s. %s - %s:%02d", GetMonth(month), day, hour, minute))
ExecuteInGameThread(function()
ExecuteAsync(function()
-- Change the date
TimeScheduler = FindFirstOf("Scheduler")
TimeScheduler.SetCurrentTime(hour, minute, 0, month, day, 1890)
-- Display the new time
DisplayClock(true)
end)
end)
end
function ChangeDateKeyBind(month)
ChangeDate(month, 1, 0, 0)
end
-- Hooks -------------------------------------------------------------------------
-- Hook to initialize on Loading Screen
NotifyOnNewObject("/Script/Phoenix.Loadingcreen", function(self)
println("HOOK: Loading screen initialization")
worldInitialized = true
StopTimer()
end)
-- Hook to start the timer once the initialization has finished
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
-- Check if the initialization has completed
if worldInitialized then
-- Reset the initialization flag
worldInitialized = false
println("HOOK: Load / reload complete - displaying the clock")
-- Start the world timer
-- Check that we don't start a new timer if one is already started
if not timerStarted then
timerStarted = true
StartTimer()
end
end
end)
-- Hook to force display the clock after the player has done the "wait" action or has fast travelled
RegisterHook("/Script/Phoenix.FastTravelManager:FinishWait", function(context)
println("HOOK: Player wait complete - displaying the clock")
ExecuteWithDelay(clockDisplayDelay, function()
DisplayClock(true)
end)
end)
-- Keybind to force display the clock to screen manually
RegisterKeyBind(clockDisplayKey, function()
println("KEYBIND: Displaying the clock manually")
ExecuteInGameThread(function()
ExecuteAsync(function()
DisplayClock(true)
end)
end)
end)
-- Keybind to force change the date manually
if dateSetEnabled then
RegisterKeyBind(dateSetKey, function()
ChangeDate(dateSetMonth, dateSetDay, dateSetHour, dateSetMinute)
end)
end
-- Manual switch to pick the month in-game
if not useRealTime then
RegisterKeyBind(Key.ONE, {manualModifierKey}, function()
ChangeDateKeyBind(1)
end)
RegisterKeyBind(Key.TWO, {manualModifierKey}, function()
ChangeDateKeyBind(2)
end)
RegisterKeyBind(Key.THREE, {manualModifierKey}, function()
ChangeDateKeyBind(3)
end)
RegisterKeyBind(Key.FOUR, {manualModifierKey}, function()
ChangeDateKeyBind(4)
end)
RegisterKeyBind(Key.FIVE, {manualModifierKey}, function()
ChangeDateKeyBind(5)
end)
RegisterKeyBind(Key.SIX, {manualModifierKey}, function()
ChangeDateKeyBind(6)
end)
RegisterKeyBind(Key.SEVEN, {manualModifierKey}, function()
ChangeDateKeyBind(7)
end)
RegisterKeyBind(Key.EIGHT, {manualModifierKey}, function()
ChangeDateKeyBind(8)
end)
RegisterKeyBind(Key.NINE, {manualModifierKey}, function()
ChangeDateKeyBind(9)
end)
RegisterKeyBind(Key.ZERO, {manualModifierKey}, function()
ChangeDateKeyBind(10)
end)
RegisterKeyBind(Key.Q, {manualModifierKey}, function()
ChangeDateKeyBind(11)
end)
RegisterKeyBind(Key.W, {manualModifierKey}, function()
ChangeDateKeyBind(12)
end)
end
-- Author: Luffy#4000 (Hogwarts Legacy Discord)
-- Base: winterelfeas#7101
-- Improvements: DarkStar (huge thanks), Little Mac, Doudoulix
function playAnimation(animName, loop)
loop = loop or false
local animSequence = LoadAsset(animName)
if not animSequence:IsValid() then
error("Animation sequence is not valid")
end
local playerCharacter = FindFirstOf("BP_Biped_Player_C")
if not playerCharacter:IsValid() then
error("Player character not found")
end
local skeletalMesh = playerCharacter:GetSkeletalMesh()
if not skeletalMesh then
error("Skeletal mesh not found")
end
-- Play the animation
skeletalMesh:PlayAnimation(animSequence, loop)
end
function stopAnim()
playerCharacter = FindFirstOf("BP_Biped_Player_C")
if not playerCharacter:IsValid() then
error("Player character not found")
end
local skeletalMesh = playerCharacter:GetSkeletalMesh()
if not skeletalMesh then
error("Skeletal mesh not found")
end
skeletalMesh:SetAnimationMode("AnimationBlueprint")
end
-- Register console command to play animation
RegisterConsoleCommandHandler("playanim", function(FullCommand, Parameters)
-- If we have no parameters then just let someone else handle this command
if #Parameters < 1 then return false end
-- Get the animation name from the command parameters
local animName = Parameters[1]
-- Get the loop parameter if provided
local loop = Parameters[2]
if loop then
loop = (loop == "true")
end
-- Play the animation
playAnimation(animName, loop)
-- Return true to indicate that this is the final handler for this command
return true
end)
RegisterKeyBind(Key.F9, function()
ExecuteInGameThread(function()
stopAnim()
end)
end)
Animation Console (Play any animation)
-- Author: pinguluk
-- Mod Nexus Page: https://www.nexusmods.com/hogwartslegacy/mods/913
-- Mod GitHub Repo: https://github.com/pinguluk/InfiniteSwiftMod
-- Version 1.1.0
-- Note: please mention me if you use this code in your mod, thanks :)
local shadowBlinkSpeed = 3000 -- CHANGE THE BLINK SPEED HERE (3000 is the default value)
local shadowBlinkAbility = nil
local shadowBlinkAbilityRootMotion = nil
local VERY_BIG_NUMBER = 999999999999999
-- Change the speed of the ShadowBlink function
function SetShadowBlinkSpeed()
print('> Setting ShadowBlink BlinkSpeed to ' .. shadowBlinkSpeed)
shadowBlinkAbilityRootMotion:SetPropertyValue("BlinkSpeed", shadowBlinkSpeed)
end
-- Change the TurnToFaceInterpTime to a very high number to make sure the character (animation) direction doesn't change and keep the normal direction (default is 0.5)
function SetShadowBlinkTurnToFaceInterpTime()
print('> Setting ShadowBlink TurnToFaceInterpTime to ' .. VERY_BIG_NUMBER)
shadowBlinkAbilityRootMotion:SetPropertyValue("TurnToFaceInterpTime", VERY_BIG_NUMBER)
end
-- Change the offset of the ShadowBlink animation end function (default is 10)
function SetShadowBlinkAnimationEnd(offset)
print('> Setting ShadowBlinkAnimationEnd to ' .. offset)
shadowBlinkAbility:SetPropertyValue("m_EndTime", {
["Offset"] = offset
})
end
-- Register the hooks to detect the input press + release for Dodge (ShadowBlink)
function SetShadowBlinkInputHooks()
print('> Registering ShadowBlink input hooks')
-- Detect DodgeAndBlink input down
RegisterHook(
"/Game/Pawn/Shared/StateTree/BTS_Biped_TopLevel.BTS_Biped_TopLevel_C:InpActEvt_DodgeAndBlinkButton_K2Node_CustomInputActionEvent_26",
function()
print('DodgeAndBlink input down')
-- Set the ShadowBlink animation end to a very big number to make sure it doesn't stop the animation
SetShadowBlinkAnimationEnd(VERY_BIG_NUMBER)
end)
-- Detect DodgeAndBlink input up
RegisterHook(
"/Game/Pawn/Shared/StateTree/BTS_Biped_TopLevel.BTS_Biped_TopLevel_C:InpActEvt_DodgeAndBlinkButton_K2Node_CustomInputActionEvent_25",
function()
print('DodgeAndBlink input up')
-- Set the ShadowBlink animation end to a very low value to make sure it stops the animation
SetShadowBlinkAnimationEnd(-1)
end)
end
-- Whenever the character is loaded, find the ShadowBlink ability & root motion and set the blink speed and register the hooks to detect the input press + release for Dodge (ShadowBlink)
RegisterHook("/Script/Phoenix.Biped_Player:OnCharacterLoadComplete", function(self)
print("=== InfiniteSwift Mod by pinguluk ===")
print("> (Re)initalising...")
shadowBlinkAbility = StaticFindObject(
"/Game/Pawn/Student/Abilities/Locomotion/ABL_ShadowBlink.Default__ABL_ShadowBlink_C:ablRootMotionModifiersTask_1")
shadowBlinkAbilityRootMotion = StaticFindObject(
"/Game/Pawn/Student/Abilities/Locomotion/ABL_ShadowBlink.Default__ABL_ShadowBlink_C:ablRootMotionModifiersTask_1.RootMotionModifierProperties_DodgeRoll_0")
SetShadowBlinkSpeed()
SetShadowBlinkTurnToFaceInterpTime()
SetShadowBlinkInputHooks()
print("InfiniteSwift Mod has been (re)initialised!")
print("===============================")
end)
Infinite Swift - GOTTA GO FAST
GitHub Repo
local BipedPlayer = nil
function Init()
BipedPlayer = FindFirstOf("Biped_Player")
if not BipedPlayer:IsValid()
then
error("No BipedPlayer found ...\n")
else
IsInitialized = true
end
end
function SetSlowJog()
BipedPlayer.JogModeSpeedCurve = BipedPlayer.WalkModeSpeedCurve
end
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
Init()
ExecuteInGameThread(function()
SetSlowJog()
end)
end)
-- Authors: (discord Hogwarts Legacy Modding)
-- winterelfeas#7101
-- Rysel#4780
local playerPawn = nil
local phoenixHUD = nil
local allowHook = false
NotifyOnNewObject("/Script/Phoenix.Loadingcreen", function(self)
allowHook = true
end)
RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
print("# DISABLE ENEMY NOTIFICATION # - Hooked")
playerPawn = Context:get().Pawn
if allowHook then
allowHook = false
RegisterHook("/Game/UI/HUD/UI_BP_PhoenixHUDWidget.UI_BP_PhoenixHUDWidget_C:SetAndShowHintMessage", function(context)
if playerPawn.bInCombatMode then
ExecuteAsync(function()
print("Disable Enemy Level Warning")
phoenixHUD = FindFirstOf("PhoenixHud_C")
phoenixHUD:HideHUDGroup("HINTHUD", nil)
end)
end
end)
end
end)
Remove High Level Enemy Warning
RegisterKeyBind(Key.TAB, function()
ExecuteInGameThread(function()
local DevMenu = FindFirstOf("UI_BP_FrontEnd_Menu_C")
if DevMenu:IsValid() then
DevMenu:DevMenuButton()
end
end)
end)
local StartPage = nil
RegisterHook("/Script/Phoenix.StartPageWidget:OnStartPageIntroStarted", function(Context)
StartPage = FindFirstOf("UI_BP_StartPage_C")
StartPage:CloseScreenWithOutro()
end)