Skip to content

Commit 7653adb

Browse files
committed
support betting on games
1 parent 4eb4569 commit 7653adb

File tree

4 files changed

+171
-24
lines changed

4 files changed

+171
-24
lines changed

src/main/java/pw/chew/mlb/commands/BettingCommand.java

Lines changed: 130 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
import com.jagrosh.jdautilities.command.SlashCommandEvent;
55
import net.dv8tion.jda.api.EmbedBuilder;
66
import net.dv8tion.jda.api.entities.MessageEmbed;
7+
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
8+
import net.dv8tion.jda.api.interactions.commands.OptionType;
9+
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
710
import net.dv8tion.jda.api.utils.TimeFormat;
811
import org.hibernate.Transaction;
912
import pw.chew.chewbotcca.util.DatabaseHelper;
1013
import pw.chew.mlb.models.Bet;
14+
import pw.chew.mlb.models.BetKind;
1115
import pw.chew.mlb.models.Profile;
16+
import pw.chew.mlb.objects.GameBlurb;
17+
import pw.chew.mlb.objects.GameState;
1218

1319
import java.util.ArrayList;
1420
import java.util.List;
@@ -18,7 +24,8 @@ public BettingCommand() {
1824
this.name = "betting";
1925
this.help = "Bet on a team";
2026
this.children = new SlashCommand[]{
21-
new BettingProfileSubCommand()
27+
new BettingProfileSubCommand(),
28+
new BettingBetSubCommand()
2229
};
2330
}
2431

@@ -40,7 +47,7 @@ protected void execute(SlashCommandEvent event) {
4047
List<Bet> bets = retrieveBets(event.getUser().getIdLong());
4148

4249
// build embed
43-
event.replyEmbeds(buildProfileEmbed(event, profile, bets)).queue();
50+
event.replyEmbeds(buildProfileEmbed(event, profile, bets)).setEphemeral(true).queue();
4451
}
4552

4653
private MessageEmbed buildProfileEmbed(SlashCommandEvent event, Profile profile, List<Bet> bets) {
@@ -58,8 +65,8 @@ private MessageEmbed buildProfileEmbed(SlashCommandEvent event, Profile profile,
5865
Bet bet = bets.get(i);
5966
betString.add("%s | %s%s - %s".formatted(
6067
TimeFormat.DATE_SHORT.format(bet.getCreatedAt()),
61-
bet.getSuccessful() ? "+" : "-",
62-
bet.getAmount(),
68+
bet.amount() > 0 ? "+" : "",
69+
bet.amount(),
6370
bet.getReason()
6471
));
6572
}
@@ -70,6 +77,122 @@ private MessageEmbed buildProfileEmbed(SlashCommandEvent event, Profile profile,
7077
}
7178
}
7279

80+
public static class BettingBetSubCommand extends SlashCommand {
81+
public BettingBetSubCommand() {
82+
this.name = "bet";
83+
this.help = "Bet on a team";
84+
this.options = List.of(
85+
new OptionData(OptionType.INTEGER, "team", "Which team to bet on", true, true),
86+
new OptionData(OptionType.INTEGER, "game", "Which game to bet on", true, true),
87+
new OptionData(OptionType.INTEGER, "amount", "How much to bet. 0 to remove bet.", true, false)
88+
.setMinValue(0)
89+
);
90+
}
91+
92+
@Override
93+
protected void execute(SlashCommandEvent event) {
94+
// options
95+
int teamId = (int) event.optLong("team", 0);
96+
int gamePk = (int) event.optLong("game", 0);
97+
int amount = (int) event.optLong("amount", 0);
98+
99+
// Check the game status
100+
GameState state = GameState.fromPk(String.valueOf(gamePk));
101+
if (state.isFinal()) {
102+
event.reply("This game is already over!").setEphemeral(true).queue();
103+
return;
104+
}
105+
if (state.inning() > 4) {
106+
event.reply("Bets cannot be placed or changed past the 4th inning! To see your bet, run /betting placed").setEphemeral(true).queue();
107+
return;
108+
}
109+
110+
// start session
111+
var session = DatabaseHelper.getSessionFactory().openSession();
112+
113+
// check for a bet, check by user_id, game_pk, and team_id
114+
Bet bet = session.createQuery("from Bet where userId = :userId and gamePk = :gamePk and teamId = :teamId", Bet.class)
115+
.setParameter("userId", event.getUser().getIdLong())
116+
.setParameter("gamePk", gamePk)
117+
.setParameter("teamId", teamId)
118+
.uniqueResult();
119+
120+
// Ensure we have enough credit to bet
121+
Profile user = retrieveProfile(event.getUser().getIdLong());
122+
123+
// Get game blurb
124+
GameBlurb blurb = new GameBlurb(gamePk + "");
125+
126+
// if bet exists, update it
127+
if (bet == null) {
128+
if (amount == 0) {
129+
event.reply("You must bet at least 1 credit!").setEphemeral(true).queue();
130+
return;
131+
}
132+
133+
if (user.getCredits() < amount) {
134+
event.reply("You don't have enough credits to bet that much! You only have " + user.getCredits() + " credits!").setEphemeral(true).queue();
135+
return;
136+
}
137+
138+
String team = blurb.away().id() == teamId ? blurb.away().name() : blurb.home().name();
139+
140+
Bet newBet = new Bet();
141+
newBet.setUserId(event.getUser().getIdLong());
142+
newBet.setGamePk(gamePk);
143+
newBet.setTeamId(teamId);
144+
newBet.setBet(amount);
145+
newBet.setKind(BetKind.PENDING);
146+
newBet.setReason("Bet on " + team + " for " + blurb.name());
147+
148+
user.setCredits(user.getCredits() - amount);
149+
150+
Transaction trans = session.beginTransaction();
151+
session.save(newBet);
152+
session.update(user);
153+
trans.commit();
154+
155+
event.reply("Bet placed!").setEphemeral(true).queue();
156+
} else if (amount == 0) {
157+
int currentBet = bet.getBet();
158+
159+
Transaction trans = session.beginTransaction();
160+
session.delete(bet);
161+
162+
user.setCredits(user.getCredits() + currentBet);
163+
session.update(user);
164+
165+
trans.commit();
166+
167+
event.reply("Bet removed!").setEphemeral(true).queue();
168+
} else {
169+
int currentBet = bet.getBet();
170+
int creditsToDeduct = amount - currentBet;
171+
if (amount > currentBet && creditsToDeduct > user.getCredits()) {
172+
event.reply("You don't have enough credits to bet that much! You only have " + user.getCredits() + " credits!").queue();
173+
return;
174+
}
175+
176+
user.setCredits(user.getCredits() - creditsToDeduct);
177+
bet.setBet(amount);
178+
179+
Transaction trans = session.beginTransaction();
180+
session.update(bet);
181+
session.update(user);
182+
trans.commit();
183+
184+
event.reply("Bet updated!").setEphemeral(true).queue();
185+
}
186+
187+
session.close();
188+
}
189+
190+
@Override
191+
public void onAutoComplete(CommandAutoCompleteInteractionEvent event) {
192+
event.replyChoices(PlanGameCommand.handleAutoComplete(event)).queue();
193+
}
194+
}
195+
73196
public static Profile retrieveProfile(long userId) {
74197
var session = DatabaseHelper.getSessionFactory().openSession();
75198
Profile profile = session.find(Profile.class, userId);
@@ -81,9 +204,9 @@ public static Profile retrieveProfile(long userId) {
81204

82205
// add initial betting credits
83206
Bet bet = new Bet();
84-
bet.setAmount(100);
85-
bet.setAutomated(true);
86-
bet.setSuccessful(true);
207+
bet.setKind(BetKind.AUTOMATED);
208+
bet.setBet(0);
209+
bet.setPayout(100);
87210
bet.setReason("Initial betting credits");
88211
bet.setUserId(userId);
89212
session.save(bet);

src/main/java/pw/chew/mlb/commands/PlanGameCommand.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.ArrayList;
2828
import java.util.Arrays;
2929
import java.util.Calendar;
30+
import java.util.Collections;
3031
import java.util.HashMap;
3132
import java.util.List;
3233
import java.util.Map;
@@ -171,6 +172,16 @@ public void handle(InteractionHook event, String gamePk, GuildChannelUnion chann
171172

172173
@Override
173174
public void onAutoComplete(CommandAutoCompleteInteractionEvent event) {
175+
event.replyChoices(handleAutoComplete(event)).queue();
176+
}
177+
178+
/**
179+
* Handles auto complete for: teams (MLB), sports, and dates (for the team)
180+
*
181+
* @param event the event
182+
* @return a list of choices, maybe empty, maybe 1 choice, maybe 25 choices, who knows.
183+
*/
184+
public static List<Command.Choice> handleAutoComplete(CommandAutoCompleteInteractionEvent event) {
174185
switch (event.getFocusedOption().getName()) {
175186
case "team" -> {
176187
// get current value of sport
@@ -187,20 +198,17 @@ public void onAutoComplete(CommandAutoCompleteInteractionEvent event) {
187198
// Ensure no duplicates and no more than 25 choices
188199
choices = choices.stream().distinct().limit(25).toList();
189200

190-
event.replyChoices(choices).queue();
191-
return;
201+
return choices;
192202
}
193203
case "sport" -> {
194-
event.replyChoices(MLBAPIUtil.getSports().asChoices()).queue();
195-
return;
204+
return MLBAPIUtil.getSports().asChoices();
196205
}
197206
case "date" -> {
198207
int teamId = event.getOption("team", -1, OptionMapping::getAsInt);
199208
String sport = event.getOption("sport", "1", OptionMapping::getAsString);
200209

201210
if (teamId == -1) {
202-
event.replyChoices(new Command.Choice("Please select a team first!", -1)).queue();
203-
return;
211+
return Collections.singletonList(new Command.Choice("Please select a team first!", -1));
204212
}
205213

206214
JSONArray games = new JSONObject(RestClient.get("https://statsapi.mlb.com/api/v1/schedule?lang=en&sportId=%S&season=2023&teamId=%S&fields=dates,date,games,gamePk,teams,away,team,teamName,id&hydrate=team".formatted(sport, teamId)))
@@ -245,13 +253,11 @@ public void onAutoComplete(CommandAutoCompleteInteractionEvent event) {
245253
// Ensure no more than 25 choices, and no duplicates
246254
choices = choices.stream().distinct().limit(25).toList();
247255

248-
event.replyChoices(choices).queue();
249-
250-
return;
256+
return choices;
251257
}
252258
}
253259

254-
event.replyChoices().queue();
260+
return Collections.emptyList();
255261
}
256262

257263
public static List<Button> buildButtons(String gamePk, GameBlurb blurb) {

src/main/java/pw/chew/mlb/models/Bet.kt

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,36 @@ open class Bet {
1414
@Column(name = "user_id", nullable = false)
1515
open var userId: Long? = null
1616

17-
@Column(name = "amount", nullable = false)
18-
open var amount: Int = 0
17+
@Column(name = "bet", nullable = false)
18+
open var bet: Int = 0
1919

20-
@Column(name = "successful", nullable = false)
21-
open var successful: Boolean = false
20+
@Column(name = "payout", nullable = false)
21+
open var payout: Int = 0
2222

23-
@Column(name = "automated", nullable = false)
24-
open var automated: Boolean = false
23+
@Column(name = "game_pk")
24+
open var gamePk: Int? = null
25+
26+
@Column(name = "team_id")
27+
open var teamId: Int? = null
28+
29+
@Enumerated(EnumType.STRING)
30+
@Column(name = "kind", nullable = false)
31+
open var kind: BetKind = BetKind.PENDING
2532

2633
@Column(name = "reason", nullable = false, length = 128)
2734
open var reason: String = ""
2835

2936
@Column(name = "created_at", nullable = false)
3037
open var createdAt: Instant = Instant.now()
38+
39+
fun amount(): Int {
40+
return payout - bet
41+
}
3142
}
43+
44+
enum class BetKind {
45+
AUTOMATED,
46+
PENDING,
47+
WIN,
48+
LOSS
49+
}

src/main/java/pw/chew/mlb/objects/GameState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public OffsetDateTime officialDate() {
6969
}
7070

7171
public int inning() {
72-
return lineScore().getInt("currentInning");
72+
return lineScore().optInt("currentInning", 0);
7373
}
7474

7575
public String inningOrdinal() {

0 commit comments

Comments
 (0)