[0.1.62115] Offsets menu

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 15 of 40
  1. #1
    ejt's Avatar Contributor
    Reputation
    196
    Join Date
    Mar 2008
    Posts
    160
    Thanks G/R
    3/107
    Trade Feedback
    0 (0%)
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    [0.1.62115] Offsets

    UPDATE: This thread is for SHARING information about offsets. If you have questions about using the offsets or other script-kiddie things then go make your own thread.

    There wasn't anything yet so lets bring out heads together and see if we can't get some good info out of this alpha build.

    I haven't looked a lot into the client just yet but this is what I found so far.

    0x1EE2990 is some sort of configuration global that has a lot of fun stuff. Further reversing needed
    Code:
    +0x638	=  ??
    +0x86D 	=  alwaysRegenMapInSP
    +0x86E 	=  alwaysDisplayLifeAndManaValues	
    +0x86F 	=  allowCowPortalWhenCowKingWasKilled
    +0x870 	=  allowLadderRunewords
    +0x871 	=  displayItemLevel			Working, adds (ilvl) to items
    +0x872 	=  allowStatUnassignment		Working (alt-click to unassign stat)
    +0x873 	=  enableUberQuest
    +0x874 	=  allowSkillUnassignment		Tested but not working (tried shift,ctrl,alt with right and left clicks and nothing seem to work) maybe just need to figure out what hotkey works
    +0x875 	=  playerDifficulty			Doesn't seem to be related to /players X, unsure
    +0x87D 	=  enableWorldEventOffline
    +0x87E 	=  enableMultipleHirelings		Works and is very awesome!!
    +0x87F 	=  enableSharedStash			If set to 0 it crashes game when you attempt to insert an item into the shared stash, it does not hide or disable the shared stash.
    +0x881 	=  worldEventMonsterClass
    +0x885 	=  worldEventGlobalMessage
    +0x985 	=  worldEventGlobalSound
    +0xD27	=  if ( (signed int)v5 >= *(_DWORD *)(result + 0xD27) )
    Here's my offsets and structures (updated sometimes maybe)

    Code:
    namespace offset
    {
    	enum D2GameOffsets : uint64_t
    	{
    		// tested globals
    		D2NetLocalClient = 0x1F18970,
    		D2NetServer = 0x1F18900,
    		Difficulty = 0x22DA192,
    		PanelManager = 0x234AF30,
    		AutomapLayer = 0x22E46E8,
    
    		// tested functions
    		GetControlUnitId = 0x14C510,
    		GetControlUnitPtr = 0x157300,
    		GetLayer = 0x296ED0,
    		GetLevel = 0x292740,
    		InitAutomapLayer = 0x176550,
    		InitLevel = 0x292D70,
    		LoadAct = 0x278BD0,
    		LoadAct_1 = 0x172750, // void LoadAct_1(Room1* room)
    		LoadAct_3 = 0x172890,
    		RevealAutomapRoom = 0x177900, // contains retcheck
    		UnloadAct = 0x278A10,
    		AddRoomData = 0x278CE0,
    		RemoveRoomData = 0x279130,
    	};
    }
    Code:
    inline blizz::AutomapLayer2** D2_AutomapLayer = 0;
    inline uint32_t* D2_Difficulty = 0;
    inline uintptr_t D2_SpoofGadget = 0;
    inline uint64_t D2_LoadAct_1 = 0;
    inline uint64_t D2_LoadAct_3 = 0;
    
    static void(__fastcall* D2_AddRoomData)(wector::blizz::Act* actMisc, uint32_t levelNo, uint32_t roomX, uint32_t roomY, wector::blizz::Room1* room1) = nullptr;
    static void(__fastcall* D2_RemoveRoomData)(wector::blizz::Act* actMisc, uint32_t levelNo, uint32_t roomX, uint32_t roomY, wector::blizz::Room1* room1) = nullptr;
    static blizz::Act*(__fastcall* D2_LoadAct)(uint32_t actId, uint32_t seed, bool a3, bool a4, uint32_t difficulty, uint32_t townLevelNo, uint64_t cb1, uint64_t cb2) = nullptr;
    static void(__fastcall* D2_UnloadAct)(blizz::Act* act) = nullptr;
    static blizz::Level* (__fastcall* D2_GetLevel)(blizz::ActMisc* a1, int32_t a2) = nullptr;
    static void(__fastcall* D2_InitLevel)(blizz::Level* a1) = nullptr;
    static blizz::AutomapLayer* (__fastcall* D2_GetLayer)(int32_t levelNo) = nullptr;
    static blizz::AutomapLayer2* (__fastcall* D2_InitAutomapLayer)(int32_t layerNo) = nullptr;
    static void(__fastcall* D2_RevealAutomapRoom)(blizz::Room1* a1, bool a2, blizz::AutomapLayer2* a3) = nullptr;
    static uint32_t(__fastcall* D2_GetControlUnitId)() = nullptr;
    static blizz::UnitAny* (__fastcall* D2_GetControlUnitPtr)(uint32_t id) = nullptr;
    Code:
    class Act;
    class ActMisc;
    class Room;
    class Path;
    class UnitData;
    class Inventory;
    class Skills;
    class Skill;
    class SkillInfo;
    class UnitAny;
    class Room1;
    class Room2;
    class Level;
    class WidgetList;
    class PresetUnit;
    
    // This is 0x9C in size, located in GetLayer (gLayerArray + 0x9C * a1)
    struct AutomapLayer
    {
    	uint32_t unk_0000[2];	// 0x0000
    	uint32_t LayerNo;		// 0x0008
    };
    
    struct AutomapLayer2
    {
    	uint32_t unk_0000[2];	// 0x0000
    	uint32_t LayerNo;		// 0x0008
    	uint32_t unk_000C;		// 0x000C
    };
    
    class Act
    {
    public:
    	char pad_0000[20]; //0x0000
    	int32_t MapSeed; //0x0014
    	Room1* pRoom1; //0x0018
    	uint32_t ActNo; //0x0020
    	char pad_0024[36]; //0x0024
    	size_t MaybeTilesPtr; //0x0048
    	char pad_0050[32]; //0x0050
    	ActMisc* pActMisc; //0x0070
    	char pad_0078[16]; //0x0078
    }; //Size: 0x0088
    static_assert(sizeof(Act) == 0x88);
    
    class CollMap
    {
    public:
    	uint32_t PosGameX; //0x0000
    	uint32_t PosGameY; //0x0004
    	uint32_t SizeGameX; //0x0008
    	uint32_t SizeGameY; //0x000C
    	uint32_t RoomPosX; //0x0010
    	uint32_t RoomPosY; //0x0014
    	uint32_t RoomSizeX; //0x0018
    	uint32_t RoomSizeY; //0x001C
    	char pad_0020[8]; //0x0020
    }; //Size: 0x0028
    static_assert(sizeof(CollMap) == 0x28);
    
    class Inventory
    {
    public:
    	uint32_t InvStamp; //0x0000
    	char pad_0004[4]; //0x0004
    	UnitAny* pOwnerUnit; //0x0008
    	UnitAny* pItemFirst; //0x0010
    	UnitAny* pItemLast; //0x0018
    	char pad_0020[32]; //0x0020
    	UnitAny* pCursorItem; //0x0040
    	char pad_0048[64]; //0x0048
    	Inventory* pOwnerInventory; //0x0088
    }; //Size: 0x0090
    static_assert(sizeof(Inventory) == 0x90);
    
    class ItemData
    {
    public:
    	uint32_t QualityNo; //0x0000
    	char N000005EA[2][8]; //0x0004
    	uint32_t OwnerGuid; //0x0014
    	char pad_0018[8]; //0x0018
    	uint32_t Flags; //0x0020
    	char pad_0024[60]; //0x0024
    }; //Size: 0x0060
    static_assert(sizeof(ItemData) == 0x60);
    
    class Level
    {
    public:
    	char pad_0000[16]; //0x0000
    	Room2* pRoom2First; //0x0010
    	char pad_0018[12]; //0x0018
    	uint32_t PosX; //0x0024
    	uint32_t PosY; //0x0028
    	uint32_t SizeX; //0x002C
    	uint32_t SizeY; //0x0030
    	char pad_0034[388]; //0x0034
    	Level* pLevelNext; //0x01B8
    	char pad_01C0[8]; //0x01C0
    	ActMisc* pActMisc; //0x01C8
    	char pad_01D0[40]; //0x01D0
    	uint32_t LevelNo; //0x01F8
    	char pad_01FC[12]; //0x01FC
    	union //0x0208
    	{
    		int32_t RoomCenterX[9]; //0x0000
    		int32_t WarpX[9]; //0x0000
    	};
    	union //0x022C
    	{
    		int32_t RoomCenterY[9]; //0x0000
    		int32_t WarpY[9]; //0x0000
    	};
    	char pad_0250[56]; //0x0250
    }; //Size: 0x0288
    static_assert(sizeof(Level) == 0x288);
    
    class MonsterData
    {
    public:
    	char pad_0000[8]; //0x0000
    	size_t N0000048D; //0x0008
    	char pad_0010[112]; //0x0010
    }; //Size: 0x0080
    static_assert(sizeof(MonsterData) == 0x80);
    
    class ObjectData
    {
    public:
    	size_t N0000049D; //0x0000
    	char pad_0008[120]; //0x0008
    }; //Size: 0x0080
    static_assert(sizeof(ObjectData) == 0x80);
    
    class OverheadMsg
    {
    public:
    	uint32_t unk_00; //0x0000
    	uint32_t Trigger; //0x0004
    	char pad_0008[16]; //0x0008
    	char Text[200]; //0x0018
    }; //Size: 0x00E0
    static_assert(sizeof(OverheadMsg) == 0xE0);
    
    class Path
    {
    public:
    	uint16_t OffsetX; //0x0000
    	uint16_t PosX; //0x0002
    	uint16_t OffsetY; //0x0004
    	uint16_t PosY; //0x0006
    	char pad_0008[8]; //0x0008
    	uint16_t TargetX; //0x0010
    	uint16_t TargetY; //0x0012
    	char pad_0014[12]; //0x0014
    	Room1* pRoom1; //0x0020
    	Room1* pRoomPrevious; //0x0028
    	char pad_0030[16]; //0x0030
    	UnitAny* pUnit; //0x0040
    	uint32_t Flags; //0x0048
    	char pad_004C[4]; //0x004C
    	uint32_t unk_50; //0x0050
    	char pad_0054[28]; //0x0054
    	UnitAny* pTargetUnit; //0x0070
    	float N000004CE; //0x0078
    	float N000007A6; //0x007C
    	float N000007A8; //0x0080
    	char pad_0084[4]; //0x0084
    }; //Size: 0x0088
    static_assert(sizeof(Path) == 0x88);
    
    class PlayerData
    {
    public:
    	char N000007AA[16]; //0x0000
    	size_t N000004D1; //0x0010
    	size_t N000004D2; //0x0018
    	size_t N000004D3; //0x0020
    	size_t N000004D4; //0x0028
    	size_t N000004D5; //0x0030
    	size_t N000004D6; //0x0038
    }; //Size: 0x0040
    static_assert(sizeof(PlayerData) == 0x40);
    
    class Room1
    {
    public:
    	Room1** pRoomsNear; //0x0000
    	char pad_0008[16]; //0x0008
    	Room2* pRoom2; //0x0018
    	char pad_0020[24]; //0x0020
    	CollMap* Coll; //0x0038
    	uint32_t dwRoomsNear; //0x0040
    	char pad_0044[4]; //0x0044
    	Act* pAct; //0x0048
    	char pad_0050[48]; //0x0050
    	uint32_t StartX; //0x0080
    	uint32_t StartY; //0x0084
    	uint32_t SizeX; //0x0088
    	uint32_t SizeY; //0x008C
    	uint32_t PosX; //0x0090
    	uint32_t PosY; //0x0094
    	uint32_t RoomSizeX; //0x0098
    	uint32_t RoomSizeY; //0x009C
    	char pad_00A0[8]; //0x00A0
    	UnitAny* pUnitFirst; //0x00A8
    	Room1* pRoomNext; //0x00B0
    	char pad_00B8[16]; //0x00B8
    	Room1* pRoomSomething; //0x00C8
    	char pad_00D0[40]; //0x00D0
    }; //Size: 0x00F8
    static_assert(sizeof(Room1) == 0xF8);
    
    class Room2
    {
    public:
    	char pad_0000[16]; //0x0000
    	Room2** pRoom2Near; //0x0010
    	uint32_t RoomsNear; //0x0018
    	char pad_001C[4]; //0x001C
    	uint32_t RoomsNear2; //0x0020
    	char pad_0024[20]; //0x0024
    	Room2* pRoom2_Unsure; //0x0038
    	char pad_0040[8]; //0x0040
    	Room2* pRoom2Next; //0x0048
    	uint32_t RoomFlags; //0x0050
    	char pad_0054[4]; //0x0054
    	Room1* pRoom1; //0x0058
    	uint32_t PosX; //0x0060
    	uint32_t PosY; //0x0064
    	uint32_t SizeX; //0x0068
    	uint32_t SizeY; //0x006C
    	char pad_0070[32]; //0x0070
    	Level* pLevel; //0x0090
    	PresetUnit* pPreset; //0x0098
    }; //Size: 0x00A0
    static_assert(sizeof(Room2) == 0xA0);
    
    class Skills
    {
    public:
    	Skill* pAttackSkill; //0x0000
    	Skill* pLeftSkill; //0x0008
    	Skill* pRightSkill; //0x0010
    	char pad_0018[16]; //0x0018
    	Skill* pMercSkill; //0x0028
    	char pad_0030[32]; //0x0030
    	Skill* pUnkSkill; //0x0050
    }; //Size: 0x0058
    static_assert(sizeof(Skills) == 0x58);
    
    class Skill
    {
    public:
    	SkillInfo* pSkillInfo; //0x0000
    	Skill* pSkillNext; //0x0008
    	char pad_0010[32]; //0x0010
    	uint32_t Level; //0x0030
    	uint32_t unk_34; //0x0034
    	uint32_t Charges; //0x0038
    	uint32_t unk_3C; //0x003C
    }; //Size: 0x0040
    static_assert(sizeof(Skill) == 0x40);
    
    class SkillInfo
    {
    public:
    	uint16_t Id; //0x0000
    	char Name[34]; //0x0002
    }; //Size: 0x0024
    static_assert(sizeof(SkillInfo) == 0x24);
    
    class UnitAny
    {
    public:
    	uint32_t UnitType; //0x0000
    	uint32_t UnitTxtId; //0x0004
    	uint32_t UnitId; //0x0008
    	uint32_t PMode; //0x000C
    	union //0x0010
    	{
    		PlayerData* PlayerData; //0x0000
    		MonsterData* MonsterData; //0x0000
    		ItemData* ItemData; //0x0000
    		ObjectData* ObjectData; //0x0000
    	};
    	char pad_0018[8]; //0x0018
    	Act* pAct; //0x0020
    	uint32_t Seed[2]; //0x0028
    	char pad_0030[8]; //0x0030
    	Path* pPath; //0x0038
    	char pad_0040[40]; //0x0040
    	uint32_t StateFlags; //0x0068
    	uint8_t EventType; //0x006C
    	char pad_006D[3]; //0x006D
    	size_t pClassCOF; //0x0070
    	char pad_0078[24]; //0x0078
    	Inventory* pInventory; //0x0090
    	char pad_0098[8]; //0x0098
    	size_t CurrentAction; //0x00A0
    	size_t LastAction; //0x00A8
    	char pad_00B0[12]; //0x00B0
    	uint16_t PosX; //0x00BC
    	uint16_t PosY; //0x00BE
    	char pad_00C0[40]; //0x00C0
    	OverheadMsg* OverheadMsg; //0x00E8
    	Skills* Skills; //0x00F0
    	char pad_00F8[28]; //0x00F8
    	uint32_t Flags; //0x0114
    	char pad_0118[48]; //0x0118
    	UnitAny* pUnitNext; //0x0148
    	char pad_0150[16]; //0x0150
    }; //Size: 0x0160
    static_assert(sizeof(UnitAny) == 0x160);
    
    class Widget
    {
    public:
    	char* pName; //0x0008
    	uint64_t NameLen; //0x0010
    	char pad_0018[24]; //0x0018
    	Widget* Parent; //0x0030
    	char pad_0038[24]; //0x0038
    	uint32_t Flags; //0x0050 flags & 0x101 = visible
    	char pad_0054[4]; //0x0054
    	Widget** Children; //0x0058
    	uint64_t numElements; //0x0060
    	uint64_t allocated; //0x0068
    	char pad_0070[24]; //0x0070
    
    	virtual void Function0() {}
    	virtual void Function1() {}
    	virtual void Function2() {}
    	virtual void Function3() {}
    	virtual void Function4() {}
    	virtual void Function5() {}
    	virtual void Function6() {}
    	virtual void Function7() {}
    	virtual void Function8() {}
    	virtual void Function9() {}
    }; //Size: 0x0088
    static_assert(sizeof(Widget) == 0x88);
    
    class Panel : public Widget
    {
    public:
    }; //Size: 0x0088
    static_assert(sizeof(Panel) == 0x88);
    
    class PanelManager : public Widget
    {
    public:
    	Widget** pWidgetList; //0x0088
    	uint64_t numElements; //0x0090
    	uint64_t allocated; //0x0098
    	Widget** pWidgetList2; //0x00A0
    	uint64_t numElements2; //0x00A8
    	uint64_t allocated2; //0x00B0
    	uint32_t N0000432E; //0x00B8
    	uint32_t ScreenWidth; //0x00BC
    	uint32_t ScreenHeight; //0x00C0
    	char pad_00C4[4]; //0x00C4
    	Widget* ActiveModal; //0x00C8
    	Widget* GlobalData; //0x00D0
    	Widget* FocusManager; //0x00D8
    	char pad_00E0[16]; //0x00E0
    }; //Size: 0x00F0
    static_assert(sizeof(PanelManager) == 0xF0);
    
    class ActMisc
    {
    public:
    	char pad_0000[288]; //0x0000
    	uint32_t StaffTombLevel; //0x0120
    	char pad_0124[516]; //0x0124
    	Room2* pRoom2First; //0x0328
    	char pad_0330[368]; //0x0330
    	Room2* pRoom2Other; //0x04A0
    	char pad_04A8[64]; //0x04A8
    	Room2* N00000828; //0x04E8
    	char pad_04F0[368]; //0x04F0
    	Room2* pRoom2HowManyAreThere; //0x0660
    	char pad_0668[64]; //0x0668
    	Room2* pRoom2OhGodAnotherOne; //0x06A8
    	char pad_06B0[424]; //0x06B0
    	Act* pAct; //0x0858
    	char pad_0860[8]; //0x0860
    	Level* pLevelFirst; //0x0868
    	uint8_t ActNo; //0x0870
    	char pad_0871[7]; //0x0871
    }; //Size: 0x0878
    static_assert(sizeof(ActMisc) == 0x878);
    
    class PresetUnit
    {
    public:
    	char pad_0000[4]; //0x0000
    	uint32_t TxtFileNo; //0x0004 Unconfirmed
    	uint32_t PosX; //0x0008 unconfirmed
    	char pad_000C[4]; //0x000C
    	PresetUnit* pPresetNext; //0x0010
    	char pad_0018[8]; //0x0018
    	uint32_t Type; //0x0020 Unconfirmed
    	uint32_t PosY; //0x0024 Unconfirmed
    	char pad_0028[32]; //0x0028
    }; //Size: 0x0048
    static_assert(sizeof(PresetUnit) == 0x48);
    Last edited by ejt; 04-26-2021 at 12:27 AM. Reason: Added offsets, function definitions and structures

    These ads disappear when you log in.

  2. Thanks dschu012, Crazyloon, MrNoble, Vilavek, Flamberge, lanzajamones, toadskin, djain, svs, malloc84 (10 members gave Thanks to ejt for this useful post)
  3. #2
    Crazyloon's Avatar Member
    Reputation
    6
    Join Date
    Apr 2021
    Posts
    5
    Thanks G/R
    2/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Any idea how we can apply these patches using Ferib's method of bypassing crc32 checks?

    We've got a text file that should make it pretty easy to apply additional patches... it looks like this:

    Code:
    0xD4AD68:9090
    0xD4E25F:909090909090
    0xCAFB9D:90B001
    0x597E1C:90909090909090
    0xC5E81C:9090C346455242: ~ MP stack corruption bypass
    0xD615F2:909090909090909090909090909090909090909090909090909090: ~ show all calsses on load (shalzuth)
    0x39FC03:9090909090909090909090909090909090909090: ~ allow chars to load (shalzuth)
    I want to do something like this to display item levels:
    0x1EE2990:871

  4. #3
    ejt's Avatar Contributor
    Reputation
    196
    Join Date
    Mar 2008
    Posts
    160
    Thanks G/R
    3/107
    Trade Feedback
    0 (0%)
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    You need to modify the memory using cheat engine or some other software that can modify it. It is a 8-bit integer, 0 = false 1 = true

  5. #4
    Crazyloon's Avatar Member
    Reputation
    6
    Join Date
    Apr 2021
    Posts
    5
    Thanks G/R
    2/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah, ok... never mind I figured it out.


    adding
    0x1EE3201:90
    to patches.txt will make item levels show

    I'm still testing the rest

    NOTE: Using this approach will not work in any version since I posted this. There is a race condition causing them to be overwritten. The suggested approach is to use Cheat Engine to modify these values manually.
    0x1EE3200:90: ~ allowLadderRunewords
    0x1EE3201:90: ~ displayItemLevel
    0x1EE31FF:90: ~ allowCowPortalWhenCowKingWasKilled
    0x1EE3203:90 ~ enableUberQuest
    0x1EE3202:90: ~ allowStatUnassignment
    0x1EE3204:90: ~ allowSkillUnassignment (doesn't seem to be working)
    0x1EE320D:90: ~ enableWorldEventOffline (Assume Uber Diablo - haven't tested)
    0x1EE320E:90: ~ enableMultipleHirelings
    //0x1EE3211:90: ~ worldEventMonsterClass (probably needs correct ID for Uber Diablo)
    //0x1EE3215:90: ~ worldEventGlobalMessage (probably needs correct ID for the string to reference)
    //0x1EE3315:90: ~ worldEventGlobalSound (probably needs correct ID for audio file to reference)
    Last edited by Crazyloon; 04-19-2021 at 11:26 AM.

  6. Thanks ZeltMarv, Flamberge (2 members gave Thanks to Crazyloon for this useful post)
  7. #5
    oclurker's Avatar Member
    Reputation
    1
    Join Date
    Apr 2021
    Posts
    2
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    +0x870 = allowLadderRunewords
    0x1EE3200:90: ~ allowLadderRunewords
    can confirm ladderrunewords are enabled!

    Ty sir @ejt

  8. #6
    ZeltMarv's Avatar Member
    Reputation
    1
    Join Date
    Apr 2021
    Posts
    5
    Thanks G/R
    4/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you!!

    Any chance you could find a patch to enable "alwaysRegenMapInSP"?

    EDIT:

    0x1EE31FC:90: ~ AlwaysRegenMapInSP

    This seems to be the switch but it doesn't seem to do anything.
    Last edited by ZeltMarv; 04-16-2021 at 08:40 PM.

  9. #7
    ejt's Avatar Contributor
    Reputation
    196
    Join Date
    Mar 2008
    Posts
    160
    Thanks G/R
    3/107
    Trade Feedback
    0 (0%)
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by ZeltMarv View Post
    Thank you!!

    Any chance you could find a patch to enable "alwaysRegenMapInSP"?

    EDIT:

    0x1EE31FC:90: ~ AlwaysRegenMapInSP

    This seems to be the switch but it doesn't seem to do anything.
    Are you sure you understand what it should do?

    Given the name I think setting it to 1 will make it so you get a new map seed every time you save and exit.

    Edit: If you insist on using the patch.txt file for making changes to the .data memory section, at least use 01 instead of 90 when setting a 8-bit integer to true.

  10. #8
    Crazyloon's Avatar Member
    Reputation
    6
    Join Date
    Apr 2021
    Posts
    5
    Thanks G/R
    2/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @ejt what was your technique for finding these values and their purpose? I would like to find others. Specifically, EnableLadderUniqueItems

  11. #9
    ejt's Avatar Contributor
    Reputation
    196
    Join Date
    Mar 2008
    Posts
    160
    Thanks G/R
    3/107
    Trade Feedback
    0 (0%)
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Crazyloon View Post
    @ejt what was your technique for finding these values and their purpose? I would like to find others. Specifically, EnableLadderUniqueItems
    Just lurking around in IDA and trying to figure out what stuff does, searching for strings and going down the rabbit hole.

  12. #10
    ejt's Avatar Contributor
    Reputation
    196
    Join Date
    Mar 2008
    Posts
    160
    Thanks G/R
    3/107
    Trade Feedback
    0 (0%)
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Before I go to bed, here are the structures I got so far, not 100% on everything but maybe it helps someone...

    Code:
    enum UnitType
    {
    	kUnitTypePlayer,
    	kUnitTypeMonster,
    	kUnitTypeObject,
    	kUnitTypeMissile,
    	kUnitTypeItem,
    	kUnitTypeRoomtile
    };
    
    enum class CharacterState : int16_t
    {
    	Unk1 = 1,
    	Running = 2,
    	Unk3 = 4,
    	Unk4 = 8,
    	RunningAndInTown = 16,
    	StandingStill = 32,
    	Walking = 64,
    	BlockingOrMoving = 128,
    	Attacking = 256,
    	Unk512 = 512,
    	Unk1024 = 1024,
    	Unk2048 = 2048,
    	Unk4096 = 4096
    };
    
    class Unit
    {
    public:
    	uint32_t UnitType; //0x0000
    	uint32_t ClassId; //0x0004
    	uint32_t NetworkId; //0x0008
    	uint32_t PMode; //0x000C
    	char *CharacterName; //0x0010
    	uint64_t unk_018; //0x0018
    	Act *pAct; //0x0020
    	uint64_t unk_028; //0x0028
    	uint64_t unk_030; //0x0030
    	Path *Path; //0x0038
    	uint64_t unk_040; //0x0040
    	uint64_t unk_048; //0x0048
    	uint32_t unk_050; //0x0050
    	uint32_t unk_054; //0x0054
    	uint64_t unk_058; //0x0058
    	uint64_t unk_060; //0x0060
    	CharacterState StateFlag; //0x0068
    	uint8_t EventType; //0x006A
    	int8_t unk_06B; //0x006B
    	uint32_t unk_06C; //0x006C
    	size_t unk_070; //0x0070
    	size_t unk_078; //0x0078
    	size_t unk_080; //0x0080
    	size_t unk_088; //0x0088
    	size_t unk_090; //0x0090
    	size_t unk_098; //0x0098
    	size_t unk_0A0; //0x00A0
    	size_t CurrentAction; //0x00A8
    	int64_t LastAction; //0x00B0
    	int16_t unk_0B8; //0x00B8
    	int16_t unk_0BA; //0x00BA
    	int16_t posX; //0x00BC
    	int16_t posY; //0x00BE
    	size_t unk_0C0; //0x00C0
    	size_t unk_0C8; //0x00C8
    	size_t unk_0D0; //0x00D0
    	uint32_t unk_0D8; //0x00D8
    	uint32_t unk_0DC; //0x00DC
    	size_t unk_0E0; //0x00E0
    	size_t unk_0E8; //0x00E8
    	SkillBook *Skills; //0x00F0
    	size_t unk_0F8; //0x00F8
    	size_t unk_100; //0x0100
    	int32_t unk_108; //0x0108
    	int32_t unk_10C; //0x010C
    	size_t unk_110; //0x0110
    	size_t unk_118; //0x0118
    	size_t unk_120; //0x0120
    	size_t unk_128; //0x0128
    	size_t unk_130; //0x0130
    	size_t unk_138; //0x0138
    	size_t unk_140; //0x0140
    	size_t unk_148; //0x0148
    	size_t unk_150; //0x0150
    	size_t unk_158; //0x0158
    }; //Size: 0x0160
    
    class Act
    {
    public:
    	char pad_0000[24]; //0x0000
    	Room *Rooms; //0x0018
    	char pad_0020[104]; //0x0020
    }; //Size: 0x0088
    
    class Path
    {
    public:
    	int16_t N000002F6; //0x0000
    	int16_t RealPosX; //0x0002
    	int16_t N000004C2; //0x0004
    	int16_t RealPosY; //0x0006
    	uint32_t N000002F7; //0x0008
    	uint32_t N0000070D; //0x000C
    	int16_t PosX; //0x0010
    	int16_t PosY; //0x0012
    	int16_t PosX2; //0x0014
    	int16_t PosY2; //0x0016
    	int16_t PosX3; //0x0018
    	int16_t PosY3; //0x001A
    	char pad_001C[4]; //0x001C
    	Room *pRoom; //0x0020
    	Room *pPreviousRoom; //0x0028
    	char pad_0030[32]; //0x0030
    	uint32_t N00000301; //0x0050
    	char pad_0054[44]; //0x0054
    	float N00000512; //0x0080
    	float N00000514; //0x0084
    	float N00000535; //0x0088
    }; //Size: 0x008C
    
    class SkillBook
    {
    public:
    	SkillInfo1 *FirstAttack; //0x0000
    	SkillInfo1 *LeftSkill; //0x0008
    	SkillInfo1 *RightSkill; //0x0010
    	char pad_0018[16]; //0x0018
    	SkillInfo1 *MercSkill; //0x0028
    	char pad_0030[32]; //0x0030
    	SkillInfo1 *UnkSkill; //0x0050
    }; //Size: 0x0058
    
    class SkillInfo1
    {
    public:
    	SkillInfo2 *Info; //0x0000
    }; //Size: 0x0008
    
    class SkillInfo2
    {
    public:
    	int16_t SkillId; //0x0000
    	char N00000422[34]; //0x0002
    }; //Size: 0x0024
    
    class Room
    {
    public:
    	char pad_0000[72]; //0x0000
    	Act *pAct; //0x0048
    	char pad_0050[48]; //0x0050
    	uint32_t N00000486; //0x0080
    	uint32_t N00000567; //0x0084
    	uint32_t N0000055E; //0x0088
    	uint32_t N0000056A; //0x008C
    	uint32_t N0000055F; //0x0090
    	uint32_t N0000056D; //0x0094
    	uint32_t N00000560; //0x0098
    	uint32_t N00000727; //0x009C
    	char pad_00A0[16]; //0x00A0
    	Room *NextRoom; //0x00B0
    	char pad_00B8[16]; //0x00B8
    }; //Size: 0x00C8
    Code:
    const char* EventTypes[] =
    {
    	"EVENTTYPE_NONE",
    	"EVENTTYPE_ATTACK",
    	"EVENTTYPE_MISSILE",
    	"EVENTTYPE_SOUND",
    	"EVENTTYPE_DOSKILL",
    };
    
    const char* PModes[] =
    {
    	"PMODE_DEATH",
    	"PMODE_NEUTRAL",
    	"PMODE_WALK",
    	"PMODE_RUN",
    	"PMODE_GETHIT",
    	"PMODE_TOWNNEUTRAL",
    	"PMODE_TOWNWALK",
    	"PMODE_ATTACK1",
    	"PMODE_ATTACK2",
    	"PMODE_BLOCK",
    	"PMODE_CAST",
    	"PMODE_THROW",
    	"PMODE_KICK",
    	"PMODE_SKILL1",
    	"PMODE_SKILL2",
    	"PMODE_SKILL4",
    	"PMODE_DEAD",
    	"PMODE_SEQUENCE",
    	"PMODE_KNOCKBACK",
    };
    
    const char* MissileEvent[] =
    {
    	"MISSILE_NOCOLLIDE",
    	"MISSILE_PLAYERKILL",
    	"MISSILE_MONSTERKILL",
    	"MISSILE_MONSTERKILL",
    	"MISSILE_ALLKILL",
    	"MISSILE_NOKILL",
    	"MISSILE_SAFE",
    	"MISSILE_BARRIERCOLLIDE",
    	"MISSILE_MISSILEKILL",
    	"MISSILE_WALLKILL",
    };

  13. Thanks Vilavek, Creepwalker (2 members gave Thanks to ejt for this useful post)
  14. #11
    lanzajamones's Avatar Member
    Reputation
    3
    Join Date
    Dec 2012
    Posts
    4
    Thanks G/R
    9/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Crazyloon View Post
    Ah, ok... never mind I figured it out.


    adding
    0x1EE3201:90
    to patches.txt will make item levels show

    I'm still testing the rest

    0x1EE3200:90: ~ allowLadderRunewords
    0x1EE3201:90: ~ displayItemLevel
    0x1EE31FF:90: ~ allowCowPortalWhenCowKingWasKilled
    0x1EE3203:90 ~ enableUberQuest
    0x1EE3202:90: ~ allowStatUnassignment
    0x1EE3204:90: ~ allowSkillUnassignment (doesn't seem to be working)
    0x1EE320D:90: ~ enableWorldEventOffline (Assume Uber Diablo - haven't tested)
    0x1EE320E:90: ~ enableMultipleHirelings
    //0x1EE3211:90: ~ worldEventMonsterClass (probably needs correct ID for Uber Diablo)
    //0x1EE3215:90: ~ worldEventGlobalMessage (probably needs correct ID for the string to reference)
    //0x1EE3315:90: ~ worldEventGlobalSound (probably needs correct ID for audio file to reference)
    I extracted the CASC storage and it seems the game uses the classic patchstring.tbl, so if it works the game should show it.
    if we could some way to modify the CASC or make game.exe load "local files" we could test more things.

    If we can access the CASC, we won't need the next beta test either, just mod the current game with the next CASC.

  15. Thanks Flamberge (1 members gave Thanks to lanzajamones for this useful post)
  16. #12
    ejt's Avatar Contributor
    Reputation
    196
    Join Date
    Mar 2008
    Posts
    160
    Thanks G/R
    3/107
    Trade Feedback
    0 (0%)
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Got a better look today, will be continuing reversing over the weekend but thought I'd share my progress in case there are others that want to get something "interesting" going.

    Code:
    enum class CharacterState : int16_t
    {
    	Unk1				= 1 << 0,
    	Running				= 1 << 1,
    	Unk3				= 1 << 2,
    	Unk4				= 1 << 3,
    	RunningAndInTown	= 1 << 4,
    	StandingStill		= 1 << 5,
    	Walking				= 1 << 6,
    	BlockingOrMoving	= 1 << 7,
    	Attacking			= 1 << 8
    };
    
    class Act;
    class Room;
    class Path;
    class UnitData;
    class Inventory;
    class SkillBook;
    class SkillInfo1;
    class SkillInfo2;
    class Room2;
    class Level;
    
    class UnitAny
    {
    public:
    	uint32_t UnitType; //0x0000
    	uint32_t ClassId; //0x0004
    	uint32_t UnitId; //0x0008
    	uint32_t PMode; //0x000C
    	UnitData* Data; //0x0010
    	uint64_t unk_018; //0x0018
    	Act* pAct; //0x0020
    	uint32_t Seed[2]; //0x0028
    	uint64_t unk_030; //0x0030
    	Path* Path; //0x0038
    	uint32_t unk_040; //0x0040
    	uint32_t unk_044; //0x0044
    	uint64_t unk_048; //0x0048
    	uint32_t unk_050; //0x0050
    	uint32_t unk_054; //0x0054
    	uint64_t unk_058; //0x0058
    	uint64_t unk_060; //0x0060
    	CharacterState StateFlag; //0x0068
    	uint8_t EventType; //0x006A
    	int8_t unk_06B; //0x006B
    	uint32_t unk_06C; //0x006C
    	size_t unk_070; //0x0070
    	size_t unk_078; //0x0078
    	size_t unk_080; //0x0080
    	size_t unk_088; //0x0088
    	Inventory* pInventory; //0x0090
    	size_t unk_098; //0x0098
    	size_t unk_0A0; //0x00A0
    	size_t CurrentAction; //0x00A8
    	int64_t LastAction; //0x00B0
    	int16_t unk_0B8; //0x00B8
    	int16_t unk_0BA; //0x00BA
    	int16_t posX; //0x00BC
    	int16_t posY; //0x00BE
    	size_t unk_0C0; //0x00C0
    	size_t unk_0C8; //0x00C8
    	size_t unk_0D0; //0x00D0
    	uint32_t unk_0D8; //0x00D8
    	uint32_t unk_0DC; //0x00DC
    	size_t unk_0E0; //0x00E0
    	size_t unk_0E8; //0x00E8
    	SkillBook* Skills; //0x00F0
    	size_t unk_0F8; //0x00F8
    	size_t unk_100; //0x0100
    	int32_t unk_108; //0x0108
    	int32_t unk_10C; //0x010C
    	uint32_t unk_110; //0x0110
    	uint32_t unk_114; //0x0114
    	size_t unk_118; //0x0118
    	size_t unk_120; //0x0120
    	size_t unk_128; //0x0128
    	size_t unk_130; //0x0130
    	size_t unk_138; //0x0138
    	size_t unk_140; //0x0140
    	UnitAny* pListNext; //0x0148
    	size_t unk_150; //0x0150
    	size_t unk_158; //0x0158
    }; //Size: 0x0160
    
    class Act
    {
    public:
    	char pad_0000[24]; //0x0000
    	Room* Rooms; //0x0018
    	char pad_0020[104]; //0x0020
    }; //Size: 0x0088
    
    class Path
    {
    public:
    	int16_t N000002F6; //0x0000
    	int16_t RealPosX; //0x0002
    	int16_t N000004C2; //0x0004
    	int16_t RealPosY; //0x0006
    	uint32_t N000002F7; //0x0008
    	uint32_t N0000070D; //0x000C
    	int16_t PosX; //0x0010
    	int16_t PosY; //0x0012
    	int16_t PosX2; //0x0014
    	int16_t PosY2; //0x0016
    	int16_t PosX3; //0x0018
    	int16_t PosY3; //0x001A
    	char pad_001C[4]; //0x001C
    	Room* pRoom; //0x0020
    	Room* pPreviousRoom; //0x0028
    	char pad_0030[32]; //0x0030
    	uint32_t N00000301; //0x0050
    	char pad_0054[44]; //0x0054
    	float N00000512; //0x0080
    	float N00000514; //0x0084
    	float N00000535; //0x0088
    }; //Size: 0x008C
    
    class SkillBook
    {
    public:
    	SkillInfo1* FirstAttack; //0x0000
    	SkillInfo1* LeftSkill; //0x0008
    	SkillInfo1* RightSkill; //0x0010
    	char pad_0018[16]; //0x0018
    	SkillInfo1* MercSkill; //0x0028
    	char pad_0030[32]; //0x0030
    	SkillInfo1* UnkSkill; //0x0050
    }; //Size: 0x0058
    
    class SkillInfo1
    {
    public:
    	SkillInfo2* Info; //0x0000
    }; //Size: 0x0008
    
    class SkillInfo2
    {
    public:
    	int16_t SkillId; //0x0000
    	char N00000422[34]; //0x0002
    }; //Size: 0x0024
    
    class Room
    {
    public:
    	char pad_0000[24]; //0x0000
    	Room2* Room2; //0x0018
    	char pad_0020[40]; //0x0020
    	Act* pAct; //0x0048
    	char pad_0050[48]; //0x0050
    	uint32_t N00000486; //0x0080
    	uint32_t N00000567; //0x0084
    	uint32_t N0000055E; //0x0088
    	uint32_t N0000056A; //0x008C
    	uint32_t N0000055F; //0x0090
    	uint32_t N0000056D; //0x0094
    	uint32_t N00000560; //0x0098
    	uint32_t N00000727; //0x009C
    	char pad_00A0[16]; //0x00A0
    	Room* NextRoom; //0x00B0
    	char pad_00B8[16]; //0x00B8
    }; //Size: 0x00C8
    
    class Room2
    {
    public:
    	char pad_0000[144]; //0x0000
    	Level* N00000AB7; //0x0090
    }; //Size: 0x0098
    
    class Level
    {
    public:
    	char pad_0000[504]; //0x0000
    	uint32_t LevelNo; //0x01F8
    	char pad_01FC[12]; //0x01FC
    }; //Size: 0x0208
    
    class LevelText
    {
    public:
    	uint8_t LevelNo; //0x0000
    	char pad_0001[3]; //0x0001
    	uint8_t LevelNo2; //0x0004
    	char pad_0005[15]; //0x0005
    	int16_t N00000BD1; //0x0014
    	int16_t N00000BD3; //0x0016
    	char pad_0018[225]; //0x0018
    	char Name[40]; //0x00F9
    	char EntranceText[40]; //0x0121
    	char LevelDesc[40]; //0x0149
    	char pad_0171[19]; //0x0171
    }; //Size: 0x0184
    
    class LevelTextArray
    {
    public:
    	LevelText N00000B65[136]; //0x0000
    }; //Size: 0xCE20
    
    class Inventory
    {
    public:
    	uint32_t InvStamp; //0x0000 0x1020304 = valid inventory
    	char pad_0004[4]; //0x0004
    	UnitAny* OwnerUnit; //0x0008
    	UnitAny* FirstItem; //0x0010
    	UnitAny* LastItem; //0x0018
    	char pad_0020[32]; //0x0020
    	UnitAny* CursorItem; //0x0040
    	char pad_0048[64]; //0x0048
    	Inventory* pOwnerInventory; //0x0088
    	char pad_0090[120]; //0x0090
    }; //Size: 0x0108
    
    class LevelInfo
    {
    public:
    	char pad_0000[156]; //0x0000
    }; //Size: 0x009C
    
    class LevelInfoArray
    {
    public:
    	LevelInfo N00001121[136]; //0x0000
    }; //Size: 0x52E0
    
    class PlayerData
    {
    public:
    	char Name[16]; //0x0000
    	size_t unk_10; //0x0010
    	size_t unk_18; //0x0018
    	size_t unk_20; //0x0020
    	size_t unk_28; //0x0028
    	size_t unk_30; //0x0030
    	size_t unk_38; //0x0038
    }; //Size: 0x0040
    
    class Waypoint
    {
    public:
    	uint8_t N000011CE; //0x0000
    }; //Size: 0x0001
    
    class ItemData
    {
    public:
    	uint32_t QualityNo; //0x0000
    	char Seed[2][8]; //0x0004
    	int32_t OwnerGuid; //0x0014
    	char pad_0018[8]; //0x0018
    	uint32_t Flags; //0x0020
    	char pad_0024[60]; //0x0024
    }; //Size: 0x0060
    
    class UnitData
    {
    public:
    	union //0x0000
    	{
    		PlayerData PlayerData; //0x0000
    		ItemData ItemData; //0x0000
    	};
    }; //Size: 0x0060
    Interestingly (but maybe not surprisingly) structures doesn't seem to have changed to much compared to original D2 which will make reversing them much easier.

    Expect a lot of things can be named wrong or be completely wrong but a lot of it should be correct with minor changes.

  17. Thanks lanzajamones (1 members gave Thanks to ejt for this useful post)
  18. #13
    MrNoble's Avatar ezclap CoreCoins Purchaser
    Reputation
    526
    Join Date
    Sep 2015
    Posts
    347
    Thanks G/R
    163/216
    Trade Feedback
    2 (100%)
    Mentioned
    6 Post(s)
    Tagged
    0 Thread(s)
    There is one function making use of that configuration offset, xref that function and you will be able to find plenty of functions making use of that function.
    For those who didn't know yet, the return value (the configStruct in our case) will be stored in register RAX when the function returns.

    func sig:
    Code:
    48 83 EC ?? E8 ?? ?? ?? ?? 48 C7 C1 FF FF FF FF


    FYI these patches are located in the .data section and do not need any special type of bypass AFAIk.
    Any fool can write code that a computer can understand. good programmers write code that humans can understand.

  19. Thanks lanzajamones (1 members gave Thanks to MrNoble for this useful post)
  20. #14
    ejt's Avatar Contributor
    Reputation
    196
    Join Date
    Mar 2008
    Posts
    160
    Thanks G/R
    3/107
    Trade Feedback
    0 (0%)
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Did some work on UI stuff today, got the panel manager offset and some structures to go with it.

    PanelManager = 0x234AF30
    There is also a copy on 0x234AF40 but haven't looked into what that is used for yet.

    InitializePanelManager = 0x5A3C50
    InitializeGameWidgets = 0x5B30B0 lot of initialization going on in there

    Code:
    class Widget;
    class WidgetList;
    class PanelManager;
    
    // Actually a list of like 33 items but not sure exactly
    // about the size yet so just added some items for testing
    class WidgetList
    {
    public:
    	Widget *N000036F1; //0x0000
    	Widget *N00004084; //0x0008
    	Widget *N00004085; //0x0010
    	Widget *N00004086; //0x0018
    	Widget *N00004087; //0x0020
    	Widget *N00004088; //0x0028
    	Widget *N00004089; //0x0030
    	Widget *N0000408A; //0x0038
    	Widget *N0000408B; //0x0040
    	Widget *N0000408C; //0x0048
    	Widget *N0000408D; //0x0050
    	Widget *N0000408E; //0x0058
    }; //Size: 0x0060
    
    class Widget
    {
    public:
    	char *pName; //0x0008
    	char pad_0010[32]; //0x0010
    	Widget *Parent; //0x0030
    	char pad_0038[24]; //0x0038
    	uint64_t Flags; //0x0050 flags & 0x10 = visible
    	WidgetList *Children; //0x0058
    	uint64_t numElements; //0x0060
    	char pad_0068[32]; //0x0068
    	
    	virtual void Function0();
    	virtual void Function1();
    	virtual void Function2();
    	virtual void Function3();
    	virtual void Function4();
    	virtual void Function5();
    	virtual void Function6();
    	virtual void Function7();
    	virtual void Function8();
    	virtual void Function9();
    }; //Size: 0x0088
    
    class PanelManager : public Widget
    {
    public:
    	WidgetList *pWidgetList; //0x0088
    	uint64_t numElements; //0x0090
    	char pad_0098[8]; //0x0098
    	WidgetList *pWidgetList2; //0x00A0
    	uint64_t numElements2; //0x00A8
    	char pad_00B0[8]; //0x00B0
    	uint32_t N0000432E; //0x00B8
    	uint32_t ScreenWidth; //0x00BC
    	uint32_t ScreenHeight; //0x00C0
    	char pad_00C4[4]; //0x00C4
    	Widget *ActiveModal; //0x00C8
    	Widget *GlobalData; //0x00D0
    	Widget *FocusManager; //0x00D8
    	char pad_00E0[16]; //0x00E0
    }; //Size: 0x00F0

  21. Thanks lanzajamones, Vilavek (2 members gave Thanks to ejt for this useful post)
  22. #15
    Crazyloon's Avatar Member
    Reputation
    6
    Join Date
    Apr 2021
    Posts
    5
    Thanks G/R
    2/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I find this very interesting. I wonder if we can figure out how to turn the console on and see if there is any interesting information in there.

    possible_console.png

    How do you find a memory offset for something like this in Cheat Engine? I understand, in Cheat Engine, we can manually add an address if we know the offset.

    So how did you go from something like this in IDA:
    .rdata:0000000141A1B528 aAllowladderrun db 'allowLadderRunewords',0

    to something like this in Cheat Engine:
    game.exe+0x1EE3200

Page 1 of 3 123 LastLast

Similar Threads

  1. WoW Offsets & WPE
    By RyanoAthens in forum World of Warcraft General
    Replies: 2
    Last Post: 03-11-2014, 10:15 PM
  2. Hiding offsets of proccess how ?
    By sabotage3d in forum World of Warcraft General
    Replies: 0
    Last Post: 03-24-2007, 09:59 AM
  3. Swimming state offset
    By sabotage3d in forum World of Warcraft General
    Replies: 0
    Last Post: 03-12-2007, 03:54 PM
  4. Enemy offsets
    By sabotage3d in forum World of Warcraft General
    Replies: 0
    Last Post: 03-12-2007, 08:13 AM
  5. How do you find memory offsets in the game?
    By koalaz2004 in forum World of Warcraft General
    Replies: 0
    Last Post: 08-18-2006, 09:40 PM
All times are GMT -5. The time now is 02:59 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2021 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2021 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search