Both sides previous revisionPrevious revisionNext revision | Previous revision |
cw4:4rpl_tools [2025/06/23 18:39] – [Request Viable Move- or Build-Cell] kalli | cw4:4rpl_tools [2025/06/30 20:12] (current) – [Pseudo Random Number Generator, based on sinus] kalli |
---|
| |
| |
===== Request Viable Move- or Build-Cell ===== | ===== Request Viable Build- or Move-Cell ===== |
| |
<hidden click here for source code> | <hidden click here for source code> |
| |
This script allows for other scripts to SEND A MESSAGE TO REQUEST A VIABLE MOVE- OR BUILD-CELL. | This script allows for other scripts to SEND A MESSAGE TO REQUEST A VIABLE BUILD- OR MOVE-CELL. |
| |
| The script is a compromise between high performance and high fidelity. The reason that it's setup to run as a separate script and not as a function, is so that it can take move/build requests from multiple sources into account: by default it won't recheck cells that were recently rejected + new searches will continue where recent previous queries stopped after finding a solution. A very high performance version exists for 3x3 units in my SQUADS map. |
The script is a compromise between high performance and high fidelity. The reason that it's setup to run as a separate script and not as a function, is so that it can take move/build requests from multiplie sources into account: it won't recheck cells that were recently rejected + new searches will continue where recent previous queries stopped after finding a solution. A very high performance version exists for 3x3 units in my SQUADS map. | |
| |
| |
| |
| |
If the units are special custom units (build in void/anywhere or build as miner/nullifier, then their GUID needs to be added to the relevant lists inside the script. | Use example for building miners: |
| |
| |
INPUT: | <code 4rpl example.4rpl>500 0 do |
<code 4rpl MultiObjective.4rpl>"requestWxWviableCell" <-UID <-cellV2 <-searchRange <-maxCreeperDepth <-noMesh <-unitWidth <-ignoreCooldown 7 listN sendmsg</code> | "requestWxWviableCell" 0 5 3 128 128 v2 256 0 0 0 0 1 0 1 1 0 14 listN sendmsg # Length > width = x direction. |
OUTPUT: 2 global variables, see example: | <-*WxWviableCellFound if |
<code 4rpl MultiObjective.4rpl><-*WxWviableCellFound if | "miner" <-*WxWviableCell ev2 0 createunitonterrain dup 1 SetUnitOccupiesLand 999 constructunit |
<-UID <-*WxWviableCell ev2 setunitmovecell | # Unlike existing units that move, newly build units do not instantly occupy the cells that they were created on, so we force a refresh of that with SetUnitOccupiesLand. |
endif</code> | endif |
| loop |
| |
| 500 0 do |
| "requestWxWviableCell" 0 3 5 128 128 v2 256 0 0 0 0 1 0 1 1 0 14 listN sendmsg # Length > width = z direction. With Z-direction we also need to change the orientation below. |
| <-*WxWviableCellFound if |
| "miner" <-*WxWviableCell ev2 0 createunitonterrain dup dup 1 setunitorientation 1 SetUnitOccupiesLand 999 constructunit |
| endif |
| loop</code> |
| |
INPUT variables explained: | INPUT variables explained: |
<-UID | |
<-cellV2: The cell where your requesting script wants to build/move the unit. | <-moveUID: can be left 0, but it's needed if you want to allow a unit to check if it's current location is viable. |
<-searchRange: the cell distance around the requested cell location, where the function will look for a suitable build/move cell. | |
| <-unitLength: footprint length in X direction. |
| |
| <-unitWidth: footprint length in Z direction. |
| |
| <-cellV2: V2 vector. The cell where your requesting script wants to build/move the unit. |
| |
| <-searchRange: the cell distance around the requested cell location, where the function will look for a viable build/move cell. |
<-maxCreeperDepth: this will check the average creeper depth in a circle with range 4. | <-maxCreeperDepth: this will check the average creeper depth in a circle with range 4. |
| |
<-noMesh: set to 1 to not allow solutions with ACTIVE mesh. | <-noMesh: set to 1 to not allow solutions with ACTIVE mesh. |
<-unitWidth: the footprint witdth=length of the unit. This assumes square units. | |
<-ignoreCooldown: set to 1 to ignore the computation optimizations. | |
| |
<code 4rpl MultiObjective.4rpl> | <-likePlatform: the unit can be placed in the void. |
# --WxW-FindViableCell-NRP-Pre-- | |
| <-likeBeacon: the unit can be placed in the void and on uneven terrain. |
| |
| <-likeMiner: the unit can only be placed on resource special terrain that covers atleast 75% of the unit footprint. |
| |
| <-likeNullifier: the unit has to be placed within nullification range of an enemy creeper. The creeper enemey has to be known to a list inside the function script. |
| |
| <-ignoreCooldown: set to 1 to ignore time based computation optimizations. Best left at 0 when the function is called by an AI script (more optimized) and set to 1 when it's initiated by the player (feels more responsive). |
| |
| <-noSkip: set to 1 for max placement coverage, but slower computations. If left at 0, then the script will not check cells that are likely to not have a proper solution, but it will also mistakenly not check some cells that do have a proper solution. For spamming 3x3 units, "1" tends to be 40% slower, while only placing about 10% more units. |
| |
| <-resetSearch: if set to 1, then all previous search history will be forgotten. |
| |
| |
| |
| <code 4rpl LxW-FindViableCell-NRP-Pre.4rpl> |
| # --LxW-FindViableCell-NRP-Pre-- |
| |
# INPUTS: "requestWxWviableCell" <-UID <-cellV2 <-searchRange <-maxCreeperDepth <-noMesh <-unitWidth <-ignoreCooldown 7 listN sendmsg | # INPUTS: "requestWxWviableCell" <-moveUID <-unitLength <-unitWidth <-cellV2 <-searchRange <-maxCreeperDepth <-noMesh <-likePlatform <-likeBeacon <-likeMiner <-likeNullifier <-ignoreCooldown <-noSkip <-resetSearch 14 listN |
# OUTPUT: global varialbles named <-*WxWviableCellFound <-*WxWviableCell | # OUTPUT: global varialbles named <-*WxWviableCellFound <-*WxWviableCell |
| |
# BASED ON SNAPPING TOOL CODE, but without the Indicator unit or the Mouse commands, and only for SQUARE units. | # BASED ON SNAPPING TOOL CODE, but without the Indicator unit or the Mouse commands, and only for SQUARE units. |
| |
$radiusLandingSpot:4 # The creeper threshhold will be checked as an average over more than the unit landing location. | $radiusLandingSpot:4 # INTEGER. The creeper threshhold will be checked as an average over more than the unit landing location. |
$cellsWithinLandingRange:69 # 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 # If no searchRange is send in the message, this is the range that will be used. | $$defaultSearchRange:20 # INTEGER. The floodfill distance. If no searchRange is send in the message, this is the range that will be used. |
| |
$$contSlot:8 # Units cannot be placed on this terrain slot. 8 is the default contaminant slot. | $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. |
$$resoSlot:1 # Miners can only be placed on resource terrain. 1 is the default resource slot. | $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. |
$$meshSlot:6 # Units that can be placed in the void, cannot be placed on mesh inside the void. 6 is the default mesh slot. | $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. |
| |
$$unitBuildTypes:" " | |
# $$footprintWidth:" " | |
# $$footprintLength:" " | |
$$voidUnitTypes:" Platform; platform" | |
$$anywhereTypes:" Chronat; beacon" | |
$$resourceTypes:" Reactor; miner" | |
$$nullifyTypes:" Nullifier; nullifier" | |
$$nullifyUnits:" emitter; airsaccauldron; blobnest; darktower; skimmerfactory; sporelauncher" # Enemy units that would be suppressed by building a nullifier near them. | $$nullifyUnits:" emitter; airsaccauldron; blobnest; darktower; skimmerfactory; sporelauncher" # Enemy units that would be suppressed by building a nullifier near them. |
| |
:requestWxWviableCellFunction | :requestWxWviableCellFunction |
<-_DATA[0] 0 setunitoccupiesland | <-_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[2] dup not if pop <-defaultSearchRange endif ->searchRange | <-_DATA ListToStack @searchWxWviableCell ->*WxWviableCellFound ->*WxWviableCell |
<-_DATA[0] getunittype <-_DATA[1] <-_DATA[3] <-_DATA[4] <-_DATA[5] @searchWxWviableCell ->*WxWviableCellFound ->*WxWviableCell | |
<-_DATA[6] ->ignoreCooldown | |
<-_DATA[0] 1 setunitoccupiesland | <-_DATA[0] 1 setunitoccupiesland |
| |
# listening channels: | # listening channels: |
"requestWxWviableCell" "requestWxWviableCellFunction" registerformsg | "requestWxWviableCell" "requestWxWviableCellFunction" registerformsg |
1 ->resetSnapIndex | 1 ->resetSearch |
| 1 ->ignoreCooldown |
| |
# When the loop was ran through fully without finding a resolution, remember that cell for 150 frames before trying the same cell again. | # 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 ->blockedCellV2List |
list ->blockedCellTimeList | list ->blockedCellTimeList |
list ->nearbyUnitsCountList | list ->nearbyUnitsCountList |
| |
# the ONCE code from the snapping tool script | |
# <-unitBuildTypes removewhitespace ";" split ->buildList | |
# <-footprintWidth removewhitespace ";" split ->widthList | |
# <-widthList 0 do <-widthList[i] 1 add 2.0 div asint ->widthList[i] loop | |
# <-footprintLength removewhitespace ";" split ->lengthList | |
# <-widthList 0 do <-lengthList[i] 1 add 2.0 div asint ->lengthList[i] loop | |
<-voidUnitTypes removewhitespace ";" split ->voidList | |
<-anywhereTypes removewhitespace ";" split ->anywhereList | |
<-resourceTypes removewhitespace ";" split ->resourceList | |
<-nullifyTypes removewhitespace ";" split ->nullifierList | |
<-nullifyUnits removewhitespace ";" split ->suppressList | <-nullifyUnits removewhitespace ";" split ->suppressList |
# unitType and prevType must be different at the start of the map. | |
<-unitType not ->prevType | |
# <-searchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange | |
| |
:searchWxWviableCell # Output: viableCell as v2 + true/false | :searchWxWviableCell # Output: viableCell as v2 + true/false |
# See vanilla snapping tool cpack for full commments. | # See vanilla snapping tool cpack for full commments. |
->width | ->resetSearch |
| ->noSkip |
| ->ignoreCooldown |
| ->checkN |
| ->checkR |
| ->placeA |
| ->placeV |
->noMesh | ->noMesh |
->creDepth | ->creDepth |
| ->searchRange |
->cell | ->cell |
->unitType | ->width |
| ->length |
<-unitType <-prevType neq if | pop # The UID has no further use. |
# <-buildList <-unitType getlistindex ->typeIndex | |
# <-widthList[<-typeIndex] ->rangeX | # The following switch checks if the search should start from scratch (=1), or if it should continue (=0) on from a previous search. |
# <-lengthList[<-typeIndex] ->rangeZ | switch |
<-resourceList <-unitType listcontains if 1 else 0 endif ->checkR | <-resetSearch case 1 endcase |
<-nullifierList <-unitType listcontains if 1 else 0 endif ->checkN | <-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 |
| |
<-anywhereList <-unitType listcontains if | <-checkN ->prevCheckN |
1 ->resetSnapIndex | <-checkR ->prevCheckR |
1 else 0 endif ->placeA | <-placeA ->prevPlaceA |
| <-placeV ->prevPlaceV |
| <-cell ->prevSearchCell |
| |
<-voidList <-unitType listcontains if | # Recreate the area to search: |
1 ->resetSnapIndex | <-searchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange |
1 else 0 endif ->placeV | <-cell ev2 0 21 <-floodRange floodfillterrain dup getlistcount ->potentialCellCount ->potentialCells |
| 0 ->startLoop |
| 0 ->skip |
| |
# 0 ->orientation | # If the search is being reset, then clear the blocked lists. |
endif | <-resetSearch If |
<-unitType ->prevType | 1 ->ignoreCooldown |
| <-blockedCellV2List clearlist |
<-cell ev2 <-prevSearchCell ev2 distancecell 6 gt if | <-blockedCellTimeList clearlist |
<-cell ->prevSearchCell | <-nearbyUnitsCountList clearlist |
1 ->resetSnapIndex | endif |
else | else |
<-prevSearchCell ->cell | # 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. |
getgameupdatecount dup 29 sub <-prevSearchUpdateCount gt if | <-searchRange dup <-prevSearchRange neq if |
->prevSearchUpdateCount | dup ->prevSearchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange |
1 ->resetSnapIndex | <-cell ev2 0 21 <-floodRange floodfillterrain dup getlistcount ->potentialCellCount ->potentialCells |
else pop endif | else pop endif |
endif | endif |
| |
# If the new searchRange is larger than the old one, then do not check if the cell was blocked. | # 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 not if | <-searchRange <-prevSearchRange gt <-ignoreCooldown OR not if |
# Check if the cell is not on the list of blocked cells. | # Check if the cell is not on the list of blocked cells. |
<-blockedCellV2List <-cell getlistindex dup -1 neq if | <-blockedCellV2List <-cell getlistindex dup -1 eq if pop else |
->index | ->index |
| |
# Try to purge a few old blocked cells from the lists, otherwise the list bloats. | # Try to purge a few old blocked cells from the lists, otherwise the list bloats. |
-1 <-index 1 sub do | -1 <-index 1 sub do |
<-blockedCellTimeList[i] 270 add <-updateCount lt if | <-blockedCellTimeList[i] <-clearCellTimer add <-updateCount lt if |
<-blockedCellV2List i removelistelement | <-blockedCellV2List i removelistelement |
<-blockedCellTimeList i removelistelement | <-blockedCellTimeList i removelistelement |
switch | switch |
# The last check on this spot was less than 3 seconds ago, so we're not checking it again now. | # The last check on this spot was less than 3 seconds ago, so we're not checking it again now. |
<-blockedCellTimeList[<-index] 90 add <-updateCount gt case | <-blockedCellTimeList[<-index] <-blockCellTimer add <-updateCount gt case |
-1 -1 v2 false return | -1 -1 v2 false return |
endcase | endcase |
# The last check on this spot was longer than 9 seconds ago, so we can check it again now. | # The last check on this spot was longer than 9 seconds ago, so we can check it again now. |
<-blockedCellTimeList[<-index] 270 add <-updateCount lt case | <-blockedCellTimeList[<-index] <-clearCellTimer add <-updateCount lt case |
<-blockedCellV2List <-index removelistelement | <-blockedCellV2List <-index removelistelement |
<-blockedCellTimeList <-index removelistelement | <-blockedCellTimeList <-index removelistelement |
<-nearbyUnitsCountList <-index removelistelement | <-nearbyUnitsCountList <-index removelistelement |
endcase | endcase |
# Check the cell again if there are now less enemies nearby than when it was blocked. | # 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 | <-cell ev2 fromcell 13 0 0 0 0 0 0 getunitsinrange getlistcount <-nearbyUnitsCountList[<-index] lt case |
<-blockedCellV2List <-index removelistelement | <-blockedCellV2List <-index removelistelement |
-1 -1 v2 false return | -1 -1 v2 false return |
endswitch | endswitch |
else pop endif | endif |
endif | |
| |
<-ignoreCooldown <-resetSnapIndex OR if | |
<-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 ->resetSnapIndex | |
else | |
# If the search range was changed, then the potentialcells 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 | endif |
| |
<-potentialCells[i] ev2 @checkCenterCell if | <-potentialCells[i] ev2 @checkCenterCell if |
@checkFootPrint if | @checkFootPrint if |
i <-width 2 div asint add ->startLoop # Optimization for mass placement. When placing the next unit, skip the next 4 potential cells by increasing the index with 3. | 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. | <-potentialCells[i] true return # LEFT ON STACK. |
endif | endif |
else | else |
<-width 3 div asint ->skip # If the center cell was blocked, then also skip the next X potential cells. | <-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 |
endif | endif |
<-special <-meshSlot eq <-height 0 eq AND case pop pop false return endcase # Units cannot be placed on mesh in the void. | <-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. | ->cZ ->cX # Used in checkFootPrint. |
<-checkR if <-special <-resourceSlot eq if <-minePot 1 add ->minePot endif endif | <-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 | endswitch |
true | true |
# 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 ->rH 1 sub ->rL | |
else pop endif | |
| |
:checkFootPrint | :checkFootPrint |
# See vanilla snapping tool cpack for full commments. | # See vanilla snapping tool cpack for full commments. |
| |
<-cZ <-rH add <-cZ <-rL sub do | <-cZ <-rHz add <-cZ <-rLz sub do |
<-cX <-rH add <-cX <-rL sub do | <-cX <-rHx add <-cX <-rLx sub do |
switch | switch |
i j | i j |
<-placeA case pop pop endcase | <-placeA case pop pop endcase |
pop pop | pop pop |
| <-checkR if <-special <-resoSlot eq if <-minePot 1 add ->minePot endif endif |
endswitch | endswitch |
<-checkR if <-special <-resourceSlot eq if <-minePot 1 add ->minePot endif endif | |
loop | loop |
loop | loop |
<-checkN if <-suppressList <-cX 0 <-cZ v3 9 0 0 0 1 0 1 getunitsinrange 0 getlistelement getunittype listcontains not if false return endif endif | <-checkR if <-minePot <-length <-width mul 0.75 mul lt if false return endif endif |
<-checkR if <-minePot <-rangeX 2 mul 1 sub <-rangeZ 2 mul 1 sub mul 0.75 mul lt if 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 false return endif | |
# endif | |
true | true |
| |
| </code> |
| |
| </hidden> |
| |
| ---- |
| |
| |
| ===== Pseudo Random Number Generator, based on sinus ===== |
| |
| <hidden click here for source code> |
| |
| Several basic functions based on Grabz' rng lite function of "<-seed sinus 10000 mul dup floor sub". |
| |
| |
| Copy the functions directly into your script or run the below script in your cpack and have other scripts send messages to request a randfloat or randint. |
| |
| |
| Difference between the functions: |
| * "seeded": provide a seed to the generator. The generated number will always be the same for the same seed. |
| * "index": these seeds are sequenced. In the same map for the same index, the generated number 1,2,3,... will be the same after map restart. |
| * "spiked": the generator is seeded with the elapsedtime of the gaming session, making the outcome uncontrollable. |
| * No prefix: these are sequenced seeds and they use index 0. |
| |
| Example code with messages: |
| <code example.4rpl> |
| 12345 ->int |
| 1 ->index |
| 0 ->first |
| 100 ->last # The last integer itself will be excluded. |
| "sinRandInt" <-first <-last 2 listN sendmsg |
| <-*sinRandInt trace |
| "sinRand01" 0 sendmsg |
| <-*sinRand01 trace |
| "indexSinRandInt" <-index <-first <-last 3 listN sendmsg |
| <-*sinRandInt trace |
| "indexSinRand01" <-index sendmsg |
| <-*sinRand01 trace |
| "spikedSinRandInt" <-first <-last 2 listN sendmsg |
| <-*sinRandInt trace |
| "spikedSinRand01" 0 sendmsg |
| <-*sinRand01 trace |
| "seededSinRandInt" <-seed <-first <-last 3 listN sendmsg |
| <-*sinRandInt trace |
| "seededSinRand01" <-seed sendmsg |
| <-*sinRand01 trace |
| </code> |
| |
| ---- |
| |
| <code SinusRNG.4rpl> |
| :once |
| # Creating lists and a starting mapconstant for the seed sequences. |
| createlist ->prevSeedList |
| createlist ->seedCountList |
| getmapsize 2 div swap 2 div swap dup2 getterrain 1 add dup 99999 floodfillterrain getlistcount ->mapConstant |
| |
| # Setting up the messages so that other scripts can request a random seed. |
| "sinRandInt" "sinRandInt_CALL" registerformsg |
| "sinRand01" "sinRand01_CALL" registerformsg |
| "indexSinRandInt" "indexSinRandInt_CALL" registerformsg |
| "indexSinRand01" "indexSinRand01_CALL" registerformsg |
| "spikedSinRandInt" "spikedSinRandInt_CALL" registerformsg |
| "spikedSinRand01" "spikedSinRand01_CALL" registerformsg |
| "seededSinRandInt" "seededSinRandInt_CALL" registerformsg |
| "seededSinRand01" "seededSinRand01_CALL" registerformsg |
| |
| :sinRandInt_CALL |
| <-_DATA listtostack @sinRandInt ->*sinRandInt |
| :sinRand01_CALL |
| @sinRand01 ->*sinRand01 |
| :indexSinRandInt_CALL |
| <-_DATA listtostack @indexSinRandInt ->*sinRandInt |
| :indexSinRand01_CALL |
| <-_DATA @indexSinRand01 ->*sinRand01 |
| :spikedSinRandInt_CALL |
| <-_DATA listtostack @spikedSinRandInt ->*sinRandInt |
| :spikedSinRand01_CALL |
| @spikedSinRand01 ->*sinRand01 |
| :seededSinRandInt_CALL |
| <-_DATA listtostack @seededSinRandInt ->*sinRandInt |
| :seededSinRand01_CALL |
| <-_DATA @seededSinRand01 ->*sinRand01 |
| |
| :sinRandInt # INPUT: integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| ->last |
| ->first |
| 0 @indexSinRand01 <-last <-first sub mul <-first add asint |
| |
| :sinRand01 # INPUT: none. |
| 0 @indexSinRand01 |
| |
| :indexSinRandInt # INPUT: the index of the seed sequence + integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| ->last |
| ->first |
| @indexSinRand01 <-last <-first sub mul <-first add asint |
| |
| :indexSinRand01 # INPUT: the "index" of the seed sequence. OUTPUT: the next seed from that sequence. |
| # The random numbers will be generated with the previous seed that is stored under that index. |
| ->i |
| <-prevSeedList[<-i] eq0 if |
| <-i <-mapConstant add 2357 mul @seededSinRand01 dup 10000000 mul 1 add asint ->prevSeedList[<-i] |
| 1 ->seedCountList[<-i] |
| else |
| <-prevSeedList[<-i] @seededSinRand01 dup 10000000 mul <-seedCountList[<-i] 1 add dup ->seedCountList[<-i] add asint ->prevSeedList[<-i] |
| endif |
| |
| :spikedSinRandInt # INPUT: integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| ->last |
| ->first |
| elapsedtime asint @seededSinRand01 <-last <-first sub mul <-first add asint |
| |
| :spikedSinRand01 |
| elapsedtime asint @seededSinRand01 |
| |
| :seededSinRandInt # INPUT: integer seed + integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| ->last |
| ->first |
| @seededSinRand01 <-last <-first sub mul <-first add asint |
| |
| :seededSinRand01 |
| # abs <-power pow <-add add sin <-sinMul mul dup floor sub |
| 1.05 pow 99419 sub sin 619 mul dup floor sub |
</code> | </code> |
| |