A script question about Party Roster

So, in the module I’m wokring on at the moment I use the Party Roster GUI a lot that can be found here (on some installations people can’t get to that GUI, but that’s another discussion we’ve already covered in another thread):

partyselect1

partyselect2

Now, the problem I have is that in a script I want to check how many people are in the roster (the total number, not just the ones currently in the party) but my scripts fail all the time. They compile and all that but they don’t work they way I want them to, so I must be doing something very wrong.

So here’s what the script looks like at the moment. Yes, I know it’s convoluted, but I couldn’t figure out another way to do it…Still, it doesn’t work the way it is now either…

At the top, the thing that I have “greyed out” that the game doesn’t check for, is my original script. When that didn’t work the way I wanted, I tried my best to do a new version which is what you see after the “greyed out” area:

/*int StartingConditional()
{

string sRoster;

object oPC = GetFirstPC();

object oRM = GetObjectByTag(GetFirstRosterMember());

int n=0;



	while (GetIsObjectValid(oRM))
	{

		n++;
		oRM = GetObjectByTag(GetNextRosterMember());

	}

	if(n>=5)
	{ 
		
		SetGlobalInt("EnoughPeopleRoster",1);
		return TRUE;
		
	}
	return FALSE;

}
*/

const string sROSTER_NELOWYN = "nelowync"; // note: this needs to be the *roster* string-id
const string sROSTER_WRENBUR = "gnome"; // note: this needs to be the *roster* string-i
const string sROSTER_FLEKSA = "fleksac"; // note: this needs to be the *roster* string-i
const string sROSTER_SEMAPHINE = "semaphine"; // note: this needs to be the *roster* string-i
const string sROSTER_LANIA = "leniac"; // note: this needs to be the *roster* string-i
const string sROSTER_MATHIAS = "mathias"; // note: this needs to be the *roster* string-i
const string sROSTER_TINDRA = "tindra"; // note: this needs to be the *roster* string-i
const string sROSTER_AVIE = "avie"; // note: this needs to be the *roster* string-i
const string sROSTER_SETH = "seth"; // note: this needs to be the *roster* string-i


int StartingConditional()
{

	int n=0;
	object oPC = GetFirstPC();
	/*
	object oNelowyn = GetObjectByTag(sROSTER_NELOWYN);
	object oWrenbur = GetObjectByTag(sROSTER_WRENBUR);
	object oFleksa = GetObjectByTag(sROSTER_FLEKSA);
	object oLania = GetObjectByTag(sROSTER_LANIA);
	object oSemaphine = GetObjectByTag(sROSTER_SEMAPHINE);
	object oTindra = GetObjectByTag(sROSTER_TINDRA);
	object oMathias = GetObjectByTag(sROSTER_MATHIAS);
	object oAvie = GetObjectByTag(sROSTER_AVIE);
	object oSeth = GetObjectByTag(sROSTER_SETH);
	
  	
	object oTindra = GetObjectFromRosterName(sROSTER_TINDRA);
	object oSemaphine = GetObjectFromRosterName(sROSTER_SEMAPHINE);
	object oFleksa = GetObjectFromRosterName(sROSTER_FLEKSA);
	object oLania = GetObjectFromRosterName(sROSTER_LANIA);
	object oNelowyn = GetObjectFromRosterName(sROSTER_NELOWYN);
	object oMathias = GetObjectFromRosterName(sROSTER_MATHIAS);
	object oWrenbur = GetObjectFromRosterName(sROSTER_WRENBUR);
	object oAvie = GetObjectFromRosterName(sROSTER_AVIE);
	object oSeth = GetObjectFromRosterName(sROSTER_SETH);
	*/
	
	
		if(GetIsRosterMemberAvailable(sROSTER_TINDRA))
        {
            
			
      		n++;
       
		}	
		
		if(GetIsRosterMemberAvailable(sROSTER_SEMAPHINE))
        {
            
       		n++;

		}	
		
		if (GetIsRosterMemberAvailable(sROSTER_FLEKSA))
        {
            
    		n++;

		}
		
		if (GetIsRosterMemberAvailable(sROSTER_LANIA))
        {
            
      		n++;

		}	
		
		if (GetIsRosterMemberAvailable(sROSTER_NELOWYN))
        {
            
     		n++;

  
		}	
		
		if (GetIsRosterMemberAvailable(sROSTER_MATHIAS))
        {
            
        	n++;

  
		}	
		
		if (GetIsRosterMemberAvailable(sROSTER_WRENBUR))
        {
            
    		n++;
  
		}	
	
		if (GetIsRosterMemberAvailable(sROSTER_AVIE))
        {
            
     		n++;
  
		}	
	
		if (GetIsRosterMemberAvailable(sROSTER_SETH))
        {
            
     		n++;
		}	
 
		
	if(n>=5)
	{ 
		
		SetGlobalInt("EnoughPeopleRoster",1);
		return TRUE;
		
	}
	return FALSE;
	


  
		
}

Maybe there’s a better function for checking how many creatures are in the roster overall (not just the ones in the party), but I haven’t found one yet.

In fact, the more I think about this, if this is not working the way I thought it would, there could be huge ramafications for my current module, that I in that case need to solve somehow. Uurggh.
I really wish I could just use the first version of this script but…

Ok, this makes me really sad. I don’t know how I’m going to solve this problem, since it’s now become a HUGE problem with my current module.

I did a test just now to see how certain things work. I added the companion Mathias through dialogue to the party. Then I went to the Party Select GUI and removed him from the party. I’ve always thought that even if he’s not in the party anymore, he’s of course a roster member, since you can add him to the party from the Party Select GUI. Now that appears not to be the case, and I’m confused as heck by this.

My test script, which I added to a dialogue, looks like this. I ran it and got no message on screen:

const string sROSTER_MATHIAS = "mathias"; // note: this needs to be the *roster* string-i

void main()
{
    object oPC = GetFirstPC();

	object oMathias = GetObjectFromRosterName(sROSTER_MATHIAS);
	
	if(GetIsObjectValid(oMathias))
	{
		
		SendMessageToPC(oPC,"Mathias is in the roster");
	
	
	}
	
}

If anybody knows a solution to this, I would be very grateful to hear it. Otherwise…well, I don’t know what to do with my current module. Maybe just throw it away or somehow remake it from scratch.

EDIT: Did a new test, and that calmed me down a bit. This script actually sent me a message thankfully:

const string sROSTER_MATHIAS = "mathias"; // note: this needs to be the *roster* string-i

void main()
{
    object oPC = GetFirstPC();

	/*
	object oMathias = GetObjectFromRosterName(sROSTER_MATHIAS);
	
	if(GetIsObjectValid(oMathias))
	{
		
		SendMessageToPC(oPC,"Mathias is in the roster");
	
	
	}
	*/
	
	if(GetIsRosterMemberAvailable(sROSTER_MATHIAS))
	{
		
		SendMessageToPC(oPC,"Mathias is in the roster");
	
	
	}
	
	
}

EDIT again: I changed the first script in my first post to something I thought should have worked, since GetIsRosterMemberAvailable worked in the other test script, but the first script in my first post still don’t give the result I’m expecting. There must be something wrong there.

hi Ag, I wrote up a little roster primer with a couple of example functions …

// The roster is (primarily) just a list of strings. It is not character-objects
// however, associated with each rostername is a few extra variables ...
//
// int GetIsRosterMemberCampaignNPC(string sRosterName);
// - a campaign NPC is on the roster but has been flagged to not appear in the
//   PartyRoster gui.
//
// int GetIsRosterMemberSelectable(string sRosterName);
// - a selectable NPC can be added and removed from the party by the player in
//   the PartyRoster gui. An unselectable NPC cannot be added or removed by the
//   player (this is how to force a companion to stay in the party).
//
// object GetObjectFromRosterName(string sRosterName);
// - if the returned object is valid, the character-object that corresponds to
//   the rostername exists (has been instantiated) in the current module. If not
//   valid, then the companion is currently only an abstraction in the
//   rosterlist.
//
// string GetRosterNameFromObject(object oCreature);
// - this should return an empty string if the given creature is not a
//   roster-object. And vice versa.
//
// int GetIsRosterMemberAvailable(string sRosterName);
// - returns TRUE if a given roster-object is both selectable and not currently
//   in a party.


// Counts entries in the rosterlist.
// - this does not consider whether rostermembers are Selectable, Available,
//   CampaignNPCs, or are instantiated; it's just the raw count on the roster
int GetRosterCount()
{
	int i = 0;

	string sRoster = GetFirstRosterMember();
	while (sRoster != "")
	{
		++i;
		sRoster = GetNextRosterMember();
	}
	return i;
}

// Counts entries in the rosterlist that appear on the PartyRoster GUI.
// - this does not consider whether rostermembers are Selectable, Available, or
//   are instantiated
int GetRosterCountOnPartyGui()
{
	int i = 0;

	string sRoster = GetFirstRosterMember();
	while (sRoster != "")
	{
		if (!GetIsRosterMemberCampaignNPC(sRoster))
			++i;

		sRoster = GetNextRosterMember();
	}
	return i;
}


// int GetIsRosterMember(object oMember);
// - I avoid this function because i've seen it bug out when a rostername has
//   been removed and re-added to the rosterlist ... but if you never remove a
//   name from the rosterlist it should be ok.
2 Likes
//	Reports the number/name of all roster members.

void main()
{
	int nCount = 0;
	string sRosterName = GetFirstRosterMember();
	
	while (sRosterName != "")
	{
		nCount++;
		SendMessageToPC(GetFirstPC(FALSE), IntToString(nCount) + " : " + sRosterName);
		sRosterName = GetNextRosterMember();
	}
}
2 Likes

Thanks, guys!

Both your scripts still use the GetFirstRosterMember and GetNextRosterMember but that didn’t work for me in my script. I’ll try it out though. Maybe I did some mistake.

I have one situation where I do this, actually. Better avoid that function then.

EDIT: Alright, just saw that I need to change @travus’ script to a StartingConditional for it to be usable to me, and testable.

EDIT2: I now used one of the functions of @kevL_s script and turned it into this:

//	Reports the number/name of all roster members.
//  Tested and works perfectly.
int GetRosterCount()
{
	int i = 0;

	string sRoster = GetFirstRosterMember();
	while (sRoster != "")
	{
		++i;
		sRoster = GetNextRosterMember();
	}
	return i;
}


int StartingConditional()
{

	
	if(GetRosterCount()>=5)
	{ 
		
		SetGlobalInt("EnoughPeopleRoster",1);
		return TRUE;
		
	}
	return FALSE;
		
}

And now it worked. So…Apparently (and I feel relieved because of that) the GetFirstRosterMember and GetNextRosterMember actually works as I hoped it would. Then to another question: What did I do wrong in my script that looked like this ('cause it didn’t work):

//My own faulty script. Don't use this!
int StartingConditional()
{

string sRoster;

object oPC = GetFirstPC();

object oRM = GetObjectByTag(GetFirstRosterMember());

int n=0;



	while (GetIsObjectValid(oRM))
	{

		n++;
		oRM = GetObjectByTag(GetNextRosterMember());

	}

	if(n>=5)
	{ 
		
		SetGlobalInt("EnoughPeopleRoster",1);
		return TRUE;
		
	}
	return FALSE;

}
// replacement function for GetIsRosterMember()
// - iffy, this does not check for an exact match on the current rosterlist
int GetIsOnRoster_short(object oCreature)
{
	return GetRosterNameFromObject(oCreature) != "";
}

// replacement function for GetIsRosterMember()
int GetIsOnRoster_long(object oCreature)
{
	string sRoster0 = GetRosterNameFromObject(oCreature);
	if (sRoster0 != "")
	{
		string sRoster = GetFirstRosterMember();
		while (sRoster != "")
		{
			if (sRoster == sRoster0)
				return TRUE;

			sRoster = GetNextRosterMember();
		}
	}
	return FALSE;
}

uhm tags are not rosternames … (?) And if they are (because you keep them the same) then perhaps a rostermember was not instantiated so the while() loop broke early …

Thanks for that script! I don’t think I need to use GetIsRosterMember though in the situation I talked about.

Hmm, interesting…It’s true that they are not rosternames, but I indeed let them be the same…

1 Like

are all members of the roster always instantiated in your module? Because if not, then GetIsObjectValid() is gonna return FALSE and break the loop …

No they are not. At least I don’t think so. I don’t do it the way the OC does it so…

The way I do it is that when you find a companion for the first time, he or she is added to the party through this script:

/******************************************************************
Adds a Companion NPC and sets their XP equal to the PC's if they
are below. This script merges four scripts together so that you
don't have to setup all four script calls in a conversation.

This script also has a convention: the RosterName is the same as
the creature's TAG, resref, etc. They should all be named
the same.
*******************************************************************/
#include "ginc_param_const"
#include "ginc_debug"
#include "ginc_misc"

void main(string sCompanionTag)
{
//FROM: ga_roster_add_object
//Adds a NPC to the global roster of NPCs available to be added to
//a player's party. Roster Name is a 10-character name used to
//reference that NPC in other Roster related functions.
//The NPC will be left in the game world, but will now exist
//in the roster as well.

object oCompanion = GetObjectByTag(sCompanionTag);
int bResult = AddRosterMemberByCharacter(sCompanionTag, oCompanion);

//FROM: ga_roster_selectable
SetIsRosterMemberSelectable(sCompanionTag, 1);

//FROM: ga_roster_party_add
object oPC = GetFirstPC();
AddRosterMemberToParty(sCompanionTag, oPC);

	/////////////////////////////////////////////////////
	// Make the companion visible on the Roster GUI
	/////////////////////////////////////////////////////
	SetIsRosterMemberCampaignNPC(sCompanionTag, 0);
	
	/////////////////////////////////////////////////////
	// Just in case we forgot to set this, when we add a
	// companion to our party, we've met them. 
	/////////////////////////////////////////////////////
	SetLocalInt(oPC, "met_" + sCompanionTag, TRUE);


int nXP = GetPCAverageXP();
SetXP(oCompanion, nXP);
ForceRest(oCompanion);
}

The way I tested this scene was that I recruited, through dialogue and this script, 5 companions. I then took the Roster Select GUI and removed one of them. Then I run the dialogue with the starting conditional, and for some reason the game didn’t think that I had 5 or more companions in the roster. I think I’ll do a bit more testing with my own script with SendMessageToPC to see how many companions are found.

EDIT: Got really odd results when testing with my own script. Eh…I think I’ll just forget that I ever did that script and stick with yours (travus script was extremely similar so)…

So I did a test with @travus variation of the script with the messages. Just like when I tested with my own faulty script the messages were shown three times on the screen. I wonder why that is (but everything worked perfectly just as with @kevL_s variation). Here’s the version of the script for this:

//	Reports the number/name of all roster members.
int GetRosterCount()
{
	int nCount = 0;
	string sRosterName = GetFirstRosterMember();
	
	while (sRosterName != "")
	{
		nCount++;
		SendMessageToPC(GetFirstPC(FALSE), IntToString(nCount) + " : " + sRosterName);
		sRosterName = GetNextRosterMember();
	}
	return nCount;
}


int StartingConditional()
{

	
	if(GetRosterCount()>=5)
	{ 
		
		SetGlobalInt("EnoughPeopleRoster",1);
		return TRUE;
		
	}
	return FALSE;
		
}

When trying with my own faulty script and a SendMessageToPC then the game only found 2 out of 5 companions, so that was really screwed up (I had only removed 1 of the 5 from the party). Not sure why, but maybe because of the initiation thing you spoke about, @kevL_s. In any case, I’ll bury my own version of the script now.

@andgalf

// My own faulty script. Don't use this!
// - with debug
int StartingConditional()
{
	int n = 0;

	string sTag = GetFirstRosterMember();
	SendMessageToPC(GetFirstPC(FALSE), "check " + IntToString(n) + " : " + sTag);

	object oRM = GetObjectByTag(sTag);
	while (GetIsObjectValid(oRM))
	{
		n++;
		SendMessageToPC(GetFirstPC(FALSE), " . valid total= " + IntToString(n));

		sTag = GetNextRosterMember();
		SendMessageToPC(GetFirstPC(FALSE), "check " + IntToString(n) + " : " + sTag);
		oRM = GetObjectByTag(sTag);
	}

	SendMessageToPC(GetFirstPC(FALSE), "object is not instantiated sTag= " + sTag);


	if (n >= 5)
	{
		SetGlobalInt("EnoughPeopleRoster", 1);
		return TRUE;
	}
	return FALSE;
}

Thanks. I’ll try that and see what happens.

EDIT: It’s really weird, the messages I get from this. First let me say: all the companions are recruited in the exact same way, through the script I’ve already posted. The game finds 2 out of 5 companions. All of them are in the game in one area or another. I get a message that one of them isn’t initiated (well, in that case ALL of them should show that message since there’s no difference between them in this case), and one of the companions this script doesn’t recognize at all as part of the party for some reason.
The one the game doesn’t recognize at all happens to be the owner of the conversation where the starting contitional is run…if that’s got to do with anything.

With the scripts you @kevL_s and @travus have posted there are no such problems. The game finds them all, and the correct ones too.

… idk, but id wager that something is fishy in Denmark … /shrug

probably because the loop stops when it finds an uninstantiated object; therefore it doesn’t iterate completely over the entire rosterlist.

Since you’ve got a script that works, just be a bit wary that there might be an OnEnter script or somesuch that’s despawning a companion … (because other than that your idea there should work /imo)

 
ps. do you have one Module or multiple Modules in the campaign?

2 Likes

@andgalf if still interested →

// 'testroster'
/*
	Console script. Prints all creatures in the current Module and highlights
	those that are on the rosterlist.
*/

void PrintRoster();
int GetIsOnRoster(object oTarget);

void main()
{
	PrintRoster();

	object oArea = GetFirstArea();
	while (GetIsObjectValid(oArea))
	{
		SendMessageToPC(GetFirstPC(FALSE), "<c=blue>" + GetName(oArea) + " ( " + GetTag(oArea) + " )</c>");

		object oTarget = GetFirstObjectInArea(oArea);
		while (GetIsObjectValid(oTarget))
		{
			if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
			{
				if (GetIsOnRoster(oTarget))
				{
					SendMessageToPC(GetFirstPC(FALSE), "<c=red>" + GetName(oTarget) + " ( " + GetTag(oTarget) + " )</c>");
				}
				else
					SendMessageToPC(GetFirstPC(FALSE), GetName(oTarget) + " ( " + GetTag(oTarget) + " )");
			}
			oTarget = GetNextObjectInArea(oArea);
		}
		oArea = GetNextArea();
	}
}

void PrintRoster()
{
	int i = 0;

	string sRoster = GetFirstRosterMember();
	while (sRoster != "")
	{
		SendMessageToPC(GetFirstPC(FALSE), "<c=green>" + IntToString(++i) + " " + sRoster + "</c>");
		sRoster = GetNextRosterMember();
	}
	SendMessageToPC(GetFirstPC(FALSE), "");
}

int GetIsOnRoster(object oTarget)
{
	string sRoster0 = GetRosterNameFromObject(oTarget);
	if (sRoster0 != "")
	{
		string sRoster = GetFirstRosterMember();
		while (sRoster != "")
		{
			if (sRoster == sRoster0)
				return TRUE;

			sRoster = GetNextRosterMember();
		}
	}
	return FALSE;
}

This is all way over my head but I hope you’re going to give your poor gnome a name !

1 Like

LOL! You always crack me up, @Tsongo! Yes, he has a name, but in the beginning of the module I didn’t know what to call him, so I just called him “gnome” and that became the tag too. Then later, ok, actually quite early on in the module, he gets his name, and I think that name will show in the Roster Select. If it doesn’t then…well, it will have to be that way. He’s called Wrenbur, by the way.
But when testing like I do, spawning my PC in the middle of the module, his name isn’t given, since that happens in a dialogue early on. That’s why it doesn’t show in the picture.

1 Like

@kevL_s - Holy crap, you want me to get the game to list ALL creatures in my module? That’s A LOT! I think my game would crash if I tried that script.

Well, I actually only make modules, but I do them in Campaign mode (since Lance convinced me to do that for easier patching). What I mean is: Each of my modules is its own campaign, so there’s only one module per campaign.

Yeah, probably. Denmark is our beloved neighbour here where I live, but…well…they can be fishy.

Ah, yes. That makes sense now that you mention it.

1 Like

do you have more than, say, 500 critters?