Help with scripts and triggers?

Sorry to make you worry. I missed return; in the block

	{
		FloatingTextStringOnCreature("I need to ask permission to rest.", oPC, FALSE);
		return; <=== this item
	}

and it ruined everything.
Your script really works, as I wanted, and as it should be!
I feel so awkward…

NWShacker and Tarot_Redhand Спасибо за советы. I started to learn a Tutorial on NWN scripts by Celowin https://neverwintervault.org/project/nwn1/other/just-faqs-maam

In any case, I just started programming in the toolset the other day. And thanks to you, I already understand a lot. Thanks friends! :grinning:

If you want all the " if " to work separately, you need to add return; at the end of each " if " block … That’s it. This is what I wanted…

if (iFoo > 40)
{
    SpeakString("Foo is larger than 40") return;
}
if (iFoo < 20)
{
    SpeakString("Foo is lower than 20") return;
}
if (iFoo < 40, iFoo > 20)
    SpeakString("Foo is between 20 and 40")
}

Friend, help with advice! All with the same trigger in the Rest Area. I want the character, when I went into it, start to itch, well, loop through the animation …

AssignCommand (oPC, ActionPlayAnimation (ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD, 1.0,1.0));

And he finished playing it when he left the zone.
How to create a create loop on an entry trigger? And how to stop it on exiting the trigger?

On Entry:

void main()
{
    object oPC = GetEnteringObject();
    if (!GetIsPC(oPC)) return;



    object oRe = OBJECT_SELF;
    SetLocalInt (oRe, "IN", TRUE);
    if (GetLocalInt(oRe, "ENABLED") != TRUE)
    {
        FloatingTextStringOnCreature("Я должн спросить разрешение на отдых.", oPC, FALSE);
        return;
    }
    SetLocalInt(oPC, "RESTZONE", 1);
        FloatingTextStringOnCreature("Вы в зоне отдыха. Можно отдыхать.", oPC, FALSE);

    string sMess = GetName(oRe);
    if (sMess == "") return;
    DelayCommand(1.4, AssignCommand(oPC, SpeakString(sMess)));
}

On Exit:

 void main()
{
    object oPC = GetExitingObject();
    if (!GetIsPC(oPC)) return;

    object oRe = OBJECT_SELF;
    SetLocalInt (oRe, "IN", FALSE);
    if (GetLocalInt(oRe, "ENABLED") != TRUE) return;
    DeleteLocalInt(oRe, "ENABLED");
    DeleteLocalInt(oPC, "RESTZONE");
    AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD,1.0,1.0));
    FloatingTextStringOnCreature("Фу, воняет!.. Как бы не подхватить чего...", oPC);
}

This is what I need? :slightly_smiling_face:
For Loop: https://nwnlexicon.com/index.php?title=For_Loop
Do Loop: https://nwnlexicon.com/index.php?title=Do_Loop
or While Loop: https://nwnlexicon.com/index.php?title=While_Loop

I created Do Loop in Entry, but it does not work…

void main()
{
    object oPC = GetEnteringObject();
    if (!GetIsPC(oPC)) return;

    object oRe = OBJECT_SELF;
    SetLocalInt (oRe, "IN", TRUE);
    if (GetLocalInt(oRe, "ENABLED") != TRUE)
    {
        FloatingTextStringOnCreature("Я должн спросить разрешение на отдых.", oPC, FALSE);
        return;
    }
    SetLocalInt(oPC, "RESTZONE", 1);
        FloatingTextStringOnCreature("Вы в зоне отдыха. Можно отдыхать.", oPC, FALSE);

    string sMess = GetName(oRe);
    if (sMess == "") return;
    DelayCommand(1.4, AssignCommand(oPC, SpeakString(sMess)));
    return;

    int i;
    do
   {
    PrintInteger(i);
    AssignCommand (oPC, ActionPlayAnimation (ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD, 1.0,1.0));
    AssignCommand (oPC, ActionWait (2.0));
    i++;
   } while (i < 5);
}

Well, in your scripts I can see two issues at the end, the first is that you return without condition before the loop, so that loop will never run anyway.
The second issue is that, even if you removed that last return, the loop would not exactly do what you’re thinking of, as it would happen all in the same instant. To make loops that handle time you must call subroutines recursively with the DelayCommand function.
This method requires you to be very careful though, one mistake in the code (even if it compiles), may lead to a server crash or an event that keeps on running forever. So make sure that there are proper return conditions inside the recursive loops.

I’ll show you how in the following scripts:

On Enter:

void Itchy(object oPC)
{
    if (GetLocalInt(oPC, "ITCHY") != TRUE) return;
    AssignCommand(oPC, ClearAllActions());
    AssignCommand(oPC, PlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD));
    DelayCommand(6.0, Itchy(oPC));
}

void main()
{
    object oPC = GetEnteringObject();
    if (!GetIsPC(oPC)) return;

    object oRe = OBJECT_SELF;
    if (GetLocalInt(oRe, "ENABLED") != TRUE)
    {
        SetLocalInt(oPC, "ITCHY", TRUE);
        DelayCommand(0.0f, Itchy(oPC));
        FloatingTextStringOnCreature("I need to ask permission to rest.", oPC, FALSE);
        return;
    }

    SetLocalInt(oPC, "RESTZONE", 1);
    FloatingTextStringOnCreature("Safe zone. You can rest here.", oPC, FALSE);
    string sMess = GetName(oRe);
    if (sMess != "") DelayCommand(1.0, AssignCommand(oPC, SpeakString(sMess)));
}

On Exit:

void main()
{
    object oPC = GetExitingObject();
    if (!GetIsPC(oPC)) return;

    DeleteLocalInt(oPC, "ITCHY");
    DeleteLocalInt(oPC, "RESTZONE");

    object oRe = OBJECT_SELF;
    if (GetLocalInt(oRe, "ENABLED") != TRUE) return;

    DeleteLocalInt(oRe, "ENABLED");
    FloatingTextStringOnCreature("Leaving safe zone. Rest is no longer possible.", oPC, FALSE);
}

One thing I haven’t tested is that if it’s possible to rest and play an animation at the same time, something tells me that the itchy loop will interrupt resting even if you have permission to rest there, maybe the animation loop should happen only when you don’t have permission to rest?

1 Like

I applied your script. It works, but only if I move the PC in the trigger zone. It also creates confusion when my PC casts a spell, it stands up and hangs endlessly on casting a spell. I can’t get him out of the zone, the scratching animation gets in line and that’s it. He stands and tries to cast a spell :grinning:

Yes, isn’t that’s how it’s supposed to work?

As for the spell causing problem, I applied a change to the code above, however the itch will no longer apply if you have permission to rest. (you will itch only if you don’t have permission to rest in the latest version), this was done to prevent issues with resting.
I also extended the loop delay from 1 second to 6 seconds, this should make it less “continuous”, but it will give you a longer time window to move out of the trigger zone. I even removed the animation duration, as it’s not used by fire and forget animations anyway according to nwnlexicon.

1 Like

Clangeddin Thank you friend! Thanks to you, I created a great storyline with Bollocks disease. Now, when the character is resting in the area, he can pick up CHEPYHA disease, this happens by chance. If the character becomes infected during rest, then when leaving the zone it begins to itch and stagger. If not, he warns that he may get Bollocks :laughing::+1:t4:

Script PC Rest:

void main()
{
    object oPC = GetPCSpeaker();
    SetLocalInt(oPC, "TIME_TO_REST", 0);
    SetLocalInt(oPC, "REST_DIALOGUE", 1);

    object oRe = GetObjectByTag("TRIG_REST_ZONE");
    if (GetLocalInt (oRe, "IN") == TRUE)

    if (FortitudeSave(oPC, d3()+16, SAVING_THROW_TYPE_DISEASE) == 0)
    {
    effect eDis = EffectDisease(DISEASE_DREAD_BLISTERS);
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDis, oPC);
    SetLocalInt(oRe, "DISEASE", TRUE);
    }
}

On Entry:

void main()
{
    object oPC = GetEnteringObject();
    if (!GetIsPC(oPC)) return;

    object oRe = OBJECT_SELF;
    SetLocalInt (oRe, "IN", TRUE);
    if (GetLocalInt(oRe, "ENABLED") != TRUE)
    {
        FloatingTextStringOnCreature("I have to ask permission to rest.", oPC, FALSE);
        return;
    }
    SetLocalInt(oPC, "RESTZONE", 1);
        FloatingTextStringOnCreature("I can rest ... But it's dirty here", oPC, FALSE);

    string sMess = GetName(oRe);
    if (sMess == "") DelayCommand(1.4, AssignCommand(oPC, SpeakString(sMess)));
}

On Exit:

void main()
{
    object oPC = GetExitingObject();
    if (!GetIsPC(oPC)) return;

    object oRe = OBJECT_SELF;
    SetLocalInt (oRe, "IN", FALSE);
    if (GetLocalInt(oRe, "ENABLED") != TRUE) return;
    DeleteLocalInt(oRe, "ENABLED");
    DeleteLocalInt(oPC, "RESTZONE");

    if (GetLocalInt(oRe, "DISEASE") != TRUE)
   {
    FloatingTextStringOnCreature("Phew, it stinks! .. If only it wouldn’t get infected by Bollocks.", oPC);
    AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD,1.0,1.0));
   }
    if (GetLocalInt(oRe, "DISEASE") == TRUE)
    FloatingTextStringOnCreature("Fu! .. I got infected with some Bollocks!", oPC);
    DelayCommand (1.0, AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD,1.0,1.0)));
    AssignCommand(oPC,ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_DRUNK,1.0,2.0));
    SetLocalInt (oRe, "DISEASE", FALSE);
}
1 Like

I have new questions. I hope it’s not difficult for you to help? Thanks.

I hid the OnSpawn character with EffectVisualEffect of the VFX_DUR_CUTSCENE_INVISIBILITY effect of type DURATION_TYPE_PERMANENT, and I want to remove it at a certain point using a trigger. For this, I try to use the RemoveEffect function, but it fails. Even without additional conditions, in the easiest way.

OnSpawn:

void main()
{
object oNa = GetObjectByTag("NASTY");
effect Invis = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, Invis, oNa);
}

OnEntry:

void main()
{
    object oPC = GetEnteringObject();
    if (!GetIsPC(oPC)) return;

      object oNa = GetObjectByTag("NASTY");
      effect Invis = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
      RemoveEffect(oNa, Invis);
}

What is wrong? Everything seems simple :roll_eyes:

This is explained in the Lexicon entry for RemoveEffect, which also gives an example of the code you need.

1 Like

Thanks! I find it difficult to find information, the translator is not always correct.
I wrote such a script according to your example and it works :slightly_smiling_face:

This script removes the effect from another character, not PC, if the primary condition is met… And destroys its trigger.
OnEntry:

void main()
{
    object oPC = GetEnteringObject();
    if (!GetIsPC(oPC)) return;

      object oNa = GetObjectByTag("NASTY");
      effect Invis = GetFirstEffect(oNa);

      if (GetLocalInt(oPC,"KARMEN") == 2)

   while (GetIsEffectValid(Invis))
   {
   if  (GetEffectType(Invis) != DURATION_TYPE_PERMANENT)
         RemoveEffect(oNa, Invis);

   Invis = GetNextEffect(oNa);
   DestroyObject (OBJECT_SELF);
   }
}