PC drops inventory while unequipping weapons (OC, Act III, West Harbor)

hi Lance, interesting question … buckle up :)

Think about a rostermember who is despawned (aka not in the party, not at a hangout waypoint). It’s not in the Module-object.

All its items should not be in the Module-object. It and its inventory have despawned … all that stuff is saved to a .ROS file and should no longer be extant in the Module-object.

But my (rather intensive) testing and debugging indicates that it is, if the companion/rostermember was despawned in the currently loaded module. Yeah … if I give a shard to a companion and despawn the companion then GetObjectByTag() still gets an instance of the shard GetIsObjectValid(oShard) ( but there is no possessor GetItemPossessor(oShard), neither creature nor placeable container, and it’s not in an area GetArea(oShard) – this strikes me as a hardcoded bug ).

If I destroy that (fake) instance of a shard, then respawn the rostermember with (valid) shard, he still has it.

So i have to do some tomfoolery to discount fake shards as they are tallied up to 8 total.

 
Note that Ammon Jerro has a shard (in @Axe_Edge’s test save) – but his shard does not get counted (or appear as fake) since he is not spawned (and assumedly since he was not despawned in the currently loaded module – he is not in the Party when the save loads).

eg. In the following debugchat, shards #5 and #6 were given to Casavir and he was removed from the party (replaced by Bishop) before the cutscene. Those 2 shards are valid but have no possessor nor are they in an Area … but when Casavir is then respawned and checked for shards he has them also

- note that Ammon is not in the party and he has a shard but it is not found with GetObjectByTag() – it does get found properly, however, when he is spawned and checked for shards

3 Likes

aw why not, have some code ;)

const string SHARD_TAG_PRE = "nwn2_it_shard";
const int    SHARDS_TOTAL  = 8;

void tell(string sTell)
{ SendMessageToPC(GetFirstPC(FALSE), sTell); }

// kL helper for DestroyShardsRoster_start()
// Finish has to be delayed to give time for DestroyObject(oShard) to happen
// before saving out the character.
void DestroyShardsRoster_finish()
{
	tell("DestroyShardsRoster_finish()");
	object oRoster;

	string sRoster = GetFirstRosterMember();
	while (sRoster != "")
	{
		oRoster = GetObjectFromRosterName(sRoster);
		if (!GetIsObjectValid(GetFactionLeader(oRoster))) // 'oRoster' is not in the Party ->
		{
			SetScriptHidden(oRoster, FALSE);
			DespawnRosterMember(sRoster);
		}
		sRoster = GetNextRosterMember();
	}
}

// kL helper for DestroyShardsRoster_start()
int DestroyShardsInventory(object oTarget)
{
	tell("DestroyShardsInventory() " + GetName(oTarget));
	int tally = 0;

	object oShard;

	int i = 0;
	while (++i <= SHARDS_TOTAL)
	{
		oShard = GetItemPossessedBy(oTarget, SHARD_TAG_PRE + IntToString(i));
		if (GetIsObjectValid(oShard))
		{
			++tally;
			tell(". " + GetTag(oShard) + " " + GetName(GetItemPossessor(oShard)));
			DestroyObject(oShard, 0.f, FALSE);
		}
	}
	tell(". . shards= " + IntToString(tally));
	return tally;
}

// kL helper for DestroyShards()
// Those geniuses forgot that a despawned roster character could have shard(s)
// (and that shards can be stashed in containers in other Modules).
void DestroyShardsRoster_start(int tally)
{
	tell("DestroyShardsRoster_start()");
	object oRoster;

	location loc = GetLocation(GetPCSpeaker());

	string sRoster = GetFirstRosterMember();
	while (sRoster != "")
	{
		if (!GetIsObjectValid(GetObjectFromRosterName(sRoster)))
		{
			oRoster = SpawnRosterMember(sRoster, loc);
			SetScriptHidden(oRoster, TRUE);

			if ((tally += DestroyShardsInventory(oRoster)) >= SHARDS_TOTAL)
				break;
		}
		sRoster = GetNextRosterMember();
	}
	tell(". shards found total= " + IntToString(tally));
	DelayCommand(0.f, DestroyShardsRoster_finish());
}

// kL rewrite
// note: silver shards cannot be dropped on the ground. See 'k_mod_unacquire' in
// the OC Campaign folder.
void DestroyShards()
{
	tell("DestroyShards()");
	int tally = 0;

	object oShard;

	int i = 0;
	while (++i <= SHARDS_TOTAL)
	{
		oShard = GetObjectByTag(SHARD_TAG_PRE + IntToString(i));
		if (GetIsObjectValid(oShard))
		{
			object oPossessor = GetItemPossessor(oShard);
			if (GetIsObjectValid(oPossessor))
			{
				tell(". " + GetTag(oShard) + " " + GetName(oPossessor));
				// its on party that are despawned (in the current Module)
				// can remain as 'loose' its in the Module in addition to
				// being saved out on the roster character
				//
				// so don't count those loose/rogue its; count only its
				// in containers
				++tally;
			}
			else
			{
				object oArea = GetArea(oShard);
				if (GetIsObjectValid(oArea))
				{
					tell(". " + GetTag(oShard) + " " + GetName(oArea) + " ( " + GetTag(oArea) + " )");
				}
				else
					tell(". " + GetTag(oShard) + " AREA INVALID");
			}

			DestroyObject(oShard, 0.f, FALSE);
		}
	}
	tell(". . shards found= " + IntToString(tally));

	if (tally < SHARDS_TOTAL)
	{
		SendMessageToPC(GetPCSpeaker(), "<c=crimson>Checking roster for Shards ...</c>");
		DelayCommand(0.f, DestroyShardsRoster_start(tally));
	}
}
3 Likes

Puts on Devil Horns

During a multi player session, a shard is given to a PC (other than the main PC), then, the player of the shard bearing PC doesn’t make it to The Scar that day.

Devil Horns look nice
:slight_smile:

Other than Main PCs are listed in a save.

1 Like

:disguised_face:

yeh… the original designers should have tracked their shards better… agreed

( there should have been checks done in the OnEnter handlers of module etc to see if the Scar is done; if so, destroy any shards on PCs entering – this could handle both PCs and/or respawning companions* )

/mehbulehgh

 
* as well as shards that were left behind in chests (in other Modules) …

i could look into it, depends on what Modules are still accessible after The Scar

Where is IRAPS when you need him?

Here is a list of places accessible after forging the silver sword at The Scar.

Areas marked with an asterisk (*) are reachable by using the World Map immediately upon leaving The Scar.
Areas within areas are not necessarily listed.
This information is taken from my last playthrough, as well as opening up areas to look for transitions.
The encounters made while traveling seem to be within the modules listed, but some encounter areas may have been missed. I hope a PC wouldn’t leave a shard in an area where a “random encounter” occurred.
I’ll keep looking.

2100_Crossroad_Keep_A2
      Shandra's Farm     {3070}sh_farm     WM
     *Nolaloths Valley     3090_avalley     World Map(WM)
     *Strange Clearing     3190_forest     WM/(tr_3190_to_2100)

2300_Crossroad_Keep_Adv.mod
     *Crossroad Keep     2300_ck_farm     WM/p_2300_to_2310

2200_Port_Llast.mod
     *Port Llast     2200_portllast     WM/WM/WM   
     *Ember     2210_ember     WM/WM
      Duskwood Grove     2211_duskwood     WM/22_tr_duskwood_to_caverns
      Well     2220_cavernwell     dr_2220_to_2222
      Caverns     2222_cavernupper    dr_2222_to_2221/22_tr_caveexit_cl

2400_Illefarn_Ruins.mod
     *Ruins of Arvahn     2410_ogruins     WM/tr_30_zh_portal/2410_tr_protal_cl

3000_Neverwinter_A3.mod
     *Highcliff     {3010}highcliff     WM
     *Ironfist Stronghold     {3030}ir_strong     WM
     *Mount Galardrym    {3031}galardrym  WM/3032_from_3031/3033_from3031 
     *Circle of the Mere     {3041}cot_mere     WM
     *Guardian Ruins     {3051}guardruins
      WestHarbor(Scar)     {3052}westharbor     tr_to_3051/tr_to_3051    
     *Merchant Quarter     {3063}merchant     WM

3400_Merdelain.mod
      Vale of Merdelain     3400_gauntlet     3430_wp_entrance
      Inner Sanctum     3430_rsanctum

3500_Crossroad_Keep_Siege.mod
1 Like

@kevL_s

Yes, this is what we managed to conclude as a result of this post. :slight_smile:

And it sounds like the same issue I was experiencing when trying to track specific plot items. However, (if you recall), your suggestion of changing the TAG (using SetTag) at the time of each item discovery using the GetObjectByTag helped me to be able to determine when an object was specifically valid or not … and then destroy (or ignore) an “invalid” version when/if required.

This shard issue sounds similar to the one I was having? :thinking: Is not a similar change TAG option possible?

That would make recognising valid or invalid shard versions easier, wouldn’t it?

However, without looking more closely at the details, maybe there is a difference I missed. Perhaps SetTag cannot be used on an item not yet considered within a valid area or ownership in this case?

I have a lot of this (code below) for plot items … which destroys this instance of the object and makes the TAG for the item no longer valid, and thereby no longer findable … Also, bear in mind that the “item object” then completely disappears between reloads anyway. (i.e. It recognises it has been destroyed by the time we reload a game. The TAG change is just a temporary stop gap to prevent GetItemByTag from finding it incorrectly before a game reload. (*) )

SetPlotFlag(oItem, FALSE);
SetTag(oItem, "BYTAGFIX");
DestroyObject(oItem, 0.0, FALSE);

If you wanted to be more item specific (if shard tags or properties varied), then maybe use a new tag such as BYTAGFIX_ORIGNINALSHARDTAG and use FindSubString for special checks and or conditions?

(*) When a roster member is respawned, you can then destroy any BYTAGFIX items if required (having been set when asked to leave the party), or check if it is still required and us SetTag to correct it back again (if or when brought back into the party).

Although, another option I have with plot items, is to transfer all plot items to the Main PC from a despawned companion at time of despawning them. This is probably one of the easiest options, but it depends upon how the shard is setup for transfer / droppable etc.

1 Like

whoosh, I forgot about that

will have a think tomorrow

and look more at Axe’s stuff …

1 Like

heh. Upon loading Axe’s testsave there’s already a rogue shard #8

OcAct3_TheScar_rogueshardschat

code
// 'printshards'
/*
    Console script
*/

const string SHARD_TAG_PRE = "nwn2_it_shard";
const int    SHARDS_TOTAL  = 8;

void tell(string sTell)
{ SendMessageToPC(GetFirstPC(FALSE), sTell); }

//
void main()
{
	tell("PrintShards()");
	object oShard; string sShard;

	int i = 0;
	while (++i <= SHARDS_TOTAL)
	{
		sShard = SHARD_TAG_PRE + IntToString(i);

		int j = -1;
		while (GetIsObjectValid(oShard = GetObjectByTag(sShard, ++j)))
		{
			object oPossessor = GetItemPossessor(oShard);
			object oArea = GetArea(oShard);

			tell(IntToString(j) + " : " + sShard + " : "
					+ GetName(oPossessor) + " ( " + GetTag(oPossessor) + " ) "
					+ " area= " + GetName(oArea) + " ( " + GetTag(oArea) + " )");
		}
	}
}

nb. Lance you can add another case to the list: despawning a rostermember.

Workaround. If you really need to use GetObjectByTag() ( instead of an inventory function like GetItemPossessedBy() or GetFirst/NextItemInInventory() )

this should work …

object oItem = GetObjectByTag("tag");
if (GetIsObjectValid(oItem)
    && (GetIsObjectValid(GetItemPossessor(oItem)) || GetIsObjectValid(GetArea(oItem))))
{
    // oItem is not rogue here
}

alternately →

object oItem = GetObjectByTag("tag");
if (!GetIsObjectValid(oItem)
    || (!GetIsObjectValid(GetItemPossessor(oItem)) && !GetIsObjectValid(GetArea(oItem))))
{
    oItem = OBJECT_INVALID;
}

 
I wonder if this happens only to items flagged Plot … hm, i guess Barkskin potions aren’t plot eh

1 Like

@kevL_s

Yes, I thought that was going to be the case when I read this post … but the principle is the same. :slight_smile:

That’s pretty much what I did for two of my functions.

Exactly … It’s all item types. :speak_no_evil: (I just happened to be working on plot items when it raised its ugly head.)

Although, now we are aware of this kind of behaviour, I reckon we can still make good use of GetObjectByTag, as long as we consider this type of return as valid, even when not actually present. i.e. In some ways, this function is a “bonus” because it manages to locate potential items too! :slight_smile: And is why in this instance, its unusual behaviour may actually help us locate and retag the various shard pieces as we need them.

honestly, I think its just another bug

Once an item is destroyed (or otherwise removed from the Module) it should return !GetIsObjectValid()

 
am gonna Destroy that rogue shard #8 and see what happens …

[edit] it worked, shard destroyed

OcAct3_TheScar_rogueshardschat2

code
// 'printshards'

const string SHARD_TAG_PRE = "nwn2_it_shard";
const int    SHARDS_TOTAL  = 8;

void tell(string sTell)
{ SendMessageToPC(GetFirstPC(FALSE), sTell); }

//
void main()
{
	tell("PrintShards()");
	object oShard; string sShard;

	int i = 0;
	while (++i <= SHARDS_TOTAL)
	{
		sShard = SHARD_TAG_PRE + IntToString(i);

		int j = -1;
		while (GetIsObjectValid(oShard = GetObjectByTag(sShard, ++j)))
		{
			object oPossessor = GetItemPossessor(oShard);
			object oArea = GetArea(oShard);

			tell(IntToString(j) + " : " + sShard + " : "
					+ GetName(oPossessor) + " ( " + GetTag(oPossessor) + " ) "
					+ " area= " + GetName(oArea) + " ( " + GetTag(oArea) + " )");

			if (j) DestroyObject(oShard); // <-- DESTROY if (id != 0)
		}
	}
}
1 Like

Great … So in this case, we don’t get a bad return.

I’ll catch up with you Monday. :+1:

1 Like

That’s what i was thinkin’ too … so it’s additionally disconcerting to see that loading this testsave does instance a rogue-shard.

(but i don’t know how the rogue-instance happened in the first place)

[edit]
there’s a blueprint 30_reaver1.UTC that has a shard#8 but I don’t think that’s the rogue (only the shards possessed by Zhjaeve are the real thing) … because the .UTC also has nw_wplmsc006 Wicked Union scythe but GetObjectByTag() does NOT find the scythe as a rogue item.

Also looked at the module load and area load scripts (etc etc); none of them destroys any items …

Yet having unpacked and searched the files in the save, I can’t find it /aargh

 

note that Plot items can be destroyed without that line. Maybe placeables too … certainly not creatures though (?)

1 Like

Fun fact:

Ammon Jerro has silver shard 7 (fire and cold resistance) in his inventory as part of his starting equipment when he is created. He is where silver shard 7 originates.

The silver shard being in his possession is likely mentioned in a conversation, but I can’t think of which conversation.

2 Likes

The rogue shard will return as an instance until we have destroyed it and the game saved in the shard’s destroyed state, before reloading that “destroyed state” game. However, if you are saying that even in this case the instance returns, then maybe that would suggest a “backup” check is being made and a new instance being created? Or, I guess the issue could also occur, if a roster member is carrying a shard, and their state is not being updated between save and reloads somehow?

I put it in as a fail-safe, in case anything argued with me. :wink:

That’s surprising, considering what you say above.

OK, I’m intrigued to look too now. :slight_smile:

I’m not sure how far I will pursue it, as it sounds like you already have it mostly in hand, and are likely to have solved it by the time I see anything. However, maybe I can help find something?

@kevL_s

@Akhacha points out the key issues, which I also note.

To reiterate the issue as I currently understand it …

The UnequipPC function used in the script is not fit for purpose, as it overlooks both these issues, by assuming the Main PC will be the carrier of all the shards … and are also not being carried inside any bag containers the PC may be carrying. The issue is compounded (as already stated), if these shards are located elsewhere, like on a companion, and possibly even in a container they carry. And as shards may have also been placed on companions now currently despawned, we also have a continuity issue if that companion is taken back into the party with shards that are supposed to no longer exist.

I would add that there is another potential issue in a MP environment, where players can choose to switch leadership, meaning anything assumed to be on a leader, will certainly not be the case. I experienced this myself, when I recently played the campaign with a friend. After this cutscene, we noted that some shards remained in my inventory, because even though I had collected some, and he others, I would transfer leadership to him in some circumstances. (I guessed what had happened at the time, but did not look into it then, as all seemed fine elsewhere.)

ALTHOUGH, see UPDATE below, regarding Ammon Jerro speech.

0 ---- 0

Having considered the issue some more (and recognising the many potential locations the shards could end up), I am wondering (just as a suggestion) if it might be easier to approach this problem from another way … rather than try to locate all shards to destroy (at time of forging), maybe, instead, ensure all shards are forced to be carried by the host player. In a SP game, this would always be the leader anyway, and would also resolve the MP side of the problem. The “downsides” are (i) only the main PC would benefit from shard properties and (ii) we may need to give a story logical reason why this is the case. (*)

We would still need to address the broken item count in the UnequipPC function (remove it completely), but as the shards take up slots on the Main PC anyway, their destruction (at time of forging) would make way for any weapons needed to be unequipped as well as leave a slot for the new sword. EDIT: Actually, shards in container bags still needs considering if an inventory is full. I will consider that now.

(*) As the Main PC is supposed to be the “shard-bearer”, then maybe we can imply that any additional shards found can only be carried by them?

I believe reworking all shards to be placed on the Main PC (on any acquisition) may help resolve a lot of other headaches. It would require editing the k_mod_acquire to ensure any shard was placed onto the Main PC … A bit of a reverse of k_mod_unacquire, which would also need editing.

@kevL_s Also k_mod_unacquire may explain why you have a persistent shard at times, as it replaces any shard “lost”? Although, if “destroyed”, I would not have thought this to be invoked. :thinking:

If this alternative way was considered, then maybe this would work as the On Acquired script (edited official) … But bear in mind extra checks need to be added if being hosted by a DM, otherwise, they would end up with the shards!

// k_mod_unacquire
/*
    Module unacquire item script
    gets the tag of the item and calls:
    "i_<tag>_ua"
*/
// ChazM 3/1/05
// BMA-OEI 9/26/05 moved concat below string trim
// ChazM 10/20/05 - hook back in to the x2_mod_def* script

// OC
#include "ginc_death"

///////////////////////////////////////////////////////////////////////////////
// JUST RETURNS FIRST PC IN A SP GAME. (NB: COULD BE A DM IN A MP GAME SETUP!)
// MP: ALWAYS RETURNS THE SAME PLAYER, BUT THEY COULD BE A DM.
///////////////////////////////////////////////////////////////////////////////
object GetTheGameHost();
object GetTheGameHost()
{
	object oModule = GetModule();
	object oGAMEHOST = GetLocalObject(oModule, "GAMEHOST");		
	if(oGAMEHOST != OBJECT_INVALID){return oGAMEHOST;}
	
	// SETUP (BACKWARD COMPATIBLE)
	else
	{
		object oHost = OBJECT_INVALID;
		
		if(GetIsSinglePlayer())
		{
			oHost = GetFirstPC();
		} 
		
		else
		{
			object oTestHost = GetFirstPC();
			
			while(oTestHost != OBJECT_INVALID)
			{
				if(GetIsPCHost(oTestHost))
				{
					oHost = oTestHost; 
					
					// STORE FOR RETRIEVAL
					SetLocalObject(oModule, "GAMEHOST", oHost);
					
					break;
				}
			
				oTestHost = GetNextPC();	
			}
		
		}
	
		string sHOSTREF = GetPCPublicCDKey(oHost);
		SetGlobalString("HOSTREF", sHOSTREF);
		
		return oHost;
	}
}
	

const string SHARD_TAG_PREFIX = "nwn2_it_shard";

int GetIsShard(object oItem)
{
	int nChars = GetStringLength(SHARD_TAG_PREFIX);
	
	return (GetStringLeft(GetTag(oItem), nChars) == SHARD_TAG_PREFIX);
}

void main()
{
	object oItem = GetModuleItemAcquired();
	
	//GIVE ANY SHARD FOUND TO THE HOST PLAYER
	if(GetIsShard(oItem))
	{
		object oFinder = GetModuleItemAcquired();
		object oHost = GetTheGameHost();
				
		//this event would fire if the player passed the item to a party member, which we allow.
		if(oFinder != oHost)
		{
			CopyObject(oItem, GetLocation(oHost), oHost);
			DestroyObject(oItem);
		}	
	}

	ExecuteScript("x2_mod_def_unaqu", OBJECT_SELF);
/*
    object oItem = GetModuleItemLost();
    string sTag = GetTag(oItem);

    if (GetStringLength(sTag) > 11)
	{
        sTag = GetStringLeft(sTag, 11);
	}

    sTag = "i_" + sTag + "_ua";
    ExecuteScript(sTag, OBJECT_SELF);
*/
}

Oh! That may add another level of complexity. I’ll try to check that too, to see if it does complicate matters.

@Axe_Edge Just out of interest, has anyone tried selling a shard? Is that possible? I mean it does not show as a “plot” item in the item properties, so is a plot flag set somewhere else, which I cannot find. EDIT: I just checked an old saved game of my own, and it appears the plot flag has been set somewhere, as I cannot sell them.

0 ---- 0

UPDATE: Interestingly, Ammon Jerro says, "I do not believe reforging the sword will require all the shards – but as I have never done such a thing, I do not know for certain.", which means there is argument to suggest not every shard requires “destroying” upon its forging. So any shards remaining at time of its forging may be considered “not” an issue?

So, arguably, the only real issue is the items dropped at time of forging … reconsidering …

hey Lance,

please don’t fuss too much over it. I’ve gone way beyond the original issue. So the cutscene script you’re looking at is very different from the one I’m (pretty much done) working on …

the PCs hand-items now drop only for an extreme case. Ie, only if all slots are really full and none of them are shards (like you suggest, shards shall be destroyed before the SilverSword is granted, to potentially open up slots on PcSpeaker).

also done: destroy all shards in the module and on the roster, and ensure no rogue shards remain.

Plus a whackload of changes to get that cutscene to play more immersively. Characters no longer fritter about or stare off into space, etc.

And note that for Nwn2Fixes i won’t (or at least shouldn’t if at all possible) make fundamental changes to ingame mechanics, like adding restrictions on shards,

long story short: it’s working. All that’s left to do is destroy any shards that player(s) may have stashed in chests in the other Modules. (and this isn’t even strictly necessary for the ‘commit’ im working on)

 
The question of Leadership is interesting. I’ve put in some code that assumes that the Leader (-> PcSpeaker) should be the shard-bearer, although I don’t think (atm) anything will break if Leader/PcSpeaker is not the shard-bearer. But I don’t have an MP setup to test things like yourself; perhaps you can/would like to take a look and test that after i get a reasonably stable version ready.

 
The (alleged) fact that I’m seeing a rogue shard immediately after loading a save is sort of a sidenote to all this. The code I’ve written for destroying the shards should handle it okay. But it is ofc relevant to our understanding of those rogue items in general; so id like to know what causes it in this situation. But, again, wait and i can send a testcase w/ changed scripts, dialog, and a Savegame to ya,

 

The original code, it seems to me, is attempting to destroy all shards. There’s no note saying one way or the other. Those lines of dialog could be alluding to an idea that there might be more shards ‘out there’ (but that never appear ingame, aka Lore).

but that’s a neverending discussion …

 
Re. Plot shards. Their blueprints in the toolset all have Plot checked here. (ofc this doesn’t mean that placed shards, eg. on AJ or in chests or on reavers or wherever, have their flags checked also).

 
ps.   :zzz:

2 Likes

@kevL_s

Have a good rest!

Cool! :slight_smile:

At least it gave me a short diversion, and it was interesting to see how they handled the shard cutscene. :slight_smile:

My only problem here, is that I don’t have a saved game in a position to test it, especially as the person I play with is at another location … their house and not mine. :wink: That said, if you ever manage to setup a saved game where a player can connect remotely for testing your code, I can help if that is possible?

Good to know!

Oh, I see … fair point. I think I would have pursued destroying all found as well anyway. :slight_smile:

That’s weird, I only noticed non-plot in the module I loaded … but I guess they were set so elsewhere …

mine are flagged plot/droppable/identified …

3000_Neverwinter_A3.mod is dated 2007 Feb 20

(try selecting the field?)

1 Like

@kevL_s

Your version appears different to my own setup. You appear to be able to edit the properties direct from the original instance, where mine are greyed out. Let alone have plot enabled

How are you accessing the OC module?

I simply copied the OC module to my module folder and look at it from there. I had always assumed it was write protected as such (where greyed out), as I can only alter copies of object instances from any OC module. IE. If I need to alter any object, I have to make a copy of it first.

image

first, I’m using win7, which will ‘interpret’ the .NET framework (that the toolset incorporates) differently than win10.

2nd, i flagged the read-only property of any official modules that were not flagged readonly myself, after installation in 2017.

3rdly, my installation folder is not under \Program Files … Windows has too much $ecurity running there, for my taste.

4th, I can open and modify official modules, just can’t save them. (see #2, readonly)

bytesize is the same as yours, and the 1hr difference of the Modified date is just a quirk i notice every so often: am 99.9% sure they’re the same file, Lance.

2 Likes