No leave at door conversation

Hi, im working on a module and im stuck trying to figure out how to restrict leaving an area before all creatures are dead. However the tricky part in the script is to check whether the pc has a henchman or not…
Here’s the script so far and I must have missed some very very simple detail:

int StartingConditional()
{
int nNth;
int nPlayerHere;
object oCreature;
object oHenchman;
object oSlave = GetObjectByTag(“ZoneSweeperArenaofChampions”);

nNth = 1;
oCreature = GetNearestObject(OBJECT_TYPE_CREATURE, oSlave, nNth);
oHenchman = GetMaster(oCreature);
return FALSE;

while((GetIsPC(oCreature) != TRUE) && (oHenchman != OBJECT_INVALID) && (oCreature != OBJECT_INVALID))
{
    nNth++;
    oCreature = GetNearestObject(OBJECT_TYPE_CREATURE, oSlave, nNth);
    oHenchman = GetMaster(oCreature);
    if (oCreature == OBJECT_INVALID)
        {
        nNth = 1;
        }
}
return TRUE;

}

The unconditional return FALSE is just one of many issues here.

If you want something that works off the shelf, try the nw_g0_transition script in my Travel Builder package. That works on the slightly different principal of detecting an attempted area transition, with the option to stop it if conditions aren’t right.

Even if you don’t use it, have a look at how it identifies the PC first, then all the associates top-down. Easier than what you’re attempting here.

If you prefer the door conversatiin, try identifying the PC with GetPCSpeaker then use GetHenchman etc.

Hi. :smiley:

OK, let’s see what’s going on here. ::squints::

As Proleric noted, the first big problem that’s going on here is the use of the return statements. To explain: You can think of “return” as an abort point for the script; because return FALSE happens, here, nothing that comes after that can happen at all.

A dialogue node condition check needs, well, conditions that affect whether or not the result will be TRUE (the dialogue node appears) or FALSE (the dialogue node does not appear). Example:

int StartingConditional()
{
    // Retrieve a local integer from PC speaker.
    int nExample = GetLocalInt(GetPCSpeaker(), "EXAMPLE_LOCALINT");

    // If that integer is greater than 2, abort at this point and return TRUE.
    if (nExample > 2)
        return TRUE;

    // By default, return FALSE.
    return FALSE;
}

The second big problem is the while loop itself. Aside from that it cannot currently affect the outcome of the condition check at all, it cannot reliably identify either whether there is a player associate or a living non-PC creature in the area.

OK, while loop lesson - first, be aware that the condition checks in there happen in succession. There are three conditions in this while loop, being:

(GetIsPC(oCreature) != TRUE) ← It is TRUE that oCreature is not a PC.
(oHenchman != OBJECT_INVALID) ← It is TRUE that the master of oCreature is a valid object.
(oCreature != OBJECT_INVALID) ← It is TRUE that oCreature is a valid object.

The second condition will only be checked for if the first condition equals TRUE. At the moment, the first creature is being checked for whether they are not a PC, and only if they are not a PC is the check made whether oHenchman (oCreature’s somewhat misleadingly named master) is a valid object.

After that comes a check for whether oCreature itself is a valid object. That’s generally not a bad thing to check for when looping through objects, but an invalid object is always not a PC, and the master of an invalid object is always not a valid object, so this is a bit of a tangle in the order of the conditions, since the results of the third check would render the results of the first and second checks moot. So that’s a minor niggle.

So, overall, this while loop will abort the instant oCreature is a player character (GetIsPC(oCreature) != TRUE) or a non-PC creature that does not have a master. This loop is incapable of checking through all the creatures in the area - and if a PC or a non-PC creature that does not have a master is closer to the source object than a non-PC creature that does have a master, the loop will abort before finding that (at least nominally “qualified”) creature.

Still, all of this is irrelevant as long as the events in the while loop do not affect the TRUE/FALSE outcome. Even if all creatures in the area were qualified for the loop, the end result of cycling through them all would just be to set nNth back down to 1, and then move on to return TRUE by default.

I think I’d give something like this a try:

int StartingConditional()
{
    int i;
    object oCheck;
    while ((oCheck=GetNearestObject(OBJECT_TYPE_CREATURE, OBJECT_SELF, ++i)) != OBJECT_INVALID)
        {
        AssignCommand(oCheck, SpeakString(IntToString(i)));

        // If neither oCheck nor oCheck's master are player characters, and oCheck is neither dead nor dying...
        if (!(GetIsPC(oCheck) || GetIsPC(GetMaster(oCheck))) && !GetIsDead(oCheck))
            {
            // ... then there are living non-associate NPCs in the area.
            AssignCommand(oCheck, SpeakString("Live NPC found. Check ends."));
            return FALSE;
            }
        }

    return TRUE;
}
  1. Are the creatures you want to check hostile to the PC?
  2. Is this for SP or PW?
int StartingConditional()
{
	// Retrieve the PC that is currently in a conversation with the door
	object oPC = GetPCSpeaker();
	int i;

	for (i = 1; i <= GetMaxHenchmen(); i++)
	{
		if (GetIsObjectValid(GetHenchman(oPC, i)))
		{
			// PC has a henchman
			return FALSE;
		}
	}

	// Find any live enemy in the area
	object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
										oPC, 1,
										CREATURE_TYPE_IS_ALIVE, TRUE);

	if (GetIsObjectValid(oEnemy))
	{
		// Enemies are still in the area
		return FALSE;
	}

	// All checks above are passed successfully
	return TRUE;
}

Thanks for all the assistance! Scripting is very new to me and it helps alot with some pointers.
Im soon going to release my module as soon as its “finnished”.
Thanks!

1 Like