home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / jpi / map.bas < prev    next >
Encoding:
BASIC Source File  |  1998-01-29  |  18.9 KB  |  473 lines

  1. Attribute VB_Name = "Map"
  2. Public Const SEASON_SUMMER = 1
  3. Public Const MaxSeasons = 1
  4. Public Type TerrainProfile
  5.   GrassSprites As IndexGroup
  6.   WaterSprites As IndexGroup
  7.   RockObjects As IndexGroup
  8.   TreeObjects As IndexGroup
  9.   DebrisObject As IndexGroup
  10.   WaterBorderSprite As String
  11. End Type
  12. Public SeasonProfiles(MaxSeasons) As TerrainProfile
  13. Global Const MapBlockSize = 16
  14. Global Const HalfMapBlockSize = MapBlockSize / 2
  15. Global Const TERRAINTYPE_NOTHING = 0
  16. Global Const TERRAINTYPE_GRASS = 1
  17. Global Const TERRAINTYPE_WATER = 2
  18. Private Type MAPtype
  19.   Width As Integer
  20.   RealWidth As Integer
  21.   Height As Integer
  22.   RealHeight As Integer
  23.   MapName As String
  24.   EpisodeNumber As Integer
  25.   LevelNumber As Integer
  26. End Type
  27. Global BattleMap As MAPtype
  28. Public Const MAXTERRAINOVERLAYS = 12
  29. Private Type GroundBlock
  30.   TerrainType As Integer
  31.   Occupied As Boolean
  32.   OccupyingObject As Integer
  33.   DamageAmount As Integer
  34.   SpriteNumbers(MAXTERRAINOVERLAYS) As Integer
  35.   AnimFrames(MAXTERRAINOVERLAYS) As Integer
  36.   TerrainOverlayAmount As Integer
  37.   Height As Integer
  38.   Friction As Integer
  39. End Type
  40. Global Const MaxMapX = 152
  41. Global Const MaxMapY = 152
  42. Global GroundBlocks(-2 To MaxMapX + 10, -2 To MaxMapY + 10) As GroundBlock
  43. Public Sub ResetMap()
  44. Dim BlankGroundBlock As GroundBlock, BlankBattleMap As MAPtype
  45. For X = 0 To MaxMapX
  46.   For Y = 0 To MaxMapY
  47.     GroundBlocks(X, Y) = BlankGroundBlock
  48.   Next Y
  49. Next X
  50. BattleMap = BlankBattleMap
  51. End Sub
  52. Public Sub LoadSeasonProfiles()
  53. Call FileFunctions.OpenGameFile(File_TerrainProfiles, 1)
  54. Do
  55.   Line Input #1, a$
  56.   If a$ = FILETAG_ENDFILE Then Exit Do
  57.   If a$ = "[TERRAINPROFILEDEF]" Then
  58.     Line Input #1, a$
  59.     Select Case MiscFunctions.GetPropertyValue(a$)
  60.     Case "Summer"
  61.       Season = SEASON_SUMMER
  62.     End Select
  63.     SeasonProfiles(Season).GrassSprites.IndexesActive = 0
  64.     SeasonProfiles(Season).DebrisObject.IndexesActive = 0
  65.     SeasonProfiles(Season).RockObjects.IndexesActive = 0
  66.     SeasonProfiles(Season).TreeObjects.IndexesActive = 0
  67.     SeasonProfiles(Season).WaterSprites.IndexesActive = 0
  68.     Do
  69.       Line Input #1, a$
  70.       If a$ = "[ENDTERRAINPROFILE]" Then
  71.         Exit Do
  72.       End If
  73.       Select Case MiscFunctions.GetPropertyName(a$)
  74.       Case "WaterBorder:"
  75.         SeasonProfiles(Season).WaterBorderSprite = MiscFunctions.GetPropertyValue(a$)
  76.       Case "GrassSprite:"
  77.         SeasonProfiles(Season).GrassSprites.IndexesActive = SeasonProfiles(Season).GrassSprites.IndexesActive + 1
  78.         SeasonProfiles(Season).GrassSprites.Indexes(SeasonProfiles(Season).GrassSprites.IndexesActive) = GetSpriteIndex(MiscFunctions.GetPropertyValue(a$))
  79.       Case "WaterSprite:"
  80.         SeasonProfiles(Season).WaterSprites.IndexesActive = SeasonProfiles(Season).WaterSprites.IndexesActive + 1
  81.         SeasonProfiles(Season).WaterSprites.Indexes(SeasonProfiles(Season).WaterSprites.IndexesActive) = GetSpriteIndex(MiscFunctions.GetPropertyValue(a$))
  82.       Case "RockObject:"
  83.         SeasonProfiles(Season).RockObjects.IndexesActive = SeasonProfiles(Season).RockObjects.IndexesActive + 1
  84.         SeasonProfiles(Season).RockObjects.Indexes(SeasonProfiles(Season).RockObjects.IndexesActive) = Entities.GetClassNum(MiscFunctions.GetPropertyValue(a$))
  85.       Case "TreeObject:"
  86.         SeasonProfiles(Season).TreeObjects.IndexesActive = SeasonProfiles(Season).TreeObjects.IndexesActive + 1
  87.         SeasonProfiles(Season).TreeObjects.Indexes(SeasonProfiles(Season).TreeObjects.IndexesActive) = Entities.GetClassNum(MiscFunctions.GetPropertyValue(a$))
  88.       Case "DebrisObject:"
  89.         SeasonProfiles(Season).DebrisObject.IndexesActive = SeasonProfiles(Season).DebrisObject.IndexesActive + 1
  90.         SeasonProfiles(Season).DebrisObject.Indexes(SeasonProfiles(Season).DebrisObject.IndexesActive) = Entities.GetClassNum(MiscFunctions.GetPropertyValue(a$))
  91.       End Select
  92.     Loop
  93.   End If
  94. Loop
  95. Close #1
  96. End Sub
  97. Sub ChangeBattleMapSize(Width, Height)
  98. BattleMap.Width = Width
  99. BattleMap.Height = Height
  100. BattleMap.RealWidth = Width * MapBlockSize
  101. BattleMap.RealHeight = Height * MapBlockSize
  102. Call GameEngine.Initialize_BattleView
  103. End Sub
  104. Sub GenerateRandomMap(Width, Height, Season, TerrainRandomness, ForestNumber, ForestSize, RandomTreeAmount, LakeNumber, LakeSizes, Rivers, Streams, BoulderAreaNumber, BouldersPerArea, RandomBoulderAmount, DebrisPiles, DebrisPileSize, RandomDebrisAmount, DirtPathAmount, ClearingAmounts, ClearingSize)
  105. Dim TempPos As Point3D, NewPos As Point3D
  106. LevelSettings.AirFriction = 0.01
  107. LevelSettings.GravityAmount = 1
  108. Call ChangeBattleMapSize(Width, Height)
  109. Select Case Season
  110. Case SEASON_SUMMER
  111.   For X = 0 To Width
  112.     For Y = 0 To Height
  113.       GroundBlocks(X, Y).Friction = 1
  114.       GroundBlocks(X, Y).TerrainType = TERRAINTYPE_GRASS
  115.       GroundBlocks(X, Y).Height = Int(5 * Rnd)
  116.     Next Y
  117.   Next X
  118.   For I = 1 To LakeNumber
  119.     LakeX = Int(Width * Rnd)
  120.     LakeY = Int(Height * Rnd)
  121.     LakeSize = LakeSizes + Int((TerrainRandomness * Rnd) - (TerrainRandomness / 2))
  122.     TempPos.X = LakeX
  123.     TempPos.Y = LakeY
  124.     If TempPos.X < 0 Then TempPos.X = 0
  125.     If TempPos.Y < 0 Then TempPos.Y = 0
  126.     If TempPos.X > BattleMap.Width Then TempPos.X = BattleMap.Width
  127.     If TempPos.Y > BattleMap.Height Then TempPos.Y = BattleMap.Height
  128.     
  129.     For LakeDrawYaw = 1 To 360
  130.       LakeSize = LakeSize + Int(3 * Rnd) - 1
  131.       For RadiusLength = 1 To LakeSize
  132.         NewPos = Math.GetPropelCoordinates(TempPos, LakeDrawYaw, 0, RadiusLength)
  133.         If NewPos.X < 0 Then NewPos.X = 0
  134.         If NewPos.Y < 0 Then NewPos.Y = 0
  135.         If NewPos.X > BattleMap.Width Then NewPos.X = BattleMap.Width
  136.         If NewPos.Y > BattleMap.Height Then NewPos.Y = BattleMap.Height
  137.         GroundBlocks(Int(NewPos.X), Int(NewPos.Y)).TerrainType = TERRAINTYPE_WATER
  138.       Next RadiusLength
  139.     Next LakeDrawYaw
  140.   Next I
  141.   
  142.   For I = 1 To RandomTreeAmount
  143.     ForestX = Int(Width * Rnd)
  144.     ForestY = Int(Height * Rnd)
  145.     TempPos.X = ForestX
  146.     TempPos.Y = ForestY
  147.     If TempPos.X < 0 Then TempPos.X = 0
  148.     If TempPos.Y < 0 Then TempPos.Y = 0
  149.     If TempPos.X > BattleMap.Width Then TempPos.X = BattleMap.Width
  150.     If TempPos.Y > BattleMap.Height Then TempPos.Y = BattleMap.Height
  151.     If GroundBlocks(Int(TempPos.X), Int(TempPos.Y)).Occupied = False Then
  152.       If GroundBlocks(Int(TempPos.X), Int(TempPos.Y)).TerrainType = TERRAINTYPE_GRASS Then
  153.         Call SpawnObject(SeasonProfiles(SEASON_SUMMER).TreeObjects.Indexes(1), SIDE_SCENERY, TempPos.X, TempPos.Y, TempPos.Z, 0, 0)
  154.       End If
  155.     End If
  156.   Next I
  157.  
  158.   For I = 1 To RandomBoulderAmount
  159.     BoulderX = Int(Width * Rnd)
  160.     BoulderY = Int(Height * Rnd)
  161.     TempPos.X = BoulderX
  162.     TempPos.Y = BoulderY
  163.     If TempPos.X < 0 Then TempPos.X = 0
  164.     If TempPos.Y < 0 Then TempPos.Y = 0
  165.     If TempPos.X > BattleMap.Width Then TempPos.X = BattleMap.Width
  166.     If TempPos.Y > BattleMap.Height Then TempPos.Y = BattleMap.Height
  167.     If GroundBlocks(Int(TempPos.X), Int(TempPos.Y)).Occupied = False Then
  168.       If GroundBlocks(Int(TempPos.X), Int(TempPos.Y)).TerrainType = TERRAINTYPE_GRASS Then
  169.         Call SpawnObject(SeasonProfiles(SEASON_SUMMER).RockObjects.Indexes(1), SIDE_SCENERY, TempPos.X, TempPos.Y, TempPos.Z, 0, 0)
  170.       End If
  171.     End If
  172.   Next I
  173.  
  174. End Select
  175. Call AddTerrainSprites(Season)
  176. End Sub
  177. Sub AddTerrainSprites(Season)
  178. For X = 0 To MaxMapX
  179.   For Y = 0 To MaxMapY
  180.     GroundBlocks(X, Y).AnimFrames(1) = 1
  181.     GroundBlocks(X, Y).TerrainOverlayAmount = 1
  182.     'Actual Terrain
  183.     Select Case GroundBlocks(X, Y).TerrainType
  184.     Case TERRAINTYPE_GRASS
  185.       GroundBlocks(X, Y).SpriteNumbers(1) = SeasonProfiles(Season).GrassSprites.Indexes(Int(SeasonProfiles(Season).GrassSprites.IndexesActive * Rnd) + 1)
  186.       GroundBlocks(X, Y).AnimFrames(1) = Int((Sprites(GroundBlocks(X, Y).SpriteNumbers(1)).SpriteGroups(1).FrameMax) * Rnd) + 1
  187.     Case TERRAINTYPE_WATER
  188.       GroundBlocks(X, Y).SpriteNumbers(1) = SeasonProfiles(Season).WaterSprites.Indexes(Int(SeasonProfiles(Season).GrassSprites.IndexesActive * Rnd) + 1)
  189.       GroundBlocks(X, Y).AnimFrames(1) = Int(Sprites(SeasonProfiles(Season).WaterSprites.Indexes(Int(SeasonProfiles(Season).GrassSprites.IndexesActive * Rnd) + 1)).SpriteGroups(SPRITEGROUP_NORMAL).FrameMax * Rnd) + 1
  190.     End Select
  191.     'Overlay
  192.     If GroundBlocks(X, Y).TerrainType = TERRAINTYPE_GRASS Then
  193.       CurrentLayerNumber = 1
  194.       If GroundBlocks(X - 1, Y).TerrainType = TERRAINTYPE_WATER Then
  195.         CurrentLayerNumber = CurrentLayerNumber + 1
  196.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "W")
  197.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  198.       End If
  199.       If GroundBlocks(X, Y - 1).TerrainType = TERRAINTYPE_WATER Then
  200.         CurrentLayerNumber = CurrentLayerNumber + 1
  201.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "N")
  202.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  203.       End If
  204.       If GroundBlocks(X + 1, Y).TerrainType = TERRAINTYPE_WATER Then
  205.         CurrentLayerNumber = CurrentLayerNumber + 1
  206.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "E")
  207.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  208.       End If
  209.       If GroundBlocks(X, Y + 1).TerrainType = TERRAINTYPE_WATER Then
  210.         CurrentLayerNumber = CurrentLayerNumber + 1
  211.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "S")
  212.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  213.       End If
  214.       If GroundBlocks(X - 1, Y - 1).TerrainType = TERRAINTYPE_WATER Then
  215.         CurrentLayerNumber = CurrentLayerNumber + 1
  216.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "NW")
  217.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  218.       End If
  219.       If GroundBlocks(X + 1, Y - 1).TerrainType = TERRAINTYPE_WATER Then
  220.         CurrentLayerNumber = CurrentLayerNumber + 1
  221.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "NE")
  222.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  223.       End If
  224.       If GroundBlocks(X + 1, Y + 1).TerrainType = TERRAINTYPE_WATER Then
  225.         CurrentLayerNumber = CurrentLayerNumber + 1
  226.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "SE")
  227.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  228.       End If
  229.       If GroundBlocks(X - 1, Y + 1).TerrainType = TERRAINTYPE_WATER Then
  230.         CurrentLayerNumber = CurrentLayerNumber + 1
  231.         GroundBlocks(X, Y).SpriteNumbers(CurrentLayerNumber) = SpriteStuff.GetSpriteIndex(SeasonProfiles(Season).WaterBorderSprite & "SW")
  232.         GroundBlocks(X, Y).AnimFrames(CurrentLayerNumber) = 1
  233.       End If
  234.       
  235.       GroundBlocks(X, Y).TerrainOverlayAmount = CurrentLayerNumber
  236.     End If
  237.   Next Y
  238. Next X
  239. End Sub
  240. Sub LoadMap(MapFile)
  241. End Sub
  242. Public Function IsImprintSpaceNonGrass(X, Y, ImprintIndex) As Boolean
  243. On Error Resume Next
  244. PosX = X - HALFIMPRINTSIZE
  245. PosY = Y - HALFIMPRINTSIZE
  246. For X1 = 1 To IMPRINTSIZE
  247.   For Y1 = 1 To IMPRINTSIZE
  248.     If MapImprints(ObjModels(ClassNum).Attributes(ATTRIBUTE_MAPIMPRINT)).ImprintArray(X1, Y1) = True Then
  249.       If GroundBlocks(PosX + X1, PosY + Y1).TerrainType <> TERRAINTYPE_GRASS Then
  250.         IsImprintSpaceNonGrass = True
  251.         Exit Function
  252.       End If
  253.     End If
  254.   Next Y1
  255. Next X1
  256. End Function
  257. Public Function IsImprintSpaceOccupied(X, Y, ImprintIndex) As Boolean
  258. On Error Resume Next
  259. For X1 = 1 To IMPRINTSIZE
  260.   For Y1 = 1 To IMPRINTSIZE
  261.     If MapImprints(ObjModels(ClassNum).Attributes(ATTRIBUTE_MAPIMPRINT)).ImprintArray(X1, Y1) = True Then
  262.       If GroundBlocks((X - HALFIMPRINTSIZE) + X1, (Y - HALFIMPRINTSIZE) + Y1).Occupied = True Then
  263.         IsImprintSpaceOccupied = True
  264.         Exit Function
  265.       End If
  266.     End If
  267.   Next Y1
  268. Next X1
  269. End Function
  270. Public Sub PlaceMapImprint(ImprintIndex, X, Y, ObjIndex)
  271. On Error Resume Next
  272. Putx = X - HALFIMPRINTSIZE
  273. Puty = Y - HALFIMPRINTSIZE
  274. For ImprintScanX = 1 To IMPRINTSIZE
  275.   For imprintscany = 1 To IMPRINTSIZE
  276.     If MapImprints(ImprintIndex).ImprintArray(ImprintScanX, imprintscany) = True Then
  277.       GroundBlocks(ImprintScanX + Putx, imprintscany + Puty).OccupyingObject = ObjIndex
  278.       GroundBlocks(ImprintScanX + Putx, imprintscany + Puty).Occupied = True
  279.     End If
  280.   Next imprintscany
  281. Next ImprintScanX
  282. End Sub
  283. Public Sub LiftMapImprint(MapX, MapY, ObjIndex)
  284. On Error Resume Next
  285. OffX = MapX - HALFIMPRINTSIZE
  286. OffY = MapY - HALFIMPRINTSIZE
  287. For X = 1 To IMPRINTSIZE
  288.   For Y = 1 To IMPRINTSIZE
  289.     If GroundBlocks(X + OffX, Y + OffY).OccupyingObject = ObjIndex Then
  290.       GroundBlocks(X + OffX, Y + OffY).Occupied = False
  291.     End If
  292.   Next Y
  293. Next X
  294. End Sub
  295. Public Function ProjectToMapX(mX) As Integer
  296. ProjectToMapX = Int(mX / MapBlockSize)
  297. End Function
  298. Public Function ProjectToMapY(mY) As Integer
  299. ProjectToMapY = Int(mY / MapBlockSize)
  300. End Function
  301. Public Function UnProjectToMapX(mX) As Integer
  302. UnProjectToMapX = (mX * MapBlockSize) + (HalfMapBlockSize - 1)
  303. End Function
  304. Public Function UnProjectToMapY(mY) As Integer
  305. UnProjectToMapY = (mY * MapBlockSize) + (HalfMapBlockSize - 1)
  306. End Function
  307. Public Function UnProjectToMap3DPoint(OrigPoint As Point3D) As Point3D
  308. UnProjectToMap3DPoint.X = Map.UnProjectToMapX(OrigPoint.X)
  309. UnProjectToMap3DPoint.Y = Map.UnProjectToMapY(OrigPoint.Y)
  310. UnProjectToMap3DPoint.Z = OrigPoint.Z
  311. End Function
  312. Public Function RoundToMap3DPoint(OrigPoint As Point3D) As Point3D
  313. RoundToMap3DPoint.X = Map.ProjectToMapX(OrigPoint.X)
  314. RoundToMap3DPoint.X = Map.UnProjectToMapX(RoundToMap3DPoint.X)
  315. RoundToMap3DPoint.Y = Map.ProjectToMapY(OrigPoint.Y)
  316. RoundToMap3DPoint.Y = Map.UnProjectToMapY(RoundToMap3DPoint.Y)
  317. RoundToMap3DPoint.Z = OrigPoint.Z
  318. End Function
  319. Public Function ProjectToMap3DPoint(OrigPoint As Point3D) As Point3D
  320. ProjectToMap3DPoint.X = Map.ProjectToMapX(OrigPoint.X)
  321. ProjectToMap3DPoint.Y = Map.ProjectToMapY(OrigPoint.Y)
  322. ProjectToMap3DPoint.Z = OrigPoint.Z
  323. End Function
  324. Public Function SetGroundUnOccupiedByObject(ObjIndex) As Boolean
  325. If ObjModels(Objects(ObjIndex).ModelIndex).Attributes(ATTRIBUTE_MAPIMPRINT) = NOMAPIMPRINT Then
  326.   X = Objects(ObjIndex).MapPosition.X
  327.   Y = Objects(ObjIndex).MapPosition.Y
  328.   Size = ObjModels(Objects(ObjIndex).ModelIndex).Attributes(ATTRIBUTE_SIZE)
  329.   For Xplace = X - Int(Size / 2) To X + Int(Size / 2)
  330.     For Yplace = Y - Int(Size / 2) To Y + Int(Size / 2)
  331.       GroundBlocks(Xplace, Yplace).Occupied = False
  332.     Next Yplace
  333.   Next Xplace
  334. Else
  335.   Call LiftMapImprint(X, Y, ObjIndex)
  336. End If
  337. End Function
  338. Public Function SetGroundOccupiedByObject(ObjIndex) As Boolean
  339. If ObjModels(Objects(ObjIndex).ModelIndex).Attributes(ATTRIBUTE_MAPIMPRINT) = NOMAPIMPRINT Then
  340.   X = Objects(ObjIndex).MapPosition.X
  341.   Y = Objects(ObjIndex).MapPosition.Y
  342.   Size = ObjModels(Objects(ObjIndex).ModelIndex).Attributes(ATTRIBUTE_SIZE)
  343.   For Xplace = X - Int(Size / 2) To X + Int(Size / 2)
  344.     For Yplace = Y - Int(Size / 2) To Y + Int(Size / 2)
  345.       GroundBlocks(Xplace, Yplace).Occupied = True
  346.       GroundBlocks(Xplace, Yplace).OccupyingObject = ObjIndex
  347.     Next Yplace
  348.   Next Xplace
  349. Else
  350.   Call PlaceMapImprint(ObjModels(Objects(ObjIndex).ModelIndex).Attributes(ATTRIBUTE_MAPIMPRINT), X, Y, ObjIndex)
  351. End If
  352. End Function
  353. Public Function GetGroundOccupied(X, Y, Size) As Boolean
  354.   For Xplace = X - Int(Size / 2) To X + Int(Size / 2)
  355.     For Yplace = Y - Int(Size / 2) To Y + Int(Size / 2)
  356.       If GroundBlocks(Xplace, Yplace).Occupied = True Then
  357.         GetGroundOccupied = True
  358.         Exit Function
  359.       End If
  360.     Next Yplace
  361.   Next Xplace
  362. End Function
  363. Public Function IsMapBlockEmpty(P3D As Point3D) As Boolean
  364. If GroundBlocks(P3D.X, P3D.Y).Occupied = False Then IsMapBlockEmpty = True
  365. End Function
  366. Public Function IsMapBlockEmptyXY(X, Y) As Boolean
  367. If GroundBlocks(X, Y).Occupied = False Then IsMapBlockEmptyXY = True
  368. End Function
  369. Public Function GetNearestEmptyBlock(X, Y, OffLimitsTerrain, ConsiderDestinations As Boolean) As Point3D
  370. 'Searches in a clock-wise manner for an empty terrain block
  371.  
  372. If GroundBlocks(X, Y).Occupied = False Then
  373.   If GroundBlocks(X, Y).TerrainType <> OffLimitsTerrain Then
  374.     'Checks if any objects are going to that spot already
  375.     If ConsiderDestinations = True Then
  376.       For I = 1 To ObjectsActive
  377.         If Entities.CheckObject(I, OBJCHECK_ALIVE) = True Then
  378.           If Objects(I).Objective.MainDestination.X = X Then
  379.             If Objects(I).Objective.MainDestination.Y = Y Then
  380.               Occupied = True
  381.             End If
  382.           End If
  383.         End If
  384.       Next I
  385.       If Occupied = False Then
  386.         GetNearestEmptyBlock.X = X
  387.         GetNearestEmptyBlock.Y = Y
  388.         Exit Function
  389.       End If
  390.     Else
  391.       GetNearestEmptyBlock.X = X
  392.       GetNearestEmptyBlock.Y = Y
  393.       Exit Function
  394.     End If
  395.   End If
  396. End If
  397. ScanSide = 1
  398. ScanLine = 1
  399. MaxScan = 1
  400. ScanY = MaxScan
  401. ScanX = -MaxScan
  402. Do
  403.   Count = Count + 1
  404.   If Count > 400 Then
  405.     ScanX = 0
  406.     ScanY = 0
  407.     Exit Do
  408.   End If
  409.   Occupied = False
  410.   CurrentX = X + ScanX
  411.   CurrentY = Y + ScanY
  412.   If CurrentX < 0 Then CurrentX = 0
  413.   If CurrentY < 0 Then CurrentY = 0
  414.   If CurrentX > BattleMap.Width Then CurrentX = BattleMap.Width
  415.   If CurrentY > BattleMap.Height Then CurrentY = BattleMap.Height
  416.   
  417.   If GroundBlocks(CurrentX, CurrentY).Occupied = True Then
  418.     Occupied = True
  419.   Else
  420.     If GroundBlocks(CurrentX, CurrentY).TerrainType = OffLimitsTerrain Then
  421.       Occupied = True
  422.     Else
  423.       'Checks if any objects are going to that spot already
  424.       If ConsiderDestinations = True Then
  425.         For I = 1 To ObjectsActive
  426.           If Entities.CheckObject(I, OBJCHECK_ALIVE) = True Then
  427.             If Objects(I).Objective.MainDestination.X = CurrentX Then
  428.               If Objects(I).Objective.MainDestination.Y = CurrentY Then
  429.                 Occupied = True
  430.               End If
  431.             End If
  432.           End If
  433.         Next I
  434.       End If
  435.     End If
  436.   End If
  437.   If Occupied = True Then
  438.     If ScanSide = 1 Then
  439.       If ScanLine = 1 Then
  440.         ScanY = ScanY - 1
  441.         If ScanY = -MaxScan Then
  442.           ScanLine = 2
  443.         End If
  444.       Else
  445.         ScanX = ScanX + 1
  446.         If ScanX = MaxScan Then
  447.           ScanSide = 2
  448.         End If
  449.       End If
  450.     Else
  451.       If ScanLine = 2 Then
  452.         ScanY = ScanY + 1
  453.         If ScanY = MaxScan Then
  454.           ScanLine = 1
  455.         End If
  456.       Else
  457.         ScanX = ScanX - 1
  458.         If ScanX = -MaxScan Then
  459.           ScanSide = 1
  460.           ScanX = ScanX - 1
  461.           ScanY = ScanY + 1
  462.           MaxScan = MaxScan + 1
  463.         End If
  464.       End If
  465.     End If
  466.   Else
  467.     Exit Do  'Free square found!
  468.   End If
  469. Loop
  470. GetNearestEmptyBlock.X = X + ScanX
  471. GetNearestEmptyBlock.Y = Y + ScanY
  472. End Function
  473.