Save file structure

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

Post Reply

1
100%
 
Total votes: 1

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Re: Save file structure

Post by SVR » Sun Dec 21, 2003 7:53 pm

[quote=Myhrginoc";p="145681"]
The assignment must be stored in the d2s file because it does persist between games.[/quote]

The Key assignments *do* have a field for which side the skill is assigned to. But the current selection is stored in the fields I'm refering to.
The d2s has two fields, LeftSkill and RightSkill (actually 4, l/r for each weapon set). It has the skill number in it.

The hiword I'm seeing is probably just junk left there from another editor. D2 seems to ignore it, which means the skill part is really just a word (instead of a dword like I have it).

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Thu May 20, 2004 6:13 am

Hi,

i'm currently developing some sort of mule software (d2s -> txt dump) and could need some help figuring things out...

General d2s layout is clear

Things i didn't get right are the Quests and Waypoints (There are ?six? quest arrays???).

Also i need to know how to get a unique item from UniqueItems.txt. The d2s file stores an Unique id for this, but i couldn't figure out how too make a relation to the UniqueItems.txt.

Can someone help me out? Also i'm searching for an editor author who has some spare time to support me in case i don't understand some stuff (SVR seems to be unreachable) via e-mail (Don't worry, most things are clear thanx to UdieToo and the nice thread here :)

Greets

Sledge

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Re: Save file structure

Post by SVR » Thu May 20, 2004 3:03 pm

Sorry if I've missed your email Sledge. With the number of virus emails I get (100+ a day) its easy to miss the real ones ;-)

I'm pretty busy at the moment but I can help a bit. Have you read the fileformats on my site ?

There are 3 quest groups, 1 for each difficulty.
Each group has 8 words (16 bit value) per Act and there are 6 Acts.

The 8 words are ...
Act started flag(s),
6 quest status words
Act completed flag(s)


The 5 & 6th act are combined in the game and are not in the expected places. This is because non-expansion used the 5th for game status and LOD had to shift down a few words to skip it. I think you must skip 2 extra words to lineup with the 5 act.
The 4th act only uses the first three quests but the others seem to be used for something unknown.

The status word bits have no particular meaning. The game uses various "state values" to track the quest, but each seems to have some bits in common.
The quests are not in the same order as in game. (most are but some are switched around).

Waypoints also have 3 groups. each group has 6 dwords(32 bits).
1 for each act. (yes there is only 5 acts, but the save file thinks there is 6 ;-)
If the bit is 1 the waypoint is active.
These also are not in the order they appear in game and not all are used.

Edit - continued:
The unique id is just a row index into unique.txt...
Set id into setitems
magic prefix ...
magic suffix ...

Rare names are indexed into a combined table with RareSuffix.txt first followed by RarePrefix.txt

The indices don't count the "expansion" line but do count other separators ... rings,armor, etc.
Last edited by SVR on Thu May 20, 2004 3:19 pm, edited 1 time in total.

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Thu May 20, 2004 5:09 pm

[quote=SVR";p="174275"]Sorry if I've missed your email Sledge. With the number of virus emails I get (100+ a day) its easy to miss the real ones ;-)
[/quote]
:) Okay... Anyway i reached you somehow :) It was just pure luck (a post on diablo2.de mod forum) that i've found this thread on PK, else i would surely have given up on the Stat-Values... But they are excellent documented here :)

[quote=SVR";p="174275"]
I'm pretty busy at the moment but I can help a bit. Have you read the fileformats on my site ?
[/quote]
Yes, of course... This docu got me started to develop :) Most of your docu was very clear once i got the "cond1 condvalue" stuff... Excellent work by the way... Together with the docu of Trevin Beattie 90% are clear... The thing with the quests got me stopped some time, i left it and did the skills code first. I hope you don't mind if i take some infos out of the UdieToo textfiles (in particular it's properties.txt) to include in my prog?

If you find some time, include this thread in your docu please or maybe you post a link to it. That would help some people out, i think.

I thank you very very much, this helps me out more than you can imagine :) I hope i can ask few more questions here if i get in trouble (Don't panic, ieverything is clear at the moment :)

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Re: Save file structure

Post by SVR » Thu May 20, 2004 7:42 pm

Sledge";p="174299" wrote:i would surely have given up on the Stat-Values... But they are excellent documented here :)
You *have* come to the right place ;-)
I hope you don't mind if i take some infos out of the UdieToo textfiles (in particular it's properties.txt) to include in my prog?
Sure, no problem. I got it started off of one from ItemCreator myself ;-)
If you find some time, include this thread in your docu please or maybe you post a link to it. That would help some people out, i think.
I don't know why I haven't done that already ! Too many things, not enough brain cells ;-)
I hope i can ask few more questions here if i get in trouble
That's what it's here for :) D2modding would not exist without questions & answers like this.
I don't have time to think of things to do, but someone will ask a question that sparks the obsession and viola` :mrgreen:

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Sat May 22, 2004 6:26 pm

Hi there again,

today i've implemented most of the items (Rare / Magic / Unique / Set) and the last i currently work on is the rune-word stuff...

I came across 2 strange things:

- Sigons Gage (Gaunlets) seem to be in the wrong place (or my code is wrong :) I've identified some other Sets-Items too, but they are all ok...

- There seems do be an additional bit for Runewords on items???? (I just have one item with a runeword so i'm not sure if it's the item itself or my fault).
Copy from docu [FILE types.txt 0 sType specific bits 0 iQual 2]
The item has normal quality, and only if i read one bit here it seems to be !!! nearly!!!! (but nearly is crap) :) identified correctly... Here is a small dump from my debug:

------ Simple item information start --------
IsQuestItem: No (0)
IsIdentified: Yes (1)
IsDisabled: No (0)
IsDuplicateItem: No (0)
IsSocketed: Yes (1)
IsIllegalEquip: No (0)
IsPlayerEar: No (0)
IsStarterItem: No (0)
IsSimple: No (0)
IsEthereal: No (0)
IsInscribed: No (0)
Unk51: No (0)
HasRuneWord: Yes (1)
Version: 101
Location: 0
PositionOnBody: 4
GridColumn: 0
GridRow: 0
StoredIn: 1
------ Simple item information end --------
[Parse simple item]
------ Simple item information start --------
ItemType: 7br
ItemTypeName: Mancatcher
ItemClass: 3
------ Simple item information end --------
[Parse extended item]
------ Extended item 1 start --------
NumGems: 5
GUID: 2451330772
ItemLevel: 85
ItemQualityInternal: 2
HasVariableGraphic: No (0)
VariableGraphic: 0
HasClassInfo: No (0)
ClassInfo: 0
------ Extended item 1 end --------
[Parse normal quality item]
[Not implemented yet]
------ Additional extended item information start --------
HasRandom: No (0)
------ Additional extended item information end --------
[Parse extended item section 2]
Defense: 0
MaxDurability: 20 <--- This seems strange
Durability: 20
StackQuantity: 0
NumberOfSockets: 7 <--- This seems strange (It really has 5 Sockets to hold the "Honor" runeword)

I've read until Class Info word (11 bits) and then i've expected the 16 Runeword bits to come, Does somebody here know if i'm on the wrong path? Can somebody help me out? :) What am i doing wrong?

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Post by SVR » Sat May 22, 2004 7:40 pm

It all looks good. Your are *not* reading defense, I assume ?

Runewords are *not* indices into runewords.txt!
I have never (correctly) figured out the decode.
Here's my code, it works on all runewords except 1. Doomsomething I think, has 0xDxxx code that I don't understand.

Code: Select all

		if(pItem->Item.bRuneWord==1) {
			tmp=pItem->ReadBits(16);
			if(tmp==0xFFFF)
				Strings.Add("ith",y+=h,GOLD_TEXT);
			else {
				if( ((tmp&0xFF)-26)>80)
					tmp++;
				wsprintf(s,"Runeword%d",(tmp&0xFF)-26);
				pRunesText->FindRecord("name",s);

				Strings.Add(pRunesText->strValue("Rune Name"),y+=h,GOLD_TEXT);
				Strings.Add(s,y+=h,GOLD_TEXT);
			}
			if( ((tmp&0xFF)-26)>80)
				tmp--;
			wsprintf(s,"RuneWord = 0x%04x",tmp);
			Strings.Add(s,y+=h,GOLD_TEXT);
			pCnt++;
		}

This is a total hack but the runeword id is basically the ascii number of the runeword (ie, runeword"01",02 etc)
MaxDurability: 20 <--- This seems strange
Why is this strange? It's a good sign MaxDur & Dur are the same value.

I don't know why sockets is 7. Make sure you are not reading bits that don't exist. (ie; defense on weapons, stackQty etc.)
Last edited by SVR on Sat May 22, 2004 8:00 pm, edited 1 time in total.

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Post by Sledge » Sat May 22, 2004 8:46 pm

[quote=SVR";p="174620"]It all looks good. Your are *not* reading defense, I assume ?
[quote]
No, i checked it... Mhh, i triple checked all my code... I cannot imagine what i did wrong. Checked it with Udie and Udie can read it... Checked the Udie textfiles and tried it that way... I think i look in a totally wrong direction. The runeword id seems to be way out of range in the places i've checked. Even if everything seems to look ok, the runeword id is way out of range (> 15000 / > 20000)

In the extended.txt is this line

WORD wRune 16 Rune word 0 bRuneWord 1 x
ASC7 sIName 15 Inscribed Name 0 bInscribed 1 x

That's the place i read (right before the Inscribed name)... 16 bits...
Thats what comes out: 20561... Mhhh.... checked it again... Curious, now the durablity and the sockets are ok... (18 - 28 Durability 5 sockets), but my item terminator raises an error. Is there a special item list terminator for runewords? (Mhh, sorry about this strange message... I code since 6:00am... Now it's 21:35pm... I guess i should take a short break :)

Thanx for the code :) Seems to save me some research :) If you have another idea, please let me know.

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Sat May 22, 2004 9:27 pm

Back again, well... I'm a dumbass :) I've overseen the second property list for the runeword, so my terminator crashed...

Modifying this

Code: Select all

   // Parse the has set identifiers
   if (item.ItemQualityInternal = iqSetItem) then
   	parseHasSetProperties(item);

   // Parse the normal properties
	parseProperties(item, item.Properties);

   // Parse additional set properties
   if (item.ItemQualityInternal = iqSetItem) then
   	parseSetProperties(item);

   // Parse the socketed items if exists
  	if item.NumGems > 0 then
  		parseSocketItems(item); 
to this:

Code: Select all

   // Parse the has set identifiers
   if (item.ItemQualityInternal = iqSetItem) then
   	parseHasSetProperties(item);

   // Parse the normal properties
	parseProperties(item, item.Properties);

   // Parse the runeword properties
   if item.HasRuneword then
   	parseProperties(item, item.Properties);

   // Parse additional set properties
   if (item.ItemQualityInternal = iqSetItem) then
   	parseSetProperties(item);

   // Parse the socketed items if exists
  	if item.NumGems > 0 then
  		parseSocketItems(item); 
it worked ok :) And the strange value for the runeword, is when applied to your formula 55... Which is "Honor" and thats perfect :) Oh, that was a hard job this time :)

Only things to do for now are Cracked, Low, Crude items, which i do not have at the moment. Next are charms and books... And the the curious Monster thing from types.txt. (I guess thats the necros golem? Is that thing alive if i leave the game? Haven't played a necro for at least 2 Years)

Thanx again, to know someone can help out motivates a lot to go on :)

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Post by SVR » Sat May 22, 2004 10:40 pm

And the the curious Monster thing from types.txt.
Nope, that's body parts, (spleen, heart etc.). They contain a monster Id from monstats.txt. They read "Diablo's Heart" etc.
Oh, that was a hard job this time
Glad to see you got it fixed. I had hell figuring out the ascii connection to start with. It took many hours ;-)
But it may just be the string key from the string table, I never explored that posibility.

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Sun May 23, 2004 9:36 am

Good morning,

i've come over another interesting fact... I just finished the item decoding except of Low and High Quality items...

I got an exception on parsing a Crossbow type weapon (Ichorsting that is).

After a few minutes debugging i came to the conclusion that weapons do always have an durability no matter what is stated in the weapons.txt

Changing this:

Code: Select all

if not item.NoDurability then
   begin
   	// Read max durability (8 bits) (depends on nodurability flag)
   	item.MaxDurability := CharFile.ReadBitsLong(8);

   	// Read current durability (9 bits)
       if (item.MaxDurability <> 0) then
   		item.Durability := CharFile.ReadBitsLong(9);
   end;
to this

Code: Select all

if not item.NoDurability or [color=red](item.ItemClass = icWeapon)[/color] then
   begin
   	// Read max durability (8 bits) (depends on nodurability flag)
   	item.MaxDurability := CharFile.ReadBitsLong(8);

   	// Read current durability (9 bits)
       if (item.MaxDurability <> 0) then
   		item.Durability := CharFile.ReadBitsLong(9);
   end;
seems to fix it... I'm just wondering if i'm right with my conclusion or if i should change this to if not item.NoDurability or not(item.ItemClass = icMisc)

What do you think SVR?

Regards

Sledge

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Post by SVR » Sun May 23, 2004 6:36 pm

No. You should check NoDurability only for misc items.

Code: Select all

bNoDur = FALSE;

if(isMisc)
    bNoDur=pItemTxt("NoDurability");
I do this on load in the item class. bNoDur is a class BOOL is use later in the decode.

You see bNoDur in my exend2.txt condition for Durability & MaxDurability.

I don't remember for sure but I think NoDurabilty (in general) is just to not display it.
Last edited by SVR on Sun May 23, 2004 6:43 pm, edited 1 time in total.

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Sun May 23, 2004 8:24 pm

Thanx! I'll fix it!

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Mon May 24, 2004 8:56 pm

Hi there again,

i've just analyzed some more chars... Good news... Most stuff is identified correctly...

I just came to a charm that has very strange indexes into the magic pre and suffix tables:

------ Simple item information end --------
[Parse simple item]
------ Simple item information start --------
ItemType: cm1
ItemTypeName: Charm Small
ItemClass: 1
------ Simple item information end --------
[Parse extended item]
------ Extended item 1 start --------
NumGems: 0
GUID: 932241127
ItemLevel: 13
ItemQualityInternal: 4
HasVariableGraphic: Yes (1)
VariableGraphic: 0
HasClassInfo: No (0)
ClassInfo: 0
------ Extended item 1 end --------
[Parse magic item (Prefix and Suffix)]
MagicPrefixId: 366
MagicSuffixId: 726
MagicPrefix: Russet
MagicSuffix: Unknown
------ Additional extended item information start --------

This charm is normally called "crimson small charm of shock".

Both of my tables (Magic Pre/Suffix) starts at index 0. Prefix table has an max range of 600 and suffix table an max range of 675. I've checked this with UdieToo and the values of 366 and 726 seem to be right (Udie shows them too). Mhh... Looked at the name with Udie and it displays "crimson small charm of shock". The right name.

Is there a trick with the magic pre/suffixes also (like the runewords) ?
Are there some more empty lines to fill in? What am i missing this time?

Hope you can help me again... Thanx! :)

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Post by SVR » Mon May 24, 2004 10:25 pm

There are 749 lines in MagSuffix.txt why is your range only 675?

Do you / are you using an extractor to look at the txt's?
Make sure you are looking at the ones from patch_d2.mpq or your info will be wrong.

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Tue May 25, 2004 7:38 am

Well, thats it :) I'm currently using the ones from d2exp.mpq (sorry, dont have the name in mind)... Do i need to use all resources only from that file? (Unique/Set/Rare/Magic/Armor/Weapons).

I'm using your DrTester tool which is really nice to extract the files from the mpq's.

Well, i coundn't look at the patch_d2.mpq, because i'm missing some index file (.0), or so that is. So DrTester doesn't allow me to extract... Any clue where to get this from?

Edit:
Oh, ok i've just read DrTester Readme.1st... I go looking for the listfile somewhere at PK...

Edit2:
I cannot download it... Some login seems to be required. Can you send the file to me via e-mail? (sledge-hammer@t-online.de) or can i download it elsewhere?
Last edited by Sledge on Tue May 25, 2004 7:45 am, edited 2 times in total.

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Tue May 25, 2004 8:39 am

I got the listfile... Already extracted all needed files, so no need to send it to me :) Thanx!!!

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Post by SVR » Tue May 25, 2004 5:27 pm

Anytime you need a file from the mpq's, check patch_d2 first, then exp, then data or char etc.

If the file is not in patch_d2 then it is unmodded from the other versions. (just make sure the filename is in your listfile else it may be modded and you just can't see it ;-)

User avatar
Sledge
Posts: 11
Joined: Mon May 17, 2004 9:49 pm

Re: Save file structure

Post by Sledge » Tue May 25, 2004 6:32 pm

Like the RarePrefix and RareSuffix? There seem to be only .bin for them on the patch_d2.mpq

Just build up my new resources and it seems the charms get identified ok. (UdieToo is a great help when looking up the right names and stuff)

Set items also have a much simpler structure than before.

User avatar
Myhrginoc
Retired Admin
Cherub
Posts: 12062
Joined: Sat May 25, 2002 7:28 am
Location: Percussion U

Hand-picked

Re: Save file structure

Post by Myhrginoc » Thu May 27, 2004 6:31 am

You'll find quite a few bin files without txts in the 1.10 patch. Blizzard added several data types and new ways of linking between tables, so the bins needed recompiling in those cases even though the txts didn't change.
Do the right thing. It will gratify some people and astonish the rest.
~ Mark Twain
Run Diablo II in any version for mods: tutorial
The Terms of Service!! Know them, abide by them, and enjoy the forums at peace.
The Beginner's Guide v1.4: (MS Word | PDF) || Mod Running Scripts || TFW: Awakening

User avatar
jeff_childers
Posts: 6
Joined: Thu Jul 01, 2004 4:00 pm

Re: Save file structure

Post by jeff_childers » Thu Jul 01, 2004 4:29 pm

most of the documentation that I have found suggest that each JM at offset 76 the next 32 bits are ascii characters. Now I looked in ItemTypes.txt (MPQ) and a potion is 'poti' but what I decode is ' ap0' is this the correct?

additional question: some of the documentation that I have read say that an items postion is 2, 4 bit fields. How is the location decoded like this?

if I decode it in the following manner I get the correct row and column of the stash inventory and belt if both row and col begin with 0 and not 1 BUT if it is equipped the position reports where the item is equipped
say:

$pos = '66';
my($row,$col) = get_location($pos);
print "$row,$col";

sub get_location{
my (@position,$in,$count,$row,$col);
$in = $_[0];
@position = qw(0 32 64 96 128 160 192 224 256 288);

$count = 0;
foreach (@position){
if(($in >= $position[$count])&&($in < $position[$count + 1])){
$col = ($in - $position[$count]) / 2;
$row = $count;
}
$count++;
}
return $row,$col;
}

row = 2
col = 1

any thoughts or holes in my logic?

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Post by SVR » Fri Jul 02, 2004 3:45 am

If you check the docs on my site, it has loc (3 bits),pos (4 Bits),row & col (4 bits each).
These 4 values determine "where" the item is.
if loc = 0 the row & col are a valid grid position. (maybe stash, inv, store, trade etc. depending on a 5th value, "stored In" )

if loc = 1 the item is equipped and the "pos" tells which slot.

if loc = 2 the item is in the belt and the "col" value is really an index of the belt position. row contains '0' or garbage.
You *could* look at the index as 2 bits for belt row and 2 for col, but it doesn't always work. I have to look back at my code to be sure.

if loc = 6 the item is in a socket and col tells which one, I think ;-)

Check my JM format for a list of the "pos" codes and inventory.txt for the actual screen coords for each.
Last edited by SVR on Fri Jul 02, 2004 3:50 am, edited 1 time in total.

User avatar
jeff_childers
Posts: 6
Joined: Thu Jul 01, 2004 4:00 pm

Re: Save file structure

Post by jeff_childers » Sun Jul 04, 2004 4:24 pm

SVR thanks for the reply. after looking at your website

beginning at offset 76 of a JM there should be 32 bits that decodes to a ascii abbreviation of the item. As of yet none of the these abbreviations seem to jive with any of the text files that I MPQ'd I assumed that it would correspond with the type from ItemTypes.txt. Will you confirm this for me. If this is untrue where is the list for this field?

thanks
Jeff
Last edited by jeff_childers on Sun Jul 04, 2004 5:04 pm, edited 1 time in total.

User avatar
SVR
Retired staff
Arch-Angel
Posts: 1449
Joined: Sat Nov 02, 2002 11:04 pm
Location: Texas
Contact:

Hand-picked

Post by SVR » Sun Jul 04, 2004 5:14 pm

It's not byte 76.
JM records are bit streams. The ItemType starts at "bit" 76.

8 bits = byte.

Read the field as 4 8 bit ascii characters, least significant bit first...

Code: Select all

ItemType = ""
for aChar= 1 to 4
    tmp=char(0)
    for pos=1 to 8
        newBit = GetNextBit()
        tmp = tmp or (newBit shl pos)   ' how do you shift left in basic again ???
    next
    ItemType = tmp & ItemType
next
My basic is very rusty so I'm sure this code won't work, but you get the idea.
Last edited by SVR on Sun Jul 04, 2004 5:37 pm, edited 2 times in total.

User avatar
jeff_childers
Posts: 6
Joined: Thu Jul 01, 2004 4:00 pm

Re: Save file structure

Post by jeff_childers » Mon Jul 05, 2004 8:01 pm

I understand at least I assume I understand.

here are the bits for the small red potion

01001010 01001101 000100000000000010100000000000000110010100000000000000001000 00100000011000010111000000110000 001

the first 16 is JM
followed by 60 bits to the start of the type field:
00100000011000010111000000110000
now if I convert 'poti' to it binary form:
1110000 1101111 1110100 1101001
my item has 9 'on' bits
what the field should be needs 17 'on' bits. Is there a differant way to convert the field to ascii.

Post Reply

Return to “Code Editing”