Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Dicelib code into MapTool Repo #4000

Merged
merged 71 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
9d6c66c
added -SNAPSHOT qualifier
cwisniew May 3, 2015
22d0715
1.4.0 Source import
cwisniew Sep 17, 2015
95d00c7
Added rolls with bounds
cwisniew Feb 25, 2018
9937ae2
Added DragonQuest roll
cwisniew Feb 25, 2018
ddf8cb9
Gradle and gradle build updates
cwisniew Mar 30, 2019
52b8207
Add drop highest and keep lowest roll types
cwisniew Mar 30, 2019
acf1032
Fix build and add keep lowest/drop highest dice rolls
cwisniew Mar 30, 2019
a300644
Spotless reformat
cwisniew Mar 30, 2019
8a9d192
Addded roll functions to parser
cwisniew Mar 30, 2019
6673b7e
fix dice spec for dragon quest / drop highest
cwisniew Mar 30, 2019
a0cadd6
add debugging
cwisniew Mar 30, 2019
c4647a1
add debugging
cwisniew Mar 30, 2019
ceb7a64
add debugging
cwisniew Mar 30, 2019
50d044e
add debugging
cwisniew Mar 30, 2019
e65762d
add debugging
cwisniew Mar 30, 2019
ec20a00
Merge pull request #2 from cwisniew/new-roll-support
cwisniew Apr 7, 2019
73532f0
new rolls and support for listing rolled dice
cwisniew Apr 7, 2019
2907cd4
Merge pull request #3 from cwisniew/new-roll-support
cwisniew Apr 7, 2019
79472ee
changed location that rolls are recorded
cwisniew Apr 7, 2019
aaf379b
Merge pull request #4 from cwisniew/develop
cwisniew Apr 7, 2019
82e2d72
Develop (#9)
cwisniew Sep 30, 2019
0d88815
Adding new dice expressions for RerollDiceOnce - either keeping the n…
selquest Apr 22, 2020
d490113
Cleaning up extraneous unused import.
selquest Apr 23, 2020
a936d12
Providing a new RunData extension that mocks the random number genera…
selquest Apr 23, 2020
2ad1dc9
Merge pull request #29 from selquest/develop2
cwisniew Apr 25, 2020
b721cd0
Add tests for the RerollOnce expressions using the new RunDataMockFor…
selquest Apr 25, 2020
40d9cc1
Apply formatting rules from spotless
selquest Apr 25, 2020
c7cd1a3
Merge pull request #30 from selquest/develop
Phergus Apr 25, 2020
4cbf3bb
Ars Magica Stress Die Roll
cwisniew Apr 26, 2020
8a7fda3
Merge from develop
cwisniew Apr 26, 2020
b60ae1e
Merge pull request #31 from cwisniew/feature-ars-magica-stress
cwisniew Apr 26, 2020
b58383f
Merge pull request #32 from RPTools/develop
cwisniew Apr 26, 2020
695bc4b
Validate input to keep() and keepLowest() to avoid ArrayIndexOutOfBou…
selquest May 6, 2020
f37c8ab
Merge pull request #34 from selquest/develop
Phergus May 6, 2020
7fc1d92
Merge pull request #36 from RPTools/develop
Phergus May 8, 2020
8b09a8a
Fix RunData tracking of roll history, while maintaining option for pr…
selquest May 18, 2020
ffea3c9
Merge pull request #40 from selquest/develop
Phergus May 21, 2020
548cbc0
Merge pull request #42 from RPTools/develop
Phergus May 25, 2020
770ef12
add optional parameter whether to evaluate deterministically or not -…
nmeier May 31, 2020
59822d5
Merge pull request #44 from nmeier/develop
Phergus May 31, 2020
48673b5
Merge pull request #47 from RPTools/develop
Phergus Jun 3, 2020
a621272
Fix issues where incorrectly cased function name being executed as wr…
selquest Jun 22, 2020
b59be60
Merge pull request #52 from selquest/develop
Phergus Jun 22, 2020
6a00b54
Fix functions returning 0d0 rolls when invoked with improper case - n…
selquest Jun 27, 2020
b299696
Merge pull request #53 from selquest/develop
Phergus Jun 27, 2020
6d1d0a7
Make dicelib compatible with refactor to Parser in https://github.com…
nmeier Jul 11, 2020
4de7609
Merge pull request #57 from nmeier/caching
Phergus Jul 12, 2020
0b50460
Merge pull request #54 from RPTools/develop
Phergus Jul 12, 2020
b4840c1
Shadowrun improvements
phi1010 Aug 16, 2020
176b80f
Fix format
phi1010 Aug 16, 2020
e62f924
Restore Comment
phi1010 Aug 16, 2020
a7e9061
Merge pull request #61 from phi1010/sr5
Phergus Aug 29, 2020
33309b6
Merge pull request #1 from RPTools/develop
selquest Mar 14, 2021
012a40a
Inform parent RunData when child makes a roll. Add safeguards to tes…
selquest Mar 17, 2021
1cbcbdf
Merge pull request #83 from selquest/bugfix/mt-2444-json-rolls-rundata
Phergus Mar 18, 2021
1480c30
Added function "rollSubWithUpper"
aRTy42 Apr 30, 2021
c1c00d6
Added dice expressions XdYaZlW and XdYsZuW
aRTy42 Apr 30, 2021
3eba6e4
Renaming variable in rollModWithBounds
aRTy42 Apr 30, 2021
f191c0f
Update RollWithBounds.java
aRTy42 Apr 30, 2021
23e7de3
Added MockRun tests for all 6 bounded expressions
aRTy42 Apr 30, 2021
b3789ae
RollWithBounds: Now returns BigDecimal
aRTy42 Apr 30, 2021
094482f
Merge pull request #84 from RPTools/develop
Phergus Apr 30, 2021
28e0852
Merge branch 'develop' into feature-java--16
cwisniew May 7, 2021
4c9111b
Merge pull request #96 from RPTools/feature-java--16
cwisniew May 7, 2021
bd135d0
Upgrade to java 20
cwisniew Apr 24, 2023
b418a0d
Merge pull request #154 from cwisniew/feature-java-20
cwisniew Apr 24, 2023
90a98b3
Merge branch 'dicelib-merge' into develop
cwisniew Apr 25, 2023
1d0ac7d
remove external dicelib dependancy
cwisniew Apr 25, 2023
44dd4dc
update dicelib unit tests to same version of junit as MapTool
cwisniew Apr 25, 2023
db21e5d
move dicelib from "common" to "dicelib" package
cwisniew Apr 25, 2023
8fb1213
fix imports
cwisniew Apr 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,6 @@ dependencies {
implementation 'com.github.RPTools:maptool-resources:1.6.0'
// parser for macros
implementation 'com.github.RPTools:parser:1.8.3'
// dice expressions
implementation 'net.rptools.dicelib:dicelib:1.8.6'

// Currently hosted on nerps.net/repo
implementation group: 'com.jidesoft', name: 'jide-common', version: '3.7.9'
Expand Down
7 changes: 0 additions & 7 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,3 @@ include 'services:webservice'
*/

rootProject.name = 'MapTool'


sourceControl {
gitRepository(uri("https://github.com/RPTools/dicelib.git")) {
producesModule("net.rptools.dicelib:dicelib")
}
}
295 changes: 295 additions & 0 deletions src/main/java/net/rptools/dicelib/expression/ExpressionParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
/*
* This software Copyright by the RPTools.net development team, and
* licensed under the Affero GPL Version 3 or, at your option, any later
* version.
*
* MapTool Source Code is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public
* License * along with this source Code. If not, please visit
* <http://www.gnu.org/licenses/> and specifically the Affero license
* text at <http://www.gnu.org/licenses/agpl.html>.
*/
package net.rptools.dicelib.expression;

import net.rptools.dicelib.expression.function.ArsMagicaStress;
import net.rptools.dicelib.expression.function.CountSuccessDice;
import net.rptools.dicelib.expression.function.DropHighestRoll;
import net.rptools.dicelib.expression.function.DropRoll;
import net.rptools.dicelib.expression.function.ExplodeDice;
import net.rptools.dicelib.expression.function.ExplodingSuccessDice;
import net.rptools.dicelib.expression.function.FudgeRoll;
import net.rptools.dicelib.expression.function.HeroKillingRoll;
import net.rptools.dicelib.expression.function.HeroRoll;
import net.rptools.dicelib.expression.function.If;
import net.rptools.dicelib.expression.function.KeepLowestRoll;
import net.rptools.dicelib.expression.function.KeepRoll;
import net.rptools.dicelib.expression.function.OpenTestDice;
import net.rptools.dicelib.expression.function.RerollDice;
import net.rptools.dicelib.expression.function.RerollDiceOnce;
import net.rptools.dicelib.expression.function.Roll;
import net.rptools.dicelib.expression.function.RollWithBounds;
import net.rptools.dicelib.expression.function.ShadowRun4Dice;
import net.rptools.dicelib.expression.function.ShadowRun4ExplodeDice;
import net.rptools.dicelib.expression.function.ShadowRun5Dice;
import net.rptools.dicelib.expression.function.ShadowRun5ExplodeDice;
import net.rptools.dicelib.expression.function.UbiquityRoll;
import net.rptools.parser.*;
import net.rptools.parser.transform.RegexpStringTransformer;
import net.rptools.parser.transform.StringLiteralTransformer;

public class ExpressionParser {
private static String[][] DICE_PATTERNS =
new String[][] {
// Comments
new String[] {"//.*", ""},

// Color hex strings #FFF or #FFFFFF or #FFFFFFFF (with alpha)
new String[] {
"(?<![0-9A-Za-z])#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])(?![0-9A-Za-z])",
"0x$1$1$2$2$3$3"
},
new String[] {
"(?<![0-9A-Za-z])#([0-9A-Fa-f]{6,6}(?:[0-9A-Fa-f]{2,2})?)(?![0-9A-Za-z])", "0x$1"
},

// drop
new String[] {"\\b(\\d+)[dD](\\d+)[dD](\\d+)\\b", "drop($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[dD](\\d+)\\b", "drop(1, $1, $2)"},

// drop highest
new String[] {"\\b(\\d+)[dD](\\d+)[dD][hH](\\d+)\\b", "dropHighest($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[dD][hH](\\d+)\\b", "dropHighest(1, $1, $2)"},

// keep
new String[] {"\\b(\\d+)[dD](\\d+)[kK](\\d+)\\b", "keep($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[kK](\\d+)\\b", "keep(1, $1, $2)"},

// keep lowest
new String[] {"\\b(\\d+)[dD](\\d+)[kK][lL](\\d+)\\b", "keepLowest($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[kK][lL](\\d+)\\b", "keepLowest(1, $1, $2)"},

// re-roll
new String[] {"\\b(\\d+)[dD](\\d+)[rR](\\d+)\\b", "reroll($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[rR](\\d+)\\b", "reroll(1, $1, $2)"},

// re-roll once and keep the new value
new String[] {"\\b(\\d+)[dD](\\d+)[rR][kK](\\d+)\\b", "rerollOnce($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[rR][kK](\\d+)\\b", "rerollOnce(1, $1, $2)"},

// re-roll once and choose the higher value
new String[] {"\\b(\\d+)[dD](\\d+)[rR][cC](\\d+)\\b", "rerollOnce($1, $2, $3, true)"},
new String[] {"\\b[dD](\\d+)[rR][cC](\\d+)\\b", "rerollOnce(1, $1, $2, true)"},

// count success
new String[] {"\\b(\\d+)[dD](\\d+)[sS](\\d+)\\b", "success($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[sS](\\d+)\\b", "success(1, $1, $2)"},

// count success while exploding
new String[] {"\\b(\\d+)[dD](\\d+)[eE][sS](\\d+)\\b", "explodingSuccess($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[eE][sS](\\d+)\\b", "explodingSuccess(1, $1, $2)"},
new String[] {"\\b(\\d+)[eE][sS](\\d+)\\b", "explodingSuccess($1, 6, $2)"},

// show max while exploding
new String[] {"\\b(\\d+)[dD](\\d+)[oO]\\b", "openTest($1, $2)"},
new String[] {"\\b[dD](\\d+)[oO]\\b", "openTest(1, $1)"},
new String[] {"\\b(\\d+)[oO]\\b", "openTest($1, 6)"},

// explode
new String[] {"\\b(\\d+)[dD](\\d+)[eE]\\b", "explode($1, $2)"},
new String[] {"\\b[dD](\\d+)[eE]\\b", "explode(1, $1)"},

// hero
new String[] {"\\b(\\d+[.]\\d+)[dD](\\d+)[hH]\\b", "hero($1, $2)"},
new String[] {"\\b(\\d+)[dD](\\d+)[hH]\\b", "hero($1, $2)"},
new String[] {"\\b[dD](\\d+)[hH]\\b", "hero(1, $1)"},
new String[] {"\\b(\\d+[.]\\d+)[dD](\\d+)[bB]\\b", "herobody($1, $2)"},
new String[] {"\\b(\\d+)[dD](\\d+)[bB]\\b", "herobody($1, $2)"},
new String[] {"\\b[dD](\\d+)[bB]\\b", "herobody(1, $1)"},

// hero killing
new String[] {"\\b(\\d+[.]\\d+)[dD](\\d+)[hH][kK]([-+]\\d+)\\b", "herokilling($1, $2, $3)"},
new String[] {"\\b(\\d+[.]\\d+)[dD](\\d+)[hH][kK]\\b", "herokilling($1, $2, 0)"},
new String[] {"\\b(\\d+)[dD](\\d+)[hH][kK]([-+]\\d+)\\b", "herokilling($1, $2, $3)"},
new String[] {"\\b(\\d+)[dD](\\d+)[hH][kK]\\b", "herokilling($1, $2, 0)"},
new String[] {"\\b[dD](\\d+)[hH][kK]([-+]\\d+)\\b", "herokilling(1, $1, $3)"},
new String[] {"\\b[dD](\\d+)[hH][kK]\\b", "herokilling(1, $1, 0)"},

// hero killing2
new String[] {
"\\b(\\d+[.]\\d+)[dD](\\d+)[hH][kK][2]([-+]\\d+)\\b", "herokilling2($1, $2, $3)"
},
new String[] {"\\b(\\d+[.]\\d+)[dD](\\d+)[hH][kK][2]\\b", "herokilling2($1, $2, 0)"},
new String[] {"\\b(\\d+)[dD](\\d+)[hH][kK][2]([-+]\\d+)\\b", "herokilling2($1, $2, $3)"},
new String[] {"\\b(\\d+)[dD](\\d+)[hH][kK][2]\\b", "herokilling2($1, $2, 0)"},
new String[] {"\\b[dD](\\d+)[hH][kK][2]([-+]\\d+)\\b", "herokilling2(1, $1, $3)"},
new String[] {"\\b[dD](\\d+)[hH][kK][2]\\b", "herokilling2(1, $1, 0)"},

// hero killing multiplier
new String[] {"\\b(\\d+)[dD](\\d+)[hH][mM]([-+]\\d+)\\b", "heromultiplier($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[hH][mM]([-+]\\d+)\\b", "heromultiplier(1, $1, $2)"},
new String[] {"\\b(\\d+)[dD](\\d+)[hH][mM]\\b", "heromultiplier($1, $2, 0)"},
new String[] {"\\b[dD](\\d+)[hH][mM]\\b", "heromultiplier(1, $1, 0)"},
new String[] {"\\b(\\d+)[hH][mM]\\b", "heromultiplier(0, 0, $1)"},

// dice
new String[] {"\\b(\\d+)[dD](\\d+)\\b", "roll($1, $2)"},
new String[] {"\\b[dD](\\d+)\\b", "roll(1, $1)"},

// Fudge dice
new String[] {"\\b(\\d+)[dD][fF]\\b", "fudge($1)"},
new String[] {"\\b[dD][fF]\\b", "fudge(1)"},

// Ubiquity dice
new String[] {"\\b(\\d+)[dD][uU]\\b", "ubiquity($1)"},
new String[] {"\\b[dD][uU]\\b", "ubiquity(1)"},

// Shadowrun 4 Edge or Exploding Test
new String[] {"\\b(\\d+)[sS][rR]4[eE][gG](\\d+)\\b", "sr4e($1, $2)"},
new String[] {"\\b(\\d+)[sS][rR]4[eE]\\b", "sr4e($1)"},

// Shadowrun 4 Normal Test
new String[] {"\\b(\\d+)[sS][rR]4[gG](\\d+)\\b", "sr4($1, $2)"},
new String[] {"\\b(\\d+)[sS][rR]4\\b", "sr4($1)"},

// Shadowrun 5 Edge or Exploding Test
new String[] {"\\b(\\d+)[sS][rR]5[eE][gG](\\d+)\\b", "sr5e($1, $2)"},
new String[] {"\\b(\\d+)[sS][rR]5[eE]\\b", "sr5e($1)"},

// Shadowrun 5 Normal Test
new String[] {"\\b(\\d+)[sS][rR]5[gG](\\d+)\\b", "sr5($1, $2)"},
new String[] {"\\b(\\d+)[sS][rR]5\\b", "sr5($1)"},

// Add X, apply a maximum of Y
new String[] {
"\\b(\\d+)[dD](\\d+)[aA](\\d+)[uU](\\d+)\\b", "rollAddWithUpper($1, $2, $3, $4)"
},
new String[] {"\\b[dD](\\d+)[aA](\\d+)[uU](\\d+)\\b", "rollAddWithUpper(1, $1, $2, $3)"},

// Add X, apply a minimum of Y
new String[] {
"\\b(\\d+)[dD](\\d+)[aA](\\d+)[lL](\\d+)\\b", "rollAddWithLower($1, $2, $3, $4)"
},
new String[] {"\\b[dD](\\d+)[aA](\\d+)[lL](\\d+)\\b", "rollAddWithLower(1, $1, $2, $3)"},

// Subtract X, apply a maximum of Y
new String[] {
"\\b(\\d+)[dD](\\d+)[sS](\\d+)[uU](\\d+)\\b", "rollSubWithUpper($1, $2, $3, $4)"
},
new String[] {"\\b[dD](\\d+)[sS](\\d+)[uU](\\d+)\\b", "rollSubWithUpper(1, $1, $2, $3)"},

// Subtract X, apply a minimum of Y
new String[] {
"\\b(\\d+)[dD](\\d+)[sS](\\d+)[lL](\\d+)\\b", "rollSubWithLower($1, $2, $3, $4)"
},
new String[] {"\\b[dD](\\d+)[sS](\\d+)[lL](\\d+)\\b", "rollSubWithLower(1, $1, $2, $3)"},

// Roll with a minimum value per roll (e.g. treat 1s as 2s)
new String[] {"\\b(\\d+)[dD](\\d+)[lL](\\d+)\\b", "rollWithLower($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[lL](\\d+)\\b", "rollWithLower(1, $1, $2)"},

// Roll with a maximum value per roll (e.g. treat 6s as 5s)
new String[] {"\\b(\\d+)[dD](\\d+)[uU](\\d+)\\b", "rollWithUpper($1, $2, $3)"},
new String[] {"\\b[dD](\\d+)[uU](\\d+)\\b", "rollWithUpper(1, $1, $2)"},

// Dragon Quest
new String[] {"\\b(\\d+)[dD](\\d+)[qQ]#([+-]?\\d+)\\b", "rollAddWithLower($1, $2, $3, 1)"},
new String[] {"\\b[dD](\\d+)[qQ]#([+-]?\\d+)\\b", "rollAddWithLower(1, $1, $2, 1)"},
new String[] {"\\b(\\d+)[dD](\\d+)[qQ]\\b", "rollAddWithLower($1, $2, 0, 1)"},
new String[] {"\\b[dD](\\d+)[qQ]\\b", "rollAddWithLower(1, $1, 0, 1)"},

// Ars Magica Stress Die
new String[] {"\\b[aA][sS](\\d+)\\b", "arsMagicaStress($1, 0)"},
new String[] {"\\b[aA][sS](\\d+)[bB]#([+-]?\\d+)\\b", "arsMagicaStress($1, $2)"},
new String[] {"\\b[aA][nN][sS](\\d+)\\b", "arsMagicaStressNum($1, 0)"},
new String[] {"\\b[aA][nN][sS](\\d+)[bB]#([+-]?\\d+)\\b", "arsMagicaStressNum($1, $2)"},
};

private final Parser parser;

public ExpressionParser() {
this(DICE_PATTERNS);
}

public ExpressionParser(String[][] regexpTransforms) {

parser = createParser();

parser.addFunction(new CountSuccessDice());
parser.addFunction(new DropRoll());
parser.addFunction(new ExplodeDice());
parser.addFunction(new KeepRoll());
parser.addFunction(new RerollDice());
parser.addFunction(new RerollDiceOnce());
parser.addFunction(new HeroRoll());
parser.addFunction(new HeroKillingRoll());
parser.addFunction(new FudgeRoll());
parser.addFunction(new UbiquityRoll());
parser.addFunction(new ShadowRun4Dice());
parser.addFunction(new ShadowRun4ExplodeDice());
parser.addFunction(new ShadowRun5Dice());
parser.addFunction(new ShadowRun5ExplodeDice());
parser.addFunction(new Roll());
parser.addFunction(new ExplodingSuccessDice());
parser.addFunction(new OpenTestDice());
parser.addFunction(new RollWithBounds());
parser.addFunction(new DropHighestRoll());
parser.addFunction(new KeepLowestRoll());
parser.addFunction(new ArsMagicaStress());

parser.addFunction(new If());

StringLiteralTransformer slt = new StringLiteralTransformer();

parser.addTransformer(slt.getRemoveTransformer());
parser.addTransformer(new RegexpStringTransformer(regexpTransforms));
parser.addTransformer(slt.getReplaceTransformer());
}

protected Parser createParser() {
return new Parser();
}

public Parser getParser() {
return parser;
}

public Result evaluate(String expression) throws ParserException {
return evaluate(expression, new MapVariableResolver(), true);
}

public Result evaluate(String expression, VariableResolver resolver) throws ParserException {
return evaluate(expression, resolver, true);
}

public Result evaluate(String expression, VariableResolver resolver, boolean makeDeterministic)
throws ParserException {
Result ret = new Result(expression);
RunData oldData = RunData.hasCurrent() ? RunData.getCurrent() : null;
try {
RunData newRunData;
if (oldData != null) {
newRunData = oldData.createChildRunData(ret);
} else {
newRunData = new RunData(ret);
}
RunData.setCurrent(newRunData);

synchronized (parser) {
final Expression xp =
makeDeterministic
? parser.parseExpression(expression).getDeterministicExpression(resolver)
: parser.parseExpression(expression);
ret.setDetailExpression(() -> xp.format());
ret.setValue(xp.evaluate(resolver));
ret.setRolled(newRunData.getRolled());
}
} finally {
RunData.setCurrent(oldData);
}

return ret;
}
}
Loading