@@ -18,6 +18,7 @@ const gachas: Record<string, Banner> = {
1818 bannerName : "5* Banner character" ,
1919 banner : 0.5 ,
2020 guaranteed : 1 ,
21+ minConst : - 1 ,
2122 maxConst : 6 ,
2223 constFormat : "C" ,
2324 constName : "Constellations" ,
@@ -28,6 +29,7 @@ const gachas: Record<string, Banner> = {
2829 bannerName : "Specific 4* banner character" ,
2930 banner : 0.5 ,
3031 guaranteed : 1 / 3 ,
32+ minConst : - 1 ,
3133 maxConst : 6 ,
3234 constFormat : "C" ,
3335 constName : "Constellations" ,
@@ -39,6 +41,7 @@ const gachas: Record<string, Banner> = {
3941 banner : 0.75 ,
4042 guaranteed : 1 / 2 ,
4143 guaranteedPity : 3 ,
44+ minConst : 0 ,
4245 maxConst : 5 ,
4346 constFormat : "R" ,
4447 constName : "Refinements" ,
@@ -52,6 +55,7 @@ type Banner = {
5255 banner : number
5356 guaranteed : number
5457 guaranteedPity ?: number
58+ minConst : number
5559 maxConst : number
5660 maxPity : number
5761 constFormat : string
@@ -90,7 +94,7 @@ Example with 70 pulls, 10 pity and guaranteed for 5 star weapon banner: \`${conf
9094 options : [ {
9195 name : "pulls" ,
9296 description : "Amount of pulls to simulate" ,
93- type : "NUMBER " ,
97+ type : "INTEGER " ,
9498 required : true
9599 } , {
96100 name : "gacha" ,
@@ -110,13 +114,23 @@ Example with 70 pulls, 10 pity and guaranteed for 5 star weapon banner: \`${conf
110114 } , {
111115 name : "pity" ,
112116 description : "Amount of pity to start at" ,
113- type : "NUMBER " ,
117+ type : "INTEGER " ,
114118 required : false
115119 } , {
116120 name : "guaranteed" ,
117121 description : "Start with guaranteed rate up" ,
118122 type : "BOOLEAN" ,
119123 required : false
124+ } , {
125+ name : "current" ,
126+ description : "Current amount of copies to start with (default: none)" ,
127+ type : "INTEGER" ,
128+ required : false
129+ } , {
130+ name : "guaranteed_pity" ,
131+ description : "Amount of Epitomized Path to start with (for Weapon banner)" ,
132+ type : "INTEGER" ,
133+ required : false
120134 } ]
121135 } )
122136 }
@@ -125,11 +139,13 @@ Example with 70 pulls, 10 pity and guaranteed for 5 star weapon banner: \`${conf
125139 const { options } = source
126140
127141 const gacha = options . getString ( "gacha" ) ?? "char"
128- const pulls = options . getNumber ( "pulls" , true )
129- const pity = options . getNumber ( "pity" ) ?? 0
142+ const pulls = options . getInteger ( "pulls" , true )
143+ const pity = options . getInteger ( "pity" ) ?? 0
144+ const current = options . getInteger ( "current" ) ?? 0
145+ const guaranteedPity = options . getInteger ( "guaranteedPity" ) ?? 0
130146 const guaranteed = options . getBoolean ( "guaranteed" ) ?? false
131147
132- return this . run ( source , gacha , pulls , pity , guaranteed )
148+ return this . run ( source , gacha , current , pulls , pity , guaranteed , guaranteedPity )
133149 }
134150
135151 async runMessage ( source : Message , args : string [ ] ) : Promise < SendMessage | undefined > {
@@ -141,6 +157,8 @@ Example with 70 pulls, 10 pity and guaranteed for 5 star weapon banner: \`${conf
141157
142158 const pulls = parseInt ( args [ 0 ] ?? "75" )
143159 const pity = parseInt ( args [ 1 ] ?? "0" )
160+ const current = parseInt ( args [ 2 ] ?? "-1" )
161+ const guaranteedPity = parseInt ( args [ 1 ] ?? "0" )
144162
145163 let guaranteed = false
146164 if ( args [ 2 ] ?. match ( / y ( e s ) ? | t ( r u e ) ? | g ( u a r a n t e e d ) ? / ) )
@@ -149,19 +167,25 @@ Example with 70 pulls, 10 pity and guaranteed for 5 star weapon banner: \`${conf
149167 guaranteed = false
150168 else if ( args [ 2 ] )
151169 return sendMessage ( source , "Invalid 50/50, should be y(es)/g(uaranteed) or n(o)/50/50" )
152- return this . run ( source , gacha , pulls , pity , guaranteed )
170+ return this . run ( source , gacha , current , pulls , pity , guaranteed , guaranteedPity )
153171 }
154172
155- async run ( source : CommandSource , gacha : string , pulls : number , pity : number , guaranteed : boolean ) : Promise < SendMessage | undefined > {
173+ async run ( source : CommandSource , gacha : string , current : number , pulls : number , pity : number , guaranteed : boolean , guaranteedPity : number ) : Promise < SendMessage | undefined > {
156174 const banner = gachas [ gacha ]
157175
158176 if ( isNaN ( pulls ) || pulls <= 0 || pulls > 9999 )
159177 return sendMessage ( source , "Invalid pulls amount, should be a number greater than 1" )
160178 if ( isNaN ( pity ) || pity < 0 || pity > banner . maxPity )
161179 return sendMessage ( source , `Invalid pity amount, should be a number between 0 and ${ banner . maxPity } ` )
180+ if ( isNaN ( current ) || current > banner . maxConst )
181+ return sendMessage ( source , `Invalid currently owned, should be a number between -1 (not owned) and ${ banner . maxConst } ` )
182+ if ( isNaN ( guaranteedPity ) || guaranteedPity < 0 || guaranteedPity > ( banner . guaranteedPity ?? 0 ) )
183+ return sendMessage ( source , `Invalid guaranteed pity/Epitomized Path, should be a number between 0 and ${ banner . guaranteedPity ?? 0 } ` )
184+
185+ if ( current < banner . minConst ) current = banner . minConst
162186
163187 const start = Date . now ( )
164- const sims = this . calcSims ( pity , pulls , guaranteed , gacha )
188+ const sims = this . calcSims ( current , pity , pulls , guaranteed , guaranteedPity , banner )
165189 const time = Date . now ( ) - start
166190 Logger . info ( `Calculation done in ${ time } ms` )
167191
@@ -171,16 +195,14 @@ ${createTable(
171195 [ banner . constName , "Rate" ] ,
172196 sims
173197 . sort ( ( a , b ) => a . const - b . const )
174- . map ( k => [ k . const < 0 ? "/" : `${ banner . constFormat } ${ k . const } ` , `${ ( k . rate * 100 ) . toFixed ( 2 ) } %` ] )
198+ . map ( k => [ k . const == banner . minConst ? "/" : `${ banner . constFormat } ${ k . const } ` , `${ ( k . rate * 100 ) . toFixed ( 2 ) } %` ] )
175199 ) }
176200\`\`\`` )
177201 }
178202
179203 calcSims = memoize ( this . calcSimsRegular , { max : 50 } )
180204
181- private calcSimsRegular ( pity : number , pulls : number , guaranteed : boolean , bannerName : string ) : ReducedSim [ ] {
182- const banner = gachas [ bannerName ]
183-
205+ private calcSimsRegular ( current : number , pity : number , pulls : number , guaranteed : boolean , guaranteedPity : number , banner : Banner ) : ReducedSim [ ] {
184206 // Max pity / const
185207 if ( banner . guaranteed >= 1 && pulls + pity >= banner . maxPity * ( banner . maxConst * 2 - ( guaranteed ? 1 : 0 ) ) )
186208 return [ {
@@ -197,12 +219,13 @@ ${createTable(
197219 return this . calcSimsInt ( {
198220 pity,
199221 guaranteed,
200- guaranteedPity : 0 ,
201- const : - 1 ,
222+ guaranteedPity,
223+ const : current ,
202224 rate : 1
203225 } , pulls , banner )
204226 }
205227
228+
206229 private calcSimsInt ( starterSim : Sim , pulls : number , banner : Banner ) : ReducedSim [ ] {
207230 const sims : Sim [ ] = this . calcSimsExact ( [ starterSim ] , pulls , banner )
208231
@@ -232,7 +255,7 @@ ${createTable(
232255 const addOrMerge = ( sim : Sim ) => {
233256 if ( sim . rate <= 0 ) return
234257
235- const v = ( ( + sim . guaranteed ) * ( banner . maxConst + 2 ) + ( sim . const + 1 ) ) * ( banner . maxPity + 5 ) + sim . pity
258+ const v = ( ( ( sim . const + 1 ) * ( banner . maxPity + 5 ) + sim . pity ) * 2 + ( + sim . guaranteed ) ) * ( banner . guaranteedPity ?? 1 ) + sim . guaranteedPity
236259 const other = newSims [ v ]
237260
238261 if ( other ) {
@@ -254,7 +277,10 @@ ${createTable(
254277 let rate = banner . rate ( currentPity ) / 100
255278 if ( rate > 1 ) rate = 1
256279 else if ( rate < 0 ) rate = 0
257- const bannerRate = sim . guaranteed ? 1 : banner . banner
280+ const bannerRate = (
281+ sim . guaranteed ||
282+ ( banner . guaranteedPity && sim . guaranteedPity >= banner . guaranteedPity - 1 )
283+ ) ? 1 : banner . banner
258284
259285 // Failed
260286 if ( rate < 1 )
@@ -277,22 +303,22 @@ ${createTable(
277303
278304 // Got banner item but not wanted (eg. wrong rate up 4* char/5* char)
279305 if ( banner . guaranteed < 1 )
280- if ( banner . guaranteedPity && sim . guaranteedPity >= banner . guaranteedPity )
281- // https://www.hoyolab.com/article/533196
306+ if ( banner . guaranteedPity && sim . guaranteedPity >= banner . guaranteedPity - 1 )
307+ // https://www.hoyolab.com/article/533196
282308 addOrMerge ( {
283309 pity : 0 ,
284310 guaranteed : false ,
285311 guaranteedPity : 0 ,
286312 const : sim . const + 1 ,
287- rate : sim . rate * rate * bannerRate * ( 1 - banner . guaranteed )
313+ rate : sim . rate * rate * bannerRate * ( 1 - banner . guaranteed )
288314 } )
289315 else
290316 addOrMerge ( {
291317 pity : 0 ,
292318 guaranteed : false ,
293319 guaranteedPity : sim . guaranteedPity + 1 ,
294320 const : sim . const ,
295- rate : sim . rate * rate * bannerRate * ( 1 - banner . guaranteed )
321+ rate : sim . rate * rate * bannerRate * ( 1 - banner . guaranteed )
296322 } )
297323
298324 // Failed banner items (eg. 4* char rate ups vs regular 4*)
0 commit comments