Skip to content

Commit

Permalink
Parse dart skill -> target (#2235)
Browse files Browse the repository at this point in the history
  • Loading branch information
Veracity0 committed Mar 15, 2024
1 parent ba8f3e1 commit 8b84a6c
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 0 deletions.
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 @@ public static final boolean processResults(
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 @@ private static void parseLassoUsage(String responseText) {
}
}

// <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;
}

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
15 changes: 15 additions & 0 deletions src/net/sourceforge/kolmafia/webui/StationaryButtonDecorator.java
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,21 @@ private static String getActionName(final String action) {
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);
if (part != null) {
name = "darts: throw at " + part;
}
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>

0 comments on commit 8b84a6c

Please sign in to comment.