Run conversation issue

Hard to put a headline that describes what I’m trying to do here but…

The scenario is this in broad strokes: The PC gets teleported to a new area. He can be wherever in the world when this happens. All of the companions in the party will remain in the area that he was in. The other companions that are available in the roster will have to be removed completely, so that the player can’t add them in the new area through the Roster Roster/Party Select system that I use. I have received a great include script from @kevL_s that takes care of storing the area where the PC was and storing companions in the roster etc. So that’s no problem.

Now, the issue is when the PC comes back to where he left, I would want a conversation starting right away that adds the companions that were previously in the party, as well as add those to the roster that are not, but were in the roster.

The difficult part I realized now is: How do I trigger this conversation directly when the PC returns to the area where he was before? Do I have to (I would rather not) put some kind of GetGlobalInt on every ClientEnter of every area in the whole module (quite a lot of areas in this module) to run this conversation? Or could you maybe somehow add a GetModule thing where when the PC returns to wherever he is, the conversation automatically starts? Some kind of “This script starts automatically when the PC returns to where he was”?

EDIT: Here’s the script that runs when the PC is to return to the area he was in previously. Could one add to this script that a conversation is somehow run after the PC arriving in the return-area?

//New functions by kevL_s. The rest of the script by andgalf.

void SetSavedLocation(string sVar, object oObject)
{
    object oModule = GetModule();

    string sArea = GetTag(GetArea(oObject));
    SetLocalString(oModule, sVar + "_area", sArea);

    float fFace = GetFacing(oObject);
    SetLocalFloat(oModule, sVar + "_face", fFace);

    vector vObject = GetPosition(oObject);
    SetLocalFloat(oModule, sVar + "_x", vObject.x);
    SetLocalFloat(oModule, sVar + "_y", vObject.y);
    SetLocalFloat(oModule, sVar + "_z", vObject.z);
}

//
location GetSavedLocation(string sVar)
{
    object oModule = GetModule();

    object oArea = GetObjectByTag(GetLocalString(oModule, sVar + "_area"));

    float fFace = GetLocalFloat(oModule, sVar + "_face");

    float fx = GetLocalFloat(oModule, sVar + "_x");
    float fy = GetLocalFloat(oModule, sVar + "_y");
    float fz = GetLocalFloat(oModule, sVar + "_z");
    vector vObject = Vector(fx, fy, fz);

    return Location(oArea, vObject, fFace);
}

void main(string sVar)
{
	
		object oPC = GetFirstPC();
		
		location lLocation = GetSavedLocation(sVar);
		
		object oTarget=GetFirstFactionMember(oPC,FALSE);
		
		while(GetIsObjectValid(oTarget))
		{
			AssignCommand(oTarget,ClearAllActions());
			AssignCommand(oTarget,ActionJumpToLocation(lLocation));
			oTarget=GetNextFactionMember(oPC,FALSE);
		}
		
	
}

@andgalf

On returning, just check the area tag within the OnEnter script, and if conditions met, do what you need.

Sometimes, you need to get the timing right before you call the function to start the conversation. My own conversation (on area enters) work from about a 0.25 - 0.5 second delay. (Experiment with delay for your needs.)

AREA (OnClientEnter) … Fires a script, which then fires another script after the small delay (after we know PC is present), which then checks whether to start a conversation.

And use the following in the AREA (OnClientEnter) …

// ESSENTIAL TO USE THIS FUNCTION HERE !!!
object oPlayer = GetFirstEnteringPC();

As I stated, this is what I don’t want to do. 'Cause then I would have to do this on every area.

What I meant in my previous post is I know how to do it that way. I just wanted to see if there was an easier way of doing this. I have an idea though that I will try and test now.

I actually got it to work. Never thought this would have worked. I’ll modify the script a bit further. I am using CreateIpSpeaker…

//New functions by kevL_s. The rest of the script by andgalf.
#include "ginc_ipspeaker"

void SetSavedLocation(string sVar, object oObject)
{
    object oModule = GetModule();

    string sArea = GetTag(GetArea(oObject));
    SetLocalString(oModule, sVar + "_area", sArea);

    float fFace = GetFacing(oObject);
    SetLocalFloat(oModule, sVar + "_face", fFace);

    vector vObject = GetPosition(oObject);
    SetLocalFloat(oModule, sVar + "_x", vObject.x);
    SetLocalFloat(oModule, sVar + "_y", vObject.y);
    SetLocalFloat(oModule, sVar + "_z", vObject.z);
}

//
location GetSavedLocation(string sVar)
{
    object oModule = GetModule();

    object oArea = GetObjectByTag(GetLocalString(oModule, sVar + "_area"));

    float fFace = GetLocalFloat(oModule, sVar + "_face");

    float fx = GetLocalFloat(oModule, sVar + "_x");
    float fy = GetLocalFloat(oModule, sVar + "_y");
    float fz = GetLocalFloat(oModule, sVar + "_z");
    vector vObject = Vector(fx, fy, fz);

    return Location(oArea, vObject, fFace);
}

void CutSceneIpSpeaker(location lLocation, object oPC)
{

SetCutsceneMode(oPC);

CreateIPSpeaker("nelowync","test_conv2",lLocation,0.1);


}

void main(string sVar)
{
	
		object oPC = GetFirstPC();
		
		location lLocation = GetSavedLocation(sVar);
		
		//object oTarget=GetFirstFactionMember(oPC,FALSE);
		
		/*while(GetIsObjectValid(oTarget))
		{
			AssignCommand(oTarget,ClearAllActions());
			AssignCommand(oTarget,ActionJumpToLocation(lLocation));
			oTarget=GetNextFactionMember(oPC,FALSE);
		}
		*/
		
		AssignCommand(oPC,ClearAllActions());
		AssignCommand(oPC,ActionJumpToLocation(lLocation));
		
		DelayCommand(2.0,CutSceneIpSpeaker(lLocation,oPC));
		
		
		
	
		

}

In this test, to make it simple, I just recruited one of the companions, and then used that companions’ tag in the area I jumped to. I thought that when jumping between areas the script would get interrupted, but it didn’t!

I haven’t tested this theory, but you could create a custom IPSpeaker (plc_ipspeaker) with a custom heartbeat script on it that detects if the PC is in the area and a condition is met, thus causing a convo to fire. Just plop it down at the PC’s location at the point when he is teleported from the original location. Once the PC teleports back to this original area it should cause the IPSpeaker to fire the convo.
Maybe a heartbeat script on the IPSpeaker like this:

/*
	This is the heartbeat script on a custom iPointSpeaker. It detects if the player is in the area. 
	If a condition is met, a convo will fire.
*/

void main()
{
	object oPC = GetFirstPC();
	object oIP = OBJECT_SELF;
	
	if (GetArea(oPC) == GetArea(oIP))
	{
		if (GetLocalInt(oPC, "start_convo"))	// this will have to be set to TRUE sometime prior to this.
		{
			SetLocalInt(oPC, "start_convo", FALSE);
			AssignCommand(oPC, ClearAllActions());
			ActionStartConversation(oPC, "ip_convo");
		}
	}
}
2 Likes

@travus - Ah, maybe that’s even better than what I did. I’ll try your way.

Hmm, the plopping down of the iPointSpeaker was harder than I thought. I tried with object oPlaceable = SpawnPlaceableAtWP(iPointTag,sWaypoint); but I don’t have the string for the waypoint that doesn’t exist. Hmm…

You could create it at the location of the PC just before he teleports away.

Huh? Do you not have a different tag for each area by default then? i.e. I am talking “tag” not a “Global”.

Yes, I do, but if I understood you correctly you were to use the OnEnter on every area to check stuff.

Yes, I understand that but…well, I just can’t figure it out. It’s probably easy, but oPlaceable = SpawnPlaceableAtWP(iPointTag,sWaypoint); needs a string for the location that the PC is in. Ugh! Why can’t I come up with how this is done…

EDIT: Maybe I should just use CreateObject instead…

Yes, I thought you may have that already. My bad. (I have that script on every area, for that exact reason for ease of doing stuff.)

@andgalf In that case, you could set a flag (variable) on the PC (and store the area from which they came on them) and have their heartbeat (via module heartbeat) check if the conditions are met. It does not require creating any IPoint to do such this way, but the heartbeat principle is similar.

PS: A module heartbeat is a single hook, if you do not have one already.

1 Like

CreateObject(OBJECT_TYPE_PLACEABLE, "ip_resref", GetLocation(oPC));

@travus - I tried with the CreateObject thing but when returning to the area nothing happened.

Ugh, maybe I’ll just go back to the CreateIPSpeaker I had first. That seemed to work really well, actually.

@Lance_Botelle - Ugh, well I already have a “flag” (don’t quite know what that is, sorry) with the SetSavedLocation if you read my script. I might do a script that I put on the OnHeartbeat of the module but…I think I’ll try my own solution first (I understand that one the best since I came up with it myself).

1 Like

“flag” … “variable holder” … “AREALEFT” below … oArea is the PC area at time of leaving the area.

SetLocalString(oPC, “AREALEFT”, GetTag(oArea));

Then in the module HB, when conditions met where oArea of the PC now meets the “AREALEFT” area, fire your conversation …

NB: Make sure you set up a condition so the above condition is not met as TRUE from the module heartbeat prior to leaving the area where it is set!

Did you read my script?

So I already have a SetLocalString there as you can see.

Anyway, I will use my CreateIpSpeaker instead of all this. It has worked 5-6 times in a row now without failure so I think I’ll use that.

@andgalf

My info was about having the conversation start when you reached the area you were returning to, not about the return itself. Perhaps we have misunderstood one another? There are similar elements, as you need to know where you are returning to, but this was about what to do when there … start a conversation.

1 Like

Ok, maybe we misunderstood each other.

Anyway, I have solved this issue now, so…moving on.

1 Like

For future use or for poeple needing that kind of stuff, that’s how I made it in my campaign :

A general script that runs everything I need to be run on every area of my campaign, which is called on every on enter area event.

And inside that script :

	string sArea = GetStringLowerCase(GetTag(OBJECT_SELF));
	string sScriptOnEnterArea = sArea + "_on_enter";
	ExecuteScript(sScriptOnEnterArea,OBJECT_SELF);

This will launch each time a script named areatag_on_enter for the specifics instructions of each area.

2 Likes

@Shallina

Your setup is similar to mine. I use area tags to help determine area enter activities as well. The problem is, Andgalf does not have a script attached to the OnEnter hook of all of his areas. So it makes the job more tricky for him.

1 Like