|
1 | 1 | package posting |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "errors" |
4 | 5 | "fmt" |
5 | 6 | "html/template" |
6 | 7 | "math/rand" |
|
18 | 19 | msgfmtr MessageFormatter |
19 | 20 | urlRE = regexp.MustCompile(`https?://(\S+)`) |
20 | 21 | unsetBBcodeTags = []string{"center", "color", "img", "quote", "size"} |
21 | | - diceRoller = regexp.MustCompile(`(?i)(\S*)\[(\d*)d(\d+)(?:([+-])(\d+))?\](\S*)`) |
| 22 | + diceRollRE = regexp.MustCompile(`\[(\d*)d(\d+)(?:([+-])(\d+))?\]`) |
22 | 23 | ) |
23 | 24 |
|
24 | 25 | // InitPosting prepares the formatter and the temp post pruner |
@@ -134,50 +135,42 @@ func FormatMessage(message string, boardDir string) (template.HTML, error) { |
134 | 135 | return template.HTML(strings.Join(postLines, "<br />")), nil // skipcq: GSC-G203 |
135 | 136 | } |
136 | 137 |
|
137 | | -func ApplyDiceRoll(p *gcsql.Post) (rollSum int, err error) { |
138 | | - words := strings.Split(string(p.Message), " ") |
139 | | - for w, word := range words { |
140 | | - roll := diceRoller.FindStringSubmatch(word) |
141 | | - if len(roll) == 0 { |
142 | | - continue |
143 | | - } |
| 138 | +func diceRoller(numDice int, diceSides int, modifier int) int { |
| 139 | + rollSum := 0 |
| 140 | + for i := 0; i < numDice; i++ { |
| 141 | + rollSum += rand.Intn(diceSides) + 1 // skipcq: GSC-G404 |
| 142 | + } |
| 143 | + return rollSum + modifier |
| 144 | +} |
| 145 | + |
| 146 | +func ApplyDiceRoll(p *gcsql.Post) error { |
| 147 | + var err error |
| 148 | + result := diceRollRE.ReplaceAllStringFunc(string(p.Message), func(roll string) string { |
| 149 | + rollMatch := diceRollRE.FindStringSubmatch(roll) |
144 | 150 | numDice := 1 |
145 | | - if roll[2] != "" { |
146 | | - numDice, err = strconv.Atoi(roll[2]) |
147 | | - if err != nil { |
148 | | - return 0, err |
149 | | - } |
| 151 | + if rollMatch[1] != "" { |
| 152 | + numDice, _ = strconv.Atoi(rollMatch[1]) |
150 | 153 | } |
151 | | - dieSize, err := strconv.Atoi(roll[3]) |
152 | | - if err != nil { |
153 | | - return 0, err |
| 154 | + if numDice < 1 { |
| 155 | + err = errors.New("number of dice must be at least 1") |
| 156 | + return roll |
154 | 157 | } |
155 | | - if numDice < 1 || dieSize < 1 { |
156 | | - return 0, fmt.Errorf("dice roll too small") |
| 158 | + dieSize, _ := strconv.Atoi(rollMatch[2]) |
| 159 | + if dieSize <= 1 { |
| 160 | + err = errors.New("die size must be greater than 1") |
| 161 | + return roll |
157 | 162 | } |
158 | | - for i := 0; i < numDice; i++ { |
159 | | - rollSum += rand.Intn(dieSize) + 1 // skipcq: GSC-G404 |
160 | | - switch roll[4] { |
161 | | - case "+": |
162 | | - mod, err := strconv.Atoi(roll[5]) |
163 | | - if err != nil { |
164 | | - return 0, err |
165 | | - } |
166 | | - rollSum += mod |
167 | | - case "-": |
168 | | - mod, err := strconv.Atoi(roll[5]) |
169 | | - if err != nil { |
170 | | - return 0, err |
171 | | - } |
172 | | - rollSum -= mod |
173 | | - } |
| 163 | + modifierIsNegative := rollMatch[3] == "-" |
| 164 | + modifier, _ := strconv.Atoi(rollMatch[4]) |
| 165 | + if modifierIsNegative { |
| 166 | + modifier = -modifier |
174 | 167 | } |
175 | | - words[w] = fmt.Sprintf(`%s<span class="dice-roll">%dd%d`, roll[1], numDice, dieSize) |
176 | | - if roll[4] != "" { |
177 | | - words[w] += roll[4] + roll[5] |
178 | | - } |
179 | | - words[w] += fmt.Sprintf(" = %d</span>%s", rollSum, roll[6]) |
| 168 | + rollSum := diceRoller(numDice, dieSize, modifier) |
| 169 | + return fmt.Sprintf(`<span class="dice-roll">%dd%d%s%s = %d</span>`, numDice, dieSize, rollMatch[3], rollMatch[4], rollSum) |
| 170 | + }) |
| 171 | + if err != nil { |
| 172 | + return err |
180 | 173 | } |
181 | | - p.Message = template.HTML(strings.Join(words, " ")) // skipcq: GSC-G203 |
182 | | - return |
| 174 | + p.Message = template.HTML(result) // skipcq: GSC-G203 |
| 175 | + return nil |
183 | 176 | } |
0 commit comments