Advertisement
Billabob

boom tas functions

May 24th, 2025
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //initial "rngseed" is set to 1993 + I_GetRandomTimeSeed() + gametic
  2. //I_GetRandomTimeSeed() is the OS time, gametic is 0 when recording a demo
  3. //in a TAS we can just set this value in the demo header
  4. let rngseed=12
  5. let seed=0 //unsigned int, 0-4,294,967,295
  6. let rng={seed:[]}
  7. let boom
  8.  
  9. /*
  10. https://github.com/kraflab/dsda-doom/blob/356e3d7e031be592c89338d70b8c7a69b6d888d7/prboom2/src/m_random.c
  11. */
  12.  
  13. function M_ClearRandom(){
  14.     seed = (rngseed*2+1)%4294967296;
  15.     for(let i=0; i<51; i++){ //the only class used, "all_in_one", is [49]
  16.         seed=(seed*69069)%4294967296
  17.         rng.seed[i] = seed;
  18.     }
  19. }
  20. M_ClearRandom()
  21.  
  22. function P_Random(){
  23.     boom = rng.seed[49]; //unsigned long
  24.     //rng.seed[49] = ((boom*1664525) + 221297 + (49*2))%4294967296;
  25.     rng.seed[49] = ((boom*1664525) + 221395)%4294967296;
  26.     boom >>= 20
  27.     return boom&255;
  28. }
  29.  
  30. function getNextRNGValue(n=rng.seed[49]){ //emulates P_Random without modifying global vars
  31.     return ((n*1664525) + 221395)%4294967296;
  32. }
  33.  
  34. //-----------------
  35. //generic utilities
  36. //-----------------
  37.  
  38. //inp needs to be an array of objects
  39. //keys will be grabbed from index of template
  40. function printForExcel(inp,template=0,includen=false){
  41.     let ikeys=Object.keys(inp[template])
  42.     let outpstring=ikeys[0]
  43.     if(includen){
  44.         outpstring="n   "+outpstring
  45.     }
  46.     for(let i=1;i<ikeys.length;i++){
  47.         outpstring=outpstring+" "+ikeys[i]
  48.     }
  49.     for(let i=0;i<inp.length;i++){
  50.         if(includen){
  51.             outpstring=outpstring+"\n"+i+"  "+(inp[i][ikeys[0]] ?? "")
  52.         }else{
  53.             outpstring=outpstring+"\n"+(inp[i][ikeys[0]] ?? "")
  54.         }
  55.         for(let j=1;j<ikeys.length;j++){
  56.             outpstring=outpstring+" "+(inp[i][ikeys[j]] ?? "")
  57.         }
  58.     }
  59.     console.log(outpstring)
  60. }
  61.  
  62. //----------------------
  63. //holding on to the past
  64. //----------------------
  65.  
  66. //find x values, n before a specific rng.seed[49] value
  67. function getPrecedingValues(val=rng.seed[49],n=100,x=n){
  68.     for(let i=0;i<n;i++){
  69.         val = getPreviousValue(val)
  70.     }
  71.     let Ordered=[val]
  72.     for(let i=0;i<x;i++){
  73.         val=getNextRNGValue(val)
  74.         Ordered[Ordered.length]=val
  75.     }
  76.     return Ordered
  77. }
  78.  
  79. function getPreviousValue(n=rng.seed[49]){
  80.     return Number((BigInt((n-221395)%4294967296)*4276115653n)%4294967296n)
  81. }
  82.  
  83. //find initial rngseed from rng.seed[49] value
  84. function getSeedFromValue(n=rng.seed[49]){
  85.     if(n%2==0){return -1} //odd numbers only
  86.     return (Number((BigInt(n)*3602842457n)%4294967296n)-1)/2
  87. }
  88.  
  89. //---------------------
  90. //looking to the future
  91. //---------------------
  92.  
  93. //NOTE FOR THESE ROLLS:
  94. //if the enemy is asleep it can wake up after the first pellet and call RNG 3(?) times, this should be accounted for, eventually
  95.  
  96. function getSGRoll(n=rng.seed[49]){
  97.     let temprng=rng.seed[49]
  98.     rng.seed[49]=n
  99.     //rng calls are as follows:
  100.     //1: P_GunShot rolls for damage
  101.     //3: P_GunShot rolls twice for horizontal offset
  102.     //5: P_SpawnBlood rolls twice for Z offset
  103.     //6: P_SpawnMobj rolls when blood is spawned to pick a random player target
  104.     //7: P_SpawnBlood rolls for animation tic delay
  105.     //enemy is damaged
  106.     //if the enemy dies: 1 extra call for tic delay on death animation, another call if it is 64 units above you & dmg is under 40???? does RNG get called if the checks fail?
  107.     //if the enemy drops a weapon or ammo, the new thing will call RNG to pick a random player target
  108.     //if the enemy dies: P_DamageMobj RETURNS now
  109.     //if the enemy survives:
  110.     //8: P_DamageMobj rolls for pain chance
  111.     let dmgsum=0;
  112.     for(let i=0;i<7;i++){
  113.         dmgsum+=((P_Random()%3)+1)*5
  114.         for(let d=0;d<7;d++){P_Random()}
  115.     }
  116.     rng.seed[49]=temprng
  117.     return dmgsum
  118. }
  119.  
  120. function getSSGRoll(n=rng.seed[49]){
  121.     let temprng=rng.seed[49]
  122.     rng.seed[49]=n
  123.     //rng calls are as follows:
  124.     //1: A_FireShotgun2 rolls for damage
  125.     //3: A_FireShotgun2 rolls twice for horizontal offset
  126.     //5: A_FireShotgun2 rolls twice for vertical offset
  127.     //7: P_SpawnBlood rolls twice for Z offset
  128.     //8: P_SpawnMobj rolls when blood is spawned to pick a random player target
  129.     //9: P_SpawnBlood rolls for animation tic delay
  130.     //enemy is damaged
  131.     //if the enemy dies: 1 extra call for tic delay on death animation, another call if it is 64 units above you & dmg is under 40???? does RNG get called if the checks fail?
  132.     //if the enemy drops a weapon or ammo, the new thing will call RNG to pick a random player target
  133.     //if the enemy dies: P_DamageMobj RETURNS now
  134.     //if the enemy survives:
  135.     //10: P_DamageMobj rolls for pain chance
  136.     let dmgsum=0;
  137.     for(let i=0;i<20;i++){
  138.         dmgsum+=((P_Random()%3)+1)*5
  139.         for(let d=0;d<9;d++){P_Random()}
  140.     }
  141.     rng.seed[49]=temprng
  142.     return dmgsum
  143. }
  144.  
  145. function getBFGRoll(n=rng.seed[49]){
  146.     let temprng=rng.seed[49]
  147.     rng.seed[49]=n
  148.     //rng calls per tracer are as follows:
  149.     //1: P_SpawnMobj rolls for random player target
  150.     //16: 15 rolls(!!!) for damage sum - 1-8 dmg per roll
  151.     //enemy is damaged
  152.     //if the enemy dies: 1 extra call for tic delay on death animation, another call if it is 64 units above you & dmg is under 40???? does RNG get called if the checks fail?
  153.     //if the enemy drops a weapon or ammo, the new thing will call RNG to pick a random player target
  154.     //if the enemy dies: P_DamageMobj RETURNS now
  155.     //if the enemy survives:
  156.     //17: P_DamageMobj rolls for pain chance
  157.     let dmgsum=0;
  158.     for(let i=0;i<40;i++){
  159.         P_Random()
  160.         let tsum=0;
  161.         for(let k=0;k<15;k++){
  162.             tsum+=(P_Random()%8)+1
  163.         }
  164.         dmgsum+=tsum
  165.         P_Random()
  166.     }
  167.     rng.seed[49]=temprng
  168.     return dmgsum
  169. }
  170.  
  171. //get output of P_Random from this rng value
  172. function getRoll(n=rng.seed[49]){
  173.     let temprng = n
  174.     temprng >>= 20
  175.     return temprng&255;
  176. }
  177.  
  178. //make a nice table of all the outcomes from a range of rng values
  179. function predictRollsFromValue(testval=rng.seed[49],n=100,excelprint=false){
  180.     let temprng=rng.seed[49]
  181.     rng.seed[49]=testval
  182.     let rseed=getSeedFromValue(testval)
  183.     if(rseed==-1){rseed=""}
  184.     let outp=[{Index:0,RNG:testval,Result:getRoll(testval),SG:getSGRoll(testval),SSG:getSSGRoll(testval),BFG:getBFGRoll(testval),Seed:rseed}]
  185.     for(let i=1;i<=n;i++){
  186.         P_Random()
  187.         rseed=getSeedFromValue()
  188.         if(rseed==-1){rseed=""}
  189.         outp[i]={
  190.             Index:i,
  191.             RNG:rng.seed[49],
  192.             Result:getRoll(rng.seed[49]),
  193.             SG:getSGRoll(rng.seed[49]),
  194.             SSG:getSSGRoll(rng.seed[49]),
  195.             BFG:getBFGRoll(rng.seed[49]),
  196.             Seed:rseed
  197.         }
  198.     }
  199.     if(excelprint){
  200.         printForExcel(outp)
  201.     }
  202.     rng.seed[49]=temprng
  203.     return outp
  204. }
  205.  
  206. //do the same but from an initial RNG seed
  207. function predictRollsFromSeed(testseed=0,n=100,excelprint=false){
  208.     rngseed=testseed
  209.     M_ClearRandom()
  210.     return predictRollsFromValue(rng.seed[49],n,excelprint)
  211. }
  212.  
  213. //trawl through rng to find some good rolls
  214. //find n rolls >= goal
  215. //note if startrng input is passed, the "index" in the output will be the amt of rolls since startrng, not the index from 0 as used in other functions
  216. //weapon should be "SSG", "SG" or "BFG"
  217. function findHighRolls(goal,weapon,n=100,startrng=0){
  218.     let temprng=rng.seed[49]
  219.     rng.seed[49]=startrng
  220.     let outp=[]
  221.     for(let i=0;i<4294967296;i++){
  222.         if(weapon=="SSG"){
  223.             let roll=getSSGRoll(rng.seed[49])
  224.             if(roll>=goal){
  225.                 outp[outp.length]={
  226.                     Index:i,
  227.                     RNG:rng.seed[49],
  228.                     SSG:roll
  229.                 }
  230.             }
  231.         }
  232.         if(weapon=="SG"){
  233.             let roll=getSGRoll(rng.seed[49])
  234.             if(roll>=goal){
  235.                 outp[outp.length]={
  236.                     Index:i,
  237.                     RNG:rng.seed[49],
  238.                     SG:roll
  239.                 }
  240.             }
  241.         }
  242.         if(weapon=="BFG"){
  243.             let roll=getBFGRoll(rng.seed[49])
  244.             if(roll>=goal){
  245.                 outp[outp.length]={
  246.                     Index:i,
  247.                     RNG:rng.seed[49],
  248.                     BFG:roll
  249.                 }
  250.             }
  251.         }
  252.         if(outp.length>=n){
  253.             rng.seed[49]=temprng
  254.             return outp
  255.         }
  256.         P_Random()
  257.     }
  258.     console.log("couldn't find enough of them!")
  259.     rng.seed[49]=temprng
  260.     return outp
  261. }
  262.  
  263. //---------------------
  264. //an example use case
  265. //---------------------
  266.  
  267. //used for d5da5 19 max
  268.  
  269. for(let initseed = 0;initseed<1000000;initseed++){
  270.     rngseed=initseed
  271.     M_ClearRandom()
  272.     for(let i=0;i<9;i++){
  273.         P_Random()
  274.     }
  275.     totaldmg=getSSGRoll()
  276.     for(let i=0;i<248;i++){
  277.         P_Random()
  278.     }
  279.     totaldmg+=getSSGRoll()
  280.     if(totaldmg>=500){
  281.         console.log(initseed)
  282.     }
  283. }
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement