local script_dir = debug.getinfo(1, "S").source:sub(2):gsub("/", "\\"):match("(.*\\)"):sub(1, -2):match("(.*\\)"):sub(1, -2):match("(.*\\)") pcall(loadfile(script_dir .. "crossbowParryForTheModernManAndHisHKS\\hksModule-ElaDiDu-SE\\dynamicParam_Header.lua")) pcall(loadfile(script_dir .. "paramDef_Bastardized\\CreateOffsetTable.lua")) ------------------------------------------ --Custom Envs from Scripts-Data-Exposer ------------------------------------------ --Returns the int at the specified location --4th param is bitOffset if value type is BIT, otherwise it's the first pointer offset. --WARNING: OFFSETS THAT LEAD TO AN INVALID (BUT NOT NULL/0) POINTER WILL CRASH --WARNING: LUA NUMBERS ARE FLOATS, THIS MEANS THAT FOR NUMBERS GREATER THAN 16,777,216 ROUNDING INACCURACIES WILL OCCUR TraversePointerChain = 10000 --args , , , GAME_BASE = 0 CHR_INS_BASE = 1 TARGET_CHR_INS_BASE = 2 UNSIGNED_BYTE = 0 SIGNED_BYTE = 1 UNSIGNED_SHORT = 2 SIGNED_SHORT = 3 UNSIGNED_INT = 4 SIGNED_INT = 5 FLOAT = 6 BIT = 7 --Print to this mod's console --Use ExposePrint func ExposeDebugPrint = 10001 --args --Get event flag GetEventFlag = 10003 --args --Get param value. --env only returns ints so floats will still need conversion in lua --bitOffset only used if value type is BIT GetParamValue = 10004 --args , , , , , PARAM_EquipParamWeapon = 0 PARAM_EquipParamProtector = 1 PARAM_EquipParamAccessory = 2 PARAM_EquipParamGoods = 3 PARAM_ReinforceParamWeapon = 4 PARAM_ReinforceParamProtector = 5 PARAM_NpcParam = 6 PARAM_AtkParam_Npc = 7 PARAM_AtkParam_Pc = 8 PARAM_NpcThinkParam = 9 PARAM_Bullet = 10 PARAM_BulletCreateLimitParam = 11 PARAM_BehaviorParam = 12 PARAM_BehaviorParam_PC = 13 PARAM_Magic = 14 PARAM_SpEffectParam = 15 PARAM_SpEffectVfxParam = 16 PARAM_SpEffectSetParam = 17 PARAM_TalkParam = 18 PARAM_MenuColorTableParam = 19 PARAM_ItemLotParam_enemy = 20 PARAM_ItemLotParam_map = 21 PARAM_MoveParam = 22 PARAM_CharaInitParam = 23 PARAM_EquipMtrlSetParam = 24 PARAM_FaceParam = 25 PARAM_FaceRangeParam = 26 PARAM_ShopLineupParam = 27 PARAM_ShopLineupParam_Recipe = 28 PARAM_GameAreaParam = 29 PARAM_CalcCorrectGraph = 30 PARAM_LockCamParam = 31 PARAM_ObjActParam = 32 PARAM_HitMtrlParam = 33 PARAM_KnockBackParam = 34 PARAM_DecalParam = 35 PARAM_ActionButtonParam = 36 PARAM_AiSoundParam = 37 PARAM_PlayRegionParam = 38 PARAM_NetworkAreaParam = 39 PARAM_NetworkParam = 40 PARAM_NetworkMsgParam = 41 PARAM_BudgetParam = 42 PARAM_BonfireWarpParam = 43 PARAM_BonfireWarpTabParam = 44 PARAM_BonfireWarpSubCategoryParam = 45 PARAM_MenuPropertySpecParam = 46 PARAM_MenuPropertyLayoutParam = 47 PARAM_MenuValueTableParam = 48 PARAM_Ceremony = 49 PARAM_PhantomParam = 50 PARAM_CharMakeMenuTopParam = 51 PARAM_CharMakeMenuListItemParam = 52 PARAM_HitEffectSfxConceptParam = 53 PARAM_HitEffectSfxParam = 54 PARAM_WepAbsorpPosParam = 55 PARAM_ToughnessParam = 56 PARAM_SeMaterialConvertParam = 57 PARAM_ThrowDirectionSfxParam = 58 PARAM_DirectionCameraParam = 59 PARAM_RoleParam = 60 PARAM_WaypointParam = 61 PARAM_ThrowParam = 62 PARAM_GrassTypeParam = 63 PARAM_GrassTypeParam_Lv1 = 64 PARAM_GrassTypeParam_Lv2 = 65 PARAM_GrassLodRangeParam = 66 PARAM_NpcAiActionParam = 67 PARAM_PartsDrawParam = 68 PARAM_AssetEnvironmentGeometryParam = 69 PARAM_AssetModelSfxParam = 70 PARAM_AssetMaterialSfxParam = 71 PARAM_AttackElementCorrectParam = 72 PARAM_FootSfxParam = 73 PARAM_MaterialExParam = 74 PARAM_HPEstusFlaskRecoveryParam = 75 PARAM_MPEstusFlaskRecoveryParam = 76 PARAM_MultiPlayCorrectionParam = 77 PARAM_MenuOffscrRendParam = 78 PARAM_ClearCountCorrectParam = 79 PARAM_MapMimicryEstablishmentParam = 80 PARAM_WetAspectParam = 81 PARAM_SwordArtsParam = 82 PARAM_KnowledgeLoadScreenItemParam = 83 PARAM_MultiHPEstusFlaskBonusParam = 84 PARAM_MultiMPEstusFlaskBonusParam = 85 PARAM_MultiSoulBonusRateParam = 86 PARAM_WorldMapPointParam = 87 PARAM_WorldMapPieceParam = 88 PARAM_WorldMapLegacyConvParam = 89 PARAM_WorldMapPlaceNameParam = 90 PARAM_ChrModelParam = 91 PARAM_LoadBalancerParam = 92 PARAM_LoadBalancerDrawDistScaleParam = 93 PARAM_LoadBalancerDrawDistScaleParam_ps4 = 94 PARAM_LoadBalancerDrawDistScaleParam_ps5 = 95 PARAM_LoadBalancerDrawDistScaleParam_xb1 = 96 PARAM_LoadBalancerDrawDistScaleParam_xb1x = 97 PARAM_LoadBalancerDrawDistScaleParam_xss = 98 PARAM_LoadBalancerDrawDistScaleParam_xsx = 99 PARAM_LoadBalancerNewDrawDistScaleParam_win64 = 100 PARAM_LoadBalancerNewDrawDistScaleParam_ps4 = 101 PARAM_LoadBalancerNewDrawDistScaleParam_ps5 = 102 PARAM_LoadBalancerNewDrawDistScaleParam_xb1 = 103 PARAM_LoadBalancerNewDrawDistScaleParam_xb1x = 104 PARAM_LoadBalancerNewDrawDistScaleParam_xss = 105 PARAM_LoadBalancerNewDrawDistScaleParam_xsx = 106 PARAM_WwiseValueToStrParam_Switch_AttackType = 107 PARAM_WwiseValueToStrParam_Switch_DamageAmount = 108 PARAM_WwiseValueToStrParam_Switch_DeffensiveMaterial = 109 PARAM_WwiseValueToStrParam_Switch_HitStop = 110 PARAM_WwiseValueToStrParam_Switch_OffensiveMaterial = 111 PARAM_WwiseValueToStrParam_Switch_GrassHitType = 112 PARAM_WwiseValueToStrParam_Switch_PlayerShoes = 113 PARAM_WwiseValueToStrParam_Switch_PlayerEquipmentTops = 114 PARAM_WwiseValueToStrParam_Switch_PlayerEquipmentBottoms = 115 PARAM_WwiseValueToStrParam_Switch_PlayerVoiceType = 116 PARAM_WwiseValueToStrParam_Switch_AttackStrength = 117 PARAM_WwiseValueToStrParam_EnvPlaceType = 118 PARAM_WeatherParam = 119 PARAM_WeatherLotParam = 120 PARAM_WeatherAssetCreateParam = 121 PARAM_WeatherAssetReplaceParam = 122 PARAM_SpeedtreeParam = 123 PARAM_RideParam = 124 PARAM_SeActivationRangeParam = 125 PARAM_RollingObjLotParam = 126 PARAM_NpcAiBehaviorProbability = 127 PARAM_BuddyParam = 128 PARAM_GparamRefSettings = 129 PARAM_RandomAppearParam = 130 PARAM_MapGridCreateHeightLimitInfoParam = 131 PARAM_EnvObjLotParam = 132 PARAM_MapDefaultInfoParam = 133 PARAM_BuddyStoneParam = 134 PARAM_LegacyDistantViewPartsReplaceParam = 135 PARAM_SoundCommonIngameParam = 136 PARAM_SoundAutoEnvSoundGroupParam = 137 PARAM_SoundAutoReverbEvaluationDistParam = 138 PARAM_SoundAutoReverbSelectParam = 139 PARAM_EnemyCommonParam = 140 PARAM_GameSystemCommonParam = 141 PARAM_GraphicsCommonParam = 142 PARAM_MenuCommonParam = 143 PARAM_PlayerCommonParam = 144 PARAM_CutsceneGparamWeatherParam = 145 PARAM_CutsceneGparamTimeParam = 146 PARAM_CutsceneTimezoneConvertParam = 147 PARAM_CutsceneWeatherOverrideGparamConvertParam = 148 PARAM_SoundCutsceneParam = 149 PARAM_ChrActivateConditionParam = 150 PARAM_CutsceneMapIdParam = 151 PARAM_CutSceneTextureLoadParam = 152 PARAM_GestureParam = 153 PARAM_EquipParamGem = 154 PARAM_EquipParamCustomWeapon = 155 PARAM_GraphicsConfig = 156 PARAM_SoundChrPhysicsSeParam = 157 PARAM_FeTextEffectParam = 158 PARAM_CoolTimeParam = 159 PARAM_WhiteSignCoolTimeParam = 160 PARAM_MapPieceTexParam = 161 PARAM_MapNameTexParam = 162 PARAM_WeatherLotTexParam = 163 PARAM_KeyAssignParam_TypeA = 164 PARAM_KeyAssignParam_TypeB = 165 PARAM_KeyAssignParam_TypeC = 166 PARAM_MapGdRegionInfoParam = 167 PARAM_MapGdRegionDrawParam = 168 PARAM_KeyAssignMenuItemParam = 169 PARAM_SoundAssetSoundObjEnableDistParam = 170 PARAM_SignPuddleParam = 171 PARAM_AutoCreateEnvSoundParam = 172 PARAM_WwiseValueToStrParam_BgmBossChrIdConv = 173 PARAM_ResistCorrectParam = 174 PARAM_PostureControlParam_WepRight = 175 PARAM_PostureControlParam_WepLeft = 176 PARAM_PostureControlParam_Gender = 177 PARAM_PostureControlParam_Pro = 178 PARAM_RuntimeBoneControlParam = 179 PARAM_TutorialParam = 180 PARAM_BaseChrSelectMenuParam = 181 PARAM_MimicryEstablishmentTexParam = 182 PARAM_SfxBlockResShareParam = 183 PARAM_FinalDamageRateParam = 184 PARAM_HitEffectSeParam = 185 ------------------------------------------ --Custom Acts from Scripts-Data-Exposer ------------------------------------------ --Writes a value at the specified location --4th param is bitOffset if value type is BIT, otherwise it's the first pointer offset. --WARNING: OFFSETS THAT LEAD TO AN INVALID (BUT NOT NULL/0) POINTER WILL CRASH WritePointerChain = 10000 --args , , , , --Updates the player's magic module's id to the equipped magic slot, allowing the proper usage of magic with irregular methods. --See UpdateMagicIndexFully() UpdateMagicIdToActive = 10002 --Set event flag SetEventFlag = 10003 --args , --Set param value. --bitOffset only used if value type is BIT SetParamValue = 10004 --args , , , , , --Identical to ESD's ReplaceTool (function 59) ESD_ReplaceTool = 10159 --args , , ------------------------------------------ --Example functions utilizing the added acts/envs ------------------------------------------ local CHR_MODULES = 0x190 local DATA_MODULE = 0x0 local FP_MAX = 0x14C function GetFpMax() return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, CHR_MODULES, DATA_MODULE, FP_MAX) end function GetFpRate() return env(GetFp) / GetFpMax() end function ExposePrint(v) act(ExposeDebugPrint, tostring(v)) end local BEHAVIOR_MODULE = 0x28 local SPEED_MODIFIER = 0x17C8 function SetTargetSpeedModifier(modifier) act(WritePointerChain, TARGET_CHR_INS_BASE, FLOAT, modifier, CHR_MODULES, BEHAVIOR_MODULE, SPEED_MODIFIER) end --Helper functions used because env always returns an int, TraversePointerChain returns 1.0f in its int representation 0x3f800000 --Not very sophisticated, doesn't take into account NaN/Infs local factorsBy2 = {} local divisionsBy2 = {} for i = -127, 127 do factorsBy2[i] = math.pow(2, i) divisionsBy2[i] = math.pow(2, -i) end bit = {} function bit.rightShift(v, count) return math.floor(v * divisionsBy2[count]) end function bit.leftShift(v, count) return math.floor(v * factorsBy2[count]) end --Does this fully work? function bit.bAnd(v, mask) local res = 0 for i = 1, 31 do if mask % 2 == 1 then res = res + factorsBy2[i - 1] * (v % 2) end v = bit.rightShift(v, 1) mask = bit.rightShift(mask, 1) end return res end function IntBitsToFloat(val) if val == 0 then return 0 end local sign = bit.rightShift(val, 31) if sign ~= 0 then val = val + 0x80000000 end local expo = bit.rightShift(val, 23) - 127 local mantissa = bit.bAnd(val, 0x007fffff) local result = 0 for i = 0, 22 do if bit.rightShift(mantissa, i) % 2 == 1 then result = result + divisionsBy2[23 - i] end end result = (1 * factorsBy2[expo]) * (1 + result) if sign ~= 0 then result = -result end return result end local PHYSICS_MODULE = 0x68 local POS = 0x70 function GetPosition() local x = IntBitsToFloat(env(TraversePointerChain, CHR_INS_BASE, FLOAT, CHR_MODULES, PHYSICS_MODULE, POS + 0)) local y = IntBitsToFloat(env(TraversePointerChain, CHR_INS_BASE, FLOAT, CHR_MODULES, PHYSICS_MODULE, POS + 4)) local z = IntBitsToFloat(env(TraversePointerChain, CHR_INS_BASE, FLOAT, CHR_MODULES, PHYSICS_MODULE, POS + 8)) return {x = x, y = y, z = z} end local WORLD_CHR_MAN = 0x3CDCDD8 local LOCAL_PLAYER = 0x1E508 function GetLocalPlayerPosition() local x = IntBitsToFloat(env(TraversePointerChain, GAME_BASE, FLOAT, WORLD_CHR_MAN, LOCAL_PLAYER, CHR_MODULES, PHYSICS_MODULE, POS + 0)) local y = IntBitsToFloat(env(TraversePointerChain, GAME_BASE, FLOAT, WORLD_CHR_MAN, LOCAL_PLAYER, CHR_MODULES, PHYSICS_MODULE, POS + 4)) local z = IntBitsToFloat(env(TraversePointerChain, GAME_BASE, FLOAT, WORLD_CHR_MAN, LOCAL_PLAYER, CHR_MODULES, PHYSICS_MODULE, POS + 8)) return {x = x, y = y, z = z} end function GetDistanceFromLocalPlayer() local playerPos = GetLocalPlayerPosition() local pos = GetPosition() local diffX = playerPos.x - pos.x local diffY = playerPos.y - pos.y local diffZ = playerPos.z - pos.z return math.sqrt(diffX*diffX + diffY*diffY + diffZ*diffZ) end local FP = 0x148 function SetFp(fp) act(WritePointerChain, CHR_INS_BASE, SIGNED_INT, fp, CHR_MODULES, DATA_MODULE, FP) end local CHR_FLAGS_1 = 0x530 local NO_HIT_BIT_OFFSET = 3 function SetChrDebugNoHit(noHit) if noHit ~= TRUE and noHit ~= FALSE then return end act(WritePointerChain, CHR_INS_BASE, BIT, noHit, NO_HIT_BIT_OFFSET, CHR_FLAGS_1) end function IsPlayer() if env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, 0x64) == 0 then return TRUE end return FALSE end local SUPERARMOR_MODULE = 0x40 local POISE = 0x10 local UNK_FOR_POISE_TIMER = 0x14 function HalfEverythingsPoise() local size = env(TraversePointerChain, GAME_BASE, UNSIGNED_INT, WORLD_CHR_MAN, CHR_ENTRY_LIST_END) - env(TraversePointerChain, GAME_BASE, UNSIGNED_INT, WORLD_CHR_MAN, CHR_ENTRY_LIST_START) if size == 0 then return end --i = 1 to skip yourself for offset = 0x10, size, 0x10 do local poise = env(TraversePointerChain, GAME_BASE, FLOAT, WORLD_CHR_MAN, CHR_ENTRY_LIST_START, offset, CHR_MODULES, SUPERARMOR_MODULE, POISE) poise = IntBitsToFloat(poise) act(WritePointerChain, GAME_BASE, FLOAT, poise/2, WORLD_CHR_MAN, CHR_ENTRY_LIST_START, offset, CHR_MODULES, SUPERARMOR_MODULE, POISE) act(WritePointerChain, GAME_BASE, FLOAT, -1, WORLD_CHR_MAN, CHR_ENTRY_LIST_START, offset, CHR_MODULES, SUPERARMOR_MODULE, UNK_FOR_POISE_TIMER) end end function UpdateMagicIndexFully() act(UpdateMagicIdToActive) act(2026) --UpdateMagicIndexToMagicId end local CHR_CTRL = 0x58 local CHR_MANIPULATOR = 0x18 local AI = 0xC0 local NPC_THINK_ID = 0x28 function GetNpcThinkParamId() return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, CHR_CTRL, CHR_MANIPULATOR, AI, NPC_THINK_ID) end local CANNOT_MOVE_ANIM_OFFSET function GetCannotMoveAnim() local think = GetNpcThinkParamId() if think == INVALID or think == 0 then return INVALID end return env(GetParamValue, PARAM_NpcThinkParam, think, CANNOT_MOVE_ANIM_OFFSET, SIGNED_INT) end function SetCannotMoveAnim(anim) local think = GetNpcThinkParamId() if think == INVALID or think == 0 then return end act(SetParamValue, PARAM_NpcThinkParam, think, CANNOT_MOVE_ANIM_OFFSET, SIGNED_INT, anim) end local IS_CONSUMED_BYTE = 0x48 local IS_CONSUMED_BIT_OFFSET = 7 function SetItemNotConsumed(goodsId) act(SetParamValue, PARAM_EquipParamGoods, goodsId, IS_CONSUMED_BYTE, BIT, 0, IS_CONSUMED_BIT_OFFSET) end local FULL_PHYSICK = 250 local EMPTY_PHYSICK = 251 function RefillPhysick() act(ESD_ReplaceTool, FULL_PHYSICK, FULL_PHYSICK) act(ESD_ReplaceTool, EMPTY_PHYSICK, FULL_PHYSICK) end --[[ -- Erd-Tools Ptrs public enum ChrIns { ArmStyle = 0x328, CurrWepSlotOffsetLeft = 0x32C, CurrWepSlotOffsetRight = 0x330, LHandWeapon1 = 0x39C, LHandWeapon2 = 0x3A4, LHandWeapon3 = 0x3AC, RHandWeapon1 = 0x3A0, RHandWeapon2 = 0x3A8, RHandWeapon3 = 0x3B0, Arrow1 = 0x3B4, Bolt1 = 0x3B8, Arrow2 = 0x3BC, Bolt2 = 0x3C0 } ]] local PLAYER_GAME_DATA = 0x580 local EQUIP_GAME_DATA = 0x2b0 local CHR_ASM = 0x70 local ARM_STYLE = 0x8 -- byte local CURR_WEP_SLOT_OFFSET_LEFT = ARM_STYLE + (0x32C - 0x328) -- int local CURR_WEP_SLOT_OFFSET_RIGHT = ARM_STYLE + (0x330 - 0x328) -- int local L_HAND_WEAPON_1 = ARM_STYLE + (0x39C - 0x328) -- int local L_HAND_WEAPON_2 = ARM_STYLE + (0x3A4 - 0x328) -- int local L_HAND_WEAPON_3 = ARM_STYLE + (0x3AC - 0x328) -- int local R_HAND_WEAPON_1 = ARM_STYLE + (0x3A0 - 0x328) -- int local R_HAND_WEAPON_2 = ARM_STYLE + (0x3A8 - 0x328) -- int local R_HAND_WEAPON_3 = ARM_STYLE + (0x3B0 - 0x328) -- int local ARROW_1 = ARM_STYLE + (0x3B4 - 0x328) -- int local BOLT_1 = ARM_STYLE + (0x3B8 - 0x328) -- int local ARROW_2 = ARM_STYLE + (0x3BC - 0x328) -- int local BOLT_2 = ARM_STYLE + (0x3C0 - 0x328) -- int --local dataToGet = BOLT_1 --minhkslib.puts(env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + dataToGet)) function getCurrentRHWeapon() -- no need for setting weapons, just edit the params local handOffset = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + CURR_WEP_SLOT_OFFSET_RIGHT) if handOffset == 0 then return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + R_HAND_WEAPON_1) elseif handOffset == 1 then return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + R_HAND_WEAPON_2) elseif handOffset == 2 then return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + R_HAND_WEAPON_3) end end function getCurrentLHWeapon() local handOffset = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + CURR_WEP_SLOT_OFFSET_LEFT) if handOffset == 0 then return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + L_HAND_WEAPON_1) elseif handOffset == 1 then return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + L_HAND_WEAPON_2) elseif handOffset == 2 then return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + L_HAND_WEAPON_3) end end function getEquippedSetup() local weaponTable = {} weaponTable["RH1"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + R_HAND_WEAPON_1) weaponTable["RH2"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + R_HAND_WEAPON_2) weaponTable["RH3"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + R_HAND_WEAPON_3) weaponTable["LH1"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + L_HAND_WEAPON_1) weaponTable["LH2"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + L_HAND_WEAPON_2) weaponTable["LH3"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + L_HAND_WEAPON_3) weaponTable["Arrow1"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + ARROW_1) weaponTable["Bolt1"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + BOLT_1) weaponTable["Arrow2"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + ARROW_2) weaponTable["Bolt2"] = env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + BOLT_2) return weaponTable end -- handedness -- 3 = BHR -- 2 = BHL -- 1 = 1H -- 0 = no hands -- 4+/0- = invalid = weapons in both right function getHandedness() return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + ARM_STYLE) end function setHandedness(handedness) act(WritePointerChain, CHR_INS_BASE, SIGNED_INT, handedness, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + ARM_STYLE) end function getRHWeaponOffset() return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + CURR_WEP_SLOT_OFFSET_RIGHT) end function getLHWeaponOffset() return env(TraversePointerChain, CHR_INS_BASE, SIGNED_INT, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + CURR_WEP_SLOT_OFFSET_LEFT) end function setRHWeaponOffset(offset) act(WritePointerChain, CHR_INS_BASE, SIGNED_INT, offset, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + CURR_WEP_SLOT_OFFSET_RIGHT) end function setLHWeaponOffset(offset) act(WritePointerChain, CHR_INS_BASE, SIGNED_INT, offset, PLAYER_GAME_DATA, EQUIP_GAME_DATA + CHR_ASM + CURR_WEP_SLOT_OFFSET_LEFT) end function SetParamRowValue(offsetTable, paramId, attribute, value) if paramId == -1 then return false, "invalid row" end local param = offsetTable local paramType = param["paramType"] local id = paramId local attributeOffset = param["offsetTable"][attribute]["offsetDec"] local attributeTypeStr = param["offsetTable"][attribute]["typeof"] if g_debugMode then minhkslib.puts("Changing value in param: " .. paramType .. " in row: " .. id .. " of attribute: " .. attribute .. " to be: " .. value) end if attributeTypeStr == "bit" then if g_debugMode then minhkslib.puts(math.floor(attributeOffset) .. " bytes + bits: ".. math.floor((attributeOffset - math.floor(attributeOffset)) * 8)) end act(SetParamValue, paramType, id, math.floor(attributeOffset), BIT, value, math.floor((attributeOffset - math.floor(attributeOffset)) * 8)) return true, "bit op complete!" end if attributeTypeStr == "u8" then act(SetParamValue, paramType, id, math.floor(attributeOffset), UNSIGNED_BYTE, value) return true, "u8 op complete!" end if attributeTypeStr == "s8" then act(SetParamValue, paramType, id, math.floor(attributeOffset), SIGNED_BYTE, value) return true, "s8 op complete!" end if attributeTypeStr == "u16" then act(SetParamValue, paramType, id, math.floor(attributeOffset), UNSIGNED_SHORT, value) return true, "u16 op complete!" end if attributeTypeStr == "s16" then act(SetParamValue, paramType, id, math.floor(attributeOffset), SIGNED_SHORT, value) return true, "s16 op complete!" end if attributeTypeStr == "u32" then act(SetParamValue, paramType, id, math.floor(attributeOffset), UNSIGNED_INT, value) return true, "u32 op complete!" end if attributeTypeStr == "s32" then act(SetParamValue, paramType, id, math.floor(attributeOffset), SIGNED_INT, value) return true, "s32 op complete!" end if attributeTypeStr == "f32" then act(SetParamValue, paramType, id, math.floor(attributeOffset), FLOAT, value) return true, "f32 op complete!" end if attributeTypeStr == "f64" then return false, "f64 not supported" end return false, "no op performed" end function GetParamRowValue(offsetTable, paramId, attribute) if paramId == -1 then return nil, "invalid row" end local param = offsetTable local paramType = param["paramType"] local id = paramId local attributeOffset = param["offsetTable"][attribute]["offsetDec"] local attributeTypeStr = param["offsetTable"][attribute]["typeof"] if g_debugMode then minhkslib.puts("Getting value from param: " .. paramType .. " in row: " .. id .. " of attribute: " .. attribute) end if attributeTypeStr == "bit" then local value = env(GetParamValue, paramType, id, math.floor(attributeOffset), BIT, math.round(attributeOffset - math.floor(attributeOffset))) -- bit iffy coz there's no example in newhksinfo return value, "bit op complete!" elseif attributeTypeStr == "u8" then local value = env(GetParamValue, paramType, id, math.floor(attributeOffset), UNSIGNED_BYTE) return value, "u8 op complete!" elseif attributeTypeStr == "s8" then local value = env(GetParamValue, paramType, id, math.floor(attributeOffset), SIGNED_BYTE) return value, "s8 op complete!" elseif attributeTypeStr == "u16" then local value = env(GetParamValue, paramType, id, math.floor(attributeOffset), UNSIGNED_SHORT)return value, "u16 op complete!" elseif attributeTypeStr == "s16" then local value = env(GetParamValue, paramType, id, math.floor(attributeOffset), SIGNED_SHORT) return value, "s16 op complete!" elseif attributeTypeStr == "u32" then local value = env(GetParamValue, paramType, id, math.floor(attributeOffset), UNSIGNED_INT) return value, "u32 op complete!" elseif attributeTypeStr == "s32" then local value = env(GetParamValue, paramType, id, math.floor(attributeOffset), SIGNED_INT) return value, "s32 op complete!" elseif attributeTypeStr == "f32" then return nil, "f32 get not supported" elseif attributeTypeStr == "f64" then return nil, "f64 not supported" end return nil, "no op performed" end function copyRow(offsetTable, sourceRowID, destRowID) local param = offsetTable local paramType = param["paramType"] local paramLength = param["sizeOf"] local sourceId = sourceRowID local destId = destRowID for i = 0, paramLength - 1 do local sourceByte = env(GetParamValue, paramType, sourceId, i, UNSIGNED_BYTE) act(SetParamValue, paramType, destId, i, UNSIGNED_BYTE, sourceByte) end if g_debugMode then minhkslib.puts("Copied row from " .. sourceRowID .. " to " .. destRowID) end end function NumberToBytes(number) local bytes = {} for i = 1, 4 do bytes[i] = string.char(number % 256) number = math.floor(number / 256) end return table.concat(bytes) end function BytestoNumber(byteString) local number = 0 for i = 4, 1, -1 do number = number * 256 + string.byte(byteString, i) end return number end function initDeepBackups() act(SetParamValue, PARAM_EnemyCommonParam, 1, 0, UNSIGNED_BYTE, 1) -- marks the deep backups as inited in param memory if g_debugMode then minhkslib.puts("Deep backups storage inited") end local rowOffset = 1000 for paramType, rowID, rowSize in iterateDeepBackUpRows() do local paramLength = rowSize local sourceId = rowID local destId = rowID local byteString = NumberToBytes(destId) for i = 1, 4 do act(SetParamValue, PARAM_EnemyCommonParam, rowOffset, i - 1, UNSIGNED_BYTE, string.byte(byteString, i)) end byteString = NumberToBytes(paramType) for i = 1, 4 do act(SetParamValue, PARAM_EnemyCommonParam, rowOffset, i + 3, UNSIGNED_BYTE, string.byte(byteString, i)) end byteString = NumberToBytes(paramLength) for i = 1, 4 do act(SetParamValue, PARAM_EnemyCommonParam, rowOffset, i + 7, UNSIGNED_BYTE, string.byte(byteString, i)) end -- store first 4 bytes of row as the id of the row to back up and the second 4 bytes as the param type of the row to back up for i = 12, paramLength - 1 do local sourceByte = env(GetParamValue, paramType, sourceId, i - 12, UNSIGNED_BYTE) act(SetParamValue, PARAM_EnemyCommonParam, rowOffset + math.floor(i / 256), i % 256, UNSIGNED_BYTE, sourceByte) --minhkslib.puts("Byte " .. i - 12 .. " is " .. sourceByte .. " in row " .. rowID .. " in param " .. paramType .. " is now byte " .. i - 12 .. " in row " .. rowOffset .. " in enemycommonparam with value " .. env(GetParamValue, PARAM_EnemyCommonParam, rowOffset + math.floor(i / 256), i % 256, UNSIGNED_BYTE)) end if g_debugMode then minhkslib.puts("Copied to deep copy row from " .. destId .. " in param " .. paramType .. "to " .. rowOffset) end rowOffset = rowOffset + 1000 end end function readDeepBackups() if g_debugMode then minhkslib.puts("Deep backups read inited") end local rowOffset = 1000 while (true) do local bytes = {} for i = 0, 3 do table.insert(bytes, env(GetParamValue, PARAM_EnemyCommonParam, rowOffset, i, UNSIGNED_BYTE)) end local rowID = BytestoNumber(string.char(unpack(bytes))) if rowID == 0 then break end bytes = {} for i = 4, 7 do table.insert(bytes, env(GetParamValue, PARAM_EnemyCommonParam, rowOffset, i, UNSIGNED_BYTE)) end local paramType = BytestoNumber(string.char(unpack(bytes))) bytes = {} for i = 8, 11 do table.insert(bytes, env(GetParamValue, PARAM_EnemyCommonParam, rowOffset, i, UNSIGNED_BYTE)) end local paramLength = BytestoNumber(string.char(unpack(bytes))) for i = 12, paramLength - 1 do local sourceByte = env(GetParamValue, PARAM_EnemyCommonParam, rowOffset + math.floor(i / 256), i % 256, UNSIGNED_BYTE) act(SetParamValue, paramType, rowID, i - 12, UNSIGNED_BYTE, sourceByte) --minhkslib.puts("Byte " .. i - 12 .. " is " .. sourceByte .. " in row " .. rowID .. " in param " .. paramType .. " is now byte " .. i - 12 .. " in row " .. rowOffset .. " in enemycommonparam with value " .. env(GetParamValue, paramType, rowID, i - 12, UNSIGNED_BYTE, sourceByte)) end if g_debugMode then minhkslib.puts("Copied row in deep copy from " .. rowOffset .. " to " .. rowID .. " in param: " .. paramType) end rowOffset = rowOffset + 1000 end end function checkDeepBackupsInited() local sourceByte = env(GetParamValue, PARAM_EnemyCommonParam, 1, 0, UNSIGNED_BYTE) if sourceByte == 0 then minhkslib.puts("No deep backups found, initializing deep backups of the following:" .. json.encode(g_deepBackUpRows)) initDeepBackups() else minhkslib.puts("Deep backups found. Reading based on the following:" .. json.encode(g_deepBackUpRows)) readDeepBackups() end g_backUpsProcessDone = true end g_deepBackUpRows = {} -- something doesn't compile in the below sections function iterateDeepBackUpRows() local index = 0 return function() index = index + 1 if g_deepBackUpRows[index] then return g_deepBackUpRows[index].paramType, g_deepBackUpRows[index].rowID, g_deepBackUpRows[index].rowSize end end end function addToDeepBackups(paramOffset, rowID) -- you should not store the 0 row in the deep backups table.insert(g_deepBackUpRows, {paramType = paramOffset["paramType"], rowID = rowID, rowSize = paramOffset["sizeOf"]}) end -- Global table to hold all tempAllocatedRows tempAllocatedRows = {} -- Function to generate a unique rowID for tempAllocatedRows function generateUniqueRowID(paramType, startingRowValue, maxRowOffsetValue) local id = 0 repeat id = math.random(startingRowValue, startingRowValue + maxRowOffsetValue) until not tempAllocatedRows[paramType][id] return id end -- Constructor function for tempAllocatedRow objects function tempAllocatedRow(paramOffset, rowToCopyFrom, name, survivalTime, startingRowValue, endingRowValue) -- Initialize table for the specified paramType if not already present if not tempAllocatedRows[paramOffset["paramType"]] then tempAllocatedRows[paramOffset["paramType"]] = {} end local rowID = generateUniqueRowID(paramOffset["paramType"], startingRowValue, endingRowValue - startingRowValue) local currentTime = os.clock() local obj = { ID = rowID, name = name, paramOffset = paramOffset, paramType = paramOffset.paramType, creationTime = currentTime, survivalTime = survivalTime, destructor = function(self) -- Destructor function to remove itself from the table tempAllocatedRows[self.paramType][self.ID] = nil if g_debugMode then minhkslib.puts("tempAllocatedRow with ID " .. self.ID .. " has been destructed.") end end } -- Add object to table based on paramType and ID tempAllocatedRows[obj.paramType][obj.ID] = obj -- Copy data from prototype row copyRow(obj.paramOffset, rowToCopyFrom, obj.ID) if g_debugMode then minhkslib.puts("A tempAllocatedRow with ID: " .. obj.ID .. " with name: " .. obj.name .. " in param:" .. obj.paramType .. " with prototype row of " .. rowToCopyFrom .. " has been created.") end return obj end -- Function to update and check survival time of tempAllocatedRows function allocatedRowsUpdate() local currentTime = tonumber(string.format("%.0f", os.time())) for paramType, rows in pairs(tempAllocatedRows) do for rowID, row in pairs(rows) do if os.clock() - row.creationTime >= row.survivalTime then -- Call destructor function row.destructor(row) end end end end function getAllocatedRowIDFromName(paramOffset, rowName) local paramType = paramOffset["paramType"] local rowsInParam = tempAllocatedRows[paramType] if not rowsInParam then return -1 -- Failed, no rows for the given paramType end for rowID, row in pairs(rowsInParam) do if row.name == rowName then return rowID -- Found the row with the given name, return its ID end end return -1 -- Failed, no row found with the given name end function fireBullet(bulletRowID, dmyPoly) dmyPoly = dmyPoly or 21 local behaviorName = "temp fire bullet firing behavior row " .. math.random(1, 10000) tempAllocatedRow(BehaviorParamPC_Offsets, BEHAVIOR_PARAM_PC_PROTOTYPE_FIRE_BULLETS, behaviorName, 1, BEHAVIOR_PARAM_PC_BLANK_ROW_START, BEHAVIOR_PARAM_PC_BLANK_ROW_END) local spefName = "temp fire bullet firing spef row " .. math.random(1, 10000) tempAllocatedRow(SpEffectParam_Offsets, SPEFFECT_PARAM_PROTOTYPE_FIRE_BULLETS, spefName, 1, SPEFFECT_PARAM_BLANK_ROW_START, SPEFFECT_PARAM_BLANK_ROW_END) -- allocate "anonymous" behaviorparam_pc and a speffect row inheriting from the fire bullet prototype rows local behaviorRowID = getAllocatedRowIDFromName(BehaviorParamPC_Offsets, behaviorName) local spefRowID = getAllocatedRowIDFromName(SpEffectParam_Offsets, spefName) -- get the rowID for reference and set the speffect's behaviorId and dmyPolyId to the allocated row IDs SetParamRowValue(SpEffectParam_Offsets, spefRowID, "behaviorId", behaviorRowID) SetParamRowValue(SpEffectParam_Offsets, spefRowID, "dmypolyId", dmyPoly) -- set the speffect's behavior reference to the behavior row SetParamRowValue(BehaviorParamPC_Offsets, behaviorRowID, "refId", bulletRowID) -- set the behavior row's reference to the bullet row act(2002, spefRowID) -- activate the speffect end -- attempts to find the allocated row for the row name in the allocated param section and if so, terminates it function deallocateRowByName(paramOffset, rowName) local ID = getAllocatedRowIDFromName(paramOffset, rowName) if ID ~= -1 then local idObj = tempAllocatedRows[paramOffset["paramType"]][ID] if idObj then idObj.destructor(idObj) if minhkslib.g_debugMode then minhkslib.puts("Deallocated row with name: " .. rowName) end return true end end if minhkslib.g_debugMode then minhkslib.puts("Failed to deallocate row with name: " .. rowName) end return false end function makeRowBackup(paramOffset, rowID, backupName, allocatedRowIDStart, allocatedRowIDEnd) checkDeepBackupsInited() if getAllocatedRowIDFromName(paramOffset, backupName) ~= -1 then return false, "param row backup exists already" end tempAllocatedRow(paramOffset, rowID, backupName, 7770000, allocatedRowIDStart, allocatedRowIDEnd) if g_debugMode then minhkslib.puts("Created param row backup with name: " .. backupName) end return true, "param row backup created" end function SetWeaponSwordArtsCategoryRight(tae) success, errormsg = SetParamRowValue(EquipParamWeapon_Offsets, getCurrentRHWeapon(), "swordArtsParamId", tae) if g_debugMode then minhkslib.puts(errormsg) end end -- Function to create a detour function createDetour(originalFunction, newFunction) -- Store the original function in the new function's environment local original = originalFunction -- Create a wrapper that calls the new function first, then the original function return function(...) -- Call the new function newFunction(...) -- Call the original function return original(...) end end Update = createDetour(Update, allocatedRowsUpdate)