Jump to content


Photo

Looking for some help with this script


  • Please log in to reply
8 replies to this topic

#1 temnix

temnix
  • Member
  • 983 posts

Posted 29 August 2017 - 04:52 PM

Okay, clever scripters. I'm trying to get the engine to take notice of the fact that one or more party characters is in the presence of enemies without fighting (so most likely invisible or in sanctuary, however it would come about), and has been near them for some time, and that they are not news to him. So I wrote this:

 

IF
    
    Global("SEE-BUT-CALM","GLOBAL",0)
    OR(6)
    TriggerOverride(Player1,Detect([ENEMY]))
    TriggerOverride(Player2,Detect([ENEMY]))
    TriggerOverride(Player3,Detect([ENEMY]))
    TriggerOverride(Player4,Detect([ENEMY]))
    TriggerOverride(Player5,Detect([ENEMY]))
    TriggerOverride(Player6,Detect([ENEMY]))
THEN
    RESPONSE #1

    Wait(3)
    SetGlobal("SEE-BUT-CALM","GLOBAL",1)
    Continue()
    END

IF
    Global("SEE-BUT-CALM","GLOBAL",1)
    
    !TriggerOverride(Player1,Detect([ENEMY]))
    !TriggerOverride(Player2,Detect([ENEMY]))
    !TriggerOverride(Player3,Detect([ENEMY]))
    !TriggerOverride(Player4,Detect([ENEMY]))
    !TriggerOverride(Player5,Detect([ENEMY]))
    !TriggerOverride(Player6,Detect([ENEMY]))
THEN
    RESPONSE #1

    SetGlobal("SEE-BUT-CALM","GLOBAL",0)
    Continue()
    END

 

The idea is, 3 seconds after running into enemies we set a global show that we're used to them. Once they're gone, the global is reset to 0. But in those 3 seconds blocks triggered with Global("SEE-BUT-CALM","GLOBAL",0) and other conditions can happen to them. Right? Well, it's not working properly somehow. Instead those actions begin 3 seconds later, as though the trigger is by global at 1, which isn't, or as though the current character isn't detecting enemies, and he's just within ten feet of them. You see any problems with this?



#2 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 30 August 2017 - 02:47 PM

Wait() is an executable action, not a mere delay. Use timers instead.
Since you have Continue(), other global=0 blocks will return true on the first pass and get added to the action queue, executing after the wait is complete.

Retired from modding.


#3 temnix

temnix
  • Member
  • 983 posts

Posted 30 August 2017 - 04:18 PM

I'm not sure I understand the logic here. Does the engine stop and wait for Wait(), or does it bypass it somehow? Then where is Wait() happening, in a parallel dimension?



#4 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 30 August 2017 - 04:23 PM

Action queue stops and Wait()s the specified amount of time before proceeding further.

This, for instance, is one of the reasons to not use Wait() in creature scripts, as they will physically wait and do nothing until duration expires, even if trigger conditions in other blocks return true.


Retired from modding.


#5 temnix

temnix
  • Member
  • 983 posts

Posted 31 August 2017 - 06:31 AM

Well, you may want them to stop and do nothing, like here. A pause is what I want. Except it's not a good idea for baldur.bcs. I need to put this in another script. Okay, I got you. But that doesn't explain why the script above worked in reverse - why the surprise conditions started happening after three seconds instead of the no-surprise block. I wanted an interval of surprise in the presence of monsters, followed by boredom. Instead there was boredom and after three seconds - surprise.



#6 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 31 August 2017 - 08:01 AM

Well, you may want them to stop and do nothing, like here.

That's shooting your own foot. While the actor waits, he can't evaluate other blocks.

 

A pause is what I want.

Use NoAction() blockers, I guess?

 

But that doesn't explain why the script above worked in reverse - why the surprise conditions started happening after three seconds instead of the no-surprise block.

Depends on what exactly is in your script, but most likely what I said about conditions not evaluating during the wait.

And if you have Continue(), then something like this

IF
  Global("SEE-BUT-CALM","GLOBAL",0)
THEN
  RESPONSE #100
    DisplayStringHead(Myself,~Blah.~)
END

would be queued to execute after ~Wait() SetGlobal()~ finishes.


Edited by GeN1e, 31 August 2017 - 08:01 AM.

Retired from modding.


#7 temnix

temnix
  • Member
  • 983 posts

Posted 31 August 2017 - 01:10 PM

Well, you may want them to stop and do nothing, like here.

That's shooting your own foot. While the actor waits, he can't evaluate other blocks.

 

A pause is what I want.

Use NoAction() blockers, I guess?

 

But that doesn't explain why the script above worked in reverse - why the surprise conditions started happening after three seconds instead of the no-surprise block.

Depends on what exactly is in your script, but most likely what I said about conditions not evaluating during the wait.

And if you have Continue(), then something like this

IF
  Global("SEE-BUT-CALM","GLOBAL",0)
THEN
  RESPONSE #100
    DisplayStringHead(Myself,~Blah.~)
END

would be queued to execute after ~Wait() SetGlobal()~ finishes.

 

 

1 and 2) I don't want the actor to evaluate other blocks, that's the point. Then, if I'm putting Wait(), that's a hold command for a creature or a delay for a background script. NoAction() wouldn't do, because it has no duration. With it the script just continues down the list if there is a Continue(), or it is stuck forever at NoAction() if there isn't and nothing intervenes to make the triggers check false. That is, unless I put NoAction() next to some small other RESPONSE probability, like this:

 

RESPONSE #1

X

RESPONSE #1000

NoAction()

 

Then it would really take a long time for X to happen - probably, but not certainly. RESPONSE #1 may be the first thing to be rolled. I do use this sort of thing for random and approximate delays when I want them, but it wouldn't be appropriate for a pause.

 

3) Yeah, but my block triggered by Global("SEE-BUT-CALM","GLOBAL",0) was below all this in the same script. So if baldur.bcs in the beginning was just constipated by Wait(), then it should have only led to the check for Global 0 getting postponed but otherwise everything working normally. All right, I'll give you the script. I'd like to get this mechanism in, after all, just not for baldur.bcs. I'll hang it on my script mule.

 

The script makes it so that characters can be surprised (caught off guard, as I call it) when alone and active and seeing an enemy and being seen by that enemy - therefore, not invisible. The italicized blocks were put in later in an effort to prevent surprise when the character, after some time near monsters, turns visible. Without these blocks he would be caught off guard on emergence even though he had stood, concealed, near them for an hour, which makes no sense. Hence the 3 second interval allotted before they become chums.

 

 

IF             /// This bit checks for enemies and 3 seconds later instigates boredom
    
    Global("SEE-BUT-CALM","GLOBAL",0)
    OR(6)
    TriggerOverride(Player1,Detect([ENEMY]))
    TriggerOverride(Player2,Detect([ENEMY]))
    TriggerOverride(Player3,Detect([ENEMY]))
    TriggerOverride(Player4,Detect([ENEMY]))
    TriggerOverride(Player5,Detect([ENEMY]))
    TriggerOverride(Player6,Detect([ENEMY]))
THEN
    RESPONSE #1

    Wait(3)
    SetGlobal("SEE-BUT-CALM","GLOBAL",1)
    Continue()
    END

IF           /// This bit resets the mood to anxiety when no enemies are in sight anymore
    Global("SEE-BUT-CALM","GLOBAL",1)
    
    !TriggerOverride(Player1,Detect([ENEMY]))
    !TriggerOverride(Player2,Detect([ENEMY]))
    !TriggerOverride(Player3,Detect([ENEMY]))
    !TriggerOverride(Player4,Detect([ENEMY]))
    !TriggerOverride(Player5,Detect([ENEMY]))
    !TriggerOverride(Player6,Detect([ENEMY]))
THEN
    RESPONSE #1

    SetGlobal("SEE-BUT-CALM","GLOBAL",0)
    Continue()
    END

 

IF     /// And this bit is here to make sure characters get surprised only in the first few moments

Global("SEE-BUT-CALM","GLOBAL",0)

    !NumInParty(1)
    !GlobalTimerNotExpired("OFF-GUARD","GLOBAL")
    !ActuallyInCombat()
    !StateCheck(Player1,STATE_INVISIBLE)
    !StateCheck(Player1,STATE_HELPLESS)
    !StateCheck(Player1,STATE_BLIND)
    !StateCheck(Player1,STATE_CONFUSED)
    !StateCheck(Player1,STATE_FEEBLEMINDED)
    !StateCheck(Player1,STATE_SLEEPING)
    !StateCheck(Player1,STATE_BERSERK)
    !StateCheck(Player1,STATE_PANIC)
    CombatCounter(0)
    !TriggerOverride(Player1,Detect(Player2))
    !TriggerOverride(Player1,Detect(Player3))
    !TriggerOverride(Player1,Detect(Player4))
    !TriggerOverride(Player1,Detect(Player5))
    !TriggerOverride(Player1,Detect(Player6))
    OR(6)
        TriggerOverride(Player1,ModalState(BATTLESONG))
        TriggerOverride(Player1,ModalState(DETECTTRAPS))
        TriggerOverride(Player1,ModalState(TURNUNDEAD))
        TriggerOverride(Player1,ModalState(SHAMANDANCE))
        !TriggerOverride(Player1,ActionListEmpty())
        CheckStatLT(Player1,9,WIS)
    TriggerOverride(Player1,See([ENEMY]))
    !StateCheck(LastSeenBy(Player1),STATE_HELPLESS)
    !StateCheck(LastSeenBy(Player1),STATE_BLIND)
    !StateCheck(LastSeenBy(Player1),STATE_CONFUSED)
    !StateCheck(LastSeenBy(Player1),STATE_FEEBLEMINDED)
    !StateCheck(LastSeenBy(Player1),STATE_SLEEPING)
    !StateCheck(LastSeenBy(Player1),STATE_BERSERK)
    !StateCheck(LastSeenBy(Player1),STATE_PANIC)
THEN
    RESPONSE #1
        SetGlobalTimer("OFF-GUARD","GLOBAL",TWO_TURNS)
        ActionOverride(LastSeenBy(Player1),FaceObject(Player1))
        ActionOverride(Player1,FaceObject(LastSeenBy(Player1)))
        ActionOverride(Player1,ReallyForceSpellRES("OFFGU1_#",Myself))  // No such index
        Continue()
END

 

P.S. Now that I look at it, the problem is that the Global checking and the surprise checking are in the same script. If baldur.bcs, where all this was put, was stopped by Wait() and the next thing the Global inevitably set to 1, the surprise actions should never have happened. But somehow they did happen - only three seconds after meeting monsters face to face. This proviso isn't crucial, the component is pretty cool in play, but I'd appreciate it if you can think why it happens.


Edited by temnix, 31 August 2017 - 01:24 PM.


#8 GeN1e

GeN1e

    A very GAR character

  • Modder
  • 1604 posts

Posted 31 August 2017 - 03:26 PM

When your script runs for the first time, it evaluates the 1st block true and, since it has Continue(), the 3rd block as well. Actions from both blocks are added to the queue and only then that concatenation starts executing. What you really end up with is this:
   Wait(3)
    SetGlobal("SEE-BUT-CALM","GLOBAL",1)
        SetGlobalTimer("OFF-GUARD","GLOBAL",TWO_TURNS)
        ActionOverride(LastSeenBy(Player1),FaceObject(Player1))
        ActionOverride(Player1,FaceObject(LastSeenBy(Player1)))
        ActionOverride(Player1,ReallyForceSpellRES("OFFGU1_#",Myself))  // No such index
Structure like this should probably work for you (simplified, but you get the idea):
IF
  Global("seebutcalm","locals",0)
  Global("anxiety_timer","locals",0)
  Detect([ENEMY])
THEN
  RESPONSE #100
    SetGlobalTimer("anxiety_timer","locals",3)
    Continue() // safe to put it here, 4th block just will trigger on the next AI update pass
END

IF
  Global("seebutcalm","locals",0)
  GlobalGT("anxiety_timer","locals",0) // it was actually set by the previous block
  GlobalTimerExpired("anxiety_timer","locals")
THEN
  RESPONSE #100
    SetGlobal("seebutcalm","locals",1)
    SetGlobal("anxiety_timer","locals",0)
END

IF
  Global("seebutcalm","locals",1)
  !Detect([ENEMY])
THEN
  RESPONSE #100
    SetGlobal("seebutcalm","locals",0)
END

IF
  Global("seebutcalm","locals",0)
  !GlobalTimerExpired("anxiety_timer","locals")
  Detect([ENEMY])
THEN
  RESPONSE #100
    // act surprised
END

Edited by GeN1e, 31 August 2017 - 03:29 PM.

Retired from modding.


#9 temnix

temnix
  • Member
  • 983 posts

Posted 02 September 2017 - 08:25 AM

Thanks for taking the time with this. I'll try it.