User Tools

Site Tools


cw4:4rpl_tools

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
cw4:4rpl_tools [2025/06/23 18:39] – [Request Viable Move- or Build-Cell] kallicw4:4rpl_tools [2025/06/30 20:12] (current) – [Pseudo Random Number Generator, based on sinus] kalli
Line 3551: Line 3551:
  
  
-===== 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.+
  
  
Line 3565: Line 3564:
  
  
-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 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
  
Line 3593: Line 3623:
 # 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
  
Line 3621: Line 3646:
 # 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 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 
 + add 2.div asint dup ->rHx 1 sub ->rLx # For the footprint loop. 
 + else pop endif
   
- <-anywhereList <-unitType listcontains if  + <-checkN ->prevCheckN 
- ->resetSnapIndex + <-checkR ->prevCheckR 
- 1 else 0 endif ->placeA+ <-placeA ->prevPlaceA 
 + <-placeV ->prevPlaceV 
 + <-cell ->prevSearchCell
   
- <-voidList <-unitType listcontains if  + # Recreate the area to search: 
- ->resetSnapIndex + <-searchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange 
- 1 else endif ->placeV+ <-cell ev2 0 21 <-floodRange floodfillterrain dup getlistcount ->potentialCellCount ->potentialCells 
 + ->startLoop 
 + 0 ->skip
   
-0 ->orientation +If the search is being reset, then clear the blocked lists. 
- endif + <-resetSearch If 
- <-unitType ->prevType +->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 
- ->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
   
Line 3690: Line 3739:
  # 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
Line 3700: Line 3749:
  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
Line 3718: Line 3767:
  -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
   
Line 3740: Line 3776:
  <-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 potential cells by increasing the index with 3.+<-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
Line 3774: Line 3810:
  <-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
Line 3801: Line 3843:
  <-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>
  
cw4/4rpl_tools.1750703984.txt.gz · Last modified: 2025/06/23 18:39 by kalli