Post new topic    
Page 1, 2  »
Slime Knight
Send private message
Line of Sight 
 PostTue Jun 11, 2013 8:58 pm
Send private message Reply with quote
It is frustrating to have to come back and ask for help again, after spending as much time as I have reading through similar examples to learn how to write scripts better. But here I am.

I am working on a line of sight script.

I have two sources of inspiration for this. One is the script for Jailbreak, and the other is a custom script that BMR created for me presumably based off of his line of sight mechanic in Legacy.

So here are the things it needs to do:

1 - Set a loop up that will continuously loop through the appropriate amount of npcs to check each ones line of sight.
-Jailbreak and Legacy seem to differ here, but I like BMR's approach which is to trigger it using a timer.
-Both methods use a FOR loop to initiate this, this seems to work well because even if you only need line of sight for one npc
you can just set the first and last to the same.

2 - check which direction a npc is facing and set the line of sight accordingly.
- BRM uses a switch statement, and Jailbreak just uses if commands. The former seems cleaner
EDIT - I left a crucial piece of information out! A cone-shaped line of sight WOULD be ideal, but I've started out just trying to get a simple 3 tile line in the direction the npc is facing.

3 - check if any of the tiles in between you and the npc are wall tiles
- The example script I got from BMR didn't include this part. I think it would work if I put a readpassblock command into the

switch statement segment to get it to work.

4 - trigger a separate script if you are found to be within the line of sight
- this will move the npc to the square directly in front of your character


With all of that considered let's get down to code. For a little context, this part fits into the scripts I have running that causes 3

guards to patrol a campsite one at a time. Here is where I start the timer:

Code:
script, brigand, begin
   set tag(21, on)
   set tag(27,off)
   variable(brig1,brig1x,brig1y)   
   skippable wait(150)
   set tag(26, on)
   if (check tag(28) == false) then (
      #create the npc and start him walking around.
      create NPC(2, 26, 14, east)   
      set timer(0,5,3,@guardcheck)
      brig1 := NPC reference(2)



The loops for the 3 guards are basically identical in this regard.

Now here is the guardcheck script that BMR gave me, with a few modifications to get it to run etc...


Code:
script, guardcheck, begin

   #Declare all of the different variables
   #--------------------------------------
   variable(
      mex  #Hero X position
      mey  #Hero Y position
      
      npc1 #Starting NPC to check
      npc2 #Final NPC to check
      npcd #NPC Direction
      
      nx   #NPC X
      ny   #NPC Y
      
      cx   #Current X, for checking X variables for LoS
      cy   #Current Y, for checking Y variables for LoS
      
      wx   #Working X
      wy   #Working Y
      
      ctr  #Counter, for looping through the different NPCs
      
      hf   #Hero Found, becomes TRUE if hero is within a certain distance
      
      dt   #Distance Threshold, how far to detect from
   )
   #--------------------------------------
   
   
   
   #Generate all the variables
   #--------------------------
   
   if (check tag(22)) then ( npc1 := npc reference(2))
   else if (check tag(23)) then(npc1:= npc reference(3))
   else if (check tag(24)) then (npc1:= npc reference(4))
   if (check tag(22)) then ( npc2 := npc reference(2))
   else if (check tag(23)) then(npc2:= npc reference(3))
   else if (check tag(24)) then (npc2:= npc reference(4))
   hf  := FALSE
   ctr := 3
   
   dt  := 3  #Set the distance to detect at 3 tiles
   #--------------------------
   
   
   for(ctr, npc1, npc2) do(
      npcd := npc direction(npc1)
      nx   := npc x(npc1)
      ny   := npc y(npc1)
      mex := hero x(me)
      mey := hero y(me)
      
      switch(npcd) do(
         case(north) do(
            for(wy, ny, ny -- dt) do( if(wy == mey && nx == mex) then(hf := TRUE) )
         )
         case(south) do(
            for(wy, ny, ny + dt) do( if(wy == mey && nx == mex) then(hf := TRUE) )
         )
         case(west) do(
            for(wx, nx, nx -- dt) do( if(ny == mey && mex <= nx -- dt && mex >= nx) then(hf := TRUE) )
         )
         case(east) do(
            for(wx, nx, nx + dt) do( if(ny == mey && mex >= nx && mex <= nx + dt) then(hf := TRUE) )
         )
         
      )
      
      if(hf == TRUE) then(somethinghappens)
            
   )
end




script, somethinghappens, begin
   #Add what you want to happen here.
   reset game
end


Some things to note:

-In this case I ALWAYS want npc2 to be the same as npc1. I'm sure I could declare this in a prettier way.
-I was the one who put the messy-as-hell math parts into the east and west cases. I did not put it into north and south because it is easier for me to test if its working in my game with the east and west cases.

I put these in because while ny and mey HAVE to be the same, mex and nx are going to be different and within a certain range.

- I haven't implemented wall checking yet, because I want to be able to trigger the "somethinghappens" script successfully first. My idea of how to implement wall checking is by using a readpassblock statement inside the IF loop in each case.

Currently, nothing happens. I put a reset game command at the bottom underneath the if statement that calls somethinghappens, just to make sure the script was being triggered properly, and it is, but somehow HF isn't properly being set to true, so nothing happens.
Liquid Metal King Slime
Send private message
 
 PostTue Jun 11, 2013 9:12 pm
Send private message Reply with quote
It looks like you are already on the right track. Can you clarify where you need help? You said you wanted help, but you didn't mention where the script fails.

one minor suggestion:

Code:

   if (check tag(28) == false) then (
      #create the npc and start him walking around.
      create NPC(2, 26, 14, east)   
      set timer(0,5,3,@guardcheck)
      brig1 := NPC reference(2)


the "create NPC" command returns a reference, so you should do:

Code:

      brig1 := create NPC(2, 26, 14, east)   


This guarantees that you get the correct reference if there happen to be more than one copy of NPC 2 on the map.
Slime Knight
Send private message
 
 PostTue Jun 11, 2013 9:22 pm
Send private message Reply with quote
It was right at the bottom of that gargantuan post, so I definitely don't blame you for missing it.

When I walk into a guards line of sight, nothing happens. That makes me feel like the HF variable isn't being set properly, so the "somethinghappens" script isn't being called.

I mentioned that I put reset game at the bottom of the guardcheck script just to make sure it was properly being called, and I found that it was.
Liquid Metal King Slime
Send private message
 
 PostTue Jun 11, 2013 9:35 pm
Send private message Reply with quote
How is guardcheck being triggered? I see you trigger it with a "set timer" command, but is that the only place?

It looks like guardcheck runs through once, and then ends.
Slime Knight
Send private message
 
 PostTue Jun 11, 2013 11:08 pm
Send private message Reply with quote
Yes, that is the only place. I was under the impression that a timer would keep running the script every set amount of time, but reading through the definition in the dictionary again that is never implied.

I guess I have to set it up as a loop instead, then?
Metal King Slime
Send private message
 
 PostWed Jun 12, 2013 2:51 am
Send private message Reply with quote
Ah, there's the ticket. I forgot to add a set timer at the end of the LoS script.
Being from the third world, I reserve the right to speak in the third person.

Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Slime Knight
Send private message
 
 PostWed Jun 12, 2013 3:29 am
Send private message Reply with quote
BMR wrote:
Ah, there's the ticket. I forgot to add a set timer at the end of the LoS script.


I trie putting one there but there wasn't any effect.
Metal King Slime
Send private message
 
 PostWed Jun 12, 2013 6:44 am
Send private message Reply with quote
The east and west cases in that script are quite different to the north, south ones, which are of the right form. They ought to look like

Code:

         case(west) do(
            for(wx, nx, nx -- dt) do( if(ny == mey && wx == mex) then(hf := TRUE) )
         )
         case(east) do(
            for(wx, nx, nx + dt) do( if(ny == mey && wx == mex) then(hf := TRUE) )
         )


Also, I think running the script every 5*3 = 15 ticks, roughly 1 second ("5, 3" arguments to settimer) is far too infrequent. You can easily walk in front of the NPC and away again without it triggering.

You could check that the script is being triggered, and what it's doing. Are you familiar with the trace and tracevalue commands?
Metal King Slime
Send private message
 
 PostWed Jun 12, 2013 6:49 am
Send private message Reply with quote
I did some testing with the script, and found that for some reason it never triggers with npc 2. But it triggers with npc 3. Strange.
Being from the third world, I reserve the right to speak in the third person.

Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Slime Knight
Send private message
 
 PostWed Jun 12, 2013 7:51 am
Send private message Reply with quote
TMC and BMR.... You are both godsends! I didn't know about trace value, and just the other night I was lamenting how I couldn't do something like this to find what my issue was. And BMR you pointed me in the right direction.

So it was a combination of the timer not being set fast enough, and my NPCs not being set properly (I used the wrong tags).

Now lets see if I can get detecting walls working properly!
Slime Knight
Send private message
 
 PostThu Jun 13, 2013 5:35 pm
Send private message Reply with quote
Ok so I implemented a "wallcheck" script (basically a gutted version of Aethereal's Jailbreak check_walls script) which felt pretty straightforward. And yet, now the npc's don't "detect" the hero anymore. I've tried using trace value in my new script and it doesn't return anything, which leads me to believe my script isn't being triggered. But why wouldn't it?

- the wallcheck script is meant to return true if there are no walls, and false if there are.

Code:
switch(npcd) do(
         case(north) do(
            for(wy, ny, ny -- dt) do( if(wy == mey && nx == mex && wallcheck(dt,npcd,nx,ny)) then(hf := TRUE) )
         )
         case(south) do(
            for(wy, ny, ny + dt) do( if(wy == mey && nx == mex && wallcheck(dt,npcd,nx,ny)) then(hf := TRUE) )
         )
         case(west) do(
            for(wx, nx, nx -- dt) do( if(ny == mey && mex == wx && wallcheck(dt,npcd,nx,ny)) then(hf := TRUE) )
         )
         case(east) do(
            for(wx, nx, nx + dt) do( if(ny == mey && mex == wx && wallcheck(dt,npcd,nx,ny)) then(hf := TRUE) )
         )
      
          
      )


And now the wallcheck script:

Code:
script, wallcheck, tiles, direction, nx, ny,begin

   variable(i)
   for (i,1, tiles) do, begin
      if (direction == north) then (
         if (read pass block(nx, ny -- i) >> 0) then (
            exit returning(false)
         )
         if (read pass block(nx,ny -- i) == 0) then (
            return (true)
         )
      )    
      if (direction == south) then (
         if (read pass block(nx, ny + i) >> 0) then (
            exit returning(false)
         )
         if (read pass block(nx,ny + i) == 0) then (
            return (true)
         )   
      )
      if (direction == east) then (
         if (read pass block(npcx + i, npcy) >> 0) then (
            exit returning(false)
         )
         if (read pass block(npcx + i,npcy) == 0) then (
            return (true)
         )
      )
      if (direction == west) then (
         if (read pass block(npcx -- i, npcy) >> 0) then (
            exit returning(false)
         )
         if (read pass block(npcx -- i,npcy) == 0) then (
            return (true)
         )
      )
   end   
   
   
end


any ideas?
Metal King Slime
Send private message
 
 PostThu Jun 13, 2013 11:18 pm
Send private message Reply with quote
Close but no cigar. Consider what you want the script to do:

Code:
Let npc1 be the appropriate guard
For each tile X, Y in the line of 3 tiles in front of npc1 (nearest first):
   If there is a wall on the tile, stop.
   If the hero is standing on this tile, do something.


Well that's a simplication on your script actually, instead of just being the simplest fix. So a for loop could look like:

Code:

case (north)
  wx := nx
  for(wy, ny, ny -- dt) do(
    if (wallcheck(npcd, wx, wy) == false) then (break)
    if (mex == wx && mey == wy) then (hf := TRUE)
  )


And where "wallcheck" has been simplified to only check a single tile, removing the for loop.

As for the timer not happening, I don't know. Post the whole script? By the way, you can see the state of all timers in the script debugger. Press F10 twice and then V four times (you can press F1 inside the script debugger to see help, BTW).
Slime Knight
Send private message
 
 PostTue Jun 18, 2013 5:00 pm
Send private message Reply with quote
crowtongue wrote:

So it was a combination of the timer not being set fast enough, and my NPCs not being set properly (I used the wrong tags).


So after a hellish couple hours trying to get this to work, I somehow had switched the tags back to the non-working position. Props to Giz for catching this in IRC last night.

TMC wrote:
As for the timer not happening, I don't know. Post the whole script? By the way, you can see the state of all timers in the script debugger. Press F10 twice and then V four times (you can press F1 inside the script debugger to see help, BTW).


This is handy to know Smile Although I had meant that the timer was now working properly so no worries there.

The code works excellently as well, it'll be a lot easier to use this way and cleaner to boot, so thank you TMC. One thing I ended up realizing is that I no longer need to pass the npc direction as an argument to wallcheck since it is already a part of each for loop.

this is now the wallcheck script:

Code:
script, wallcheck, wx, wy, begin
   
   if (read pass block(wx,wy) >> 0) then (exit returning(false))
   if (read pass block(wx,wy) == 0) then (return (true))   
end
Metal King Slime
Send private message
 
 PostTue Jun 18, 2013 7:27 pm
Send private message Reply with quote
Ah, I mistakenly thought that wallcheck changed which walls it checked depending on the direction (eg. only east and west walls when the NPC is facing east). That's why I left the npcd argument in.
Slime Knight
Send private message
 
 PostMon Jul 08, 2013 4:54 am
Send private message Reply with quote
So a couple of problems that I'm having...

My guards are complete idiots, so I'm trying to increase their line of sight. I'd like to start by adding two squares to it, one on each side diagonally in front of the guard.

This is how I coded this:

Code:
switch(npcd) do(
         case(north) do(
            wx := nx
            if(mey == ny -- 1 && mex == wx + 1 || mex == wx --1) then (hf := TRUE)
            for(wy, ny, ny -- dt) do(
                if(wallcheck(wx,wy) == false) then (break)
                if(mex == wx && mey == wy) then(hf := TRUE)


The first "if" statement is the part I've tried to accomplish this with. I put it before the FOR statement because I don't want it to repeat 3 times. For some reason it triggers when the hero is way behind the guard.

Also...

I need to change my wallcheck routine. For example, what if you have a table? You can't walk through it, and yet you can see over it.

Code:
script, wallcheck, wx, wy, begin
   
   if (read pass block(wx,wy) >> 0) then (exit returning(false)
         )
   else if (read pass block(wx,wy) == 0 || read map block(wx,wy,72) then (return (true))


This seems to change random tiles passability in a way that seems entirely random to me.

Any ideas?
Display posts from previous:
Page 1, 2  »