Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

We need your feedback on the new forum text editor switch.
Neverwinter Nights: Enhanced Edition has been released! Visit nwn.beamdog.com to make an order. NWN:EE FAQ is available.
Soundtracks for BG:EE, SoD, BG2:EE, IWD:EE, PST:EE are now available in the Beamdog store.
Attention, new and old users! Please read the new rules of conduct for the forums, and we hope you enjoy your stay!

Seeing things last

chimericchimeric Member, Array Posts: 1,163
A question to those who have experimented with creature scripts. I have this code:

IF

Global("C&CWHITE","GLOBAL",0)
See([ANYONE])
CheckSpellState(LastSeenBy(Myself),C&CWHITE)

THEN

RESPONSE #100
        Attack(LastSeenBy(Myself))

END
As you can see, this is a vision check in two parts. One is asking whether the creature sees anyone at all. Maybe it looks at them one by one, or perhaps sees them all together. The second part is asking whether, among those it sees, the last one is in that spell state (so I suppose its "gaze" goes from one to the next, after all). Then the command is for it to attack the last creature seen - it says nothing about the spell state here. By this point - by the time we get to commands - we are just using the "anchor" hooked on to the creature from the trigger. The premise is that LastSeenByMyself() in the triggers and in the actions is the same creature. Is that actually so? It should be so, but does the checking in triggers stop after the right creature is found, or does it go on?

Example: let's say the scripted creature is surrounded by three hobgoblins, and Hobgoblin 2 is the one in the spell state. If the creature looks no further at finding him and digs into the actions sections for orders, then all is well. But if it keeps looking - because See([ANYONE]) forces it go through ALL those in sight, and the one in the spell state is not necessarily the last to be looked at - then it's going to see Hobgoblin 3. He will be the one signed in the book as LastSeen, so the action, triggered by the spell state of one creature, will actually target another. No? Yes?

This is a practical question. I have this script for a creature who I want to attack Kagain in this spell state. So it does. However, when I remove the spell state from him and put it on Edwin (and apply a Feeblemind to make the creature run its scripts anew), it goes back to hacking at the dwarf. Edwin is in sight too, with his brand-new spell state. Might it not be that the creature thinks it's enough that someone nearby is in the spell state and then hits whoever happens to be LastSeen for it? Moving Edwin away does not help: once the creature has fixed its sights on this target, there is no reason for it to re-run the script when it's on Attack(). (Or am I wrong about this?)

I could use AttackReevaluate(), but that comes with other problems.

My first thought when I saw this stubborn behavior was that Kagain's state was never really removed. So I applied another effect that set the Global to 1, a Feeblemind, and the creature obediently calmed down. When I next set the Global to 0 again and again put Edwin in the spell state, the creature did indeed switch to him. This means Kagain's state went away as intended. The above is the only explanation I have.

I wanted to use a simple See([ANYONE]) to avoid going through Nearest, SecondNearest and so forth when this snag came up.

Comments

  • ArdanisArdanis Member, Developer Posts: 1,181
    The IE scripting guide should answer most of it. If you have SoD, you can also check how e.g. bdmage01 and bdarch00 scripts go about picking a target via See() & LastSeenBy().

    One is asking whether the creature sees anyone at all. Maybe it looks at them one by one, or perhaps sees them all together. The second part is asking whether, among those it sees, the last one is in that spell state (so I suppose its "gaze" goes from one to the next, after all).

    See() itself doesn't loop, but [0] does. So, at first the script goes through objects within owner's line of sight and matches a nearest [ANYONE] among them - which is simply nearest in this case, - and then checks if the owner can See() it and flags it as LastSeenBy().

    By this point - by the time we get to commands - we are just using the "anchor" hooked on to the creature from the trigger. The premise is that LastSeenByMyself() in the triggers and in the actions is the same creature. Is that actually so? It should be so, but does the checking in triggers stop after the right creature is found, or does it go on?

    LastSeenBy() is set by the latest See() and Detect() trigger. Triggers are evaluated once, one by one, until the script restarts.

    Example: let's say the scripted creature is surrounded by three hobgoblins, and Hobgoblin 2 is the one in the spell state. If the creature looks no further at finding him and digs into the actions sections for orders, then all is well. But if it keeps looking - because See([ANYONE]) forces it go through ALL those in sight, and the one in the spell state is not necessarily the last to be looked at - then it's going to see Hobgoblin 3. He will be the one signed in the book as LastSeen, so the action, triggered by the spell state of one creature, will actually target another. No? Yes?

    See above. See([ANYONE]) will flag the nearest hobgoblin, but unless it has the spellstate active, the CheckSpellState() will return false and the block will fail with no action executed.

    I have this script for a creature who I want to attack Kagain in this spell state. So it does. However, when I remove the spell state from him and put it on Edwin (and apply a Feeblemind to make the creature run its scripts anew), it goes back to hacking at the dwarf.

    Is Kagain still closer than Edwin? If yes, then See([ANYONE]) will still return Kagain as LastSeenBy(), and since he no longer has the state, the whole block will return false.
    Attack() is not a very good action, because it sticks to attacking until the target dies. I honestly don't remember if it can be interrupted in the middle by the same script, but supposedly no. Even if it does, and See()s somebody else - i.e. will have a new LastSeenBy() marker, - no new Attack() will be issued unless Edwin gets closer than Kagain. I'm a bit puzzled by what you say about feeblemind, however... If it really did break the action, then it should stand still and do nothing.

    I wanted to use a simple See([ANYONE]) to avoid going through Nearest, SecondNearest and so forth when this snag came up.

    Nope, I'm afraid. Anything you can't put inside of []'s has to be checked via SecondNearest() etc.

    JuliusBorisov
  • chimericchimeric Member Posts: 1,163
    Okay, that puts things in perspective a bit. I now know the level of pessimism that's reasonable about LastSeen(). ;)
    Ardanis said:


    Is Kagain still closer than Edwin? If yes, then See([ANYONE]) will still return Kagain as LastSeenBy(), and since he no longer has the state, the whole block will return false.

    I don't remember who was closer, but I think the Kagain-Edwin problem had to do with the fact that the scripted creature was stuck on Attack(), even after the spell state had been moved off. What exactly goes on there will never become clear, I suspect, but my best bet now is editing the spell that makes the creature run this attack script. I should start the effects with a 1-second Feeblemind. (Feeblemind kills running scripts and forces a creature to reassess the hierarchy of tiers when it comes to; creatures always run the script of the highest tier available to them, they are never free of the tyranny of scripts. They only get a break so long as Feeblemind and possibly Hold Person etc. are in effect.) With Feeblemind on top of effects every use of the spell will begin with an order to cease and desist, then the creature will look for targets again.

    It is still a one-second pause, though, plus the time the new check for states will take... It would be ideal if I could stick a Feeblemind in the global effects of the other spell, the one that sets the target, to hit everyone on the map who is attacking under the influence of the first spell. Pass it through Apply Effects List and a second spell state. That way choosing a new target would automatically free everyone hitting on the old one. Come to think of it, this may be necessary, or they'll never stop.

Sign In or Register to comment.