Char Editor

This forum is for discussions on how to edit what can not be edited through the txt files, needless to say this isn't about battle net hacking.

Moderators: Nefarius, Havvoric

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Char Editor

Post by Trevor » Sun Dec 04, 2011 7:29 pm

I have made so many changes to the texts that most char editors fail. So I decided that I would create my own and started moving through the d2s file structure post that has been provided. I noticed that making any minor change to the d2s file screws it over unless you edit the checksum. So, off I went hunting and found the following C++ code for the check sum.

viewtopic.php?f=8&t=7102&hilit=checksum

Is it still the correct code - that post is almost 9 years old?

If it is, is there an easier way to get the checksum rather than running through the entire file? IE if I change my Str from 10 to 50, surely I can reflect the 0x0a being changed to 0x32 without going through the whole file??? If not, I'll live with it.
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
kidpaddle94
Forum Legend
Principality
Posts: 2057
Joined: Thu Aug 13, 2009 2:54 pm
Location: localhost
Canada

Re: Char Editor

Post by kidpaddle94 » Sun Dec 04, 2011 8:33 pm

one of the easy way is to modify Udietoo. That's what I did for another mod editor.
That's pretty simple, to resume, you just change the path looking for patch_d2.mpq to your custom patch. In this new patch, you store your mod files.

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Mon Dec 05, 2011 1:11 am

I dont give out the texts for my mod. So I have to create something for someone if he/she wants to try out the mod.
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Mon Dec 05, 2011 7:57 am

the hash is still correct, but its not needed unless you've changed the savefile structure, thats the only thing that really breaks the editors.
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Mon Dec 05, 2011 4:33 pm

Well, I wasn't going to post this right away until I was ready to tackle the checksum but I guess, it's time. I have changed the structure.

A) Chars are created with a custom potion that allows them to customize their stats at creation. I save a 32 bit itemstat flag to the save file to prohibit multiple uses of the potion.
B) Every char has a class specific quest that is tied to defeating a particular boss who drops a potion. The potion saves another 32 bit itemstat counter to the save file that opens up special skills. This counter is increased in Norm, NM, and Hell.

So my first question - where is this information saved in the file? At the end? Is it's location in the savefile tied to the itemstat id? Or do I just guess and test?

I'll ask more questions when I get ready to actually calculate it (to make sure I understand that post.)
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Mon Dec 05, 2011 5:56 pm

thats not what I meant by changing the structure, I meant that you have literally changed the structure by recoding it(ie: my skills aren't saved as an slvl, they are an id+slvl).

That data is saved in the character statstream section, which is at a variable position in the file (as it has streams before and after it).
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Tue Dec 06, 2011 7:04 am

Ok. So a question. Is there any defining byte that marks the start of the character statstream? I'm assuming that the extra bytes I am saving to the file are in the same place relative to the start of the character statstream. If this assumption is wrong, got any hints for me? :) Thank you.

EDIT: Is OneInTen's description of the bitfield for char stats correct?
viewtopic.php?f=8&t=9011&start=50
My Itemstatcost has 29s rather than 31s for the last two entries.
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Tue Dec 06, 2011 10:12 am

There is a defineing WORD used to indicate each section start. as for that topic, its right for vanilla, but everything you need is in itemstatcost, just note that stats with no value aren't saved.

see this: viewtopic.php?f=8&t=9011
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Thu Dec 08, 2011 5:10 am

EDIT: I think I got. What a weird way of reading a string. Off to confirm the next stat.
EDIT 2: Yup I got it. Wow. Talking about making life difficult for yourself.

Ok Binary string time.
The pic below shows the stat section of the char save file.

Image

Taking the first four bytes after the stream maker "67 66" I have

00 60 09 10

I converted each byte into bits getting

0000 0000 0110 0000 0000 1001 0001 0000

According to this post
OneInTen" wrote:OK, I've traced through the save routine and decoded the stats portion of the save file.

Code: Select all

ID    Desc                      Width
00    Str                       10
01    Dex                       10
02    Con                       10
03    Energy                    10
04    Skill pts                 10
05    Stat pts                  8
06    HP current                21
07    HP base                   21
08    Mana current              21
09    Mana base                 21
10    Stamina current           21
11    Stamina base              21
12    Level                     7
13    XP                        32
14    Gold inventory            31
15    Gold stash                31
The way to use this table is that the game stores the ID in 9 bits, followed by the value in the number of bits indicated by width.
So I take the first 9 bits = 0 0000 0000 = the str itemstat id of 0 :)

I then take the next 10 bits = 11 0000 0000 = which should equal the value of the str on my char.
Sadly 11 0000 0000 = 768 not 176 which is the current str on my char. :(
If I reverse the bits, I get 00 0000 0011 = 3 :(

I'm not sure what I'm doing wrong. Any help would be appreciated.
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Thu Dec 08, 2011 11:25 am

you need to use the CVsSaveBits column as the width, not that table.
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Sun Dec 18, 2011 8:14 am

Ok so this is where I'm at.

Image

The numbers are correct.
The Life and Max Life sections look funny but thats because life is mostly controlled via a passive skill and not charstats so the base never changes even if your life is 4242/4242 when you save the game.
WP Level is an anti rushing feature. WPs will kill you if you are too low of a level.
The Potion of Destiny allows you to customize your character upon creation.
The Elixir of Grace enables stat potions to be used.
There are three class specific quests that I added. If you do the quest, you can access to some locked skills.
All and all, everything is correct, though I forgot to add a section for the number of Skill Tomes read... tomorrow's job.

I was reading in the save file structure thread and the thread seems to focus on the item stream. I would prefer to go after the wp stream or quest stream next. Do you know where any information is on the WP stream and how it's organized? That particular thread doesnt really offer much other than where the stream starts and finishes. I found something awhile ago posted by Paul but I forgot to save his page. His page was not hosted on this site but on his own private one with a link to it somewhere around here.

Any help/suggestions/guidance is appreciated. :)
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Sun Dec 18, 2011 9:33 am

only items and stats are steams, the rest are just structured chunks:
viewtopic.php?p=433280#p433280
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Sat Dec 31, 2011 3:04 am

Ok, I've made some progress; however, I need some help with the Quest stuff. I'm trying to decipher the bits in the quest section of the save file but I'm lost. I've read Nec's thread (it looks like a 2d array) and found this thread:

viewtopic.php?f=8&t=22194

I'm not sure how to piece it all together. I appreciate any assistance on deciphering this string of bits.

This is what I've accomplished so far. Quests are the last thing I want to code.

http://www3.telus.net/public/TMNICKLE/C ... or%205.jpg
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Sat Dec 31, 2011 11:54 am

the quest data is a set of bitflags for each quest:

Code: Select all

enum eD2VanilliaQuestFlags
{
    QFLAG_REWARD_GRANTED                = 0,
    QFLAG_REWARD_PENDING                = 1,
    QFLAG_QUEST_STARTED                 = 2,
    QFLAG_QUEST_LEAVE_TOWN              = 3,
    QFLAG_QUEST_ENTER_AREA              = 4,
    QFLAG_CUSTOM_1                      = 5,
    QFLAG_CUSTOM_2                      = 6,
    QFLAG_CUSTOM_3                      = 7,
    QFLAG_CUSTOM_4                      = 8,
    QFLAG_CUSTOM_5                      = 9,
    QFLAG_CUSTOM_6                      = 10,	//0xA
    QFLAG_CUSTOM_7                      = 11,	//0xB
    QFLAG_UPDATE_QUEST_LOG              = 12,	//0xC
    QFLAG_PRIMARY_GOAL_ACHIEVED         = 13,	//0xD
    QFLAG_QUEST_COMPLETED_NOW           = 14,   //0xE
    QFLAG_QUEST_COMPLETED_BEFORE        = 15,   //0xF
};
the custom flags depends on the quest
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Sat Dec 31, 2011 5:35 pm

This helps. However, it appears that I have more bits than I need. Here's a picture to explain where I'm stuck - basically where does the Act 1 section start? (I hope you're not color blind)

Image
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Sat Dec 31, 2011 11:57 pm

that are way more that just 6 quests per act ;) to be exact, there are 41 sets of flags per difficulty, to check a quest flag you do:

Code: Select all

/* 
	Date: Wed Aug 05 17:58:33 2009
	Author: Necrolis
	Function: QUESTS_CheckFlag
	Address: D2Common.#11107
	Comments:
*/

BOOL __fastcall QUESTS_CheckFlag(D2QuestFlagStrc* pQuestData, DWORD nQuest, DWORD nFlag)
{
	if(pQuestData == NULL)
		return FALSE;

	BYTE* pQuestFlags = pQuestData->pBuffer;
	DWORD i = (nQuest << 4) | nFlag;
	DWORD fFlags = pQuestFlags[i >> 3];
	return ((fFlags & gdwBitMask[i & 7]) ? TRUE : FALSE);
}
or more simply:

Code: Select all

DWORD i = (nQuest << 4) | nFlag;
BYTE Flags = pArray[i >> 3];
return fFlags & (1 << (i & 7));
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Fri Jan 06, 2012 7:37 am

OK - I have some things working and somethings failing. This is what I have so far. I can read and edit all WP information, skill level information, and quest information. Currently, I have not enabled the ability to edit stats though I can correctly read them. (but the edit ability is coming). I wanted to test out my changes and I'm happy with the results. Everything I can edit can be exported and re-imported matching exactly what I changed. Because I have a dozen or so test files at various stages in the game and my program reads those values, quests, wp, skills, etc correctly, I'm confident I got it right. TY Necrolis.

What is failing is my understanding of C++ and the code I linked to in the first post of this thread. The code calculates the checksum. This is what I have in C#, and is to the best of my ability what I think that C++ code is doing. (For all you guru's - don't laugh too hard, I'm a rookie coder but having fun nonetheless.) When looking at the C++ code and my code below, what am I doing wrong? The checksum is close but not the same.

Code: Select all

        private void CalculateCheckSum()
        {
               // Convert the checksum code found at https://d2mods.info/forum/viewtopic.php?f=8&t=7102&hilit=checksum
               // posted by Krabat into C# with an intermediate level of knowledge at best.
            
               uint uiTempSum = 0;     // Initialize the sum to zero.
               uint uiStrangeBoolFromC = 0;  // C++ boolean ?? that C# doesnt seem to like very much
            
               // Reinitialize Checksum to 0 
               // FYI
               // iCheckSumLocation is correctly found at +0x0C  :)
               // Test Save File = 3D 32 61 C0 according to XVI32.  Because everything seems to be backwards, I display
               //   the check sum as C0 61 32 3D in my program.  This is the value I am trying to reproduce in this method.
               // byD2SFile is a byte array that contains all the bytes in the test d2s file.  
               //   The bytes are read into the array from the d2s file one byte at a time and a counter is increased by 1
               //       to keep track of the number of bytes read in.  This counter is called iNumBytes.
               //   The bytes match the save file when opened up with XVI32 both in number and in value. :)

               byD2SFile[iCheckSumLocation] = 0;
               byD2SFile[iCheckSumLocation + 1] = 0;
               byD2SFile[iCheckSumLocation + 2] = 0;
               byD2SFile[iCheckSumLocation + 3] = 0;
               for (int i = 0; i < iNumBytes; i++) // Sum over all the bytes in the save file
               {
                      uiTempSum = (uiTempSum << 1) + byD2SFile[i];
                      uiStrangeBoolFromC = (uiTempSum & 0x80000000);  // This is the weird stuff in the C++ code I'm not sure about.
                      if (uiStrangeBoolFromC > 0) uiTempSum = uiTempSum + 1;
               }
               listBox1.Items.Add(string.Format("Checksum = {0}", uiTempSum)); // Display the integer value of the checksum
        }
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Fri Jan 06, 2012 12:55 pm

the C++ hashing algo used is a little miss-leading, its actually bit rotation that is done. your thing fails because you add before the rotation is complete (so if the addition of the next byte rolls the sign bit, the rotation is incorrect), in C# it should look like:

Code: Select all

private uint32 HashFile()
{
    uint32 Hash = 0;
    File[12] = 0;
    File[13] = 0;
    File[14] = 0;
    File[15] = 0;
    for(uint i = 0; i < FileLength; i++)
    {
        Hash = (Hash << 1) | (Hash >> 31); //this is bit rotation, aka _rotl in C
        Hash += File[i];
    }

    File[12] = (Hash >> 24) & 0xFF;
    File[13] = (Hash >> 16) & 0xFF;
    File[14] = (Hash >> 8) & 0xFF;
    File[15] = (Hash) & 0xFF;
    return Hash;
}
(you should really use marshaled structs for the header ;))
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Fri Jan 06, 2012 10:58 pm

TY Necrolis! It works perfect. I'd be happy to send you a case of beer for your time. :)

However I do have 3 noob questions.
Question 1

Code: Select all

uiTempSum = ((uiTempSum << 1) | (uiTempSum >> 31));
This is how I understand the line of code you gave me. Whatever my sum is, left shift it 1 bit OR right shift it 31 bits. Let this new result be equal to my sum. How does the program know what branch of the OR to do?

Question 2

Code: Select all

uiCS = (uiCS<<1) + ( uiCS & 0x80000000 ? 1 : 0 ); 
This is a portion of the code in C++ that I followed. I want to know if this is correct. I've stared at it for awhile now. It's not clear to me how this is a rotation.

uiCS & 0x80000000 must produce either 0x00000000 or 0x80000000 depending on whether or not the leading bit in uiCS is a 0 or 1 respectively. This is where the confusion starts. If the result was 0x00000000, I thought it was adding nothing to the entire checksum and if the the result was 0x80000000, I thought the checksum was being increased by 1 because of the '+' infront of (uiCS & 0x80.....) If it's not doing that, what is it doing?

The other train of thought I had was its not adding one or zero, but rather setting the lead bit to 0 or 1. The reason why I rejected this idea was - how does it help? If the leading bit is already a 1, ANDing it with 0x80000000 is not going to change anything and if the lead bit is 0, ANDing it with 0x80000000 is not going to do anything either.

Needless to say, I'm still totally confused.

Question 3
Necrolis" wrote:(you should really use marshaled structs for the header )
What is a marshaled structure?
I've used a number of structures and lists to make this program work. There are so many bits and bytes to keep track of, I dont know any other way. Maybe when I take the next level of C#, I will learn a more efficient way to do this but for now, here's my growing list of structures and lists. (I have as many of them as I do so I know exactly what I'm editing and where I'm editing it. Easy debugging ftw. :) Efficiency ftl :()

Code: Select all

        public List<strctCharData> LstCharData = new List<strctCharData>();
        public List<strctWPData> LstNORMWPData = new List<strctWPData>();
        public List<strctWPData> LstNMWPData = new List<strctWPData>();
        public List<strctWPData> LstHELLWPData = new List<strctWPData>();
        public List<strctPlayerSkills> LstAmazonData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstAssassinData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstBarbarianData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstDruidData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstNecromancerData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstPaladinData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstSorceressData = new List<strctPlayerSkills>();
        public List<strctQuest> LstPlayerQuestData = new List<strctQuest>();
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Trevor
Forum Legend
Principality
Posts: 2068
Joined: Sat Aug 05, 2006 11:03 pm
Location: Alberta Canada
Canada

Hand-picked

Re: Char Editor

Post by Trevor » Mon Dec 03, 2012 9:48 pm

I want to add more functionality to my editor. When a HC char dies, what do I need to edit so I can "revive" him?
AfterMath Overview: http://www.aftermathcentral.com

Following the path of least resistance is what makes rivers and men crooked.
- Author Unknown

Mod Completion: Always under Construction
D2SE Compatible Only

Playing AfterMath v3.0.1 ~ 1020 MB
Released March 31, 2017

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Tue Dec 04, 2012 8:42 am

Hmmm, seems I never noticed your older reply... anyways, newest question first
Trevor" wrote:I want to add more functionality to my editor. When a HC char dies, what do I need to edit so I can "revive" him?
You need to unset the has died flag, at +0x24 from the start of the file, the flags are:

Code: Select all

enum eD2GameFlags
{
	GFLAG_NEWBIE		=		0x001, //first time entering the game
	GFLAG_HARDCORE		=		0x004,
	GFLAG_HASDIED		=		0x008,
	GFLAG_EXPANSION		=		0x020,
	GFLAG_NOTLADDER		=		0x040
};
so basically, just do:

Code: Select all

pHeader->fFlags &= ~GFLAG_HASDIED;
Trevor" wrote: However I do have 3 noob questions.
Question 1

Code: Select all

uiTempSum = ((uiTempSum << 1) | (uiTempSum >> 31));
This is how I understand the line of code you gave me. Whatever my sum is, left shift it 1 bit OR right shift it 31 bits. Let this new result be equal to my sum. How does the program know what branch of the OR to do?

Question 2

Code: Select all

uiCS = (uiCS<<1) + ( uiCS & 0x80000000 ? 1 : 0 ); 
This is a portion of the code in C++ that I followed. I want to know if this is correct. I've stared at it for awhile now. It's not clear to me how this is a rotation.

uiCS & 0x80000000 must produce either 0x00000000 or 0x80000000 depending on whether or not the leading bit in uiCS is a 0 or 1 respectively. This is where the confusion starts. If the result was 0x00000000, I thought it was adding nothing to the entire checksum and if the the result was 0x80000000, I thought the checksum was being increased by 1 because of the '+' infront of (uiCS & 0x80.....) If it's not doing that, what is it doing?

The other train of thought I had was its not adding one or zero, but rather setting the lead bit to 0 or 1. The reason why I rejected this idea was - how does it help? If the leading bit is already a 1, ANDing it with 0x80000000 is not going to change anything and if the lead bit is 0, ANDing it with 0x80000000 is not going to do anything either.

Needless to say, I'm still totally confused.

Question 3
Necrolis" wrote:(you should really use marshaled structs for the header )
What is a marshaled structure?
I've used a number of structures and lists to make this program work. There are so many bits and bytes to keep track of, I dont know any other way. Maybe when I take the next level of C#, I will learn a more efficient way to do this but for now, here's my growing list of structures and lists. (I have as many of them as I do so I know exactly what I'm editing and where I'm editing it. Easy debugging ftw. :) Efficiency ftl :()

Code: Select all

        public List<strctCharData> LstCharData = new List<strctCharData>();
        public List<strctWPData> LstNORMWPData = new List<strctWPData>();
        public List<strctWPData> LstNMWPData = new List<strctWPData>();
        public List<strctWPData> LstHELLWPData = new List<strctWPData>();
        public List<strctPlayerSkills> LstAmazonData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstAssassinData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstBarbarianData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstDruidData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstNecromancerData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstPaladinData = new List<strctPlayerSkills>();
        public List<strctPlayerSkills> LstSorceressData = new List<strctPlayerSkills>();
        public List<strctQuest> LstPlayerQuestData = new List<strctQuest>();
1. a bitwise OR is always executed, the code says, combine the bits resulting from a right shift by 31 and a left shift by 1 (this is bit rotation, aka a bit shift the does wrapping).
2. the `uiCS & 0x80000000 ? 1 : 0` part extracts the most significant bit then turns it into an LSB via the ternary operator, this is the same as a right shift by 31, adding the result to the left shift of 1 yields the rotation.
3. marshaled structs allow direct and easy access to the structed parts of the save file, see this or this.
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

D2Joy
Posts: 3
Joined: Fri Jul 10, 2020 4:08 pm

Re: Char Editor

Post by D2Joy » Tue Jul 14, 2020 11:49 pm

fixed my corrupted d2s with

Code: Select all

uiCS = ((uiCS<<1) |( uiCS >> 31))+ (unsigned)buf[i];
That is ALL needed,
be aware that next line just brings in ERROR.

Code: Select all

uiCS = (uiCS<<1) + ( uiCS & 0x80000000 ? 1 : 0 ); //tested to be WRONG
ps. before fixing the checksum, be sure to set its 4 bytes to 00 00 00 00 by hex editor, as itself is right included in the sumcheck, tricky~

User avatar
Necrolis
Senior Admin
Throne
Posts: 9125
Joined: Sat Mar 25, 2006 1:22 pm
Location: The Land of the Dead
South Africa

Hand-picked

Re: Char Editor

Post by Necrolis » Wed Jul 15, 2020 2:10 am

D2Joy wrote:
Tue Jul 14, 2020 11:49 pm
fixed my corrupted d2s with

Code: Select all

uiCS = ((uiCS<<1) |( uiCS >> 31))+ (unsigned)buf[i];
That is ALL needed,
be aware that next line just brings in ERROR.

Code: Select all

uiCS = (uiCS<<1) + ( uiCS & 0x80000000 ? 1 : 0 ); //tested to be WRONG
ps. before fixing the checksum, be sure to set its 4 bytes to 00 00 00 00 by hex editor, as itself is right included in the sumcheck, tricky~
This exactly what the code I posted does...
Image
Netiquette, Do you USE it?!?! | Nefarius' Fixed TXT Files | Terms Of Service
Blackened | Day of Death | D2GFEx
"What was yours is mine. Your land, your people, and now your life." - Lim-Dul, the Necromancer
Judgement is Final, Death is Eternal

Return to “Code Editing”