Line of Sight

Make games! Discuss those games here.

Moderators: Bob the Hamster, marionline, SDHawk

User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Line of Sight

Post by crowtongue »

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: Select all

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: Select all

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&#40;wx, nx, nx -- dt&#41; do&#40; if&#40;ny == mey && mex <= nx -- dt && mex >= nx&#41; then&#40;hf &#58;= TRUE&#41; &#41;
			&#41;
			case&#40;east&#41; do&#40;
				for&#40;wx, nx, nx + dt&#41; do&#40; if&#40;ny == mey && mex >= nx && mex <= nx + dt&#41; then&#40;hf &#58;= TRUE&#41; &#41;
			&#41;
			
		&#41;
		
		if&#40;hf == TRUE&#41; then&#40;somethinghappens&#41;
				
	&#41;
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.
Last edited by crowtongue on Tue Jun 11, 2013 9:09 pm, edited 2 times in total.
User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7658
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

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: Select all

   if &#40;check tag&#40;28&#41; == false&#41; then &#40;
      #create the npc and start him walking around.
      create NPC&#40;2, 26, 14, east&#41;   
      set timer&#40;0,5,3,@guardcheck&#41;
      brig1 &#58;= NPC reference&#40;2&#41;
the "create NPC" command returns a reference, so you should do:

Code: Select all

      brig1 &#58;= create NPC&#40;2, 26, 14, east&#41;   
This guarantees that you get the correct reference if there happen to be more than one copy of NPC 2 on the map.
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

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.
User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7658
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

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.
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

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?
User avatar
BMR
Metal King Slime
Posts: 3310
Joined: Mon Feb 27, 2012 2:46 pm
Location: The Philippines
Contact:

Post by BMR »

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
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

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.
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

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: Select all

         case&#40;west&#41; do&#40;
            for&#40;wx, nx, nx -- dt&#41; do&#40; if&#40;ny == mey && wx == mex&#41; then&#40;hf &#58;= TRUE&#41; &#41;
         &#41;
         case&#40;east&#41; do&#40;
            for&#40;wx, nx, nx + dt&#41; do&#40; if&#40;ny == mey && wx == mex&#41; then&#40;hf &#58;= TRUE&#41; &#41;
         &#41; 
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?
User avatar
BMR
Metal King Slime
Posts: 3310
Joined: Mon Feb 27, 2012 2:46 pm
Location: The Philippines
Contact:

Post by BMR »

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
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

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!
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

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: Select all

switch&#40;npcd&#41; do&#40;
			case&#40;north&#41; do&#40;
				for&#40;wy, ny, ny -- dt&#41; do&#40; if&#40;wy == mey && nx == mex && wallcheck&#40;dt,npcd,nx,ny&#41;&#41; then&#40;hf &#58;= TRUE&#41; &#41;
			&#41;
			case&#40;south&#41; do&#40;
				for&#40;wy, ny, ny + dt&#41; do&#40; if&#40;wy == mey && nx == mex && wallcheck&#40;dt,npcd,nx,ny&#41;&#41; then&#40;hf &#58;= TRUE&#41; &#41;
			&#41;
			case&#40;west&#41; do&#40;
				for&#40;wx, nx, nx -- dt&#41; do&#40; if&#40;ny == mey && mex == wx && wallcheck&#40;dt,npcd,nx,ny&#41;&#41; then&#40;hf &#58;= TRUE&#41; &#41;
			&#41;
			case&#40;east&#41; do&#40;
				for&#40;wx, nx, nx + dt&#41; do&#40; if&#40;ny == mey && mex == wx && wallcheck&#40;dt,npcd,nx,ny&#41;&#41; then&#40;hf &#58;= TRUE&#41; &#41;
			&#41;
		
		 	
		&#41;
And now the wallcheck script:

Code: Select all

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

	variable&#40;i&#41;
	for &#40;i,1, tiles&#41; do, begin
		if &#40;direction == north&#41; then &#40;
			if &#40;read pass block&#40;nx, ny -- i&#41; >> 0&#41; then &#40;
				exit returning&#40;false&#41;
			&#41;
			if &#40;read pass block&#40;nx,ny -- i&#41; == 0&#41; then &#40;
				return &#40;true&#41;
			&#41;
		&#41; 	
		if &#40;direction == south&#41; then &#40;
			if &#40;read pass block&#40;nx, ny + i&#41; >> 0&#41; then &#40;
				exit returning&#40;false&#41;
			&#41;
			if &#40;read pass block&#40;nx,ny + i&#41; == 0&#41; then &#40;
				return &#40;true&#41;
			&#41;	
		&#41;
		if &#40;direction == east&#41; then &#40;
			if &#40;read pass block&#40;npcx + i, npcy&#41; >> 0&#41; then &#40;
				exit returning&#40;false&#41;
			&#41;
			if &#40;read pass block&#40;npcx + i,npcy&#41; == 0&#41; then &#40;
				return &#40;true&#41;
			&#41;
		&#41;
		if &#40;direction == west&#41; then &#40;
			if &#40;read pass block&#40;npcx -- i, npcy&#41; >> 0&#41; then &#40;
				exit returning&#40;false&#41;
			&#41;
			if &#40;read pass block&#40;npcx -- i,npcy&#41; == 0&#41; then &#40;
				return &#40;true&#41;
			&#41;
		&#41;
	end	
	
	
end
any ideas?
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Close but no cigar. Consider what you want the script to do:

Code: Select all

Let npc1 be the appropriate guard
For each tile X, Y in the line of 3 tiles in front of npc1 &#40;nearest first&#41;&#58;
   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: Select all

case &#40;north&#41;
  wx &#58;= nx
  for&#40;wy, ny, ny -- dt&#41; do&#40;
    if &#40;wallcheck&#40;npcd, wx, wy&#41; == false&#41; then &#40;break&#41;
    if &#40;mex == wx && mey == wy&#41; then &#40;hf &#58;= TRUE&#41;
  &#41; 
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).
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

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 :) 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: Select all

script, wallcheck, wx, wy, begin
	
	if &#40;read pass block&#40;wx,wy&#41; >> 0&#41; then &#40;exit returning&#40;false&#41;&#41;
	if &#40;read pass block&#40;wx,wy&#41; == 0&#41; then &#40;return &#40;true&#41;&#41;	
end
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

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.
Last edited by TMC on Tue Jun 18, 2013 7:27 pm, edited 1 time in total.
User avatar
crowtongue
Slime Knight
Posts: 115
Joined: Mon Feb 25, 2013 4:57 pm

Post by crowtongue »

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: Select all

switch&#40;npcd&#41; do&#40;
			case&#40;north&#41; do&#40;
				wx &#58;= nx
				if&#40;mey == ny -- 1 && mex == wx + 1 || mex == wx --1&#41; then &#40;hf &#58;= TRUE&#41;
				for&#40;wy, ny, ny -- dt&#41; do&#40;
					 if&#40;wallcheck&#40;wx,wy&#41; == false&#41; then &#40;break&#41;
					 if&#40;mex == wx && mey == wy&#41; then&#40;hf &#58;= TRUE&#41; 
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: Select all

script, wallcheck, wx, wy, begin
	
	if &#40;read pass block&#40;wx,wy&#41; >> 0&#41; then &#40;exit returning&#40;false&#41;
			&#41;
	else if &#40;read pass block&#40;wx,wy&#41; == 0 || read map block&#40;wx,wy,72&#41; then &#40;return &#40;true&#41;&#41;
This seems to change random tiles passability in a way that seems entirely random to me.

Any ideas?
Post Reply