From cb221e6bb2d346e8a634d629a42b5f0b13639ffc Mon Sep 17 00:00:00 2001 From: Ocame Date: Thu, 17 Jul 2025 23:02:05 +0200 Subject: [PATCH] roll Implemntation --- .../Simpleroll/SimplerollCommand.java | 101 +++++++++++++++ .../Simpleroll/SimplerollLogic.java | 119 ++++++++++++++++++ .../wuerfelbot/commands/CommandManager.java | 4 + .../output/DiceOutputFormatter.java | 2 + 4 files changed, 226 insertions(+) create mode 100644 src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollCommand.java create mode 100644 src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollLogic.java diff --git a/src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollCommand.java b/src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollCommand.java new file mode 100644 index 0000000..ea1e142 --- /dev/null +++ b/src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollCommand.java @@ -0,0 +1,101 @@ +package de.ocame.wuerfelbot.Simpleroll; + + +import de.ocame.wuerfelbot.commands.ICommand; +import de.ocame.wuerfelbot.output.DiceOutputFormatter; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; + +import java.util.Arrays; +import java.util.List; + +public class SimplerollCommand implements ICommand { + + + private final SimplerollLogic rollLogic; + private final DiceOutputFormatter outputFormatter; + + public SimplerollCommand() { + this.rollLogic = new SimplerollLogic(); + this.outputFormatter = new DiceOutputFormatter(); + } + + @Override + public String getName() { + // Der primäre Name für den Text-Befehl + return "roll"; + } + + @Override + public String getDescription() { + return "Würfelt Würfel nach verschiedenen Notationen (z.B. 9, 9d4, 3w8, 9 +4)."; + } + + // --- Slash Command Handling (Wird leer gelassen oder eine Fehlermeldung gesendet) --- + @Override + public void executeSlash(SlashCommandInteractionEvent event) { + // Dieser Befehl ist nicht für Slash-Commands vorgesehen. + event.reply(outputFormatter.formatError("Dieser Befehl ist nur als Text-Befehl (!roll oder !r) verfügbar.")).setEphemeral(true).queue(); + } + + // --- Text Command Handling (Bestehend, mit Erweiterungen) --- + @Override + public void executeText(MessageReceivedEvent event, String[] args) { + if (args.length == 0) { + event.getChannel().sendMessage(outputFormatter.formatError("Verwendung: `!roll [+]` oder `!r [+]`")).queue(); + return; + } + + String notation = args[0]; + int modifier = 0; + + // Versuche, einen optionalen Modifikator zu parsen, wenn mehr Argumente vorhanden sind + if (args.length > 1) { + // Kombiniere die restlichen Argumente zu einem String und versuche zu parsen + String modifierPart = String.join("", Arrays.copyOfRange(args, 1, args.length)); + try { + if (modifierPart.startsWith("+") || modifierPart.startsWith("-")) { + modifier = Integer.parseInt(modifierPart); // Parser handhabt +/- + } else { + // Wenn es keine + oder - gibt, aber weitere Argumente, behandle es als Fehler + event.getChannel().sendMessage(outputFormatter.formatError("Ungültiger Modifikator-Format. Verwende `+4` oder `-2`.")).queue(); + return; + } + } catch (NumberFormatException e) { + event.getChannel().sendMessage(outputFormatter.formatError("Ungültiger Modifikator: '" + modifierPart + "'. Bitte gib eine Zahl ein.")).queue(); + return; + } + } + + try { + SimplerollLogic.RollResult result = rollLogic.performRoll(notation, modifier); + // EmbedBuilder response = outputFormatter.DCDefaultOutput(getEffectiveName(event) + result.getTitle(), result.getDescription(), result.isGlitch()); + EmbedBuilder response = outputFormatter.DCDefaultOutput(getEffectiveName(event) + result.getTitle(), result.getDescription(), false); + event.getChannel().sendMessageEmbeds(response.build()).queue(); + } catch (IllegalArgumentException e) { + event.getChannel().sendMessage(outputFormatter.formatError(e.getMessage())).queue(); + } catch (Exception e) { + System.err.println("Fehler beim Ausführen von Text-Befehl roll/r: " + e.getMessage()); + e.printStackTrace(); + event.getChannel().sendMessage(outputFormatter.formatError("Ein unerwarteter Fehler ist beim Würfeln aufgetreten.")).queue(); + } + } + + @Override + public CommandData getSlashCommandData() { + return null; + } + + + private String getEffectiveName(MessageReceivedEvent event) { + if (event.getMember() == null) { + return ""; + } + return event.getMember().getEffectiveName() + " "; + } +} \ No newline at end of file diff --git a/src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollLogic.java b/src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollLogic.java new file mode 100644 index 0000000..147f0df --- /dev/null +++ b/src/main/java/de/ocame/wuerfelbot/Simpleroll/SimplerollLogic.java @@ -0,0 +1,119 @@ +package de.ocame.wuerfelbot.Simpleroll; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class SimplerollLogic { + + // Eine einzige Instanz von Random für alle Würfeloperationen + private final Random random; + + // Pattern für Notationen wie "9d4" oder "3w8" + private static final Pattern DICE_NOTATION_PATTERN = Pattern.compile("(\\d+)[dw](\\d+)"); + + public SimplerollLogic() { + this.random = new Random(); + } + + /** + * Führt einen Würfelwurf basierend auf der Notation und einem optionalen Modifikator durch. + * + * @param notation Die Würfelnotation (z.B. "9", "9d4", "3w8"). + * @param modifier Ein optionaler Integer-Modifikator, der zur Gesamtsum addiert wird. + * @return Ein {@link RollResult}-Objekt mit den detaillierten Ergebnissen. + * @throws IllegalArgumentException Wenn die Notation ungültig ist oder andere Parameterfehler auftreten. + */ + public RollResult performRoll(String notation, int modifier) { + if (notation == null || notation.trim().isEmpty()) { + throw new IllegalArgumentException("Würfelnotation darf nicht leer sein."); + } + + int numberOfDice; + int sides; + String parsedNotation = notation.trim().toLowerCase(); // Normalize input + + Matcher matcher = DICE_NOTATION_PATTERN.matcher(parsedNotation); + + if (matcher.matches()) { + // Format: XdY oder XwY (z.B. "9d4", "3w8") + numberOfDice = Integer.parseInt(matcher.group(1)); + sides = Integer.parseInt(matcher.group(2)); + } else { + // Format: X (z.B. "9") -> Würfelt X W6 + try { + numberOfDice = Integer.parseInt(parsedNotation); + sides = 6; // Standard: W6, wenn nur Anzahl angegeben + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Ungültige Würfelnotation: '" + notation + "'. Erwartet wird Zahl (z.B. 9) oder NdS (z.B. 9d4)."); + } + } + + if (numberOfDice < 1 || numberOfDice > 1000) { // Angemessene Grenzen festlegen + throw new IllegalArgumentException("Anzahl der Würfel muss zwischen 1 und 1000 liegen."); + } + if (sides < 2 || sides > 1000) { // Angemessene Grenzen festlegen (mind. 2 Seiten, max 1000) + throw new IllegalArgumentException("Würfel müssen mindestens 2 und höchstens 1000 Seiten haben."); + } + + List rolls = new ArrayList<>(numberOfDice); + int sum = 0; + + for (int i = 0; i < numberOfDice; i++) { + int roll = random.nextInt(sides) + 1; // Würfelt 1 bis 'sides' + rolls.add(roll); + sum += roll; + } + + // Addiere den Modifikator zur Summe + sum += modifier; + + return new RollResult(rolls, sum, notation + "w" + sides, modifier); + } + + /** + * Innere Klasse zum Kapseln der Würfelergebnisse. + */ + public static class RollResult { + private final List rolls; + private final int sum; + private final String notation; + private final int modifier; + + public RollResult(List rolls, int sum, String notation, int modifier) { + this.rolls = rolls; + this.sum = sum; + this.notation = notation; + this.modifier = modifier; + } + + public List getRolls() { + return rolls; + } + + public int getSum() { + return sum; + } + + public String getNotation() { + return notation; + } + + public int getModifier() { + return modifier; + } + + public String getDescription() { + return "(" + rolls.stream().map(String::valueOf) + .collect(Collectors.joining(", ")) + ")"; + } + + public String getTitle() { + String message = "%rolls%: %hits%"; + return message.replace("%rolls%", rolls.size() + (modifier!=0 ? (modifier<0?"-":"+") + modifier : "")).replace("%hits%", Integer.toString(sum)); + } + } +} \ No newline at end of file diff --git a/src/main/java/de/ocame/wuerfelbot/commands/CommandManager.java b/src/main/java/de/ocame/wuerfelbot/commands/CommandManager.java index 915e362..c00c1f0 100644 --- a/src/main/java/de/ocame/wuerfelbot/commands/CommandManager.java +++ b/src/main/java/de/ocame/wuerfelbot/commands/CommandManager.java @@ -2,6 +2,7 @@ package de.ocame.wuerfelbot.commands; import de.ocame.wuerfelbot.Earthdawn.EarthdawnCommand; +import de.ocame.wuerfelbot.Simpleroll.SimplerollCommand; import de.ocame.wuerfelbot.core.LoggerUtil; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; @@ -33,6 +34,9 @@ public class CommandManager { // Füge deine Befehlsimplementierungen hier hinzu //addCommand(new SimpleRollCommand()); addCommand(new EarthdawnCommand()); + SimplerollCommand simplerollCmd = new SimplerollCommand(); + addCommand(simplerollCmd); // Registriert unter "roll" + commands.put("r", simplerollCmd); // Alias für SimpleRollCommand // Hier können wir auch die Slash-Befehle bei Discord registrieren updateSlashCommands(); diff --git a/src/main/java/de/ocame/wuerfelbot/output/DiceOutputFormatter.java b/src/main/java/de/ocame/wuerfelbot/output/DiceOutputFormatter.java index 9afa106..91c6b02 100644 --- a/src/main/java/de/ocame/wuerfelbot/output/DiceOutputFormatter.java +++ b/src/main/java/de/ocame/wuerfelbot/output/DiceOutputFormatter.java @@ -34,6 +34,8 @@ public class DiceOutputFormatter { /** * Formatiert ein allgemeines Würfelergebnis. + * nur für tests + * * @param result Das Ergebnis des Würfels. * @param notation Die Würfelnotation (z.B. "1d6"). * @return Der formatierte String.