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

Parse dart skill -> target #2235

Merged
merged 2 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/data/defaults.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,7 @@ user _creepyVoodooDollUsed false
user _crimbo21ColdResistance 0
user _crimboTraining false
user _crimboTree false
user _currentDartboard
user _cursedKegUsed false
user _cursedMicrowaveUsed false
user _dailyDungeonMalwareUsed false
Expand Down
44 changes: 44 additions & 0 deletions src/net/sourceforge/kolmafia/request/FightRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,7 @@
FightRequest.updateCombatData(urlString, encounter, responseText);
FightRequest.parseCombatItems(responseText);
FightRequest.parseAvailableCombatSkills(responseText);
FightRequest.parseDartboard(responseText);

// Now that we have processed the page, generated the decorated HTML
FightRequest.lastDecoratedResponseText =
Expand Down Expand Up @@ -4576,6 +4577,49 @@
}
}

// <div id="dboard" style="position: relative; width: 138px; height: 148px">...</div><small>Click
// to throw
private static final Pattern DARTBOARD_PATTERN =
Pattern.compile("<div id=\"dboard\".*?>(.*?)</div><small>Click to throw", Pattern.DOTALL);

// <div class="ed_part ed_6_1"><form action="fight.php" method="post"><input type="hidden"
// name="action" value="skill"/><input type="hidden" name="whichskill"
// value="7513"/><button>watermelon</button></form></div>
private static final Pattern DART_PATTERN =
Pattern.compile(
"<div class=\"ed_part.*?name=\"whichskill\" value=\"(\\d+)\".*?<button>([^<]+)</button>",
Pattern.DOTALL);

public static Map<Integer, String> dartSkillToPart = new HashMap<>();

private static void parseDartboard(final String responseText) {
// Assume no dart skills are available
dartSkillToPart.clear();

if (!responseText.contains("dboard")) {
return;
}

Matcher dartboardMatcher = FightRequest.DARTBOARD_PATTERN.matcher(responseText);
if (!dartboardMatcher.find()) {
return;

Check warning on line 4605 in src/net/sourceforge/kolmafia/request/FightRequest.java

View check run for this annotation

Codecov / codecov/patch

src/net/sourceforge/kolmafia/request/FightRequest.java#L4605

Added line #L4605 was not covered by tests
}

Matcher dartMatcher = FightRequest.DART_PATTERN.matcher(dartboardMatcher.group(1));
while (dartMatcher.find()) {
Integer skill = Integer.valueOf(dartMatcher.group(1));
String part = dartMatcher.group(2);
dartSkillToPart.put(skill, part);
}

String value =
dartSkillToPart.entrySet().stream()
.map(e -> String.valueOf(e.getKey()) + ":" + e.getValue())
.sorted()
.collect(Collectors.joining(","));
Preferences.setString("_currentDartboard", value);
}

public static final void parseCombatItems(String responseText) {
// The current round will be zero when the fight is over.
// If you run with the WOWbar, the combat item dropdown will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,21 @@
case 5012: // Disco Face Stab
name = "facestab";
break;

case SkillPool.DART_PART1:
case SkillPool.DART_PART2:
case SkillPool.DART_PART3:
case SkillPool.DART_PART4:
case SkillPool.DART_PART5:
case SkillPool.DART_PART6:
case SkillPool.DART_PART7:
case SkillPool.DART_PART8:
// Darts: Throw at %part1
String part = FightRequest.dartSkillToPart.get(skillId);

Check warning on line 945 in src/net/sourceforge/kolmafia/webui/StationaryButtonDecorator.java

View check run for this annotation

Codecov / codecov/patch

src/net/sourceforge/kolmafia/webui/StationaryButtonDecorator.java#L945

Added line #L945 was not covered by tests
if (part != null) {
name = "darts: throw at " + part;

Check warning on line 947 in src/net/sourceforge/kolmafia/webui/StationaryButtonDecorator.java

View check run for this annotation

Codecov / codecov/patch

src/net/sourceforge/kolmafia/webui/StationaryButtonDecorator.java#L947

Added line #L947 was not covered by tests
}
break;
}

return name;
Expand Down
52 changes: 52 additions & 0 deletions test/net/sourceforge/kolmafia/request/FightRequestTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@
import internal.helpers.Cleanups;
import internal.helpers.RequestLoggerOutput;
import internal.network.FakeHttpClientBuilder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import net.sourceforge.kolmafia.AscensionClass;
import net.sourceforge.kolmafia.AscensionPath.Path;
import net.sourceforge.kolmafia.KoLAdventure;
Expand Down Expand Up @@ -2702,4 +2705,53 @@ public void advancedResearchFailureIsDetected() {
}
}
}

@Nested
class DartHolster {
@ParameterizedTest
@CsvSource({
"six_no_duplicates, junksprite hubcap bender, arm;wing;leg;head;butt;torso",
"six_with_duplicates, fruit golem, watermelon;butt;grapes;grapefruit;banana;watermelon",
"four_no_duplicates, skullbat, head;wing;butt;torso",
"four_with_duplicates, spectral jellyfish, tentacle;head;butt;tentacle"
})
public void canParseDartboard(String file, String monsterName, String partNames) {
var cleanups = new Cleanups(withProperty("_currentDartboard", ""), withFight(0));
try (cleanups) {
String html = html("request/test_fight_darts_" + file + ".html");

// Derive expected skills

// These are the partnames as they are presented in the
// particular responseText. KoL seems to start counting them
// with skill 7513, although duplicate part names will be
// assigned the same (earlier assigned) skill number.

String[] parts = partNames.split("\\s*;\\s*");

Map<String, Integer> partMap = new HashMap<>();
// Assume/require that the property is sorted by skill ID
Map<Integer, String> skillMap = new TreeMap<>();
int skillId = 7513;

for (String part : parts) {
if (!partMap.containsKey(part)) {
partMap.put(part, skillId);
skillMap.put(skillId++, part);
}
}

String expected =
skillMap.entrySet().stream()
.map(e -> String.valueOf(e.getKey()) + ":" + e.getValue())
.collect(Collectors.joining(","));

String url = "fight.php?ireallymeanit=1710016436";
FightRequest.registerRequest(true, url);
FightRequest.processResults(null, null, html);

assertThat("_currentDartboard", isSetTo(expected));
}
}
}
}
29 changes: 29 additions & 0 deletions test/root/request/test_fight_darts_four_no_duplicates.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<html><head>
<script language=Javascript>
<!--
if (parent.frames.length == 0) location.href="game.php";
top.charpane.location.href="charpane.php";
//-->
</script>
<script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/keybinds.min.2.js"></script>
<script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/window.20111231.js"></script>
<script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/jquery-1.3.1.min.js"></script>
<script language="javascript" src="https://d2uyhvukfffg5a.cloudfront.net/scripts/core.js"></script><script src="https://d2uyhvukfffg5a.cloudfront.net/scripts/fight.js"></script>
<script>
var onturn = 1;

</script> <link rel="stylesheet" type="text/css" href="https://d2uyhvukfffg5a.cloudfront.net/styles.20230117d.css">
<style> body * { image-rendering: auto!important;} </style><style type='text/css'>
.faded {
zoom: 1;
filter: alpha(opacity=35);
opacity: 0.35;
-khtml-opacity: 0.35;
-moz-opacity: 0.35;
}
</style>

</head>

<body>
<center><table width=95% cellspacing=0 cellpadding=0><tr><td style="color: white;" align=center bgcolor=blue><b>Combat!</b></td></tr><tr><td style="padding: 5px; border: 1px solid blue;"><center><table><tr><td><center><table><tr><td><div id=monsterpic style='position: relative;'> <img id='monpic' src="https://d2uyhvukfffg5a.cloudfront.net/adventureimages/skullbat.gif" width=100 height=100></div><td align="center" id="dartboardtd"><style>.ed_part button { border: 0; outline: 0; background: none!important; padding: 12px 0px 12px 0px!important; cursor: pointer; position: absolute; top: 50px; left: 82px; pointer-events: auto; } .ed_part form { display: inline; } .ed_part img { position: absolute; top: 0; left: 0} .ed_part { position: absolute; transform-origin: center; top: 0; left: 0; height: 138px; width: 138px; pointer-events: none; } .ed_4_1 button { color: white; }.ed_4_1 { transform: rotate(-45deg); } .ed_4_2 { transform: rotate(45deg);} .ed_4_3 { transform: rotate(-135deg); } .ed_4_3 button { transform: scale(-1,-1); } .ed_4_4 { transform: rotate(135deg) ; } .ed_4_4 button { color: white; transform: scale(-1,-1); }#dboard .ed_0 button, .nobull { background-color: transparent!important; height: 18px; width: 18px; border-radius: 18px; position: absolute; top: 58px; left: 60px; }</style><div id="dboard" style="position: relative; width: 138px; height: 148px" ><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/dartboard_4.png" height="138" width="138" style="" /><div class="ed_part ed_4_1"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7513"/><button>head</button></form></div><div class="ed_part ed_4_2"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7514"/><button>wing</button></form></div><div class="ed_part ed_4_3"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7515"/><button>butt</button></form></div><div class="ed_part ed_4_4"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7516"/><button>torso</button></form></div><div class="ed_part ed_0"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7521"/><button title="bullseye" alt="bullseye"></button></form></div></div><small>Click to throw<br>3 darts left</td></td><td id='fmsg' valign=center>You're fighting <span id='monname'>a skullbat</span></td><!-- MONSTERID: 45 --><td width=30></td><td id='fstats'><table><tr><td width=30><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/nicesword.gif width=30 height=30 alt="Enemy's Attack Power" title="Enemy's Attack Power"></td><td width=50 valign=center align=left><b><font size=+2>16</font></b></td><td><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/beastflavor.gif alt="This monster is a Beast" title="This monster is a Beast"></td></tr><tr><td width=30><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/whiteshield.gif width=30 height=30 alt="Enemy's Defense" title="Enemy's Defense"></td><td width=50 valign=center align=left><b><font size=+2>14</font></b></td><td><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/circle.gif width=30 height=30 alt="This monster has no particular elemental alignment." title="This monster has no particular elemental alignment."></td></tr><tr><td width=30><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/hp.gif width=30 height=30 alt="Enemy's Hit Points" title="Enemy's Hit Points"></td><td width=50 valign=center align=left><b><font size=+2>10</font></b></td><td><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/watch.gif alt="Initiative +60%" title="Initiative +60%"></td></tr></table></td></tr></table><br><script type="text/javascript">var monsterstats = {"hp":"10","def":"14","off":"16"};</script></center><blockquote>This is pretty creepy -- it's a bat with a skull instead of a body. Most bats have skulls in addition to their body, but, y'know.</blockquote><center><p>You jot down some notes quickly, before the fight starts.<br><center><i><small>(You gain 1 research point)</small></i></center><p>You get the jump on it.<p><table cellpadding=10 cellspacing=0><tr><td align='center'><form name=useitem action=fight.php method=post style='display: inline; margin: 0 0.5em 0 0.5em'><input type=hidden name=whichskill value=7512d><input type=hidden name=action value="skill"><input class=button type=submit onclick="return killforms(this);" value="Advanced Research"></form></td></tr><tr><td align='center'><form name=useitem action=fight.php method=post><input type=hidden name=action value="useitem"><select name=whichitem><option value=0>(select an item)</option><option picurl=cosmicball2 value=10891>cosmic bowling ball (1)</option><option picurl=sitgrub value=11124>extra-grubby grub (2)</option><option picurl=hairwad value=1922>gob of wet hair (1)</option><option picurl=goto value=4948>GOTO (1)</option><option picurl=junkjagged value=6738>jagged scrap metal (1)</option><option picurl=firecrack value=747>Knob Goblin firecracker (2)</option><option picurl=seltzer value=344>Knob Goblin seltzer (3)</option><option picurl=seltzer value=345>Knob Goblin superseltzer (1)</option><option picurl=leftovers value=1777>leftovers of indeterminate origin (1)</option><option picurl=junkmolten value=6740>molten scrap metal (1)</option><option picurl=canlid value=559>razor-sharp can lid (2)</option></select> <input class=button type=submit onclick="return killforms(this);" value="Use Item"></form></td></tr><tr><td align='center'><form name=wpra action=fight.php method=post><input type=hidden name=action value=runaway><input type=submit class=button onclick="return killforms(this);" value="Run Away"></form></td></tr></table></td></tr></table></center></td></tr><tr><td height=4></td></tr></table></center></body></html>
29 changes: 29 additions & 0 deletions test/root/request/test_fight_darts_four_with_duplicates.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<html><head>
<script language=Javascript>
<!--
if (parent.frames.length == 0) location.href="game.php";
top.charpane.location.href="charpane.php";
//-->
</script>
<script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/keybinds.min.2.js"></script>
<script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/window.20111231.js"></script>
<script language=Javascript src="https://d2uyhvukfffg5a.cloudfront.net/scripts/jquery-1.3.1.min.js"></script>
<script language="javascript" src="https://d2uyhvukfffg5a.cloudfront.net/scripts/core.js"></script><script src="https://d2uyhvukfffg5a.cloudfront.net/scripts/fight.js"></script>
<script>
var onturn = 1;

</script> <link rel="stylesheet" type="text/css" href="https://d2uyhvukfffg5a.cloudfront.net/styles.20230117d.css">
<style> body * { image-rendering: auto!important;} </style><style type='text/css'>
.faded {
zoom: 1;
filter: alpha(opacity=35);
opacity: 0.35;
-khtml-opacity: 0.35;
-moz-opacity: 0.35;
}
</style>

</head>

<body>
<center><table width=95% cellspacing=0 cellpadding=0><tr><td style="color: white;" align=center bgcolor=blue><b>Combat!</b></td></tr><tr><td style="padding: 5px; border: 1px solid blue;"><center><table><tr><td><center><table><tr><td><div id=monsterpic style='position: relative;'> <img id='monpic' src="https://d2uyhvukfffg5a.cloudfront.net/adventureimages/jellyfish.gif" width=100 height=100></div><td align="center" id="dartboardtd"><style>.ed_part button { border: 0; outline: 0; background: none!important; padding: 12px 0px 12px 0px!important; cursor: pointer; position: absolute; top: 50px; left: 82px; pointer-events: auto; } .ed_part form { display: inline; } .ed_part img { position: absolute; top: 0; left: 0} .ed_part { position: absolute; transform-origin: center; top: 0; left: 0; height: 138px; width: 138px; pointer-events: none; } .ed_4_1 button { color: white; }.ed_4_1 { transform: rotate(-45deg); } .ed_4_2 { transform: rotate(45deg);} .ed_4_3 { transform: rotate(-135deg); } .ed_4_3 button { transform: scale(-1,-1); } .ed_4_4 { transform: rotate(135deg) ; } .ed_4_4 button { color: white; transform: scale(-1,-1); }#dboard .ed_0 button, .nobull { background-color: transparent!important; height: 18px; width: 18px; border-radius: 18px; position: absolute; top: 58px; left: 60px; }</style><div id="dboard" style="position: relative; width: 138px; height: 148px" ><img src="https://d2uyhvukfffg5a.cloudfront.net/otherimages/dartboard_4.png" height="138" width="138" style="" /><div class="ed_part ed_4_1"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7513"/><button>tentacle</button></form></div><div class="ed_part ed_4_2"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7514"/><button>head</button></form></div><div class="ed_part ed_4_3"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7515"/><button>butt</button></form></div><div class="ed_part ed_4_4"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7513"/><button>tentacle</button></form></div><div class="ed_part ed_0"><form action="fight.php" method="post"><input type="hidden" name="action" value="skill"/><input type="hidden" name="whichskill" value="7521"/><button title="bullseye" alt="bullseye"></button></form></div></div><small>Click to throw<br>3 darts left</td></td><td id='fmsg' valign=center>You're fighting <span id='monname'>a Spectral Jellyfish</span></td><!-- MONSTERID: 93 --><td width=30></td><td id='fstats'><table><tr><td width=30><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/nicesword.gif width=30 height=30 alt="Enemy's Attack Power" title="Enemy's Attack Power"></td><td width=50 valign=center align=left><b><font size=+2>70</font></b></td><td><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/beastflavor.gif alt="This monster is a Beast" title="This monster is a Beast"></td></tr><tr><td width=30><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/whiteshield.gif width=30 height=30 alt="Enemy's Defense" title="Enemy's Defense"></td><td width=50 valign=center align=left><b><font size=+2>65</font></b></td><td><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/circle.gif width=30 height=30 alt="This monster has no particular elemental alignment." title="This monster has no particular elemental alignment."></td></tr><tr><td width=30><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/hp.gif width=30 height=30 alt="Enemy's Hit Points" title="Enemy's Hit Points"></td><td width=50 valign=center align=left><b><font size=+2>60</font></b></td><td><img src=https://d2uyhvukfffg5a.cloudfront.net/itemimages/watch.gif alt="Initiative +60%" title="Initiative +60%"></td></tr></table></td></tr></table><br><script type="text/javascript">var monsterstats = {"hp":"60","def":"65","off":"70"};</script></center><blockquote>This is the enslaved spirit of a jellyfish that didn't quite make it to Jellyfish Heaven (where jellyfish go, to get away from Mormons and drunk Eskimos.)</blockquote><center><p>You jot down some notes quickly, before the fight starts.<br><center><i><small>(You gain 1 research point)</small></i></center><p>You get the jump on it.<p><table cellpadding=10 cellspacing=0><tr><td align='center'><form name=useitem action=fight.php method=post style='display: inline; margin: 0 0.5em 0 0.5em'><input type=hidden name=whichskill value=7512d><input type=hidden name=action value="skill"><input class=button type=submit onclick="return killforms(this);" value="Advanced Research"></form></td></tr><tr><td align='center'><form name=useitem action=fight.php method=post><input type=hidden name=action value="useitem"><select name=whichitem><option value=0>(select an item)</option><option picurl=cosmicball2 value=10891>cosmic bowling ball (1)</option><option picurl=sitgrub value=11124>extra-grubby grub (2)</option><option picurl=hairwad value=1922>gob of wet hair (1)</option><option picurl=goto value=4948>GOTO (1)</option><option picurl=junkjagged value=6738>jagged scrap metal (1)</option><option picurl=firecrack value=747>Knob Goblin firecracker (2)</option><option picurl=seltzer value=344>Knob Goblin seltzer (3)</option><option picurl=seltzer value=345>Knob Goblin superseltzer (1)</option><option picurl=leftovers value=1777>leftovers of indeterminate origin (1)</option><option picurl=junkmolten value=6740>molten scrap metal (1)</option><option picurl=canlid value=559>razor-sharp can lid (2)</option></select> <input class=button type=submit onclick="return killforms(this);" value="Use Item"></form></td></tr><tr><td align='center'><form name=wpra action=fight.php method=post><input type=hidden name=action value=runaway><input type=submit class=button onclick="return killforms(this);" value="Run Away"></form></td></tr></table></td></tr></table></center></td></tr><tr><td height=4></td></tr></table></center></body></html>