To avoid the location problems, use local string variable on the NPC to get the target trigger’s tag. Or build a list of triggers to enable them in bulk.
Your script really works, as I wanted, and as it should be! Thanks friend!
if(...) { /* code */ }
else if(...) { /* code */ }
else if(...) { /* code */ }
else { /* code */ }
Or use the less verbose switch
statement if you wish to test several int
constants against one variable (probably N/A in this case).
I tried the “else if” editor writes a compilation error. Maybe I’m doing it wrong, it’s very difficult, each sign and its position means a lot. I’ll try … I’m waiting for a comment from Clangeddin Well explains with examples
Compilation error…
11/21/2019 20:54:51: error. ‘dm_trig_rest_en’ is not compiled.
dm_trig_rest_en.nss (12): ERROR: OPERATOR “else” SHOULD BE USED TOGETHER WITH “if”.
Umm, why?
Else
must immediately follow if
's compound, like this:
if(iFoo > 40)
{
SpeakString("Foo is larger than 40")
}
else if(iFoo < 20)
{
SpeakString("Foo is lower than 20")
}
else
{
SpeakString("Foo is between 20 and 40")
}
You can chain as many else if
s as you want.
EDIT: how switch
works: https://en.wikipedia.org/wiki/Switch_statement
This seems strange, the code I posted above should work, I did not test it myself, however, there could be an issue of language barrier here, maybe I’m not understanding what you actually want to be done.
What I understood is that there’s someone you ask for permission to rest, and he gives you permission to rest to the nearest rest zone, and the scripts I posted above should exactly do that.
I’ll do some testing and see if there’s some unforeseen issues that arised.
I have tested the scripts I made and they work as I intended them, maybe you meant something else?
As you can see from the video, triggers also tend to be laggy and wanky, so they might give the impression they’re not working at first, as they either stop the character or just plainly not recognize the on enter event and you must click on them a few times before they actually fire.
The problem is this -
You Have (pseudo code)
if()
{
code block
}
statement //this is the problem - compiler sees it as following the if() and not as part of it
else if()
With an if() You can either have a single statement or a code block. You cannot have a code block followed by a statement and then expect the compiler treat both as belonging to that if(). Which is why the following else if() throws an error.
As you are just starting out on scripting you might like to check this thread out. It has loads of links to tutorials and tools to help you.
TR
( and that’s one good reason among others for standardized indentation )
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!
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?
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?
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
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.
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
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);
}
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
This is explained in the Lexicon entry for RemoveEffect, which also gives an example of the code you need.
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
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);
}
}