Post new topic    
Page 1, 2  »
Slime Knight
Send private message
Breaking out of a script 
 PostFri May 17, 2013 3:42 am
Send private message Reply with quote
So this seems like it should be super easy, but something isn't working.

Basically I have 3 scripts that control 3 npcs and make them patrol an encampment. You put something in the big barrel they are drinking from and they fall asleep. So... I want this line:

"while (hero x(hero:Hero) == 31, and, hero y(hero:Hero) == 14) do("

to basically stop the npc movement script and trigger another script instead. I stuck "exit script" in there to check if I could make it work at all. The scripts keep running like nothing happened. I'm positive those are the right X, Y coordinates too. What am I doing wrong here?

Code:
script,brigand3,begin
   variable(brig3,brig3start,tag24,tag25)
   brig3start := check tag(23)
   tag24 := check tag(24)
   tag25 := check tag(25)
   
   while (tag25 == false) do (
      while (current map == 7) do (
         while (hero x(hero:Hero) == 31, and, hero y(hero:Hero) == 14) do(
            if (key is pressed(key:space)) then (
               set tag(21,off)
               set tag (23,off)
               set tag (24, off)
               exit script
               )
if(brig3start == true) then(   
            wait(100)
            create NPC(4, 30, 13, west)   
            brig3 := NPC reference(4)
            walk NPC(brig3,west,1)
            wait for NPC(brig3)
            set tag(24,on)
            wait (200)
            set tag (24,off)
            walk NPC(brig3,south,1)


(this goes on for a while like this...)


                                wait for npc(brig3)
            destroy NPC(brig3)
            set tag(23,off)
            set tag(21,on)
            brigand

         
               )
            )
         )
      
   
   )
end
Metal King Slime
Send private message
 
 PostFri May 17, 2013 10:45 am
Send private message Reply with quote
Apparently you want the script to stop if at any time the player moves off the tile. Well, I'm afraid that while loops don't mean "continuing running this stuff until this condition becomes false". Rather, it means "run this stuff repeatedly, but check whether the condition is still true before each run". What you want isn't actually very straight forward, though I'll wait to tell you how until you confirm what you want. Even if we had such a script construct, it probably wouldn't be safe to use. What is meant to happen if the script is interrupted in the middle of that 200 tick wait? Should tag 24 stay on permanently? If it is interrupted before "destroy NPC(brig3)" should the npc stand around forever?

Also, do you intend that the script end immediately if the player presses space at any time? Same problem (though at least you did specify what you want the tags to be this time).


Lots of other comments:

I recommend using the names of tags in your HSI file ("include, (gamename).hsi" at the top of your scripts file) so that you can write (say) "set tag(tag: what this is, on)" instead of "set tag(21, on)".

Also, don't write "hero x(hero:Hero)". The argument to heroX, heroY isn't a hero ID, it's a caterpillar party slot. Normally you want the position of the leader, so would write "hero x(me)" or "hero x(0)" ('me' is equal to 0, usually used in that context).

You shouldn't nest loops in the following way:

Code:
while (tag25 == false) do (
  while (current map == 7) do (
    while (hero x(hero:Hero) == 31, and, hero y(hero:Hero) == 14) do(
      ...
    )
  )
)


Consider what happens if the hero moves off the tile, but the current map is still 7. Then it becomes equivalent to:

Code:
while (tag25 == false) do (
  while (current map == 7) do (
    while (false) do ()
  )
)


and you have an infinite loop, stuck between the 2nd and 3rd while loops. Instead, combine all the conditions together (note that && is nearly the same as using ", and,", however we recommend using && instead... it doesn't matter much though):

Code:
while (tag25 == false && current map == 7 && hero x(me) == 31 && hero y(me) == 14) do(
  ...
)


Also, if the tag25 variable never changes, it is a bit odd to put it in the loop condition like that.
Slime Knight
Send private message
 
 PostFri May 17, 2013 3:55 pm
Send private message Reply with quote
TMC wrote:
Apparently you want the script to stop if at any time the player moves off the tile. Well, I'm afraid that while loops don't mean "continuing running this stuff until this condition becomes false". Rather, it means "run this stuff repeatedly, but check whether the condition is still true before each run". What you want isn't actually very straight forward, though I'll wait to tell you how until you confirm what you want. Even if we had such a script construct, it probably wouldn't be safe to use. What is meant to happen if the script is interrupted in the middle of that 200 tick wait? Should tag 24 stay on permanently? If it is interrupted before "destroy NPC(brig3)" should the npc stand around forever?

Also, do you intend that the script end immediately if the player presses space at any time? Same problem (though at least you did specify what you want the tags to be this time).


OK so here is what i want. I want the script to keep running normally, unless you are on that square, pressing spacebar, while tag 24 is on. Since tag 24s only use is to provide a small period where you can press spacebar, after the script is over i will turn it off permanently (or maybe use it for the same purpose somewhere later.)

when that is pressed I want to completely stop the script that is running at whatever point it was at, and execute a new one that is the NPC falling asleep on the ground.

I didn't include the tag 24 part yet, or the actual movement i want to take place because I couldn't figure out how to make the script stop in the first place.

tag 25 is there because there was a way to trigger the scripts in the first place, and when I call the loop to put the npc to sleep I want it to set a one time tag to make it so that can never happen again. Seemed an easy enough way to do that. Although I guess instead of putting it in the three scripts, I could just add it to the first one.

TMC wrote:

Lots of other comments:

I recommend using the names of tags in your HSI file ("include, (gamename).hsi" at the top of your scripts file) so that you can write (say) "set tag(tag: what this is, on)" instead of "set tag(21, on)".


Normally I just name the variables that check the tag, I added those tags in last to see if it helped at all, but forgot to change them before i posted. Sorry!

TMC wrote:

Also, don't write "hero x(hero:Hero)". The argument to heroX, heroY isn't a hero ID, it's a caterpillar party slot. Normally you want the position of the leader, so would write "hero x(me)" or "hero x(0)" ('me' is equal to 0, usually used in that context).


You've told me this before, but I think I misunderstood. Anyways, this makes that slightly easier.

TMC wrote:

You shouldn't nest loops in the following way:

Code:
while (tag25 == false) do (
  while (current map == 7) do (
    while (hero x(hero:Hero) == 31, and, hero y(hero:Hero) == 14) do(
      ...
    )
  )
)


Consider what happens if the hero moves off the tile, but the current map is still 7. Then it becomes equivalent to:

Code:
while (tag25 == false) do (
  while (current map == 7) do (
    while (false) do ()
  )
)


and you have an infinite loop, stuck between the 2nd and 3rd while loops. Instead, combine all the conditions together (note that && is nearly the same as using ", and,", however we recommend using && instead... it doesn't matter much though):

Code:
while (tag25 == false && current map == 7 && hero x(me) == 31 && hero y(me) == 14) do(
  ...
)



i wasn't sure if you could structure things that way, but now that I know you can it definitely saves lots of space. Also I hadn't thought of that infinite loop.

TMC wrote:

Also, if the tag25 variable never changes, it is a bit odd to put it in the loop condition like that.


tag25 does change, just not in this script! should have clarified.
Metal King Slime
Send private message
 
 PostSun May 19, 2013 1:51 am
Send private message Reply with quote
Quote:
Basically I have 3 scripts that control 3 npcs and make them patrol an encampment.


Unfortunately this is a problem... you can't have three scripts running at once. Triggering a script causes all others to pause until it's done. Your options are: 1) combine the three scripts into one, interleaving the commands for each NPC, which is not so easy if the NPCs follow separate paths 2) rewrite each script like a state machine, removing all the waits and calling all three scripts each tick 3) get the NPCs to move about without using scripts (eg. using "always turn right")... unlikely to be feasible

How you exit the script(s) depends on the method you choose. 3) isn't very practical, and 2) is pretty advanced so I definitely don't recommend it.

crowtongue wrote:

TMC wrote:

Also, if the tag25 variable never changes, it is a bit odd to put it in the loop condition like that.


tag25 does change, just not in this script! should have clarified.


Just to be clear: tag number 25 changes, but the "tag25" variable doesn't. So if I understand correctly, you could just have written "if (check tag(25) == false) then ( #rest of script )" instead.
Slime Knight
Send private message
 
 PostSun May 19, 2013 9:09 am
Send private message Reply with quote
TMC wrote:
Quote:
Basically I have 3 scripts that control 3 npcs and make them patrol an encampment.


Unfortunately this is a problem... you can't have three scripts running at once. Triggering a script causes all others to pause until it's done. Your options are: 1) combine the three scripts into one, interleaving the commands for each NPC, which is not so easy if the NPCs follow separate paths 2) rewrite each script like a state machine, removing all the waits and calling all three scripts each tick 3) get the NPCs to move about without using scripts (eg. using "always turn right")... unlikely to be feasible


Thankfully they only patrol one at a time. It is three different scripts that call each other after finishing. I'm gonna work on this for another couple hours see if I can't get anywhere
Metal King Slime
Send private message
 
 PostSun May 19, 2013 10:19 am
Send private message Reply with quote
Do you mean that you have to poison three different wells; each time a new guard appears? And can you leave the map with the task unfinished and come back later to reattempt?

I can tell you how to stop the script (it's not straight forward), but first I want to ensure we're thinking about the same problem
Slime Knight
Send private message
 
 PostSun May 19, 2013 6:20 pm
Send private message Reply with quote
TMC wrote:
Do you mean that you have to poison three different wells; each time a new guard appears? And can you leave the map with the task unfinished and come back later to reattempt?

I can tell you how to stop the script (it's not straight forward), but first I want to ensure we're thinking about the same problem


Leaving the map isn't an issue (although I would probably like to know how to do this in that scenario.)

The guards appear one at a time, and go through a different routine, are destroyed, then there is a call to a separate script which is the next guard. That's why I had them separated into different scripts. I was hoping that as long as I stop the script before the call to the next one it would be easier to deal with them differently.

The first and second guards can be stopped, but it results in a "game over" scenario, it's only the third one I want to start another script.

Hopefully this all makes sense now.
Metal King Slime
Send private message
 
 PostMon May 20, 2013 11:18 pm
Send private message Reply with quote
Here is a wiki article about this: Scripts:Skippable cutscene

Maybe it makes sense to use a tag instead of a global variable, since you seem to be using one already anyway. Lets assume tag 26 indicates that the script should stop because the well has been poisoned, and it should also stop if you leave map 7. Then skippable wait and so on would contain the condition "check tag(26) || current map <> 7", and your scripts would look something like this:

Code:

script,brigand3,begin

  skipping waits := false
  while (skipping waits == false) do, begin
    skippable wait(100)
    # ...
  end

  if (check tag(26)) then (
    # Whatever happens when you poison the well, but not when you leave the map
    set tag(21,off)
    set tag (23,off)
    set tag (24, off)
  )
end
Slime Knight
Send private message
 
 PostTue May 21, 2013 2:54 am
Send private message Reply with quote
This is great, and I would have never been able to figure it out on my own. Thanks so much for taking the time.

There are a couple things to point out though. You had written "npc is moving" in a while statement, did you mean "npc is walking"?

Also the first script takes "ticks" as an argument, and then decrements them at the end of the script. The second script, "skippable wait for npc" doesn't take them as an argument, so when you try and decrement them the compiler gives you an error.
Metal King Slime
Send private message
 
 PostTue May 21, 2013 3:31 am
Send private message Reply with quote
Ah! Thanks for pointing those out. I always seem to write "npc is moving" instead of "npc is walking". I haven't actually tested any of the scripts (that's what users are for :P) so there might be other bugs.
Slime Knight
Send private message
 
 PostTue May 21, 2013 5:27 am
Send private message Reply with quote
TMC wrote:

Code:

script,brigand3,begin

  skipping waits := false
  while (skipping waits == false) do, begin
    skippable wait(100)
    # ...
  end

  if (check tag(26)) then (
    # Whatever happens when you poison the well, but not when you leave the map
    set tag(21,off)
    set tag (23,off)
    set tag (24, off)
  )
end


None of this is going my way. Using a script that way gives me an error about "expecting top level decleration, but found flow control if."

I've tried a couple workarounds but none of them stop the script from looping back to the first guard again, even if i've managed to get the third guard to dissapear.
Metal King Slime
Send private message
 
 PostTue May 21, 2013 4:19 pm
Send private message Reply with quote
That error indicates that you have an extra ) or end somewhere before the if. (You can try pasting your script into this and it will re-indent it according to the brackets, which can help to find the mistake.)

Quote:
I've tried a couple workarounds but none of them stop the script from looping back to the first guard again, even if i've managed to get the third guard to dissapear.


OK, I see that I really did misunderstand the flow of the script. You want to loop through the scripts for each of the three guards in order, and be able to stop anywhere in those three scripts, right? So you could write a seperate script for each guard, which don't contain any while loops but use "skippable wait", etc, as before, and have a master script which calls them in order:

Code:

script,brigands,begin

  skipping waits := false
  while (skipping waits == false) do, begin
    brigand 1
    brigand 2
    brigand 3
  end

  if (check tag(26)) then (
    # Whatever happens when you poison the well, but not when you leave the map
    set tag(21,off)
    set tag (23,off)
    set tag (24, off)
  )
end
Slime Knight
Send private message
 
 PostTue May 21, 2013 5:39 pm
Send private message Reply with quote
Oh boy. Now it doesn't call the brigand scripts at all. This is really just beyond me. All the code is a lot cleaner now I'll post the relevant bits.

Skippable commands:

Code:
script, skippable wait, ticks, begin
   while (skipping waits == false || ticks > 0 || current map == 7 || hero x(me) == 31
   || hero y(me) == 14 || check tag(25) == false) do (
      if (key is pressed(key:space)) then (
         skipping waits := true
         set tag(25, on)
      )
      wait(1)
      ticks -=1
   )
end

script, skippable wait for npc, npc, begin
   while(skipping waits == false || npc is walking(npc) == true || current map == 7 || hero x(me) == 31
   || hero y(me) == 14 || check tag(25) == false) do (
      if (key is pressed(key:space)) then (
         skipping waits := true
         set tag(25, on)
      )
      wait(1)
   )
end

script, skippable walk npc, npc, direction, distance, begin
   if (skipping waits == false) then (
      walk npc(npc, direction, distance)
   )
end


The next part is the script that calls the "master" one. It is leaving another map onto the current one.

Code:
plotscript, leaveferry, begin
   variable (quest_tip)
   quest_tip := check tag (19)
   teleport to map   (7,5,15)
   set hero direction(me, left)
   show map
   fade screen out()
   wait (1)
   fade screen in
   if (quest_tip == true) then (
      show text box (23)
      wait for text box
      set tag(19, off)
   )
   callbrigands   
end

script, callbrigands, begin
     skipping waits := false
     while (skipping waits == false) do, begin
          brigand
          brigand2
          brigand3
     end

     if (check tag(25)) then (
       # Whatever happens when you poison the well, but not when you leave the map
      create NPC(5, 30, 13, west)
     )
end
   


NPC 5 is a guy lying on his side. The next bits are my brigand scripts.

Code:

script, brigand, begin
   variable(brig1)   
   skippable wait(100)
   create NPC(2, 26, 14, east)   
   brig1 := NPC reference(2)
   skippable walk NPC(brig1,north,1)
   skippable wait for NPC(brig1)
   skippable walk NPC(brig1,east,1)
   skippable wait for NPC(brig1)
   skippable wait(100)
   skippable walk NPC(brig1,south,1)
   skippable wait for NPC(brig1)
   skippable walk NPC(brig1,east,2)
   skippable wait for NPC(brig1)
   skippable wait(200)
   skippable walk NPC(brig1,west,2)
   skippable wait for NPC(brig1)
   skippable walk NPC(brig1,north,1)
   skippable wait for NPC(brig1)
   set NPC direction(brig1,east)
   skippable wait (200)
   skippable walk NPC(brig1,north,1)
   skippable wait for NPC(brig1)
   set NPC direction(brig1, north)
   skippable wait for NPC(brig1)
   skippable wait(50)
   skippable walk NPC(brig1,south,2)
   skippable wait for NPC(brig1)
   set NPC direction(brig1, west)
   skippable walk NPC(brig1,west,1)
   skippable wait for npc(brig1)
   destroy NPC(brig1)
   
end

script,brigand2,begin
   variable(brig2)      
   skippable wait (100)
   create NPC(3, 28, 11, south)   
   brig2 := NPC reference(3)
   skippable walk NPC(brig2,south,1)
   skippable wait for NPC(brig2)
   skippable wait(200)
   skippable walk NPC(brig2,east,1)
   skippable wait for NPC(brig2)
   skippable walk NPC(brig2,south,2)
   skippable wait for NPC(brig2)
   set NPC direction(brig2,east)
   skippable wait for NPC(brig2)
   skippable wait (100)
   skippable walk NPC(brig2,north,2)
   skippable wait for NPC(brig2)
   skippable walk NPC(brig2,west,1)
   skippable wait for NPC(brig2)
   set NPC direction (brig2, south)
   skippable wait (200)
   skippable walk NPC(brig2,east,2)
   skippable wait for NPC(brig2)
   skippable walk NPC(brig2,south,1)
   skippable wait for NPC(brig2)
   set NPC direction(brig2,east)
   skippable wait (50)
   skippable walk NPC (brig2,west,1)
   skippable wait for NPC(brig2)
   skippable walk NPC(brig2, north,1)
   skippable wait for NPC(brig2)
   skippable walk NPC(brig2, west,1)
   skippable wait for NPC(brig2)
   skippable walk NPC(brig2, north,1)
   set NPC direction(brig2, north)
   skippable wait for npc(brig2)
   destroy NPC(brig2)
end

script,brigand3,begin
   variable(brig3)
   skippable wait(100)
   create NPC(4, 30, 13, west)   
   brig3 := NPC reference(4)
   skippable walk NPC(brig3,west,1)
   skippable wait for NPC(brig3)
   skippable skippable wait (200)
   skippable walk NPC(brig3,south,1)
   skippable wait for NPC(brig3)
   set NPC direction(brig3, east)
   skippable wait(200)
   skippable walk NPC(brig3,north,1)
   skippable wait for NPC(brig3)
   set NPC direction(brig3, west)
   skippable wait for NPC(brig3)   
   skippable wait (200)
   skippable walk NPC(brig3,south,1)
   skippable wait for NPC(brig3)
   skippable walk npc(brig3,west,3)
   skippable wait(50)
   skippable walk npc(brig3, east,3)
   skippable wait for npc(brig3)
   skippable walk npc(brig3, north,1)
   skippable wait for npc(brig3)
   skippable walk npc (brig3,east,1)
   skippable wait for npc(brig3)
   destroy NPC(brig3)      
end


Any idea?
Metal King Slime
Send private message
 
 PostTue May 21, 2013 6:06 pm
Send private message Reply with quote
Edited, my previous reply was full of errors

OK, firstly I see lots of use of || (or) where && (and) should have been used. You want "skippable wait for NPC" to keep going while the NPC is still moving AND while the the skip flag is false. Also "current map == 7" should have been "current map <> 7".

I see you added "hero x(me) == 31 || hero y(me) == 14" and a check for pressing space in the skippable scripts. I thought that the intention of the position check was to see whether the player activates the barrel. As in, they can walk around as normal, and when they use the barrel something happens. By having a check like this if the player ever moves off that tile, or doesn't start at 31,14 to begin with, then everything stops. I assume that the player isn't meant to be stationary. I recommended earlier to just replace this check with an NPC which sets tag 25.


There's confusion here due to there being so many different things signalling that the scripts should be stopped. We need to think through this clearly:

tag 25 indicates the well is poisoned
current map <> 7 is obvious
skipping waits indicates the scripts should exit, which is if either of the above are true. Which means that we could just replace "skipping waits" with "current map <> 7 || check tag(25)" everywhere and then completely remove the skipping waits variable. Lets just leave it in for now.

So here are the scripts:

Code:

script, skippable wait, ticks, begin
   while (skipping waits == false && ticks > 0) do (
      if (current map <> 7 || check tag(25)) then (
         skipping waits := true
      )
      wait(1)
      ticks -=1
   )
end

script, skippable wait for npc, npc, begin
   while(skipping waits == false && npc is walking(npc) == true) do (
      if (current map <> 7 || check tag(25)) then (
         skipping waits := true
      )
      wait(1)
   )
end

script, skippable walk npc, npc, direction, distance, begin
   if (skipping waits == false) then (
      walk npc(npc, direction, distance)
   )
end



If you really don't want to use an NPC for some reason, then you can add this inside each of the 'skippable' scripts:

Code:

      if (hero x(me) == 31 && hero y(me) == 14 && key is pressed(key:space)) then (
         set tag(25, on)
      )


End of edit
Slime Knight
Send private message
 
 PostTue May 21, 2013 7:06 pm
Send private message Reply with quote
So making those changes to the skippable loops freezes the game as soon as callbrigands is called.

I'm sorry I'm really not following now.

I couldn't find where you recommended me to replace the position check with an NPC that sets a tag, nor do I really understand that.

What I want is a check to see while a script is running if you are on the right square, and pressing the spacebar. If that happens it will trigger the skippable waits and end the script. I don't want the character to remain stationary at all, was the issue that I used a while loop and not an if?

So I can change this in skippable waits to a tag check, but then where do I check the spacebar and position?

I added this to the "callbrigands" script:

Code:
if (key is pressed(key:space) && hero X(me) == 31 && hero Y(me) == 14) then (
        set tag (25,on)
     )
Display posts from previous:
Page 1, 2  »