Aller au contenu

Photo

PC, companion, cohorts: terminology and scripting


  • Veuillez vous connecter pour répondre
18 réponses à ce sujet

#1
Orion7486

Orion7486
  • Members
  • 161 messages
Hi all,
I was hoping for some clarification that is used by manuals and community as to the terminolgy of PC, companions, cohorts, and fellow PC's that the player makes(per SoZ)
1. Companions are builder created npc's that can join the PC's party.  Are cohorts, introduced in SoZ, the same thing as companions?
2. What are additional PC's created by the player and added to original PC's party(per SoZ) called?

In scripting, how are companions, cohorts, and additional PC's defined and differentiated?
I'm talking about functions like GetIsPC, GetFirstPC, GetFirstInFaction, GetOwnedByPlayer, etc.
Is the player's original PC, and any additional player created PC's in player's party considered the same thing in scripting?
3. Are companions/cohorts considered as PC's for function calls?
4. With GetIsPC, it checks to see if creature is player controlled.  Does that mean if that character is in PC's party, whether it be companion, cohort, or additional PC, that it would return true, as long as the player has clicked on that character?
5.With GetIsOwnedByPlayer, I would think that is only for the original PC and additional player created PC's; not any companions/cohorts even if that companion/cohort is currently clicked on.

Thanks in advance for any insight given.

#2
Dann-J

Dann-J
  • Members
  • 3 161 messages
I don't think SoZ 'cohorts' are any different to 'companions' in previous NWN2 campaigns. They are NPCs that are pre-defined within the campaign/module you are playing.

SoZ introduced the ability to import (and later export) your own custom party (shamelessly copying Icewind Dale II), however I believe the party leader is always the 'FirstPC' (and 'FirstInFaction' and 'FactionLeader') while others are simply faction/roster members like any other 'companion'. It's just that you have more control over their creation and advancement.

I had the impression that GetIsOwnedByPlayer only returned true for their animal companion (druids, rangers, clerics with the 'animal' domain), wizard familiars, or summoned creatures (and perhaps dominated creatures?). I don't think roster members count as being 'owned' by the PC (unlike 'Henchmen' in NWN1). Someone please correct me if I'm wrong there.

Modifié par DannJ, 08 décembre 2010 - 12:44 .


#3
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
Companions and cohorts are the same thing.



I call the party members created via the party editor "player-created party members".



Scriptwise the differences are that standard companions and associates will have tags, but player-created party members do not have tags. The main PC also does not have a tag. You can tell the difference between the main PC and the player-created party members by checking the roster. All of them will be in the faction, but the main PC is not in the roster.



In the King's Festival campaign I have a debug item called the State of the Party Report that prints out information about the party using the following scripts:



// ginc_bb_stringlib
// by Brendan Bellina, Nov 2009

// Some useful generic string functions

// Return string of sText repeated nCount times with optional string sDelimiter in between
string repeatString(string sText, int nCount = 1, string sDelimiter = "");

// Return string right justified to specified length. Returns entire string if length exceeds specified length.
string printStringRight(string sText, int nLength = 0, string sChar = " ");

// Return string of sText repeated nCount times with optional string sDelimiter in between
string repeatString(string sText, int nCount = 1, string sDelimiter = "")
{
	string sOutput = "";
	if (nCount < 1) return "";
	int i;
	for (i = 0; i < nCount; i++)
	{
		sOutput += sText;
		if ( i < nCount - 1 && sDelimiter != "") sOutput += sDelimiter;
	}
	return sOutput; 
}

// Return string right justified to specified length. Returns entire string if length exceeds specified length.
string printStringRight(string sText, int nLength = 0, string sChar = " ")
{
	int nStringLength = GetStringLength(sText);
	if (nStringLength >= nLength ) return sText;
	return (repeatString(sChar, (nLength - nStringLength)) + sText);
}



// i_bb_it_partyreport_ac
// by Brendan Bellina
// Nov 2009

// Updated Jan 2010

// bb_it_partyreport OnActivate handler
// This script is executed automatically when the item is activated
// To trigger properly the name of the script MUST be "i_" + itemtag + "_ac"
// Also to make the item usable set Item Property to Cast Spell: Unique Power on Self

// Generates a state of the party report.

#include "ginc_debug"
#include "ginc_bb_stringlib"

// Determine if object is a player created PC (other than the main PC)
//  Standard companions and associates will have tags but player created PC's will not.
//  The main PC will be in the faction but not be in the roster, and will not have a tag.
// by Brendan Bellina, Jan 2010
int GetIsPlayerCreatedPC(object oPC=OBJECT_SELF);

void ReportOut(object oPC, string sOut)
{
	PrettyDebug (sOut);
	SendMessageToPC(oPC, sOut);
}

// Determine if object is a player created PC (other than the main PC)
//  Standard companions and associates will have tags but player created PC's will not.
//  The main PC will be in the faction but not be in the roster, and will not have a tag.
// by Brendan Bellina, Jan 2010
int GetIsPlayerCreatedPC(object oPC)
{
	return ( (GetTag(oPC) == "")
		&& (GetIsPC(oPC) == FALSE)
		&& (GetIsRosterMember(oPC) == TRUE) );
}

// Create a report on a party member from a PC
string ReportMemberState(object oPM, object oPC)
{
	string sOut = "";
	string sResponse;
	string sName = GetName(oPM);
	if (sName == "")
		sOut += "Name: [None]" + " [tag: " + GetTag(oPM) + "]";
	else
	{
		sOut += "Name: " + GetName(oPM) + " [tag: " + GetTag(oPM) + "]" + "\\n";
		
		// Is Player Created?
		sResponse = (GetIsPlayerCreatedPC(oPM)==TRUE)?"Y":"N";
		sOut += "Player Created PC: " + sResponse + " : ";
		// Is a PC?
		sResponse = (GetIsPC(oPM)==TRUE)?"Y":"N";
		sOut += "PC: " + sResponse + " : ";
		
		// Is FirstPC?
		sResponse = (GetFirstPC()==oPM)?"Y":"N";
		sOut += "FirstPC: " + sResponse + " : ";

		// Is in party?
		sResponse = (GetFactionEqual(oPM,oPC)==TRUE)?"Y":"N";
		sOut += "In party: " + sResponse + " : ";
		
		// Is Faction Leader?
		sResponse = (oPM == GetFactionLeader(oPC))?"Y":"N";
		sOut += "Is faction leader: " + sResponse + " : ";
		
		// Is Dead?
		sResponse = (GetIsDead(oPM, TRUE)==TRUE)?"Y":"N";
		sOut += "Dead: " + sResponse + " : ";
		
		// Is Dying?
		sResponse = ((GetIsDead(oPM, FALSE)==TRUE) && (GetIsDead(oPM, TRUE)==FALSE))?"Y":"N";
		sOut += "Dying: " + sResponse + " : ";
		
		// Is an associate?
		sResponse = (GetAssociateType(oPM)!=ASSOCIATE_TYPE_NONE)?"Y":"N";
		sOut += "Associate: " + sResponse + " : ";

		// Is a henchman?
		sResponse = (GetAssociateType(oPM)==ASSOCIATE_TYPE_HENCHMAN)?"Y":"N";
		sOut += "Henchman: " + sResponse + " : ";

		// Is an animal companion?
		sResponse = (GetAssociateType(oPM)==ASSOCIATE_TYPE_ANIMALCOMPANION)?"Y":"N";
		sOut += "Animal Companion: " + sResponse + " : ";

		// Is a familiar?
		sResponse = (GetAssociateType(oPM)==ASSOCIATE_TYPE_FAMILIAR)?"Y":"N";
		sOut += "Familiar: " + sResponse + " : ";

		// Is summoned (excludes familiars and animal companions)?
		sResponse = (GetAssociateType(oPM)==ASSOCIATE_TYPE_SUMMONED)?"Y":"N";
		sOut += "Summoned: " + sResponse + " : ";

		// Is dominated?
		sResponse = (GetAssociateType(oPM)==ASSOCIATE_TYPE_DOMINATED)?"Y":"N";
		sOut += "Dominated: " + sResponse + " : ";
		
		// Is in conversation?
		sResponse = (IsInConversation(oPM)==TRUE)?"Y":"N";
		sOut += "Conversing: " + sResponse + " : ";
		
		// Is in current area?
		sResponse = (GetArea(oPM) == GetArea(oPC))?"Y":"N";
		sOut += "In this area: " + sResponse + " : ";
			
		// Is Roster Member?
		sResponse = (GetIsRosterMember(oPM)==TRUE)?"Y":"N";
		sOut += "Roster Member: " + sResponse + " : ";
	
		// Is Available Roster Member?
		sResponse = (GetIsRosterMemberAvailable(GetRosterNameFromObject(oPM))==TRUE)?"Y":"N";
		sOut += "Available: " + sResponse + " : ";
	
		// Is Selectable Roster Member?
		sResponse = (GetIsRosterMemberSelectable(GetRosterNameFromObject(oPM))==TRUE)?"Y":"N";
		sOut += "Selectable: " + sResponse + " : ";
	
		// Is Roster Member Campaign NPC?
		sResponse = (GetIsRosterMemberCampaignNPC(GetRosterNameFromObject(oPM))==TRUE)?"Y":"N";
		sOut += "Campaign NPC: " + sResponse + " : ";

		// Distance from Activator?
		sResponse = FloatToString(GetDistanceBetween(oPM, oPC));
		sOut += "Distance away: " + sResponse;
	}
	return sOut;
}

void GeneratePartyReport(object oPC)
{
	ReportOut (oPC, "State of the Party Report");
	ReportOut (oPC, "   Current area: " + GetTag(GetArea(oPC)) );
	ReportOut (oPC, "All Faction members:");
	int bPCsOnly = FALSE; // set to TRUE for listing PCs only
	object oFM = GetFirstFactionMember( oPC, bPCsOnly );
	while (GetIsObjectValid(oFM))
	{
		ReportOut (oPC, ReportMemberState(oFM, oPC));
		oFM = GetNextFactionMember( oPC, bPCsOnly );
	}

	ReportOut (oPC, "Roster members: (current NPC party limit " + IntToString(GetRosterNPCPartyLimit()) + ")" );
	string sRosterName = GetFirstRosterMember();
	while (sRosterName != "")
	{
		ReportOut (oPC, ReportMemberState( GetObjectFromRosterName( sRosterName ), oPC ) );
		sRosterName = GetNextRosterMember();
	}
}
	
void main()
{
	//PrettyDebug("i_bb_it_partyreport_ac: Party Report");
//	object oPC = (GetPCSpeaker()==OBJECT_INVALID?OBJECT_SELF:GetPCSpeaker());

    object oPC      = GetItemActivator();
//    object oItem    = GetItemActivated();

	GeneratePartyReport( oPC );
}



Regards

#4
Dorateen

Dorateen
  • Members
  • 477 messages

DannJ wrote...

SoZ introduced the ability to import (and later export) your own custom party (shamelessly copying Icewind Dale II), 


This is some light-hearted humor, right? I mean, I don't want to read too much into an innocent, flippant remark.

I would hope you are aware that custom parties are not unique to Icewind Dale II, and have a long history as a convention in computer role-playing games, especially Dungeons & Dragons computer role-playing games.

Harumph!

#5
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages

Dorateen wrote...

DannJ wrote...

SoZ introduced the ability to import (and later export) your own custom party (shamelessly copying Icewind Dale II), 


This is some light-hearted humor, right? I mean, I don't want to read too much into an innocent, flippant remark.

I would hope you are aware that custom parties are not unique to Icewind Dale II, and have a long history as a convention in computer role-playing games, especially Dungeons & Dragons computer role-playing games.

Harumph!


Perhaps he meant the ability to name/describe a party and import/export it as a unit, as opposed to creating/importing/exporting individuals?

#6
Orion7486

Orion7486
  • Members
  • 161 messages
Thanks, for the clarification. So, if I understand correctly, the player can be in control of only 1 member at a time. So, GetIsPC would return true if the currently clicked on creature would be the original PC, a player created party member, or a companion/cohort?



Also, with GetIsOwnedByPlayer, would that get only the original PC and other player created party members, but not companions/cohorts?

#7
Dann-J

Dann-J
  • Members
  • 3 161 messages

Dorateen wrote...

DannJ wrote...

SoZ introduced the ability to import (and later export) your own custom party (shamelessly copying Icewind Dale II), 


This is some light-hearted humor, right? I mean, I don't want to read too much into an innocent, flippant remark.


I believe IWD2 was the first 'Forgotten Realms' D&D-based computer game to use it, so it was hardly innovative for it to appear in NWN2: SoZ.

It was one of the things I liked best about IWD2 (that, and 'heart of fury' mode). The dwarf  voice set was also quite amusing; if you re-ordered your IWD2 party so a dwarven character was made leader, he would say something like "Oh, that's right. When things go badly, put the dwarf up front!". That was another great thing about the IWD2 party system - you could nominate different party members as leader at different times, rather than being stuck with the same leader for the whole game.

#8
kevL

kevL
  • Members
  • 4 056 messages
I'm a bit confused on the issue also, so let's set this out and see if some sense can be made:

(note, I haven't tested any of this)


1. returns TRUE for any Companion/Cohort that is currently controlled

int GetIsPC(object oCreature);
// * Returns TRUE if oCreature is a Player Controlled character.
// NOTE: If the passed in creature is owned by the player, but the player is
// currently controlling another creature, this will return FALSE
// To check for ownership, see GetIsOwnedByPlayer()


2. returns TRUE only if the original PC is currently controlled
(might return TRUE for the original PC controlled or not!)
(Will this return TRUE if oCreature is not currently controlled
and *not* the original PC, but is still a member of PC's faction?
I suspect it does.)

int GetIsOwnedByPlayer( object oCreature );
// Description: Checks to see if this creature is owned by a player
// Returns: TRUE if oCreature is owned by a player.
// Note that if this creature is being controlled by the player, but is
// not the player's original "owned" character, this will return
// FALSE. You can check for control with GetIsPC()


3. returns TRUE iff original PC, or is created with SoZ party creator

int GetIsPlayerCreated( object oCreature );
// Characters created through the party creation mechanics
// are stored in the Roster system but are flagged as
// PlayerCreated to distinguish them from normal Roster
// contained NPCs. Note that if the character is not
// in the roster /at all/, this function returns false.
// This script function can query that flag.
// oCreature - object id of a creature to check


4. returns TRUE if created with SoZ party creator, or is regular Companion/Cohort

int GetIsRosterMember( object oMember );
//This returns true if the object passed in is in fact a roster member.
//If they are a roster member, then they exist within the roster table


5. returns !OBJECT_INVALID iff oAssociate (OBJECT_SELF) is an Associate (Henchman), Familiar, Summons, or Dominated-being

object GetMaster(object oAssociate=OBJECT_SELF);
// Get the master of oAssociate.


6. returns TRUE iff it's a possessed familiar, doh!

int GetIsPossessedFamiliar(object oCreature);
// This will return TRUE if the creature running the script is a familiar currently
// possessed by his master.
// returns FALSE if not or if the creature object is invalid


7. returns TRUE if it's a member of the PC-party or GetMaster() returns a member of the PC-party

int GetFactionEqual(object oFirstObject, object oSecondObject=OBJECT_SELF);
// * Returns TRUE if the Faction Ids of the two objects are the same

If Kaldor (et al.) wants to jump in with some Yes/Noes that'd be very welcome.

(nb. iff == if and only if)

#9
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages

Orion7486 wrote...

Thanks, for the clarification. So, if I understand correctly, the player can be in control of only 1 member at a time. So, GetIsPC would return true if the currently clicked on creature would be the original PC, a player created party member, or a companion/cohort?

Also, with GetIsOwnedByPlayer, would that get only the original PC and other player created party members, but not companions/cohorts?


GetIsPC(oPC) returns true if oPC is a player object. That means either the FirstPC in a single-player game or each of the player PC's in a multi-player game. It will not return true for anyone else in the party. I tried executing my script from a controller companion and the companion still showed false for GetIsPC, so I do not think controlling makes a difference.

GetIsOwnedByPlayer appears to only be true for the player objects also. It is not true for companions or player-created party members, or cohorts, or associates.

Player objects (the main PC for each player) are not in the roster. They are in the faction though.

Regards

Modifié par Kaldor Silverwand, 09 décembre 2010 - 04:07 .


#10
kevL

kevL
  • Members
  • 4 056 messages

Kaldor Silverwand wrote...

GetIsPC(oPC) returns true if oPC is a player object. That means either the FirstPC in a single-player game or each of the player PC's in a multi-player game. It will not return true for anyone else in the party. I tried executing my script from a controller companion and the companion still showed false for GetIsPC, so I do not think controlling makes a difference.

hm, you got me to sit on my b*tt and make some tests:

I used a crate with a simple damage effect with the conditional
if (GetIsPC)
and it gave the damage whether I was controlling the PC or Companion. When I used
if (GetIsOwnedByPlayer)
however, you're right it was only the actual PC that took damage.

Then I hooked up a
while
loop that ran through the faction, and
if (GetIsOwnedByPlayer)
gave damage only to the PC, whether or not it was controlled; but
if (GetIsPC)
gives damage to only the controlled character - PC or companion.

go figur

So if I had to revise #1 (above) it would be, returns TRUE for any PC/Companion/Cohort that is currently controlled (not sure about "player-created party members", though it should be the same). And #2 would be, returns TRUE for the original PC, controlled or not (again, not sure about player-created party members, though my guess is it hits each one but not regular Companions/Cohorts). So, to get to the moral, if you want to check for any in the PC-party, use
GetFactionEqual()
- which should catch Associates, Summons, Familiars, etc. also

And if ya want to eliminate those hangers-on, ya'll got to get creative with something like

if (GetIsPlayerCreated(oPC) || GetIsRosterMember(oPC))
or
if (GetFactionEqual(oTarget, oPC) && (GetMaster(oTarget) == OBJECT_INVALID))

man, this is cuttin' into my gaming time Posted Image

#11
Shallina

Shallina
  • Members
  • 1 011 messages
No IW2 wasn't the first at all to do that. It's more like it was actually one of the last where we were able to make our full party ourself.



BG1 or BG2 allowed you to do your full party, or to play 1 char and get cohort found in game to come with you. they gave you the choice, like many other games, TOEE for exemple.



That SOZ feature is actually a return to the "roots" that were shamelessly forgoten where player did have the choice to make their own party or to have NPC join them.

#12
Dorateen

Dorateen
  • Members
  • 477 messages

DannJ wrote...

Dorateen wrote...

DannJ wrote...

SoZ introduced the ability to import (and later export) your own custom party (shamelessly copying Icewind Dale II), 


This is some light-hearted humor, right? I mean, I don't want to read too much into an innocent, flippant remark.


I believe IWD2 was the first 'Forgotten Realms' D&D-based computer game to use it, so it was hardly innovative for it to appear in NWN2: SoZ.


Hey, I love IWD2 also (and of course the original Icewind dale) so we are on the same page, here.

I just want to clarify, the Forgotten Realms series of Dungeons & Dragons based computer role-playing games really started with the SSI Gold box game Pool of Radiance. There was a full four title release set around the Dalelands and Moonsea region, plus two more games set in the Savage Frontier.

Then there was the Eye of the Beholder trilogy set in Waterdeep and Myth Drannor.

These are all from the early to mid 1990's and predate the Infinity Engine and the latter Storm of Zehir.

The language of "shamelessly copied" just confused me a little. Obviously, what Obsidian did was going back to the roots of Old School cRPG (much to the chagrin of its many detractors) and this ought to be applauded.

Thanks for the reply!

Modifié par Dorateen, 09 décembre 2010 - 02:19 .


#13
kevL

kevL
  • Members
  • 4 056 messages
at the risk of derailing this thread ..

Some functions I missed the first time 'round (just trying to make a list of all the ways to 'grab' a PC or ally):

(nb. SP-easy, MP gets complicated)

8. returns original PC or currently controlled object (depending on switch)

object GetFirstPC(int bOwnedCharacter=TRUE);
// Get the first PC in the player list.
// This resets the position in the player list for GetNextPC().
//bOwnedCharacter, if true, returns the first player's owned PC
//object. If false, returns the first player's currently controlled
//object.


9. .. not sure if bPCOnly switch includes Companions/Cohorts

object GetFirstFactionMember(object oMemberOfFaction, int bPCOnly=TRUE);
// Get the first member of oMemberOfFaction's faction (start to cycle through
// oMemberOfFaction's faction).
// * Returns OBJECT_INVALID if oMemberOfFaction's faction is invalid.


10. .. note, returns a string; should not include PCs, only Companions/Cohorts

string GetFirstRosterMember();
//This gets the first roster member in the list. Roster members are
//sorted by the order that they were added to the roster.
//It is to be coupled with GetNextRosterMember() if one needs to
//iterate over the roster
//Returns an empty string if there are no roster members
//The string return value is the roster name of the first roster member.

these of course, should be used with  
GetNext...
 to iterate through characters.

& don't forget
GetIsFriend()
GetIsEnemy()
GetIsNeutral()
GetIsReactionTypeFriendly()
GetIsReactionTypeHostile()
GetIsReactionTypeNeutral()

and, of course
GetIsDM()
GetIsDMPossessed()


.. resume program.

#14
Orion7486

Orion7486
  • Members
  • 161 messages

kevL wrote...

So if I had to revise #1 (above) it would be, returns TRUE for any PC/Companion/Cohort that is currently controlled (not sure about "player-created party members", though it should be the same). And #2 would be, returns TRUE for the original PC, controlled or not (again, not sure about player-created party members, though my guess is it hits each one but not regular Companions/Cohorts). So, to get to the moral, if you want to check for any in the PC-party, use

GetFactionEqual()
- which should catch Associates, Summons, Familiars, etc. also

Well, based on how I understand the function comments, it seems that your observations would be correct, ie. GetISPC comes back true for original PC, player created party member, or companion, and only if it is the currently clicked on character;; and GetIsOwnedByPlayer comes back true only for a player created character, such as original PC and player created party member, not companions.
But, Kaldor came up with basically the opposite, and he seems to know what he's about on these boards, so I'm still a tad confused...I think.

#15
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
I wrote the Party Report (scripts earlier in the thread) because the comments in most of these functions are just not clear. I agree that my testing does not match the results kevL found. I'm not sure why though. I suggest you download King's Festival and play around with the script yourself. It is easy to add additional checks into it. I'll do some more testing myself. I'd also like to test some of the functions while playing a multi-player game and see how they respond.



Regards

#16
Orion7486

Orion7486
  • Members
  • 161 messages
Thanks for the insights. Downloaded it and will be taking a look at it.

#17
kevL

kevL
  • Members
  • 4 056 messages
Two years later:
i feel I've come to terms with this.

C-info

#18
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
I'm glad someone has figured it all out. Thanks.

Regards

#19
kevL

kevL
  • Members
  • 4 056 messages
lol, yah ...

btw at the bottom of the script you'll find a function that i believe returns the OwnedPC (truePC, realPC, mainPC, whatver) *no matter what PC-faction creature is passed in*

at least in SP (single-player). I imagine you'll want to run the script through some tests before trusting it for MP, but it should be good other than that function, which I think in MP returns the OwnedPC of the faction leader (if a Roster-like object is passed in) but the OwnedPC itself if that is passed in. It can be corrected further by commenting out one of the Else clauses. I guess it could be handy for writing journal entries/ local_vars, eg. on a consistent character etc.