I have a script I’m using right now that checks for the PCs or a companion’s “insight”. Since this is no skill or ability that’s included in NWN2, I did my own homebrewn version where I check for intelligence + wisdom + d20 against a dc of 17 in this case. I had my own script for this that’s quite convoluted (but it works), but here’s kevL_s’ version that’s much more compact. It’s a starting conditional script to be placed on a node in a conversation, preferably a red node…well, you all know how starting conditional works so…:
// kevL_s more compact version of my script
int StartingConditional(string sTag)
{
object oPC;
if (sTag == "$PC")
oPC = GetFirstPC();
else
oPC = GetObjectByTag(sTag);
int i = GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
int w = GetAbilityModifier(ABILITY_WISDOM, oPC);
return d20() + i + w >= 17;
}
And here’s my variation of Tsongo’s “don’t go there yet” script. A bit more compact perhaps:
void main()
{
object oPC = GetFirstPC();
if(GetJournalEntry("questtag",oPC) <1)
{
FloatingTextStringOnCreature("You have no reason to leave this area.", GetFirstPC(FALSE), FALSE);
return;
}
else
JumpPartyToArea(oPC, GetWaypointByTag("waypointtag"));
}
And my recruiting companions script that I’ve “stolen” from somewhere years ago that works really well:
/******************************************************************
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);
}
Another one that I really like is when you enter a conversation the companions place themselves in a great formation looking at the NPC who owns the dialogue. This script is made by travus and kevL_s. I use it a lot in my latest module and the one I’m working on now:
// ga_jump_face_npc
/*
Jumps companions into formation and makes them face the sFacee at random intervals.
The party will then be immobilized to prevent them from moving around during the convo.
Place this on the very first node of the dialog.
Use this in conjunction with the remove_csi script to remove the immobilization effect.
sFacee - The tag of the NPC to talk to.
fSpacing - The spacing between party menbers. The minimum is 0.8.
script by travus with additions of kevL_s
*/
#include "ginc_group"
#include "nw_i0_spells"
void FaceParty(object oPC, string sFacee)
{
vector v = GetPosition(GetObjectByTag(sFacee));
object oFM = GetFirstFactionMember(oPC, FALSE);
while (GetIsObjectValid(oFM))
{
AssignCommand(oFM, ClearAllActions());
DelayCommand(GetRandomDelay(), AssignCommand(oFM, SetFacingPoint(v, TRUE)));
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oFM);
oFM = GetNextFactionMember(oPC, FALSE);
}
}
void main(string sFacee, float fSpacing)
{
object oPC = GetFirstPC();
if (fSpacing < 0.8) fSpacing = 0.8f;
ResetGroup(PARTY_GROUP_NAME);
GroupAddFaction(PARTY_GROUP_NAME, oPC, GROUP_LEADER_FIRST, TRUE);
GroupSetBMAFormation(PARTY_GROUP_NAME, fSpacing);
GroupSetNoise(PARTY_GROUP_NAME);
GroupMoveToFormationLocation(PARTY_GROUP_NAME, GetLocation(oPC), MOVE_JUMP_INSTANT);
DelayCommand(0.1f, FaceParty(oPC, sFacee));
}
At the end of the conversation you need to run this script by travus so that the companions are no longer immobilized:
// remove_csi
/*
Place this on the last node of the dialog to remove the immobilize effect
from the ga_jump_face_convo script.
*/
#include "x0_i0_petrify"
void main()
{
object oPC = GetFirstPC();
object oFM = GetFirstFactionMember(oPC, FALSE);
while (GetIsObjectValid(oFM))
{
RemoveEffectOfType(oFM, EFFECT_TYPE_CUTSCENEIMMOBILIZE);
oFM = GetNextFactionMember(oPC, FALSE);
}
}
And another favourite by kevL_s: When you speak to an innkeeper the PC doesn’t run around the counter to talk to the innkeeper (I mean, who does that in the real world?) but teleports to a waypoint in front of the counter instead. You need a waypoint for that and this script is to be put on the OnConversation of the Innkeeper NPC:
// 'oc_bartender'
/*
OnConversation script for innkeeper. Script by kevL_s.
*/
const string TAG_WAYPOINT = "innkeeptalk";
const float DEFAULT_DIST_DIALOG = 2.f;
void BeginDialog(object oSpeaker);
// OBJECT_SELF is innkeeper
void main()
{
object oPc = GetLastSpeaker();
if (GetDistanceToObject(oPc) > DEFAULT_DIST_DIALOG)
{
AssignCommand(oPc, ClearAllActions());
object oWaypoint = GetNearestObjectByTag(TAG_WAYPOINT);
AssignCommand(oPc, ActionMoveToObject(oWaypoint, TRUE, 0.f));
object oSpeaker = OBJECT_SELF; // req'd - do not put OBJECT_SELF directly into the next call
AssignCommand(oPc, ActionDoCommand(BeginDialog(oSpeaker)));
}
else // standard start conversation ->
{
ClearAllActions();
BeginConversation();
}
}
// OBJECT_SELF is pc here
void BeginDialog(object oSpeaker)
{
ClearAllActions();
SetFacingPoint(GetPosition(oSpeaker));
object oPc = OBJECT_SELF; // req'd - do not put OBJECT_SELF directly into the next calls
AssignCommand(oSpeaker, ClearAllActions());
AssignCommand(oSpeaker, SetFacingPoint(GetPosition(oPc)));
AssignCommand(oSpeaker, ActionStartConversation(oPc));
}