Change portrait through scripting?

@andgalf

OK, I managed to get a step closer … Bunnies, not hares (hairs) … WIP …

This just proves a concept of being able to change the portrait at the moment. Now to automate it …

At the moment, I am not able to extract data as easily as I wanted to (it’s probably just me), but I have an xml file that dedicates a switch of portrait at the moment … but is currently limited to a single portrait name. It’s something I may be able to “improve” moving forward, but as long as I can automate what I currently have, then at least it works as a one xml file per portrait switch.

UPDATE: And here we go via a conversation …

@andgalf Let me know if you think this is what you were after! I assume it is, but don’t want to assume you intend to rework your module unless you want to.

All the same, I can upload the xml and script for anyone who is interested. At the moment, there is one simple conversation script (which can be rewritten if the event needs to be done some other way), and an XML script (and supporting gui script). The XML script simply sits in your campaign folder (or wherever you want it), and contains a reference to the tga file you want to update as a portrait. You simply edit this to refer to a tga in your campaign folder (or wherever), and it works.

2 Likes

@Lance_Botelle The first suggestion with the picture seems more along the line of what I would like. The other, with the video, although neat, just brings up the character screen and the player still has to click on his portrait to the left to get up the custom portrait selection screen. At least that’s how I interpret the video. It’s a step on the way to make it easier to the player, I suppose, but…So with the video, I think one could just as well write to the player how to do it, BUT if you somehow could manage to get the custom portrait selection screen up directly instead of just the character screen, then THAT would be really cool. This screen is the one I call custom portrait selection screen:

Sorry, no. This is for the Thenueh character that I’ve shown you pictures of before, and I’ve found another haircut for her (or two that I think match her face quite well, even though they need to be tweaked a bit for me to be pleased with it). For some reason she wants to cut her long hair since it’s in the way when she and the PC are out adventuring together.

One of the haircuts is from Rashi which I have tried contacting, but she hasn’t replied for a few months now, and the other is an old haircut from aerishairstyles, that looks good but is just a slight bit too “high” (if that makes sense) to my taste, and not as high resolution as Rashi’s amazing hairstyles.
Rashi’s haircut would need to be closer to the head (again the head thing) and I would like a strand of hair that covers her left I to be removed, since I like her eyes.

This is no problem, since I only want them to choose one predetermined new portrait (or skip the new portrait, I guess, if the player doesn’t like it).

@andgalf ,

The picture was just to show work in progress and still required the player to select, which is very similar to the default way anyway.

The video shows you having it changed via the conversation (or event you choose). I only left the character sheet open to show it had changed there as well as in the side bar. This is exactly what happens when you change a portrait. (It even did this in the still shot, but you do not see it.)

From what you are saying now, it sounds like you are trying to change the “side bar portrait” only. i.e. Not change the character sheet image when changing the side bar one. If that is the case, then you have misinterpreted the “portrait protocol”, which ties character sheet image with the same portrait in the side bar images. Separating them is probably considered “illogical” as they refer to the same thing.

If you are referring to just the side-bar portrait, then I believe I had something like this once before, but ironically, I abandoned it because it was not changing the other, which is what I now managed to do here. :sweat_smile:

Anyway, perhaps you can clarify.

EDIT: Look at the side bar portrait on the right hand side. It has also changed.

This, by comparison, is really easy to do, but I still do not understand your reasoning? I mean, even if you do automate opening the portrait selection GUI, then what is the point for the player? Are you now instructing them to select a new portrait? The way I did it, you automatically apply the exact portrait you intend them to apply from that screen you just opened for them without making them read your instructions, find the portrait and apply it. Am I missing something else here?

If I’m not mistaken, I “just” have the kissing animations for winged characters and the jumping/running one now left to do, so don’t hesitate if Thenueh tells you she absolutely needs her hair cut! :wink:

No, no, no. I didn’t realize the portrait changed. In that case it’s great. Of course I don’t just want to change side bar portrait only.

Again, I didn’t understand the video. If this is the case, that the portrait actually changes, then that’s really what I am looking for.

EDIT: Watched the video again, and now I see that it’s the dwarf portrait that changes to that of a bunny. I would very much like to have this code from you, if it’s not too hard to implement. Awesome!

I believe so, yes. I just need to go over what you sent me last. Things are happening so fast now, I’m a bit overwhelmed. :grinning:
And yes, she will insist on having a new haircut, but you can persuade her not to cut her lovely long hair. I’ll have to write that piece of dialogue… :grinning:

Thank goodness for that. I thought I had totally lost the plot. :wink:

I will post it up shortly. I am just tweaking it a little …

Also, “bunny” was the link to a joke … bunnies …hares … hairs … haircut. Get it?

From a distance all bunnies look like hares/hairs … perhaps it’s just my crazy sense of humour.

Anyway, here is another video showing more of the changes I have been making of late anyway, including the part that changes portraits on the fly. Consider it a prelude to my blog post …

AND THE SCRIPTS

THE XML EXAMPLE (MUST BE UNIQUE FOR EACH PORTRAIT USED)
NB: This is the default example that uses the stock ico_rabbit.tga image.

This means the XML MUST be called lbforce_ico_rabbit.xml. Inside this unique XML file, note where the ico_rabbit is. This is the part that would be changed if you ever want to change the name of the image the new portrait will use. So, if you have a portrait image called fred.tga, then you would copy the default template and call it lbforce_fred.xml and you would edit the file to change the ico_rabbit to fred. Or, more precisely: BG_OBJECT_ico_rabbit.tga becomes BG_OBJECT_fred.tga.

<?xml version="1.0" encoding="NWN2UI">

<!--
	INSTANT PORTRAIT CHANGE - BY LANCE BOTELLE (PROOF OF CONCEPT) 

	Replace the "ico_rabbit.tga" text below with the tga image you wish to use as a portrait. Save the xml. (Use unique xml files and calls for each portrait change.)
	See the  ALB_CHANGE_PORTRAIT conversation script for more information.
-->

<UIScene name="SCREEN_PORTRAIT_FORCE" x=ALIGN_CENTER y=ALIGN_CENTER modal=false width=388 height=400 fadeout="0.3" fadein="0.3" 
	draggable=true backoutkey=true scriptloadable=true priority="SCENE_INGAME"  OnAdd=UIObject_Misc_ExecuteServerScript("gui_alb_changeportrait","CHANGEPORTRAIT")  />
	

	<UIListbox name="BGLIST" x=ALIGN_CENTER y=70 width=360 height=280 yPadding=4 xPadding=0 update=true hidden=true
		showpartialchild=true scrollbaronright=true unequalcontrols=true scrollsegmentsize=30 hidescrollbarwhennotneeded=false snaptobottom=false>		
				
			<UIPane name="BGLIST_PROTO" width=300 height=86 prototype="true">

			<UIButton name="BGLIST_OBJECT_TEXT" x=0 y=0 width=78 height=86 
				OnUpdate0=UIObject_Misc_ExtractData("BG_OBJECT_ico_rabbit.tga","string",0,local:0)				
				OnUpdate1=UIButton_Input_SetPortrait(local:0)>
			</UIButton>
			<UIIcon name="CUSTOM_PORTRAIT_ICON_1" img="ico_rabbit.tga" x=2 y=13 width=64 height=64 />							

			</UIPane>
		

	</UIListbox>

THE SUPPORTING GUI SCRIPT

This script MUST be called gui_alb_changeportrait, as the XML refers to this name. If your event script (like my conversation example below) stores the string, then this script NEVER needs to change. Just use it as it is.

///////////////////////////////////////////////////////////////////////////////////////////
// CHANGE PORTRAIT SUPPORT GUI SCRIPT (WIP)
// (*) NB: WHATEVER XXX.TGA STRING IS PASSED HERE MUST ALSO BE IN THE UNIQUE XML FILE
///////////////////////////////////////////////////////////////////////////////////////////

void BuildPortraitList(object oPC, string sPortrait);
void BuildPortraitList(object oPC, string sPortrait)
{
	// SETUP VARS
	string sBGListItemRef = sPortrait; 	// CHANGE THIS TO THE PORTRAIT YOU WANT TO CHANGE TO (*)
	string sBGName = " ";				// ACTUAL NAME DISPLAYED THE LIST WHEN MADE	
	string sENCINFO = "       ";		// ADDITIONAL TEXT (PRIOR ACNAME) - USE FOR SPACER.
	string sImage = "ico_rabbit";		// IMAGE DISPLAYED FOR LIST ITEM (NEVER SEEN)	
	
	string sBGID = sBGListItemRef;
	
	AddListBoxRow(oPC, "SCREEN_PORTRAIT_FORCE", "BGLIST", "BG_OBJECT_"+sBGListItemRef, "BGLIST_OBJECT_TEXT="+sENCINFO + " " + sBGName, "BGLIST_OBJECT_IMAGE="+sImage+".tga", "0="+sBGID, "");		
}

void main(string sOption, string sBackground)
{	
	if(sOption == "CHANGEPORTRAIT")
	{
		object oPlayer = OBJECT_SELF;	
		object oPC = GetControlledCharacter(oPlayer);
		
		string sPortrait = GetLocalString(oPC, "NEWPORTRAIT");
		
		//SendMessageToPC(oPC, "TESTED FIRED> " + sBackground);
		
		if(sBackground != "0"){return;}
		
		BuildPortraitList(oPC, sPortrait);	
		
		CloseGUIScreen(oPlayer, "SCREEN_PORTRAIT_FORCE");	
	}
}

AN EXAMPLE EVENT SCRIPT (VIA CONVERSATION)

This is just an example of how you can call the script. This uses a conversation call, but can easily be altered for another event, like pulling a lever. This script is called alb_changeportrait.

/////////////////////////////////////////////////////////////////////////////////////////
// CHANGE A PORTRAIT VIA NEW XML AND SCRIPTING (WORK IN PROGRESS) BY LANCE BOTELLE
// THIS ASSUMES CALLED FROM A CONVERSATION - REWRITE FOR OTHER SITUATIONS
// THIS ALSO ASSUMES THE PC IS IN THE PARTY (IT IS NOT FOR NPCS)
// NB: This is currently setup as as a SINGLE IMAGE portrait change per xml file.
// Therefore, if you need more than one portrait image change you would need to 
// rename each xml file accordingly AND ensure the xml code inside is updated. (See xml file.)
// FORMAT: THE sImageRef IS USED TO NAME THE XML FILE AND PORTRAIT IMAGE SELECT
/////////////////////////////////////////////////////////////////////////////////////////

void main(string sPCTagToPortraitChange = "", string sImageRef = "")
{
	object oPC = GetPCSpeaker();	
	
	if(sPCTagToPortraitChange != "")
	{
		object oPCChange = GetObjectByTag(sPCTagToPortraitChange);
		
		if(oPC != oPCChange)
		{
			oPC = SetOwnersControlledCompanion(oPC, oPCChange);
		}
	}
	
	// DEFAULT REQUIRES CONFIRMING
	if(sImageRef == "")
	{
		sImageRef = "ico_rabbit";
	}
	
	// UNIQUE XML FILE
	string sXMLFile = "lbforce_" + sImageRef + ".xml";
	
	// STORE IMAGE ON PC TO HANGE
	string sImageTAG = sImageRef + ".tga";		
	
	SetLocalString(oPC, "NEWPORTRAIT", sImageTAG);
	
	//SendMessageToPC(oPC, ">> " + sXMLFile + " >>> " + sImageTAG); // DEBUG
	
	// ENSURE THE NAME OF THE XML FILE FOR EACH PORTRAIT IS UNIQUE
	// EG: IF DEFAULT ico_rabbit IS PASSED, THEN THE SUPPORTING XML SHOULD BE CALLED lbforce_ico_rabbit.xml
	// THIS UNIQUE XML FILE WILL CONTAIN A REFERENCE TO THE IMAGE THE PORTRAIT IT USES (ico_rabbit.tga)
	// BE SURE TO HAVE THE TGA IMAGE IN YOUR SETUP AND EDIT ANY XML FILES YOU INTEND TO USE
	DisplayGuiScreen(oPC, "SCREEN_PORTRAIT_FORCE", 0, sXMLFile);
}

FIVE STEP BY STEP SETUP

  1. Copy lbforce_ico_rabbit.xml, gui_alb_changeportrait and alb_changeportrait to your campaign directory or wherever you keep them.

  2. Find a TGA file you wish to use as a portrait and make note of its filename. Eg: xavier.tga.

  3. Make a copy of lbforce_ico_rabbit.xml and call it lbforce_xavier.xml. Put in normal file location.

  4. Edit the lbforce_xavier.xml and replace BG_OBJECT_ico_rabbit.tga withBG_OBJECT_xavier.tga. Save the update.

  5. Add alb_changeportrait to a conversation and make sure that the second parameter is xavier.

All should be ready to go!

NOTE:

A) This is VERY case sensitive.
B) Only ever edit copies of the XML template as provided.
C) Be sure you do NOT add the suffix tga anywhere as the code adds this when required.

FINALLY: If I can ever get UIObject_Misc_ExtractData to work as I was expecting, then we can make this even easier to implement. I may have just missed something obvious. If anybody picks this up to play with, then please give me a heads up if you are able to extract the data from the object more efficiently. If I get the time and inclination, I will take another look. (I am probably just not using AddListBoxRow correctly. I thought I could add a variable this way, but could not do so as I thought.) For now, it is what it is!

1 Like

Ok, that was…far-fetched…but it even works in swedish because Bunny is actually “hare” or “kanin” in swedish (though hair is “hår” (don’t know if you can see the “a” with the ring on top, or if it shows like something else) in swedish so maybe it doesn’t work that well). I didn’t get it 'till you said it though.

:+1: Scripts and new video now posted.

Ask if you have any setup questions.

@andgalf

A five step by step instructions now included in the last post.

1 Like

Thanks, I hope I get it. It seems quite straight forward, actually. I’ll read through a bit now. Might come back tomorrow with questions…we’ll see.

In the XML file, shouldn’t I also change here the img=“ico_rabbit.tga” to for example xavier.tga?

I’ll try that, since I don’t see the logic in keeping the ico_rabbit.tga in this place since I don’t have a tga file with that name. I hope I’m not wrong. I guess I’ll see.

@Lance_Botelle - Ok, so I’ve tried everything now, but nothing I do makes it work. I don’t have a clue as to what I’m doing wrong here. I hope you’re around tomorrow and can answer this. So, here’s what I did:

  1. Copied the three scripts. Everyone of them I put in the campaign folder. I made sure to save the scripts in the toolset apart from the xml of course.The xml file I called lbforce_ico_rabbit.xml and put it in the campaign folder. I then copied it and renamed it to lbforce_thenuehp2.xml since the portrait I have is called thenuehp2.tga. Since at first I couldn’t get hold of the portrait, I stored it, like I use to, in my hak pak. When things didn’t work I copied it to my portraits folder, then to my module folder and then to my campaign folder. I can now choose it from inside the game by manually changing portraits.

  2. Here are what my scirpts look like. Maybe I missed something?

The XML file:

<?xml version="1.0" encoding="NWN2UI">

<!--
	INSTANT PORTRAIT CHANGE - BY LANCE BOTELLE (PROOF OF CONCEPT) 

	Replace the "ico_rabbit.tga" text below with the tga image you wish to use as a portrait. Save the xml. (Use unique xml files and calls for each portrait change.)
	See the  ALB_CHANGE_PORTRAIT conversation script for more information.
-->

<UIScene name="SCREEN_PORTRAIT_FORCE" x=ALIGN_CENTER y=ALIGN_CENTER modal=false width=388 height=400 fadeout="0.3" fadein="0.3" 
	draggable=true backoutkey=true scriptloadable=true priority="SCENE_INGAME"  OnAdd=UIObject_Misc_ExecuteServerScript("gui_alb_changeportrait","CHANGEPORTRAIT")  />
	

	<UIListbox name="BGLIST" x=ALIGN_CENTER y=70 width=360 height=280 yPadding=4 xPadding=0 update=true hidden=true
		showpartialchild=true scrollbaronright=true unequalcontrols=true scrollsegmentsize=30 hidescrollbarwhennotneeded=false snaptobottom=false>		
				
			<UIPane name="BGLIST_PROTO" width=300 height=86 prototype="true">

			<UIButton name="BGLIST_OBJECT_TEXT" x=0 y=0 width=78 height=86 
				OnUpdate0=UIObject_Misc_ExtractData("BG_OBJECT_thenuehp2.tga","string",0,local:0)				
				OnUpdate1=UIButton_Input_SetPortrait(local:0)>
			</UIButton>
			<UIIcon name="CUSTOM_PORTRAIT_ICON_1" img="ico_rabbit.tga" x=2 y=13 width=64 height=64 />							

			</UIPane>
		

	</UIListbox>

I also tried with this version of the XML file but that did nothing either:

<?xml version="1.0" encoding="NWN2UI">

<!--
	INSTANT PORTRAIT CHANGE - BY LANCE BOTELLE (PROOF OF CONCEPT) 

	Replace the "ico_rabbit.tga" text below with the tga image you wish to use as a portrait. Save the xml. (Use unique xml files and calls for each portrait change.)
	See the  ALB_CHANGE_PORTRAIT conversation script for more information.
-->

<UIScene name="SCREEN_PORTRAIT_FORCE" x=ALIGN_CENTER y=ALIGN_CENTER modal=false width=388 height=400 fadeout="0.3" fadein="0.3" 
	draggable=true backoutkey=true scriptloadable=true priority="SCENE_INGAME"  OnAdd=UIObject_Misc_ExecuteServerScript("gui_alb_changeportrait","CHANGEPORTRAIT")  />
	

	<UIListbox name="BGLIST" x=ALIGN_CENTER y=70 width=360 height=280 yPadding=4 xPadding=0 update=true hidden=true
		showpartialchild=true scrollbaronright=true unequalcontrols=true scrollsegmentsize=30 hidescrollbarwhennotneeded=false snaptobottom=false>		
				
			<UIPane name="BGLIST_PROTO" width=300 height=86 prototype="true">

			<UIButton name="BGLIST_OBJECT_TEXT" x=0 y=0 width=78 height=86 
				OnUpdate0=UIObject_Misc_ExtractData("BG_OBJECT_thenuehp2.tga","string",0,local:0)				
				OnUpdate1=UIButton_Input_SetPortrait(local:0)>
			</UIButton>
			<UIIcon name="CUSTOM_PORTRAIT_ICON_1" img="thenuehp2.tga" x=2 y=13 width=64 height=64 />							

			</UIPane>
		

	</UIListbox>

The gui_alb_changeportrait script looks like this on my end:

///////////////////////////////////////////////////////////////////////////////////////////
// CHANGE PORTRAIT SUPPORT GUI SCRIPT (WIP)
// (*) NB: WHATEVER XXX.TGA STRING IS PASSED HERE MUST ALSO BE IN THE UNIQUE XML FILE
///////////////////////////////////////////////////////////////////////////////////////////

void BuildPortraitList(object oPC, string sPortrait);
void BuildPortraitList(object oPC, string sPortrait)
{
	// SETUP VARS
	string sBGListItemRef = sPortrait; 	// CHANGE THIS TO THE PORTRAIT YOU WANT TO CHANGE TO (*)
	string sBGName = " ";				// ACTUAL NAME DISPLAYED THE LIST WHEN MADE	
	string sENCINFO = "       ";		// ADDITIONAL TEXT (PRIOR ACNAME) - USE FOR SPACER.
	string sImage = "ico_rabbit";		// IMAGE DISPLAYED FOR LIST ITEM (NEVER SEEN)	
	
	string sBGID = sBGListItemRef;
	
	AddListBoxRow(oPC, "SCREEN_PORTRAIT_FORCE", "BGLIST", "BG_OBJECT_"+sBGListItemRef, "BGLIST_OBJECT_TEXT="+sENCINFO + " " + sBGName, "BGLIST_OBJECT_IMAGE="+sImage+".tga", "0="+sBGID, "");		
}

void main(string sOption, string sBackground)
{	
	if(sOption == "CHANGEPORTRAIT")
	{
		object oPlayer = OBJECT_SELF;	
		object oPC = GetControlledCharacter(oPlayer);
		
		string sPortrait = GetLocalString(oPC, "NEWPORTRAIT");
		
		//SendMessageToPC(oPC, "TESTED FIRED> " + sBackground);
		
		if(sBackground != "0"){return;}
		
		BuildPortraitList(oPC, sPortrait);	
		
		CloseGUIScreen(oPlayer, "SCREEN_PORTRAIT_FORCE");	
	}
}

When things didn’t work I tried this:

///////////////////////////////////////////////////////////////////////////////////////////
// CHANGE PORTRAIT SUPPORT GUI SCRIPT (WIP)
// (*) NB: WHATEVER XXX.TGA STRING IS PASSED HERE MUST ALSO BE IN THE UNIQUE XML FILE
///////////////////////////////////////////////////////////////////////////////////////////

void BuildPortraitList(object oPC, string sPortrait);
void BuildPortraitList(object oPC, string sPortrait)
{
	// SETUP VARS
	string sBGListItemRef = sPortrait; 	// CHANGE THIS TO THE PORTRAIT YOU WANT TO CHANGE TO (*)
	string sBGName = " ";				// ACTUAL NAME DISPLAYED THE LIST WHEN MADE	
	string sENCINFO = "       ";		// ADDITIONAL TEXT (PRIOR ACNAME) - USE FOR SPACER.
	string sImage = "thenuehp2";		// IMAGE DISPLAYED FOR LIST ITEM (NEVER SEEN)	
	
	string sBGID = sBGListItemRef;
	
	AddListBoxRow(oPC, "SCREEN_PORTRAIT_FORCE", "BGLIST", "BG_OBJECT_"+sBGListItemRef, "BGLIST_OBJECT_TEXT="+sENCINFO + " " + sBGName, "BGLIST_OBJECT_IMAGE="+sImage+".tga", "0="+sBGID, "");		
}

void main(string sOption, string sBackground)
{	
	if(sOption == "CHANGEPORTRAIT")
	{
		object oPlayer = OBJECT_SELF;	
		object oPC = GetControlledCharacter(oPlayer);
		
		string sPortrait = GetLocalString(oPC, "NEWPORTRAIT");
		
		//SendMessageToPC(oPC, "TESTED FIRED> " + sBackground);
		
		if(sBackground != "0"){return;}
		
		BuildPortraitList(oPC, sPortrait);	
		
		CloseGUIScreen(oPlayer, "SCREEN_PORTRAIT_FORCE");	
	}
}

And the alb_changeportrait looks like this:

/////////////////////////////////////////////////////////////////////////////////////////
// CHANGE A PORTRAIT VIA NEW XML AND SCRIPTING (WORK IN PROGRESS) BY LANCE BOTELLE
// THIS ASSUMES CALLED FROM A CONVERSATION - REWRITE FOR OTHER SITUATIONS
// NB: This is currently setup as as a SINGLE IMAGE portrait change per xml file.
// Therefore, if you need more than one portrait image change you would need to 
// rename each xml file accordingly AND ensure the xml code inside is updated. (See xml file.)
// FORMAT: THE sImageRef IS USED TO NAME THE XML FILE AND PORTRAIT IMAGE SELECT
// EG: 
/////////////////////////////////////////////////////////////////////////////////////////

void main(string sPCTagToPortraitChange = "", string sImageRef = "thenuehp2")
{
	object oPC = GetPCSpeaker();	
	
	if(sPCTagToPortraitChange != "")
	{
		oPC = GetObjectByTag(sPCTagToPortraitChange);
	}
	
	// DEFAULT REQUIRES CONFIRMING
	if(sImageRef == "")
	{
		sImageRef = "thenuehp2";
	}
	
	// UNIQUE XML FILE
	string sXMLFile = "lbforce_" + sImageRef + ".xml";
	
	// STORE IMAGE ON PC TO HANGE
	string sImageTAG = sImageRef + ".tga";		
	
	SetLocalString(oPC, "NEWPORTRAIT", sImageTAG);
	
	//SendMessageToPC(oPC, ">> " + sXMLFile + " >>> " + sImageTAG); // DEBUG
	
	// ENSURE THE NAME OF THE XML FILE FOR EACH PORTRAIT IS UNIQUE
	// EG: IF DEFAULT ico_rabbit IS PASSED, THEN THE SUPPORTING XML SHOULD BE CALLED lbforce_ico_rabbit.xml
	// THIS UNIQUE XML FILE WILL CONTAIN A REFERENCE TO THE IMAGE THE PORTRAIT IT USES (ico_rabbit.tga)
	// BE SURE TO HAVE THE TGA IMAGE IN YOUR SETUP AND EDIT ANY XML FILES YOU INTEND TO USE
	DisplayGuiScreen(oPC, "SCREEN_PORTRAIT_FORCE", 0, sXMLFile);
}

With the sPCTagToPortraitChange I write in the conversation: thenueh. That’s the tag name of the companion.
I also tried moving the xml file to the module folder instead. Still nothing happens ingame.
Should the alb_changeportrait be at the end node of the conversation? I tried in the middle of the conversation and then at the end of the conversation and nothing worked.

Has anyone else tried Lance’s solution and got it to work?

@andgalf,

Good Morning!

No, this does not need to be changed. It is a placeholder only.

OK, I found the issue. I am working on it. (It is to do with selecting the PC to change.)

UPDATE:

OK, so trying to change a third-party PC appears tricky. i.e. It appears you can only change the portrait of the PC you currently control. So, there are two options I can see, if it is any help to you …

  1. Ensure the player is playing thenueh when calling the conversation script.
  2. We force the player into controlling thenueh at the time of calling the script.

Both should be quite doable. The first simply uses the scripts I have already posted. (Although, I am going to replace them with ones that will also allow the second option.)

I will repost my updated scripts here and update the earlier post too.

EDIT: I have updated one of the previous scripts (the conversation one) to remove the first parameter of choosing the PC to change at this stage, due to the issue found. That script can still be used if the PC portrait to change is the one being used in the conversation, but I will now work on a script that can change the portrait of a PC not yet controlled.

QUESTION: @andgalf Is the PC that you want the haircut done already in the party or not? I had assumed they are in the party at least. If they are no longer in the party, then that is another stage of scripting required. Here are the scripting stages required … I need to know which applies to your requirements.

  1. PC that requires portrait change needs to be the currently controlled PC.
  2. If in party, force swap of PC controlled, prior calling portrait change XML.
  3. If not in party, add to party and force swap to controlled prior calling XML change. (Remove again?)

Considerations …

i) A fade to black to allow swaps to not be seen.

Yes, she is.

I cannot know before hand if the player is controlling Thenueh, but when you enter a conversation, to me it seems it always switches to the PC, but I don’t know… Anyway, I think it would be good if the script could change it to her character being controlled somehow like you mention.

@andgalf

Great to here that she is already in the party! :+1: That will make things a lot easier.

I think I recall you setting a campaign variable to force conversations to always start from your main pc after another issue you had once. That may be why your conversations always switch back to that PC. It may be something you may wish to check moving forward, as it could have other repercussions.

If it is any help, I use an opposite rule, in that the player can start a conversation from any PC, and only force back to the main pc when required. The upside is it keeps a degree of logical flow, the downside is that you may need to consider your scripts more closely.

Hopefully, I can write a script that works for both logical approaches.

NOTE: In the new script below, the player will be left playing the new PC with the haircut. If you wish to automatically switch the player back to their original conversation starting PC, you can script that, but in your style game, I doubt it matters.

@andgalf

OK, try this replacement conversation script …

I just updated this script at 11.57. Be sure to have the latest.
Let me know if this now works for you. I tested it my end and it works for me.

IMPORTANT: ONLY PASS PARAMETERS VIA THE CONVERSATION NODE LIKE THIS:

/////////////////////////////////////////////////////////////////////////////////////////
// CHANGE A PORTRAIT VIA NEW XML AND SCRIPTING (WORK IN PROGRESS) BY LANCE BOTELLE
// THIS ASSUMES CALLED FROM A CONVERSATION - REWRITE FOR OTHER SITUATIONS
// THIS ALSO ASSUMES THE PC IS IN THE PARTY (IT IS NOT FOR NPCS)
// NB: This is currently setup as as a SINGLE IMAGE portrait change per xml file.
// Therefore, if you need more than one portrait image change you would need to 
// rename each xml file accordingly AND ensure the xml code inside is updated. (See xml file.)
// FORMAT: THE sImageRef IS USED TO NAME THE XML FILE AND PORTRAIT IMAGE SELECT
/////////////////////////////////////////////////////////////////////////////////////////

void main(string sPCTagToPortraitChange = "", string sImageRef = "")
{
	object oPC = GetPCSpeaker();	
	
	if(sPCTagToPortraitChange != "")
	{
		object oPCChange = GetObjectByTag(sPCTagToPortraitChange);
		
		if(oPC != oPCChange)
		{
			oPC = SetOwnersControlledCompanion(oPC, oPCChange);
		}
	}
	
	// DEFAULT REQUIRES CONFIRMING
	if(sImageRef == "")
	{
		sImageRef = "ico_rabbit";
	}
	
	// UNIQUE XML FILE
	string sXMLFile = "lbforce_" + sImageRef + ".xml";
	
	// STORE IMAGE ON PC TO HANGE
	string sImageTAG = sImageRef + ".tga";		
	
	SetLocalString(oPC, "NEWPORTRAIT", sImageTAG);
	
	//SendMessageToPC(oPC, ">> " + sXMLFile + " >>> " + sImageTAG); // DEBUG
	
	// ENSURE THE NAME OF THE XML FILE FOR EACH PORTRAIT IS UNIQUE
	// EG: IF DEFAULT ico_rabbit IS PASSED, THEN THE SUPPORTING XML SHOULD BE CALLED lbforce_ico_rabbit.xml
	// THIS UNIQUE XML FILE WILL CONTAIN A REFERENCE TO THE IMAGE THE PORTRAIT IT USES (ico_rabbit.tga)
	// BE SURE TO HAVE THE TGA IMAGE IN YOUR SETUP AND EDIT ANY XML FILES YOU INTEND TO USE
	DisplayGuiScreen(oPC, "SCREEN_PORTRAIT_FORCE", 0, sXMLFile);
}
1 Like

@Lance_Botelle - Thank you! Now it worked. No problems at all. :slightly_smiling_face:

1 Like

I’m so glad we managed to do this. It’s quite astonishing what you can achieve through xml coding that you can’t do with regular scripting. Makes me think that this game is, despite all, extremely versatile.

1 Like

I believe there may be one or two others in the community who could improve on what I did, simply because I still struggle with XML and there is probably a better way. If I could understand the ExtractData functions better, maybe it would help.

As you say though, XML adjustments is a great facility for us to get around a number of obstacles. :+1:

Yeah, it’s like you fool the game into doing what you want.

1 Like