Blind monster

Claudius33… Good idea but it’s a bit late now that mod was finished ages ago.

If the only issue is saving then is there a function to no allow saves ? I know NWN2 has a really generous save system that allows you to save during fights ( unlike a lot of other games ) so maybe it’s not possible. But if it was you could create an autosave before the area and if it all goes wrong the player has to start again from that point.

1 Like

Tsongo,
You can use the function DoSinglePlayerAutoSave() (single player only) to autosave the game before entering a potentially hazardous area.
There is only one autosave slot (it will be overwritten each time you use the function), so choose wisely when to use it.
I’m not aware of any mechanism preventing a save.

@andgalf

This is the sort of thing I would do. It actually works really well … I did not continue any further as you believe you have a working solution, but I reckon this (with extra code for reloading) could look really cool.

UPDATE: OK, This appears to do exactly what you need … It now also preserves the last location saved by the sole PC actor.

UPDATE: OK, I also added a pseudo heartbeat to update the PCs location every 3 seconds. That way, the PC will be very close to the save position on a reload.

WHAT IS HAPPENING: The only real governing factor here is placing a variable of 1 in “ACTOR” on the sole PC. The code does the rest. The only thing you would need to do is to reverse the hiding and restore the party GUI when the acting is over. Give that I go if you want, and let me know if you need any help doing so. Basically, you would need to loop through the PCs, unhide them (probably jump to controlled PC first), remove the ACTOR variable from the acting PC and restore the Party Bar GUI. :slight_smile: (You could also optimise the code by ignoring the location storing if the player ended up using their main PC anyway. ie. The save location is correct using the Main PC as you know.) UPDATE: I added a LBStopActing function to the library below, which works in testing. i.e. Restores all the PCs and interface.

THIS FUNCTION (LBSetPartyActor) SETS UP THE SOLE PC ACTOR:-

Use it in any way where you can pass a PC into oNewActor. All PCs apart from this one will disappear, leaving the player in control of this PC only. (Also removes Party Bar to prevent swapping PCs that way too.)

NB: The script is currently only tested via a useable object. So, some parts may need tweaking.

///////////////////////////////////////////////////////////////////////////////////////////////////
// MAKE A COMPANION THE SOLE PC UNDER PLAYER COMMAND
///////////////////////////////////////////////////////////////////////////////////////////////////

#include "ginc_overland"

void UpdateLocation(object oNewActor)
{
	SetLocalLocation(oNewActor, "MYLOCATION", GetLocation(oNewActor));
	
	if(GetLocalInt(oNewActor, "ACTOR"))
	{
		DelayCommand(3.0, UpdateLocation(oNewActor));
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// MAKE A COMPANION THE SOLE PC UNDER PLAYER COMMAND
///////////////////////////////////////////////////////////////////////////////////////////////////
void LBSetPartyActor(object oNewActor);
void LBSetPartyActor(object oNewActor)
{		
	object oFM = GetFirstFactionMember(oNewActor, FALSE);
	
	while(oFM != OBJECT_INVALID)
	{
		AssignCommand(oFM, ClearAllActions(TRUE));
	
		if(oFM == oNewActor)
		{
			SetLocalInt(oNewActor, "ACTOR", 1);
			SetScriptHidden(oNewActor, FALSE);
			DelayCommand(0.1f, SetFactionLeader(oNewActor));
                        DelayCommand(0.1f, UpdateLocation(oNewActor));
		}
		
		else
		{
			SetScriptHidden(oFM, TRUE, FALSE);
		}
	
		oFM = GetNextFactionMember(oNewActor, FALSE);
	}	
	
	CloseGUIScreen(oNewActor, GUI_SCREEN_DEFAULT_PARTY_BAR);
}

void main()
{
          object oPC = GetLasteUsedBy();   // NB: Untested with any other hook. So may require tweaking.
          LBSetPartyActor(oPC);
}

THESE FUNCTIONS USED IN YOUR AREA CLIENT ENTER TO RESET THE ACTOR (IF REQUIRED):

// ALSO NEED TO RESTART THE RECORDER
void UpdateLocation(object oNewActor)
{
	SetLocalLocation(oNewActor, "MYLOCATION", GetLocation(oNewActor));
	
	if(GetLocalInt(oNewActor, "ACTOR"))
	{
		DelayCommand(3.0, UpdateLocation(oNewActor));
	}
}

void ResetLocation(object oPC)
{
	location lLoc = GetLocalLocation(oPC, "MYLOCATION");
	AssignCommand(oPC, ActionJumpToLocation(lLoc));
	
	// ALSO NEED TO RESTART THE RECORDER
	DelayCommand(0.1, UpdateLocation(oPC));
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// RESETS THE CURRENT PC ACTING AND RETURNS TRUE IF SUCCESSFUL (AND CLOSES PARTY BAR IF SO)
///////////////////////////////////////////////////////////////////////////////////////////////////
int LBResetActor(object oPC);
int LBResetActor(object oPC)
{		
	int iACTING = 0;
	
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	while(oFM != OBJECT_INVALID)
	{
		AssignCommand(oFM, ClearAllActions(TRUE));
	
		if(GetLocalInt(oFM, "ACTOR"))
		{					
			SetOwnersControlledCompanion(oPC, oFM);
			iACTING = 1;
			SetScriptHidden(oFM, FALSE);
			DelayCommand(0.1f, SetFactionLeader(oFM));                        
			DelayCommand(0.1f, UpdateLocation(oFM));
		}
		
		else
		{
			SetScriptHidden(oFM, TRUE, FALSE);
		}
	
		oFM = GetNextFactionMember(oPC, FALSE);
	}	
	
	if(iACTING){CloseGUIScreen(oPC, GUI_SCREEN_DEFAULT_PARTY_BAR);}
	
	return iACTING;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// RETURNS TRUE IF ANY PC IS GOING IT ALONE (ACTING)
///////////////////////////////////////////////////////////////////////////////////////////////////
int LBRequireResetCheck(object oPC);
int LBRequireResetCheck(object oPC)
{	
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	while(oFM != OBJECT_INVALID)
	{	
		if(GetLocalInt(oFM, "ACTOR"))
		{		
			return 1;
		}		
	
		oFM = GetNextFactionMember(oPC, FALSE);
	}	
		
	return 0;
}

void main()
{
        object oLeader = GetFirstEnteringPC();
        // CHECKS IF WE NEED TO RUN AN ACTOR
	if(LBRequireResetCheck(oLeader)){LBResetActor(oLeader); return;}
}

I will update with a video here to demonstrate - I will leave the PCS “LEVEL UP” shout going so you can “see” where the other hidden PCs are.

VIDEO DEMO …

ALTERNATIVELY AS A LIBRARY (INCLUDE) SETUP (alb_functions_acting):

///////////////////////////////////////////////////////////////////////////////////////////////////
// PLAYER FORCED TO CONTROL A SINGLE PC FUNCTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////
// RESTARTS THE LOCATION FOR A LONE PC
///////////////////////////////////////////////////////////////////////////////////////////////////
void UpdateLocation(object oNewActor);
void UpdateLocation(object oNewActor)
{
	SetLocalLocation(oNewActor, "MYLOCATION", GetLocation(oNewActor));
	
	if(GetLocalInt(oNewActor, "ACTOR"))
	{
		DelayCommand(3.0, UpdateLocation(oNewActor));
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// SETS THE LOCATION FOR A LONE PC
///////////////////////////////////////////////////////////////////////////////////////////////////
void ResetLocation(object oPC);
void ResetLocation(object oPC)
{
	location lLoc = GetLocalLocation(oPC, "MYLOCATION");
	AssignCommand(oPC, ActionJumpToLocation(lLoc));
	
	// ALSO NEED TO RESTART THE RECORDER
	DelayCommand(0.1, UpdateLocation(oPC));
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// RESETS THE CURRENT PC ACTING AND RETURNS TRUE IF SUCCESSFUL (AND CLOSES PARTY BAR IF SO)
///////////////////////////////////////////////////////////////////////////////////////////////////
int LBResetActor(object oPC);
int LBResetActor(object oPC)
{		
	int iACTING = 0;
	
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	while(oFM != OBJECT_INVALID)
	{
		AssignCommand(oFM, ClearAllActions(TRUE));
	
		if(GetLocalInt(oFM, "ACTOR"))
		{		
			SetOwnersControlledCompanion(oPC, oFM);
			iACTING = 1;
			SetScriptHidden(oFM, FALSE);
			DelayCommand(0.1f, SetFactionLeader(oFM));
			DelayCommand(0.1f, UpdateLocation(oFM));
		}
		
		else
		{
			SetScriptHidden(oFM, TRUE, FALSE);
		}
	
		oFM = GetNextFactionMember(oPC, FALSE);
	}	
	
	if(iACTING){CloseGUIScreen(oPC, GUI_SCREEN_DEFAULT_PARTY_BAR);}
	
	return iACTING;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// RETURNS TRUE IF ANY PC IS GOING IT ALONE (ACTING)
///////////////////////////////////////////////////////////////////////////////////////////////////
int LBRequireResetCheck(object oPC);
int LBRequireResetCheck(object oPC)
{	
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	while(oFM != OBJECT_INVALID)
	{	
		if(GetLocalInt(oFM, "ACTOR"))
		{			
			return 1;
		}		
	
		oFM = GetNextFactionMember(oPC, FALSE);
	}	
		
	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// MAKE A COMPANION THE SOLE PC UNDER PLAYER COMMAND
///////////////////////////////////////////////////////////////////////////////////////////////////
void LBSetPartyActor(object oNewActor);
void LBSetPartyActor(object oNewActor)
{		
	object oFM = GetFirstFactionMember(oNewActor, FALSE);
	
	while(oFM != OBJECT_INVALID)
	{
		AssignCommand(oFM, ClearAllActions(TRUE));
	
		if(oFM == oNewActor)
		{
			SetLocalInt(oNewActor, "ACTOR", 1);
			SetScriptHidden(oNewActor, FALSE);
			DelayCommand(0.1f, SetFactionLeader(oNewActor));
			DelayCommand(0.1f, UpdateLocation(oNewActor));
		}
		
		else
		{
			SetScriptHidden(oFM, TRUE, FALSE);
		}
	
		oFM = GetNextFactionMember(oNewActor, FALSE);
	}	
	
	CloseGUIScreen(oNewActor, GUI_SCREEN_DEFAULT_PARTY_BAR);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// RESTORE ALL PC CONTROL
///////////////////////////////////////////////////////////////////////////////////////////////////
void LBStopActing(object oActor);
void LBStopActing(object oActor)
{		
	object oFM = GetFirstFactionMember(oActor, FALSE);
	
	while(oFM != OBJECT_INVALID)
	{
		AssignCommand(oFM, ClearAllActions(TRUE));
	
		if(oFM == oActor)
		{
			DeleteLocalInt(oActor, "ACTOR");			
		}
		
		else
		{
			AssignCommand(oFM, ActionJumpToObject(oActor));
			SetScriptHidden(oFM, FALSE);
		}
	
		oFM = GetNextFactionMember(oActor, FALSE);
	}	
	
	DisplayGuiScreen(oActor, GUI_SCREEN_DEFAULT_PARTY_BAR, 0);
}

Then scripts would add this library as an include to keep things tidy …

EXAMPLE ON USED

///////////////////////////////////////////////////////////////////////////////////////////////////
// MAKE A COMPANION THE SOLE PC UNDER PLAYER COMMAND
///////////////////////////////////////////////////////////////////////////////////////////////////

##include "alb_functions_acting"

void main()
{
object oPC = GetLastUsedBy();
LBSetPartyActor(oPC);
}

AND THE AREA CLIENT ENTER (RESTORING)

///////////////////////////////////////////////////////////////////////////////////////////////////
// RESTORE A COMPANION AS THE SOLE PC UNDER PLAYER COMMAND
///////////////////////////////////////////////////////////////////////////////////////////////////

##include "alb_functions_acting"

void main()
{
object oPC = GetFirstEnteringPC();
if(LBRequireResetCheck(oLeader)){LBResetActor(oLeader); return;} // REMOVE RETURN IF REQUIRED
}
2 Likes

Thanks for all the replies. I’m very, very tired right now, so I won’t do any testing of this at the moment. Maybe in a few days, we’ll see. The video looks interesting. I hope you can still access the inventory of the companion you control, but I don’t see why not.

As I said in my previous post, I’m quite happy with the way works now for me, so maybe I’ll just leave it be since I’m a bit sick of testing this scene for the quatrilionth time. I know to go back here should I really want something like this at a later stage though.

As to the question about the portrait bar: Yes it’s still active. I don’t know how to script away that. I guess I’ll have to read your code to get an idea of how to do that.

1 Like

@andgalf

Check it out when you are up to it. Inventory should not be a problem.

You may find this method easier to implement in the long run. Less WPs to worry about. But go with what works best for you.

1 Like