# --LxW-FindViableCell-NRP-Pre-- # INPUTS: "requestWxWviableCell" <-moveUID <-unitLength <-unitWidth <-cellV2 <-searchRange <-maxCreeperDepth <-noMesh <-likePlatform <-likeBeacon <-likeMiner <-likeNullifier <-ignoreCooldown <-noSkip <-resetSearch 14 listN # OUTPUT: global varialbles named <-*WxWviableCellFound <-*WxWviableCell # Contains snapping tool movecell requests, so that multiple units can request a viable cell from a single source, without double checking cells. # BASED ON SNAPPING TOOL CODE, but without the Indicator unit or the Mouse commands, and only for SQUARE units. $radiusLandingSpot:4 # INTEGER. The creeper threshhold will be checked as an average over more than the unit landing location. $cellsWithinLandingRange:69 # INTEGER, see previous radius. The creeper threshhold will be checked as an average over more than the unit landing location. $$defaultSearchRange:20 # INTEGER. The floodfill distance. If no searchRange is send in the message, this is the range that will be used. $groupDist:7 # Integer or float distance. Requests that are closer together than this distance, will be grouped together, so that later searches can continue on from previous searches. $blockCellTimer:90 # INTEGER. Amount of frames under which queries will be grouped together & searches around cells that were found to be blocked, will not be done again. $clearCellTimer:270 # INTEGER. Amount of frames after which the blocked cells will be forgotten. In between these 2 values, searches will only be done again if there are less units around than when the cell was last found to be blocked. $$contSlot:8 # VALUE EDITOR SETTING. Units cannot be placed on this terrain slot. 8 is the default contaminant slot. $$resoSlot:1 # VALUE EDITOR SETTING. Miners can only be placed on resource terrain. 1 is the default resource slot. $$meshSlot:6 # VALUE EDITOR SETTING. Units that can be placed in the void, cannot be placed on mesh inside the void. 6 is the default mesh slot. $$nullifyUnits:" emitter; airsaccauldron; blobnest; darktower; skimmerfactory; sporelauncher" # Enemy units that would be suppressed by building a nullifier near them. :requestWxWviableCellFunction <-_DATA[0] 0 setunitoccupiesland # With this line, an existing unit's current cell will be a possible result from the search for a viable cell. <-_DATA ListToStack @searchWxWviableCell ->*WxWviableCellFound ->*WxWviableCell <-_DATA[0] 1 setunitoccupiesland :once # listening channels: "requestWxWviableCell" "requestWxWviableCellFunction" registerformsg 1 ->resetSearch 1 ->ignoreCooldown # When the loop was ran through fully without finding a resolution, remember that cell for 90 frames before trying the same cell again. list ->blockedCellV2List list ->blockedCellTimeList list ->nearbyUnitsCountList <-nullifyUnits removewhitespace ";" split ->suppressList :searchWxWviableCell # Output: viableCell as v2 + true/false # See vanilla snapping tool cpack for full commments. ->resetSearch ->noSkip ->ignoreCooldown ->checkN ->checkR ->placeA ->placeV ->noMesh ->creDepth ->searchRange ->cell ->width ->length pop # The UID has no further use. # The following switch checks if the search should start from scratch (=1), or if it should continue (=0) on from a previous search. switch <-resetSearch case 1 endcase <-length <-prevLength neq case 1 endcase <-width <-prevWidth neq case 1 endcase <-checkN <-prevCheckN neq case 1 endcase <-checkR <-prevCheckR neq case 1 endcase <-placeA <-prevPlaceA neq case 1 endcase <-placeV <-prevPlaceV neq case 1 endcase <-cell ev2 <-prevSearchCell ev2 distancecell <-groupDist gt if 1 else <-prevSearchCell ->cell # Group the search query together with previous closeby queries. <-ignoreCooldown if getgametickcount else getgameupdatecount endif dup <-prevSearchUpdateCount gt if ->prevSearchUpdateCount 1 else pop 0 endif endif endswitch if # If the search starts from scratch, then the new settings have to be remembered for the next function call. # Adjust the footprint array depending on the requested width in the function call. <-width dup <-prevWidth neq if dup ->prevWidth 1 add 2.0 div asint dup ->rHz 1 sub ->rLz # For the footprint loop. else pop endif <-length dup <-prevLength neq if dup ->prevLength 1 add 2.0 div asint dup ->rHx 1 sub ->rLx # For the footprint loop. else pop endif <-checkN ->prevCheckN <-checkR ->prevCheckR <-placeA ->prevPlaceA <-placeV ->prevPlaceV <-cell ->prevSearchCell # Recreate the area to search: <-searchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange <-cell ev2 0 21 <-floodRange floodfillterrain dup getlistcount ->potentialCellCount ->potentialCells 0 ->startLoop 0 ->skip # If the search is being reset, then clear the blocked lists. <-resetSearch If 1 ->ignoreCooldown <-blockedCellV2List clearlist <-blockedCellTimeList clearlist <-nearbyUnitsCountList clearlist endif else # If the search continues on from before, but the search range was changed, then the potential cells will need to be adjusted, without adjusting the start of the loop. <-searchRange dup <-prevSearchRange neq if dup ->prevSearchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange <-cell ev2 0 21 <-floodRange floodfillterrain dup getlistcount ->potentialCellCount ->potentialCells else pop endif endif # If the new searchRange is larger than the old one, then do not check if the cell was recently found to be blocked. <-searchRange <-prevSearchRange gt <-ignoreCooldown OR not if # Check if the cell is not on the list of blocked cells. <-blockedCellV2List <-cell getlistindex dup -1 eq if pop else ->index getgameupdatecount ->updateCount # Try to purge a few old blocked cells from the lists, otherwise the list bloats. -1 <-index 1 sub do <-blockedCellTimeList[i] <-clearCellTimer add <-updateCount lt if <-blockedCellV2List i removelistelement <-blockedCellTimeList i removelistelement <-nearbyUnitsCountList <-index removelistelement <-index 1 sub ->index endif loop switch # The last check on this spot was less than 3 seconds ago, so we're not checking it again now. <-blockedCellTimeList[<-index] <-blockCellTimer add <-updateCount gt case -1 -1 v2 false return endcase # The last check on this spot was longer than 9 seconds ago, so we can check it again now. <-blockedCellTimeList[<-index] <-clearCellTimer add <-updateCount lt case <-blockedCellV2List <-index removelistelement <-blockedCellTimeList <-index removelistelement <-nearbyUnitsCountList <-index removelistelement endcase # Check the cell again if there are now less units nearby than when it was blocked. <-cell ev2 fromcell 13 0 0 0 0 0 0 getunitsinrange getlistcount <-nearbyUnitsCountList[<-index] lt case <-blockedCellV2List <-index removelistelement <-blockedCellTimeList <-index removelistelement <-nearbyUnitsCountList <-index removelistelement endcase # Too recent and still the same amount of units nearby, so don't check again: -1 -1 v2 false return endswitch endif endif <-potentialCellCount <-startLoop do <-skip if <-skip 1 sub ->skip else <-potentialCells[i] ev2 @checkCenterCell if @checkFootPrint if i <-noSkip if 1 else <-width endif add ->startLoop # Optimization for mass placement. When placing the next unit, skip the next few potential cells. <-potentialCells[i] true return # LEFT ON STACK. endif else <-noSkip if 0 else <-width 3 div asint 1 add endif ->skip # If the center cell was blocked, then also skip the next X potential cells. endif endif loop <-potentialCellCount ->startLoop # If the loop was not interrupted by return, then all cells were blocked in some way. <-blockedCellV2List <-cell appendtolist <-blockedCellTimeList getgameupdatecount appendtolist <-nearbyUnitsCountList <-cell ev2 fromcell 13 0 0 0 0 0 0 getunitsinrange getlistcount appendtolist -1 -1 v2 false # LEFT ON STACK. :checkCenterCell # Inputs: x and z of cell. dup2 <-radiusLandingSpot 0 1 0 getcreeperinrange <-cellsWithinLandingRange div <-creDepth gt if pop pop false return endif dup2 getterrain dup ->height if <-placeV if pop pop false return endif 0 ->checkO else <-placeV <-placeA OR if 0 else 1 endif ->checkO endif <-checkR if 0 ->minePot endif # dup2 is still on the stack. switch dup2 getcelloccupiedcount <-checkO neq case pop pop false return endcase # dup2 getterrain <-height neq case pop pop false return endcase # Useless on center cell. # dup2 getcreeper <-creDepth gt case pop pop false return endcase dup2 getmeshhealth gt0 <-noMesh AND case pop pop false return endcase dup2 getterraformmarker gt0 case pop pop false return endcase dup2 getterrainspecial dup ->special <-contSlot eq case pop pop false return endcase <-special <-meshSlot eq <-height 0 eq AND case pop pop false return endcase # Units cannot be placed on mesh in the void. ->cZ ->cX # Used in checkFootPrint. <-checkR if <-special <-resoSlot eq if <-minePot 1 add ->minePot else pop pop false return endif endif <-checkO if "platform" <-cX 0 <-cZ v3 2.9 0 0 0 2 1 0 getunits 0 getlistelement getunitcell <-cX <-cZ distancecell 2.828427 approximately not if pop pop false return endif endif <-checkN if <-suppressList <-cX 0 <-cZ v3 9 0 0 0 1 0 1 getunitsinrange 0 getlistelement getunittype listcontains not if pop pop false return endif endif endswitch true :checkFootPrint # See vanilla snapping tool cpack for full commments. <-cZ <-rHz add <-cZ <-rLz sub do <-cX <-rHx add <-cX <-rLx sub do switch i j # dup2 <-cZ eq swap <-cX eq AND case pop pop endcase # The center cell was already checked and OK. dup2 getcelloccupiedcount <-checkO neq case pop pop false return endcase dup2 getterrain <-height neq case pop pop false return endcase # dup2 getcreeper <-creDepth gt case pop pop false return endcase dup2 getmeshhealth gt0 <-noMesh AND case pop pop false return endcase dup2 getterraformmarker gt0 case pop pop false return endcase dup2 getterrainspecial dup ->special <-contSlot eq case pop pop false return endcase # dup2 getterrainspecial <-meshSlot eq <-height 0 eq AND case pop pop false return endcase # Prevents platforms from being placed on mesh in the void. Not relevant for this script. <-special <-meshSlot eq <-height 0 eq AND case pop pop false return endcase # Units cannot be placed on mesh in the void. <-placeA case pop pop endcase pop pop <-checkR if <-special <-resoSlot eq if <-minePot 1 add ->minePot endif endif endswitch loop loop <-checkR if <-minePot <-length <-width mul 0.75 mul lt if false return endif endif true