poke 53280, 0: poke 53281, 0
dim mapname as string * 16
print "{WHITE}{CLR}";
input "map name? "; mapname;

memset $d800, 1000, 8

load mapname, 8 

'-----------------CONSTANTS--------------------------
const RASTER_LINE = $d011 

const WALL = 35 ' "#"
const PLAYER_CHAR = 42 ' "*"
const COMPUTER_CHAR = 0 ' "@"
const EMPTY_CHAR = 32 ' " "

const PLAYERSTART_X = 1 : const PLAYERSTART_Y = 1
const COMPUTERSTART_X = 38 : const COMPUTERSTART_Y = 23

const MAXDIR = 3

CONST JOY2 = $dc00
'----------------------------------------------------

'---------------INITIALIZATION-----------------------
Dim tPlayer_x as BYTE : Dim tPlayer_y as BYTE : Dim tPlayer_x_Old as BYTE : Dim tPlayer_y_Old as BYTE
tPlayer_x = PLAYERSTART_X : tPlayer_y = PLAYERSTART_Y : tPlayer_x_Old = PLAYERSTART_X : tPlayer_y_Old = PLAYERSTART_Y

Dim tComputer_x as BYTE : Dim tComputer_y as BYTE : Dim tComputer_x_Old as BYTE : Dim tComputer_y_Old as BYTE
tComputer_x = COMPUTERSTART_X : tComputer_y = COMPUTERSTART_Y : tComputer_x_Old = COMPUTERSTART_X : tComputer_y_Old = COMPUTERSTART_Y

Dim tFuturePoint_x as BYTE fast : Dim tFuturePoint_y as BYTE fast : Dim tFuturePoint_Direction as BYTE fast
tFuturePoint_x = 0: tFuturePoint_y = 0 : tFuturePoint_Direction = 0

Dim bMoveNow as BYTE : bMoveNow = 0

Dim tVecComputerPlayer_Xdiff as INT : Dim tVecComputerPlayer_Ydiff as INT : Dim tVecComputerPlayer_XdiffABS as INT : Dim tVecComputerPlayer_YdiffABS as INT
tVecComputerPlayer_Xdiff = 0 : tVecComputerPlayer_Ydiff = 0 : tVecComputerPlayer_XdiffABS = 0 : tVecComputerPlayer_YdiffABS = 0
Dim tVecSimulToPlayer_Xdiff as INT : Dim tVecSimulToPlayer_Ydiff as INT
tVecSimulToPlayer_Xdiff = 0 : tVecSimulToPlayer_Ydiff = 0
Dim tVectorDir_X as BYTE : Dim tVectorDir_Y as BYTE
tVectorDir_X = 0 : tVectorDir_Y = 0
Dim tWallVectorDir_X as BYTE : Dim tWallVectorDir_Y as BYTE
tWallVectorDir_X = 0 : tWallVectorDir_Y = 0
Dim tWallPosition_Y as BYTE : Dim tWallPosition_X as BYTE
tWallPosition_Y = 0 : tWallPosition_X = 0

Dim nBresenhamDiff as INT : nBresenhamDiff = 0
Dim bLineMoreVertical as BYTE : bLineMoreVertical = 0

Dim nDirectionScalar as BYTE
nDirectionScalar = 0

Dim bWllFllwMode as BYTE : bWllFllwMode = 0
Dim bStrictExitMode as BYTE : bStrictExitMode = 0
dim nSimulatorNumber as BYTE fast : nSimulatorNumber = 0

dim aSimulators_Y(2) as BYTE: dim aSimulators_X(2) as BYTE: dim aSimulators_WalkDir(2) as BYTE: dim aSimulators_StartWalkDir(2) as BYTE

Dim scrAddrCache(25) as WORD @loc_scrAddrCache
loc_scrAddrCache:
DATA AS WORD 1024, 1064, 1104, 1144, 1184, 1224, 1264, 1304, 1344, 1384
DATA AS WORD 1424, 1464, 1504, 1544, 1584, 1624, 1664, 1704, 1744, 1784
DATA AS WORD 1824, 1864, 1904, 1944, 1984

Dim bresenCache(25) as WORD @loc_bresenCache
loc_bresenCache:
DATA AS WORD 49152, 49192, 49232, 49272, 49312, 49352, 49392, 49432, 49472, 49512
DATA AS WORD 49552, 49592, 49632, 49672, 49712, 49752, 49792, 49832, 49872, 49912
DATA AS WORD 49952, 49992, 50032, 50072, 50112

dim JoyValue as BYTE
'----------------------------------------------------

'------------------FUNCTIONS-------------------------
function screen_peek as BYTE(screen_x as BYTE, screen_y as BYTE) STATIC
    return peek(scrAddrCache(screen_y) + screen_x)
end function

sub plotLine(x0 as INT, y0 as INT, x1 as INT, y1 as INT) STATIC
    Dim dx as INT : dx = abs(x1 - x0)
    Dim sx as INT : sx = -1 : if x0 < x1 then sx = 1 ' sx = x0 < x1 ? 1 : -1
    Dim dy as INT : dy = cint(0) - abs(y1 - y0)
    Dim sy as INT : sy = -1 : if y0 < y1 then sy = 1 ' sy = y0 < y1 ? 1 : -1
    Dim brError as INT : brError = dx + dy
    Dim e2 as INT
    
    plotLine_whiletrue:
		poke bresenCache(y0) + x0, 1 'plot(x0, y0)
        if x0 = x1 AND y0 = y1 then exit sub
        e2 = shl(brError, 1) '2 * brError
        if e2 >= dy then
            if x0 = x1 then exit sub
            brError = brError + dy
            x0 = x0 + sx
        end if
        if e2 <= dx then
            if y0 = y1 then exit sub
            brError = brError + dx
            y0 = y0 + sy
        end if
    goto plotLine_whiletrue
end sub
'----------------------------------------------------

'---------------MAIN LOOP----------------------------
'	*** DRAW ***
mainLoop:
    if tPlayer_x <> tPlayer_x_Old or tPlayer_y <> tPlayer_y_Old then
        charat tPlayer_x_Old, tPlayer_y_Old, EMPTY_CHAR
        tPlayer_x_Old = tPlayer_x : tPlayer_y_Old = tPlayer_y
    end if
    if tComputer_x <> tComputer_x_Old or tComputer_y <> tComputer_y_Old then
        charat tComputer_x_Old, tComputer_y_Old, EMPTY_CHAR
        tComputer_x_Old = tComputer_x : tComputer_y_Old = tComputer_y
    end if
    charat tPlayer_x, tPlayer_y, PLAYER_CHAR, 1 ' 1 = white
    charat tComputer_x, tComputer_y, COMPUTER_CHAR, 13 ' 13 = cyan
	'Pauses for 2 frames
    wait RASTER_LINE, 128 : wait RASTER_LINE, 128, 128 : wait RASTER_LINE, 128 : wait RASTER_LINE, 128, 128
	
'	*** PLAYER MOVEMENT ***
    tFuturePoint_x = tPlayer_x : tFuturePoint_y = tPlayer_y
	JoyValue = peek(JOY2)
	if (JoyValue AND  1) XOR  1 then tFuturePoint_y = tFuturePoint_y - 1 'UP 
	if (JoyValue AND  2) XOR  2 then tFuturePoint_y = tFuturePoint_y + 1 'DOWN
	if (JoyValue AND  4) XOR  4 then tFuturePoint_x = tFuturePoint_x - 1 'LEFT
	if (JoyValue AND  8) XOR  8 then tFuturePoint_x = tFuturePoint_x + 1 'RIGHT

    if screen_peek(tPlayer_x, tFuturePoint_y) <> WALL Then tPlayer_y = tFuturePoint_y
    if screen_peek(tFuturePoint_x, tPlayer_y) <> WALL Then tPlayer_x = tFuturePoint_x
	
'	*** COMPUTER MOVEMENT ***
	on bMoveNow goto skipMovement, doMovement
	doMovement:
		on bWllFllwMode goto WallFollowFalse, WallFollowTrue
		WallFollowFalse:
			tVecComputerPlayer_Xdiff = cint(tPlayer_x) - tComputer_x
			tVecComputerPlayer_XdiffABS = abs(tVecComputerPlayer_Xdiff)
			tVecComputerPlayer_Ydiff = cint(tPlayer_y) - tComputer_y
			tVecComputerPlayer_YdiffABS = abs(tVecComputerPlayer_Ydiff)
			if tVecComputerPlayer_YdiffABS >= tVecComputerPlayer_XdiffABS Then bLineMoreVertical = 1 Else bLineMoreVertical = 0
			tVectorDir_X = cbyte(sgn(tVecComputerPlayer_Xdiff))
			tVectorDir_Y = cbyte(sgn(tVecComputerPlayer_Ydiff))
			on bLineMoreVertical goto BresenhamHorizontal, BresenhamVertical
			BresenhamVertical:
				nBresenhamDiff = shl(tVecComputerPlayer_XdiffABS, 1) - tVecComputerPlayer_YdiffABS
				goto BresenhamEnd
			BresenhamHorizontal:
				nBresenhamDiff = shl(tVecComputerPlayer_YdiffABS, 1) - tVecComputerPlayer_XdiffABS
			BresenhamEnd:
			if nBresenhamDiff <= 0 then
				on bLineMoreVertical goto LineMoreVerticalFalse, LineMoreVerticalTrue
				LineMoreVerticalFalse:
					tVectorDir_Y = 0
					goto LineMoreVerticalEnd
				LineMoreVerticalTrue:
					tVectorDir_X = 0
				LineMoreVerticalEnd:
			end if
			
			tFuturePoint_y = tComputer_y + tVectorDir_Y
			if screen_peek(tComputer_x, tFuturePoint_y) = WALL then
				tWallVectorDir_Y = tVectorDir_Y
			else
				tWallVectorDir_Y = 0
			end if
			
			tFuturePoint_x = tComputer_x + tVectorDir_X
			if screen_peek(tFuturePoint_x, tComputer_y) = WALL then
				tWallVectorDir_X = tVectorDir_X
			else
				tWallVectorDir_X = 0
			end if
			
			if tWallVectorDir_Y <> 0 and tWallVectorDir_X <> 0 then
				on bLineMoreVertical goto WallVectorHorizontal, WallVectorVertical
				WallVectorHorizontal:
					tWallVectorDir_Y = 0
					goto WallVectorEnd
				WallVectorVertical:
					tWallVectorDir_X = 0
				WallVectorEnd:
			end if
			
			if tWallVectorDir_X <> 0 or tWallVectorDir_Y <> 0 then
				'-------------------------- WALL HANDLING -------------------------
				on tWallVectorDir_Y + 1 goto wallNorth, noYwall, wallSouth ' -1, 0, 1
				wallNorth:
					nDirectionScalar = 0 'north
					goto DirectionScalarFound
				wallSouth:
					nDirectionScalar = 2 'south
					goto DirectionScalarFound
				noYwall:
					on tWallVectorDir_X + 1 goto wallWest, DirectionScalarFound, wallEast ' -1, 0, 1
					wallWest:
						nDirectionScalar = 3 'west
						goto DirectionScalarFound
					wallEast:
						nDirectionScalar = 1 'east
				DirectionScalarFound:
				
				tWallPosition_Y = tComputer_y + tWallVectorDir_Y
				tWallPosition_X = tComputer_x + tWallVectorDir_X
				
				memset 49152, 1000, 0
				call plotLine(tWallPosition_X, tWallPosition_Y, tPlayer_x, tPlayer_y)
				
				'Simulator INIT
				aSimulators_Y(0) = tComputer_y
				aSimulators_X(0) = tComputer_x
				aSimulators_WalkDir(0) = (nDirectionScalar + 1) AND MAXDIR
				aSimulators_StartWalkDir(0) = aSimulators_WalkDir(0)
				
				aSimulators_Y(1) = tComputer_y
				aSimulators_X(1) = tComputer_x
				aSimulators_WalkDir(1) = (nDirectionScalar - 1) AND MAXDIR
				aSimulators_StartWalkDir(1) = aSimulators_WalkDir(1)
				
				'Simulator LAUNCH
				nSimulatorNumber = 0
				SimulatorLoopStart:
					tFuturePoint_Direction = aSimulators_WalkDir(nSimulatorNumber)
					CheckWallStartLoop:
						tFuturePoint_y = aSimulators_Y(nSimulatorNumber)
						tFuturePoint_x = aSimulators_X(nSimulatorNumber)
						on tFuturePoint_Direction goto SimulDirNorth, SimulDirEast, SimulDirSouth, SimulDirWest
						SimulDirNorth:
							tFuturePoint_y = tFuturePoint_y - 1
							goto SimulDirExit
						SimulDirEast:
							tFuturePoint_x = tFuturePoint_x + 1
							goto SimulDirExit
						SimulDirSouth:
							tFuturePoint_y = tFuturePoint_y + 1
							goto SimulDirExit
						SimulDirWest:
							tFuturePoint_x = tFuturePoint_x - 1 
						SimulDirExit:
						if peek(scrAddrCache(tFuturePoint_y) + tFuturePoint_x) <> WALL Then Goto CheckWallExitLoop
						on nSimulatorNumber goto WalkDirIncrease, WalkDirDecrease
						WalkDirIncrease:
							tFuturePoint_Direction = (tFuturePoint_Direction + 1) AND MAXDIR
							goto WalkDirEndOnGoTo
						WalkDirDecrease:
							tFuturePoint_Direction = (tFuturePoint_Direction - 1) AND MAXDIR
						WalkDirEndOnGoTo:
						goto CheckWallStartLoop
					CheckWallExitLoop:
					
					aSimulators_Y(nSimulatorNumber) = tFuturePoint_y
					aSimulators_X(nSimulatorNumber) = tFuturePoint_x
					
					if peek(bresenCache(tFuturePoint_y) + tFuturePoint_x) = 1 then goto SimulatorLoopExit
					
					on nSimulatorNumber goto WalkDirDecrAgainstWall, WalkDirIncrAgainstWall
					WalkDirDecrAgainstWall:
						tFuturePoint_Direction = (tFuturePoint_Direction - 1) AND MAXDIR
						goto WalkDirAgainstWallEnd
					WalkDirIncrAgainstWall:
						tFuturePoint_Direction = (tFuturePoint_Direction + 1) AND MAXDIR
					WalkDirAgainstWallEnd:
					
					aSimulators_WalkDir(nSimulatorNumber) = tFuturePoint_Direction
					
					nSimulatorNumber = nSimulatorNumber XOR 1 'Alternates 1, 0, 1, 0, ...
					
					goto SimulatorLoopStart
				SimulatorLoopExit:
				
				bWllFllwMode = 1
				bStrictExitMode = 1
				nDirectionScalar = aSimulators_StartWalkDir(nSimulatorNumber) ' ReUse!
					
			else 'if tWallVectorDir_X <> 0 or tWallVectorDir_Y <> 0 then
				if screen_peek(tFuturePoint_x, tFuturePoint_y) = WALL then
					on bLineMoreVertical goto DiagonalHorizontal, DiagonalVertical
					DiagonalHorizontal:
						tFuturePoint_y = tComputer_y
						goto DiagonalEnd
					DiagonalVertical:
						tFuturePoint_x = tComputer_x
					DiagonalEnd:
				end if
				tComputer_y = tFuturePoint_y
				tComputer_x = tFuturePoint_x
				
				goto skipMovement
				
			end if 'if tWallVectorDir_X <> 0 or tWallVectorDir_Y <> 0 then

		WallFollowTrue:
			WllFllwCheckWallStartLoop:
			tFuturePoint_y = tComputer_y
			tFuturePoint_x = tComputer_x
			on nDirectionScalar goto ComputerNorth, ComputerEast, ComputerSouth, ComputerWest
			ComputerNorth:
				tFuturePoint_y = tFuturePoint_y - 1
				goto ComputerDirEnd
			ComputerEast:
				tFuturePoint_x = tFuturePoint_x + 1 
				goto ComputerDirEnd
			ComputerSouth:
				tFuturePoint_y = tFuturePoint_y + 1
				goto ComputerDirEnd
			ComputerWest:
				tFuturePoint_x = tFuturePoint_x - 1 
			ComputerDirEnd:
			if screen_peek(tFuturePoint_x, tFuturePoint_y) <> WALL Then Goto WllFllwCheckWallExitLoop
			on nSimulatorNumber goto ComputerIncrease, ComputerDecrease
			ComputerIncrease:
				nDirectionScalar = (nDirectionScalar + 1) AND MAXDIR
				goto ComputerDirEndOnGoTo
			ComputerDecrease:
				nDirectionScalar = (nDirectionScalar - 1) AND MAXDIR
			ComputerDirEndOnGoTo:
			goto WllFllwCheckWallStartLoop
			WllFllwCheckWallExitLoop:
			
			tComputer_y = tFuturePoint_y
			tComputer_x = tFuturePoint_x
			
			on bStrictExitMode goto skipStrictExit, checkStrictExit
			checkStrictExit:
				if tWallVectorDir_Y <> 0 and tComputer_y = tWallPosition_Y then
					bStrictExitMode = 0
				else
					if tWallVectorDir_X <> 0 and tComputer_x = tWallPosition_X then
						bStrictExitMode = 0
					end if
				end if
			skipStrictExit:
			
			tVecSimulToPlayer_Ydiff = abs(cint(tPlayer_y) - aSimulators_Y(nSimulatorNumber))
			tVecSimulToPlayer_Xdiff = abs(cint(tPlayer_x) - aSimulators_X(nSimulatorNumber))
			tVecComputerPlayer_Ydiff = abs(cint(tPlayer_y) - tComputer_y)
			tVecComputerPlayer_Xdiff = abs(cint(tPlayer_x) - tComputer_x)
			
			'DEBUG: let me see where the simulator is, 19 = "S"
			'charat aSimulators_X(nSimulatorNumber), aSimulators_Y(nSimulatorNumber), 19
			
			on bStrictExitMode goto StrictExitModeOff, StrictExitModeOn
			StrictExitModeOff:
				'DEBUG: let me see the wall Computer bumped into, in yellow
				'charat tWallPosition_X, tWallPosition_Y, WALL, 7
				if tVecComputerPlayer_Ydiff + tVecComputerPlayer_Xdiff <= tVecSimulToPlayer_Ydiff + tVecSimulToPlayer_Xdiff Then
					bWllFllwMode = 0 ' *** EXITING FROM WALL FOLLOWING MODE! ***
					'DEBUG: turn off simulator and wall
					'charat aSimulators_X(nSimulatorNumber), aSimulators_Y(nSimulatorNumber), 32
					'charat tWallPosition_X, tWallPosition_Y, WALL, 8
					goto skipMovement
				end if
				goto StrictExitModeEnd
			StrictExitModeOn:
				'DEBUG: let me see the wall Computer bumped into, in white
				'charat tWallPosition_X, tWallPosition_Y, WALL, 1
				if tVecComputerPlayer_Ydiff <= tVecSimulToPlayer_Ydiff then
					if tVecComputerPlayer_Xdiff <= tVecSimulToPlayer_Xdiff then
						bWllFllwMode = 0 ' *** EXITING FROM WALL FOLLOWING MODE! ***
						'DEBUG: turn off simulator and wall
						'charat aSimulators_X(nSimulatorNumber), aSimulators_Y(nSimulatorNumber), 32
						'charat tWallPosition_X, tWallPosition_Y, WALL, 8
						goto skipMovement
					end if
				end if
			StrictExitModeEnd:
			
			on nSimulatorNumber goto ComputerDecrAgainstWall, ComputerIncrAgainstWall
			ComputerDecrAgainstWall:
				nDirectionScalar = (nDirectionScalar - 1) AND MAXDIR
				goto ComputerAgainstWallEnd
			ComputerIncrAgainstWall:
				nDirectionScalar = (nDirectionScalar + 1) AND MAXDIR
			ComputerAgainstWallEnd:

	skipMovement:
		bMoveNow = bMoveNow XOR 1 'Alternating 0, 1, 0, 1, 0, 1, ...

goto mainLoop
'----------------------------------------------------

