@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.
(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
}