From ba7d2094ee19735d621bf089c52cabf4faed8d2c Mon Sep 17 00:00:00 2001 From: Jarv <6jarv91@gmail.com> Date: Fri, 29 Mar 2024 02:26:30 +0100 Subject: [PATCH 1/3] Admin can do as many expensive ops as they like --- cmd/jarvbot/time.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/jarvbot/time.go b/cmd/jarvbot/time.go index 9a2381d..4e32436 100644 --- a/cmd/jarvbot/time.go +++ b/cmd/jarvbot/time.go @@ -27,6 +27,9 @@ func removeRoleAfterDuration(ds *discordgo.Session, guildID string, memberID str var usersOnExpensiveOperationCooldown = make(map[string]struct{}) func userExpensiveOperationOnCooldown(userID string) bool { + if userID == adminID { + return false + } _, inCooldown := usersOnExpensiveOperationCooldown[userID] return inCooldown } From ff2a07bbaceb6577bb33e06a70cb7042da3977d0 Mon Sep 17 00:00:00 2001 From: Jarv <6jarv91@gmail.com> Date: Fri, 29 Mar 2024 02:26:41 +0100 Subject: [PATCH 2/3] Go mod changes --- go.mod | 2 +- go.sum | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 27c663f..4ad605e 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/bwmarrin/discordgo v0.27.1 github.com/enescakir/emoji v1.0.0 github.com/j4rv/genshinartis v0.0.0-20230911183910-b19c3dc323f3 + github.com/j4rv/rollssim v0.0.0-20240329011720-1ac34fe7b422 github.com/jmoiron/sqlx v1.3.5 github.com/mattn/go-sqlite3 v1.14.22 github.com/robfig/cron/v3 v3.0.1 @@ -13,7 +14,6 @@ require ( require ( github.com/gorilla/websocket v1.5.1 // indirect - github.com/j4rv/rollssim v0.0.0-20240328173749-ed06730e3472 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/sys v0.18.0 // indirect diff --git a/go.sum b/go.sum index 18192db..d36a619 100644 --- a/go.sum +++ b/go.sum @@ -9,14 +9,8 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/ github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/j4rv/genshinartis v0.0.0-20230911183910-b19c3dc323f3 h1:bdBq6XxKRQvZWRyunxC/Svo5cTEfJ49S75qBvOUSH9w= github.com/j4rv/genshinartis v0.0.0-20230911183910-b19c3dc323f3/go.mod h1:NXUI4xa2rw8D2BjTBqgT6934wIJXJgn1vG9x/FGXW4E= -github.com/j4rv/rollssim v0.0.0-20240328145921-b2c451d22b1d h1:lAPUtWKh8GSUIlD0W0pvihcuTey9+oThRyYiamTALjU= -github.com/j4rv/rollssim v0.0.0-20240328145921-b2c451d22b1d/go.mod h1:giZ+GfPdq1sGjpWZHM5YSQ7Pfz2/doB9I2uSUXl/ZxU= -github.com/j4rv/rollssim v0.0.0-20240328153522-13b27c74ce9e h1:+0hVvtd5zchRJM0io+PHwbm3cQtTb1kkQPYOKYJZZF0= -github.com/j4rv/rollssim v0.0.0-20240328153522-13b27c74ce9e/go.mod h1:giZ+GfPdq1sGjpWZHM5YSQ7Pfz2/doB9I2uSUXl/ZxU= -github.com/j4rv/rollssim v0.0.0-20240328172521-0660e174d545 h1:HYsFGFpYIRotH/vrUfKdORN0RPSctSCHM2aCuOQRcmg= -github.com/j4rv/rollssim v0.0.0-20240328172521-0660e174d545/go.mod h1:giZ+GfPdq1sGjpWZHM5YSQ7Pfz2/doB9I2uSUXl/ZxU= -github.com/j4rv/rollssim v0.0.0-20240328173749-ed06730e3472 h1:z6LRJfZUXlw5R9koVUlsAb9GoFp2NLC1ihyjfPNacso= -github.com/j4rv/rollssim v0.0.0-20240328173749-ed06730e3472/go.mod h1:giZ+GfPdq1sGjpWZHM5YSQ7Pfz2/doB9I2uSUXl/ZxU= +github.com/j4rv/rollssim v0.0.0-20240329011720-1ac34fe7b422 h1:hB8eYD6EUsqv8KagIC/vVrm1/k9exSi/o+Za2fcvTrM= +github.com/j4rv/rollssim v0.0.0-20240329011720-1ac34fe7b422/go.mod h1:giZ+GfPdq1sGjpWZHM5YSQ7Pfz2/doB9I2uSUXl/ZxU= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= @@ -27,18 +21,12 @@ github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxU github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= From ce7e657a8aade8cfc5f85581e3eeefdc31d6675a Mon Sep 17 00:00:00 2001 From: Jarv <6jarv91@gmail.com> Date: Fri, 29 Mar 2024 02:30:40 +0100 Subject: [PATCH 3/3] Star Rail chances slash command --- cmd/jarvbot/genshin.go | 147 ++++++++++++++++++++++++++++------ cmd/jarvbot/slash_commands.go | 107 ++++++++++++++++++++++--- 2 files changed, 218 insertions(+), 36 deletions(-) diff --git a/cmd/jarvbot/genshin.go b/cmd/jarvbot/genshin.go index e652ac1..0ea6389 100644 --- a/cmd/jarvbot/genshin.go +++ b/cmd/jarvbot/genshin.go @@ -15,7 +15,7 @@ import ( ) const genshinTeamSize = 4 -const genshinChanceIterations = 1000 +const gachaPullChanceIterations = 1000 const averagePullsNote = "**Note:** The average rolls spent on each banner include successful attempts and failed attempts. This includes the best case scenarios of not needing to spend all your pulls to get your desired characters/weapons, and the worst case scenarios of spending all your pulls and not getting your desired characters/weapons." // Command Answers @@ -179,7 +179,7 @@ func answerGenshinChance(ds *discordgo.Session, ic *discordgo.InteractionCreate) cumResult := rollssim.WantedRollsResult{} successCount := 0 - for i := 0; i < genshinChanceIterations; i++ { + for i := 0; i < gachaPullChanceIterations; i++ { charBanner := rollssim.GenshinCharRoller{ MihoyoRoller: rollssim.MihoyoRoller{ CurrSRPity: charPity, @@ -210,43 +210,138 @@ func answerGenshinChance(ds *discordgo.Session, ic *discordgo.InteractionCreate) } func formatGenshinChanceResult(result rollssim.WantedRollsResult, successCount int) string { - formatted := fmt.Sprintf("## Chance of success: %.2f%%\n", - divideToFloat(successCount, genshinChanceIterations)*100, + formatted := fmt.Sprintf("## Chance of Success: %.2f%%\n", + divideToFloat(successCount, gachaPullChanceIterations)*100, ) if result.CharacterBannerRollCount > 0 { formatted += fmt.Sprintf(`### Character banner: - Average rate up 5\*s characters: %.2f - Average standard 5\*s characters: %.2f - Average rate up 4\*s characters: %.2f - Average standard 4\*s: %.2f - Average rolls spent on character banner: %.2f + Average Rate-Up 5\* Characters: %.2f + Average Standard 5\* Characters: %.2f + Average Rate-Up 4\* Characters: %.2f + Average Standard 4\*s: %.2f + Average Wishes spent on Character banner: %.2f `, - divideToFloat(result.CharacterBannerRateUpSRCount, genshinChanceIterations), - divideToFloat(result.CharacterBannerStdSRCount, genshinChanceIterations), - divideToFloat(result.CharacterBannerRateUpRareCount, genshinChanceIterations), - divideToFloat(result.CharacterBannerStdRareCount, genshinChanceIterations), - divideToFloat(result.CharacterBannerRollCount, genshinChanceIterations), + divideToFloat(result.CharacterBannerRateUpSRCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerStdSRCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerRateUpRareCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerStdRareCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerRollCount, gachaPullChanceIterations), ) } if result.WeaponBannerRollCount > 0 { formatted += fmt.Sprintf(`### Weapon banner: - Average chosen rate up weapons: %.2f - Average non-chosen rate up weapons: %.2f - Average standard 5\* weapons: %.2f - Average rate up 4\*s weapons: %.2f - Average standard 4\*s: %.2f - Average rolls spent on weapon banner: %.2f + Average Chosen Rate-Up 5\* Weapons: %.2f + Average Non-Chosen Rate-Up 5\* Weapons: %.2f + Average Standard 5\* Weapons: %.2f + Average Rate-Up 4\* Weapons: %.2f + Average Standard 4\*s: %.2f + Average Wishes spent on Weapon banner: %.2f `, - divideToFloat(result.WeaponBannerChosenRateUpCount, genshinChanceIterations), - divideToFloat(result.WeaponBannerNotChosenRateUpCount, genshinChanceIterations), - divideToFloat(result.WeaponBannerStdSRCount, genshinChanceIterations), - divideToFloat(result.WeaponBannerRateUpRareCount, genshinChanceIterations), - divideToFloat(result.WeaponBannerStdRareCount, genshinChanceIterations), - divideToFloat(result.WeaponBannerRollCount, genshinChanceIterations), + divideToFloat(result.WeaponBannerChosenRateUpCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerNotChosenRateUpCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerStdSRCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerRateUpRareCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerStdRareCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerRollCount, gachaPullChanceIterations), + ) + } + + formatted += averagePullsNote + + return formatted +} + +func answerStarRailChance(ds *discordgo.Session, ic *discordgo.InteractionCreate) { + defer func() { + if r := recover(); r != nil { + notifyIfErr("answerStarRailChance panic", fmt.Errorf("%v", r), ds) + } + }() + options := optionMap(ic.ApplicationCommandData().Options) + rollCount := int(options["roll_count"].IntValue()) + charCount := int(options["char_count"].IntValue()) + weaponCount := int(options["weapon_count"].IntValue()) + charPity := optionIntValueOrZero(options["char_pity"]) + charGuaranteed := optionBoolValueOrFalse(options["guaranteed_sr_char"]) + charRarePity := optionIntValueOrZero(options["char_rare_pity"]) + charRareGuaranteed := optionBoolValueOrFalse(options["guaranteed_rare_char"]) + weaponPity := optionIntValueOrZero(options["weapon_pity"]) + weaponGuaranteed := optionBoolValueOrFalse(options["guaranteed_sr_weapon"]) + weaponRarePity := optionIntValueOrZero(options["weapon_rare_pity"]) + weaponRareGuaranteed := optionBoolValueOrFalse(options["guaranteed_rare_weapon"]) + + cumResult := rollssim.WantedRollsResult{} + successCount := 0 + + for i := 0; i < gachaPullChanceIterations; i++ { + charBanner := rollssim.StarRailCharRoller{ + MihoyoRoller: rollssim.MihoyoRoller{ + CurrSRPity: charPity, + GuaranteedRateUpSR: charGuaranteed, + CurrRarePity: charRarePity, + GuaranteedRateUpRare: charRareGuaranteed, + }, + } + weaponBanner := rollssim.StarRailLCRoller{ + MihoyoRoller: rollssim.MihoyoRoller{ + CurrSRPity: weaponPity, + GuaranteedRateUpSR: weaponGuaranteed, + CurrRarePity: weaponRarePity, + GuaranteedRateUpRare: weaponRareGuaranteed, + }, + } + result := rollssim.CalcStarRailWantedRolls(rollCount, charCount, weaponCount, &charBanner, &weaponBanner) + cumResult.Add(result) + + if result.CharacterBannerRateUpSRCount >= charCount && result.WeaponBannerRateUpSRCount >= weaponCount { + successCount++ + } + } + + _, err := textRespond(ds, ic, formatStarRailChanceResult(cumResult, successCount)) + notifyIfErr("answerStarRailChance", err, ds) +} + +func formatStarRailChanceResult(result rollssim.WantedRollsResult, successCount int) string { + formatted := fmt.Sprintf("## Chance of Success: %.2f%%\n", + divideToFloat(successCount, gachaPullChanceIterations)*100, + ) + + if result.CharacterBannerRollCount > 0 { + formatted += fmt.Sprintf(`### Character banner: + Average Rate-Up 5\* Characters: %.2f + Average Standard 5\* Characters: %.2f + Average Rate-Up 4\* Characters: %.2f + Average Standard 4\*s: %.2f + Average Warps spent on Character banner: %.2f + +`, + divideToFloat(result.CharacterBannerRateUpSRCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerStdSRCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerRateUpRareCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerStdRareCount, gachaPullChanceIterations), + divideToFloat(result.CharacterBannerRollCount, gachaPullChanceIterations), + ) + } + + if result.WeaponBannerRollCount > 0 { + formatted += fmt.Sprintf(`### Light Cone banner: + Average Rate-Up 5\* Light Cones: %.2f + Average Standard 5\* Light Cones: %.2f + Average Rate-Up 4\* Light Cones: %.2f + Average Standard 4\*s: %.2f + Average Warps spent on Light Cone banner: %.2f + +`, + divideToFloat(result.WeaponBannerRateUpSRCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerStdSRCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerRateUpRareCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerStdRareCount, gachaPullChanceIterations), + divideToFloat(result.WeaponBannerRollCount, gachaPullChanceIterations), ) } diff --git a/cmd/jarvbot/slash_commands.go b/cmd/jarvbot/slash_commands.go index f603617..7dc8852 100644 --- a/cmd/jarvbot/slash_commands.go +++ b/cmd/jarvbot/slash_commands.go @@ -46,7 +46,7 @@ var slashCommands = []*discordgo.ApplicationCommand{ { Type: discordgo.ApplicationCommandOptionInteger, Name: "roll_count", - Description: "The amount of rolls you have.", + Description: "The amount of wishes you have.", Required: true, MinValue: &zero, MaxValue: 1500, @@ -125,6 +125,92 @@ var slashCommands = []*discordgo.ApplicationCommand{ }, }, }, + { + Name: "star_rail_chances", + Description: "Your chance to get a Honkai: Star Rail character with specific constellations and refinements", + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "roll_count", + Description: "The amount of warps you have.", + Required: true, + MinValue: &zero, + MaxValue: 1400, + }, + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "char_count", + Description: "The amount of characters you want to pull. 0 for none, 1 for E0, 7 for E6.", + Required: true, + MinValue: &zero, + MaxValue: 7, + }, + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "weapon_count", + Description: "The amount of light cones you want to pull. 0 for none, 1 for S1, 5 for S5.", + Required: true, + MinValue: &zero, + MaxValue: 5, + }, + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "char_pity", + Description: "Your limited character banner 5* pity count.", + Required: false, + MinValue: &zero, + MaxValue: 89, + }, + { + Type: discordgo.ApplicationCommandOptionBoolean, + Name: "guaranteed_sr_char", + Description: "If the next 5* character is guaranteed to be the rate up.", + Required: false, + }, + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "char_rare_pity", + Description: "Your limited character banner 4* pity count.", + Required: false, + MinValue: &zero, + MaxValue: 9, + }, + { + Type: discordgo.ApplicationCommandOptionBoolean, + Name: "guaranteed_rare_char", + Description: "If the next 4* character is guaranteed to be a rate up.", + Required: false, + }, + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "weapon_pity", + Description: "Your limited light cone banner 5* pity count.", + Required: false, + MinValue: &zero, + MaxValue: 89, + }, + { + Type: discordgo.ApplicationCommandOptionBoolean, + Name: "guaranteed_sr_weapon", + Description: "If the next 5* light cone is guaranteed to be the rate up.", + Required: false, + }, + { + Type: discordgo.ApplicationCommandOptionInteger, + Name: "weapon_rare_pity", + Description: "Your limited light cone banner 4* pity count.", + Required: false, + MinValue: &zero, + MaxValue: 9, + }, + { + Type: discordgo.ApplicationCommandOptionBoolean, + Name: "guaranteed_rare_weapon", + Description: "If the next 4* light cone is guaranteed to be a rate up.", + Required: false, + }, + }, + }, { Name: "strongbox", Description: "Do Strongbox rolls of your set of choice", @@ -205,15 +291,16 @@ var slashCommands = []*discordgo.ApplicationCommand{ } var slashHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ - "help": answerHelp, - "8ball": answer8ball, - "avatar": answerAvatar, - "genshin_chances": expensiveSlashCommand(answerGenshinChance), - "strongbox": expensiveSlashCommand(answerStrongbox), - "character": answerCharacter, - "abyss_challenge": answerAbyssChallenge, - "warn": answerWarn, - "warnings": answerWarnings, + "help": answerHelp, + "8ball": answer8ball, + "avatar": answerAvatar, + "genshin_chances": expensiveSlashCommand(answerGenshinChance), + "star_rail_chances": expensiveSlashCommand(answerStarRailChance), + "strongbox": expensiveSlashCommand(answerStrongbox), + "character": answerCharacter, + "abyss_challenge": answerAbyssChallenge, + "warn": answerWarn, + "warnings": answerWarnings, } func expensiveSlashCommand(expensiveOp func(ds *discordgo.Session, ic *discordgo.InteractionCreate)) func(ds *discordgo.Session, ic *discordgo.InteractionCreate) {