Can we force close "SCREEN_TARGETED_OBJECT" Target GUI?

Hi All,

I asked this a long while ago, but never had any resolution. As it is still something I would like to resolve if possible, I will pose the query again, and see if anybody found (or has) a solution they can share.

Basically, is there a way we can force close the TARGET GUI (the GUI that shows the player’s current target object) via scripting? (It causes is a minor problem if a target is still selected when calling some scripts.)

Using something as simple as “CloseGUIScreen(OBJECT_SELF, “SCREEN_TARGETED_OBJECT”)” has not worked for me.

Thanks in advance.

i (still) don’t think so, Lance

i mean… there are many functs that should have been hardcoded as a matter of course but weren’t. eg, Setters for every getter

GetPlayerCurrentTarget()
SetPlayerCurrentTarget(OBJECT_INVALID) <- doesn't exist
1 Like

That’s what I find too. :frowning:

Thanks for having another look though.

1 Like

I believe I managed to achieve what you asked, if I understood correctly.

Instead of closing the screen, I just hid every pane/component of it.
Keep in mind I did this with modified XMLs from my UI mod, so it should be a bit different for the default UI.

  1. As usual, check that the script begins with gui_ in its name:
  2. Also make sure that the involved xmls have scriptloadable=“true” in the Scene parameters
  3. Targeting is handled by TWO xmls, not just one. One for objects (target_object.xml) and one for enemies (target_enemy.xml), so both have to be called to make sure it always works.

Here’s how I impletemented it in a heartbeat script for a quick test module I made to make it work with the UI from my mod. It toggles the target UI off and on every 6 seconds, automatically. It was done this way just to show how it works in principle.
As I said before, some commands would be different for the standard UI because the panes/objects are named differently than the ones I used.

void ToggleTargetUI(object oPC, int nSTATE, int nFEEDBACK = FALSE)
{
	int nHIDE = TRUE;
	string sTXT = "Closing Target UI";
	if (nSTATE == TRUE)
	{
		nHIDE = FALSE;
		sTXT = "Showing Target UI";
	}
	SetGUIObjectHidden(oPC, "SCREEN_TARGETED_OBJECT", "TARGETSTYLE_new", nHIDE);
	SetGUIObjectHidden(oPC, "SCREEN_TARGETED_OBJECT", "portrait", nHIDE);
	SetGUIObjectHidden(oPC, "SCREEN_TARGETED_ENEMY", "TARGETSTYLE_new", nHIDE);
	SetGUIObjectHidden(oPC, "SCREEN_TARGETED_ENEMY", "portrait", nHIDE);
	if (nFEEDBACK == TRUE) FloatingTextStringOnCreature(sTXT, oPC, FALSE);
}

void main()
{
	object oPC = GetFirstPC();
	int nSTATE = GetLocalInt(oPC, "TARGET_UI_STATE");
	ToggleTargetUI(oPC, nSTATE, TRUE);
	if (nSTATE == TRUE) DeleteLocalInt(oPC, "TARGET_UI_STATE");
	else SetLocalInt(oPC, "TARGET_UI_STATE", TRUE);
}

You can see its results in this video:

Hi Clangeddin,

Thanks for responding! :slight_smile:

Unfortunately, I have a nasty feeling that this may only be “hiding” (as per what you say) as opposed to “closing” it completely. In other words, the “target” is still valid even when “hidden”, whereas “closing” (which is what I was after) would remove the target too.

The problem I am having, is that if a player keeps a target “open”, then some scripting keeps this target, which then interferes with some scripting calls I have.

i.e. When I call this function object oTarget = GetPlayerCurrentTarget(oPC); there are times when I would like to close/remove the object returned (which has been targetted at some point by the player and perhaps forgotten about), but other times leave it as the current target, which I may have automated. (Just tested a force examine on an OBJECT_INVALID, but it did not work. :frowning: )

As an example, if you are able to write a small test script that returns the name/tag of oTarget using the above function, then “hide” the target GUI, and run the test script again - my guess would be that even though we no longer see the target window, the code would still return the oTarget object as it is still the current target even though we cannot see it via the GUI. If, however, it returns OBJECT_INVALID, then you will have indeed found a solution - although it would also mean the “hide” works differently from what I have seen in other GUI usage. :wink:

The only other possibility I am trying to track down is how the official code store this target - For example I know that a “player target” is retrieved with GetLocalObject(oFM, “N2_PLAYER_QUEUED_TARGET”);, maybe there is somewhere else (similar) where the official code stores the targets that can be manipulated somehow.

Thanks for helping - and do let me know if you do manage to make the object INVALID via scripting.

Lance

Ok, if the target is a creature, I managed to solve it, it’s very easy actually and probably yields the best results.

void main()
{
	object oPC = GetFirstPC();
	object oTARGET = GetPlayerCurrentTarget(oPC);
	SetScriptHidden(oTARGET, TRUE);
	DelayCommand(0.0f, SetScriptHidden(oTARGET, FALSE));
}

For other types of objects there’s a workaround that involves destroying and recreating immediatly a copy of it. It’s not really pretty to see, but I suppose that in the end it achieves what you ask for.

1 Like

This subroutne appears to yield “satisfactory” results overall, by no means it’s perfect, there are situations that it doesn’t cover, like items in your inventory, and it might cause some issues with usable placeables if they are using certain on-spawn scripts or if their script set is different than their template resref (in that case they will stop working entirely).
However, I think it’s pretty much the closest you’ll come to what you’re looking for.

void RemoveTargetWorkaround(object oPC)
{
	object oTARGET = GetPlayerCurrentTarget(oPC);
	if (oTARGET == OBJECT_INVALID) return;
	if (GetItemPossessor(oTARGET) != OBJECT_INVALID) return;
	
	int nTYPE = GetObjectType(oTARGET);
	if (nTYPE == OBJECT_TYPE_CREATURE)
	{
		SetScriptHidden(oTARGET, TRUE);
		DelayCommand(0.0f, SetScriptHidden(oTARGET, FALSE));
		return;
	}
	
	object oNEW;
	int nINV = GetHasInventory(oTARGET);
	location lTARGET = GetLocation(oTARGET);
	if (nTYPE == OBJECT_TYPE_ITEM)
	{
		if (nINV == TRUE) oNEW = CopyObject(oTARGET, lTARGET);
		else oNEW = CopyItem(oTARGET, OBJECT_INVALID, TRUE);
	}
	else
	{
		oNEW = CreateObject(nTYPE, GetResRef(oTARGET), lTARGET, FALSE, GetTag(oTARGET));
		SetPlotFlag(oNEW, GetPlotFlag(oTARGET));
		SetUseableFlag(oNEW, GetUseableFlag(oTARGET));
		if (nINV == TRUE)
		{
			location lNEW = GetLocation(oNEW);
			object oITEM = GetFirstItemInInventory(oTARGET);
			while (oITEM != OBJECT_INVALID)
			{
				if (GetHasInventory(oITEM) == TRUE) CopyObject(oTARGET, lNEW, oNEW);
				else CopyItem(oTARGET, oNEW, TRUE);
				oITEM = GetNextItemInInventory(oTARGET);
			}
		}
	}
	
	SetPlotFlag(oTARGET, FALSE);
	AssignCommand(oTARGET, SetIsDestroyable(TRUE, FALSE));
	DestroyObject(oTARGET, 0.0f, FALSE);
}
1 Like

Thanks for taking a closer look at this for me Clangeddin.

This looks helpful, although I respect the fact that destroying and recreating objects can be “dodgy” especially objects that we still need for whatever reason - and especially if they contain some special variable or associated scripting.

However, I appreciate this gives me another approach to consider, especially if it removes the target - and thankfully, it may be enough to give me what I need change some aspects, even if I cannot fix all the areas it would have been good to do.

For now, I need to weigh up the advantages over any potential pitfalls for doing so, especially as the issue I am trying to fix is more “cosmetic” than anything else.

I am going to look over my own code and see if I can add any of your above code to my own situation where I can make use of it, so thanks for that. :slight_smile:

Lance.

I have been trying to work with these latest workarounds, but I am encountering problems with placeables that require their integrity when it comes to item drops, etc. i.e. Destroying and recreating does do what I need, but it causes other issues that I am not confident I would be able to iron all out.

In the meanwhile I tried working on the idea of refocussing a PC onto a new target, which I could then immediately destroy, but I was even unable to force the player to target something else, which would have appeared in the GUI. :frowning:

However, I do wonder if this idea still holds potential: Somehow change the target, which can then be destroyed, thereby removing the target altogether. I know it seems we cannot pass an invalid object to try to make a PC lose a target, but I thought it might be possible to have them be forced to “target” another valid object - even if temporary?

Just some thoughts …