/**
* Copyright (c) 2005-2017, KoLmafia development team
* http://kolmafia.sourceforge.net/
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* [1] Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* [2] Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* [3] Neither the name "KoLmafia" nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package net.sourceforge.kolmafia.request;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.kolmafia.AdventureResult;
import net.sourceforge.kolmafia.EdServantData;
import net.sourceforge.kolmafia.FamiliarData;
import net.sourceforge.kolmafia.KoLAdventure;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.KoLmafia;
import net.sourceforge.kolmafia.Modifiers;
import net.sourceforge.kolmafia.Modifiers.Modifier;
import net.sourceforge.kolmafia.Modifiers.ModifierList;
import net.sourceforge.kolmafia.PastaThrallData;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.StaticEntity;
import net.sourceforge.kolmafia.VYKEACompanionData;
import net.sourceforge.kolmafia.objectpool.EffectPool;
import net.sourceforge.kolmafia.objectpool.FamiliarPool;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.persistence.AdventureSpentDatabase;
import net.sourceforge.kolmafia.persistence.ConcoctionDatabase;
import net.sourceforge.kolmafia.persistence.EffectDatabase;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.SpelunkyRequest;
import net.sourceforge.kolmafia.session.BatManager;
import net.sourceforge.kolmafia.session.ChoiceManager;
import net.sourceforge.kolmafia.session.Limitmode;
import net.sourceforge.kolmafia.session.ResultProcessor;
import net.sourceforge.kolmafia.session.TurnCounter;
import net.sourceforge.kolmafia.swingui.MallSearchFrame;
import net.sourceforge.kolmafia.swingui.RequestFrame;
import net.sourceforge.kolmafia.textui.command.SnowsuitCommand;
import net.sourceforge.kolmafia.utilities.HTMLParserUtils;
import net.sourceforge.kolmafia.utilities.LockableListFactory;
import net.sourceforge.kolmafia.utilities.StringUtilities;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class CharPaneRequest
extends GenericRequest
{
private static final AdventureResult ABSINTHE = EffectPool.get( EffectPool.ABSINTHE );
private static long lastResponseTimestamp = 0;
private static String lastResponse = "";
private static boolean canInteract = false;
private static int turnsThisRun = 0;
private static boolean inValhalla = false;
public static boolean compactCharacterPane = false;
public static boolean familiarBelowEffects = false;
private static final HtmlCleaner cleaner = HTMLParserUtils.configureDefaultParser();
public CharPaneRequest()
{
super( "charpane.php" );
}
public static final void reset()
{
CharPaneRequest.lastResponseTimestamp = 0;
CharPaneRequest.lastResponse = "";
CharPaneRequest.canInteract = false;
CharPaneRequest.turnsThisRun = 0;
CharPaneRequest.inValhalla = false;
}
@Override
protected boolean retryOnTimeout()
{
return true;
}
@Override
public String getHashField()
{
return null;
}
public static final boolean canInteract()
{
return CharPaneRequest.canInteract;
}
public static final boolean inValhalla()
{
return CharPaneRequest.inValhalla;
}
public static final void liberateKing()
{
// Set variables without making requests
CharPaneRequest.canInteract = true;
KoLCharacter.setRestricted( false );
}
public static final void setInteraction()
{
CharPaneRequest.setInteraction( CharPaneRequest.checkInteraction() );
}
public static final void setInteraction( final boolean interaction )
{
if ( CharPaneRequest.canInteract != interaction )
{
if ( interaction && KoLCharacter.getRestricted() )
{
// Refresh skills & familiars when leaving
// ronin or hardcore from a restricted path
RequestThread.postRequest( new CharSheetRequest() );
RequestThread.postRequest( new CampgroundRequest( "bookshelf" ) );
RequestThread.postRequest( new FamiliarRequest() );
KoLCharacter.setRestricted( false );
}
CharPaneRequest.canInteract = interaction;
MallSearchFrame.updateMeat();
}
if ( interaction )
{
ConcoctionDatabase.setPullsRemaining( -1 );
}
}
public static boolean processResults( String responseText )
{
return CharPaneRequest.processResults( CharPaneRequest.lastResponseTimestamp, responseText );
}
public static boolean processResults( long responseTimestamp, String responseText )
{
if ( CharPaneRequest.lastResponseTimestamp > responseTimestamp )
{
return false;
}
CharPaneRequest.lastResponseTimestamp = responseTimestamp;
CharPaneRequest.lastResponse = responseText;
// Are we in a limitmode?
if ( responseText.contains( ">Last Spelunk</a>" ) )
{
KoLCharacter.setLimitmode( Limitmode.SPELUNKY );
SpelunkyRequest.parseCharpane( responseText );
return true;
}
if ( responseText.contains( "You're Batfellow" ) )
{
KoLCharacter.setLimitmode( Limitmode.BATMAN );
BatManager.parseCharpane( responseText );
return true;
}
if ( KoLCharacter.getLimitmode() != null && KoLCharacter.getLimitmode().equals( Limitmode.SPELUNKY ) )
{
KoLCharacter.setLimitmode( null );
}
// We can deduce whether we are in compact charpane mode
CharPaneRequest.compactCharacterPane = responseText.contains( "<br>Lvl. " );
// If we are in Valhalla, do special processing
if ( KoLCharacter.getLimitmode() == null && ( responseText.contains( "otherimages/spirit.gif" ) ||
responseText.contains( "<br>Lvl. <img" ) ) )
{
processValhallaCharacterPane( responseText );
return true;
}
CharPaneRequest.inValhalla = false;
// KoL now includes Javascript variables in each charpane
//
// var turnsplayed = 232576;
// var turnsthisrun = 232576;
// var rollover = 1268537400;
// var rightnow = 1268496181;
// var pwdhash = "...";
//
// "turnsThisRun" is of interest for several reasons: we can
// use it to order (some) charpane requests, even if the
// timestamp is the same, and we can use it to synchronize
// KolMafia with KoL's turn counter
int turnsThisRun = parseTurnsThisRun( responseText );
int mafiaTurnsThisRun = KoLCharacter.getCurrentRun();
if ( turnsThisRun < CharPaneRequest.turnsThisRun ||
turnsThisRun < mafiaTurnsThisRun )
{
// turnsThisRun = 426 CharPaneRequest.turnsThisRun = 426 mafiaTurnsThisRun = 427
// And yet, this was a new charpane. Don't process it, but don't respond with
// 304 Not Modified
return true;
}
CharPaneRequest.turnsThisRun = turnsThisRun;
KoLCharacter.setTurnsPlayed( parseTurnsPlayed( responseText ) );
// Since we believe this update, synchronize with it
ResultProcessor.processAdventuresUsed( turnsThisRun - mafiaTurnsThisRun );
CharPaneRequest.parseAvatar( responseText );
CharPaneRequest.setLastAdventure( responseText );
CharPaneRequest.refreshEffects( responseText );
CharPaneRequest.setInteraction();
// Refresh effects and modifiers before updating stats, since new effects
// can mean that we should not check for incorrect substat values
KoLCharacter.recalculateAdjustments();
// The easiest way to retrieve the character pane data is to
// use regular expressions. But, the only data that requires
// synchronization is the modified stat values, health and
// mana.
if ( CharPaneRequest.compactCharacterPane )
{
CharPaneRequest.handleCompactMode( responseText );
}
else
{
CharPaneRequest.handleExpandedMode( responseText );
}
KoLCharacter.updateStatus();
CharPaneRequest.checkVYKEACompanion( responseText );
if ( KoLCharacter.inAxecore() )
{
CharPaneRequest.checkClancy( responseText );
}
else if ( KoLCharacter.isJarlsberg() )
{
CharPaneRequest.checkCompanion( responseText );
}
else if ( KoLCharacter.isSneakyPete() )
{
// No familiar-type checking needed
}
else if ( KoLCharacter.isEd() )
{
CharPaneRequest.checkServant( responseText );
}
else
{
CharPaneRequest.checkFamiliar( responseText );
}
CharPaneRequest.checkPastaThrall( responseText );
CharPaneRequest.checkRadSickness( responseText );
CharPaneRequest.checkAbsorbs( responseText );
// Mana cost adjustment may have changed
LockableListFactory.sort( KoLConstants.summoningSkills );
LockableListFactory.sort( KoLConstants.usableSkills );
RequestFrame.refreshStatus();
return true;
}
public static final String getLastResponse()
{
return CharPaneRequest.lastResponse;
}
// <a class='nounder ' target=mainpane href="charsheet.php"><img src="https://s3.amazonaws.com/images.kingdomofloathing.com/otherimages/classav41_f.gif" width=60 height=100 border=0></a>
public static final Pattern AVATAR_PATTERN =
Pattern.compile( "<img +src=[^>]*?(?:images.kingdomofloathing.com|/images)/([^>\'\"\\s]+)" );
public static final void parseAvatar( final String responseText )
{
Matcher avatarMatcher = CharPaneRequest.AVATAR_PATTERN.matcher( responseText );
if ( avatarMatcher.find() )
{
KoLCharacter.setAvatar( avatarMatcher.group( 1 ) );
}
}
// <td align=center><img src="http://images.kingdomofloathing.com/itemimages/karma.gif" width=30 height=30 alt="Karma" title="Karma"><br>0</td>
public static final Pattern KARMA_PATTERN = Pattern.compile( "karma.gif.*?<br>([^<]*)</td>" );
// <td align=right>Karma:</td><td align=left><b>122</b></td>
public static final Pattern KARMA_PATTERN_COMPACT = Pattern.compile( "Karma:.*?<b>([^<]*)</b>" );
private static final void processValhallaCharacterPane( final String responseText )
{
// We are in Valhalla
CharPaneRequest.inValhalla = true;
KoLCharacter.setAvatar( "otherimages/spirit.gif" );
// We have no stats as an Astral Spirit
KoLCharacter.setStatPoints( 1, 0L, 1, 0L, 1, 0L );
KoLCharacter.setHP( 1, 1, 1 );
KoLCharacter.setMP( 1, 1, 1 );
KoLCharacter.setAvailableMeat( 0 );
KoLCharacter.setAdventuresLeft( 0 );
KoLCharacter.setMindControlLevel( 0 );
// No active status effects
KoLConstants.recentEffects.clear();
KoLConstants.activeEffects.clear();
// No modifiers
KoLCharacter.recalculateAdjustments();
KoLCharacter.updateStatus();
// You certainly can't interact with the "real world"
CharPaneRequest.setInteraction( false );
// You do, however, have Karma available to spend in Valhalla.
Pattern pattern = CharPaneRequest.compactCharacterPane ?
CharPaneRequest.KARMA_PATTERN_COMPACT :
CharPaneRequest.KARMA_PATTERN ;
Matcher matcher = pattern.matcher( responseText );
int karma = matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
Preferences.setInteger( "bankedKarma", karma );
}
public static final Pattern TURNS_THIS_RUN_PATTERN = Pattern.compile( "var turnsthisrun = (\\d*);" );
private static final int parseTurnsThisRun( final String responseText )
{
Matcher matcher = CharPaneRequest.TURNS_THIS_RUN_PATTERN.matcher( responseText );
if ( matcher.find() )
{
return StringUtilities.parseInt( matcher.group( 1 ) );
}
return -1;
}
public static final Pattern TURNS_PLAYED_PATTERN = Pattern.compile( "var turnsplayed = (\\d*);" );
private static final int parseTurnsPlayed( final String responseText )
{
Matcher matcher = CharPaneRequest.TURNS_PLAYED_PATTERN.matcher( responseText );
if ( matcher.find() )
{
return StringUtilities.parseInt( matcher.group( 1 ) );
}
return -1;
}
private static final boolean checkInteraction()
{
// If he's freed the king, that's good enough
if ( KoLCharacter.kingLiberated() )
{
return true;
}
// If he's in Hardcore, nope
if ( KoLCharacter.isHardcore() )
{
return false;
}
// If he's in Bad Moon, nope
if ( KoLCharacter.inBadMoon() )
{
return false;
}
// If the charsheet does not say he can't interact or api.php
// says roninleft == 0, ok.
// (this will be true for any Casual run, for an unascended
// character, or for a sufficiently lengthy softcore run)
if ( !KoLCharacter.inRonin() )
{
return true;
}
// Last time we checked the char sheet or api.php, he was still
// in ronin. See if he still is.
if ( KoLCharacter.getCurrentRun() >= 1000 )
{
return true;
}
// Otherwise, no way.
return false;
}
private static final void handleCompactMode( final String responseText )
{
try
{
CharPaneRequest.handleStatPoints( responseText, CharPaneRequest.compactStatsPattern );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
try
{
CharPaneRequest.handleMiscPoints( responseText, CharPaneRequest.MISC_PATTERNS[ KoLCharacter.inZombiecore() ? 2 : 0 ] );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
try
{
CharPaneRequest.handleMindControl( responseText, CharPaneRequest.compactMCPatterns );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
try
{
CharPaneRequest.handleInebriety( responseText, CharPaneRequest.compactInebrietyPatterns );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
// Do NOT read fullness from the charpane; it is optional, so
// we have to track it manually, anyway
}
private static final void handleExpandedMode( final String responseText )
{
try
{
CharPaneRequest.handleStatPoints( responseText, CharPaneRequest.expandedStatsPattern );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
try
{
CharPaneRequest.handleMiscPoints( responseText, CharPaneRequest.MISC_PATTERNS[ KoLCharacter.inZombiecore() ? 3 : 1 ] );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
try
{
CharPaneRequest.handleMindControl( responseText, CharPaneRequest.expandedMCPatterns );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
try
{
CharPaneRequest.handleInebriety( responseText, CharPaneRequest.expandedInebrietyPatterns );
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
// Do NOT read fullness from the charpane; it is optional, so
// we have to track it manually, anyway
}
private static final Pattern makeStatPattern( final String musString, final String mysString, final String moxString )
{
return Pattern.compile( musString + ".*?<b>(.*?)</b>.*?" + mysString + ".*?<b>(.*?)</b>.*?" + moxString + ".*?<b>(.*?)</b>" );
}
private static final Pattern compactStatsPattern =
CharPaneRequest.makeStatPattern( "Mus", "Mys", "Mox" );
private static final Pattern expandedStatsPattern =
CharPaneRequest.makeStatPattern( "Muscle", "Mysticality", "Moxie" );
private static final Pattern modifiedPattern =
Pattern.compile( "<font color=(?:red|blue)>(\\d+)</font> \\((\\d+)\\)" );
private static final void handleStatPoints( final String responseText, final Pattern pattern )
throws Exception
{
Matcher statMatcher = pattern.matcher( responseText );
if ( !statMatcher.find() )
{
return;
}
int[] modified = new int[ 3 ];
int[] unmodified = new int[ 3 ];
for ( int i = 0; i < 3; ++i )
{
Matcher modifiedMatcher = modifiedPattern.matcher( statMatcher.group( i + 1 ) );
if ( modifiedMatcher.find() )
{
modified[ i ] = StringUtilities.parseInt( modifiedMatcher.group( 1 ) );
unmodified[ i ] = StringUtilities.parseInt( modifiedMatcher.group( 2 ) );
}
else
{
modified[ i ] = unmodified[ i ] =
StringUtilities.parseInt( statMatcher.group( i + 1 ).replaceAll( "<[^>]*>", "" ).replaceAll(
"[^\\d]+", "" ) );
}
}
Modifiers mods = KoLCharacter.getCurrentModifiers();
boolean equalize = mods.getString( Modifiers.EQUALIZE ).length() != 0;
boolean mus_equalize = mods.getString( Modifiers.EQUALIZE_MUSCLE ).length() != 0;
boolean mys_equalize = mods.getString( Modifiers.EQUALIZE_MYST ).length() != 0;
boolean mox_equalize = mods.getString( Modifiers.EQUALIZE_MOXIE ).length() != 0;
boolean mus_limit = (int) mods.get( Modifiers.MUS_LIMIT ) != 0;
boolean mys_limit = (int) mods.get( Modifiers.MYS_LIMIT ) != 0;
boolean mox_limit = (int) mods.get( Modifiers.MOX_LIMIT ) != 0;
boolean checkMus = !equalize && !mus_equalize && !mus_limit;
boolean checkMys = !equalize && !mys_equalize && !mys_limit;
boolean checkMox = !equalize && !mox_equalize && !mox_limit;
long baseMus = checkMus ? CharPaneRequest.checkStat( KoLCharacter.getTotalMuscle(), unmodified[ 0 ] ) : KoLCharacter.getTotalMuscle();
long baseMys = checkMys ? CharPaneRequest.checkStat( KoLCharacter.getTotalMysticality(), unmodified[ 1 ] ) : KoLCharacter.getTotalMysticality();
long baseMox = checkMox ? CharPaneRequest.checkStat( KoLCharacter.getTotalMoxie(), unmodified[ 2 ] ) : KoLCharacter.getTotalMoxie();
KoLCharacter.setStatPoints( modified[ 0 ],
baseMus,
modified[ 1 ],
baseMys,
modified[ 2 ],
baseMox );
}
private static final long checkStat( long currentSubstat, final int baseStat )
{
if ( currentSubstat < KoLCharacter.calculatePointSubpoints( baseStat ) )
{
currentSubstat = KoLCharacter.calculatePointSubpoints( baseStat );
}
else if ( currentSubstat >= KoLCharacter.calculatePointSubpoints( baseStat + 1 ) )
{
currentSubstat = KoLCharacter.calculatePointSubpoints( baseStat + 1 ) - 1;
}
return currentSubstat;
}
private static final Pattern [][] MISC_PATTERNS =
{
// Compact
{
Pattern.compile( "HP:.*?<b>(.*?)/(.*?)</b>" ),
Pattern.compile( "MP:.*?<b>(.*?)/(.*?)</b>" ),
Pattern.compile( "Meat.*?<b>(.*?)</b>" ),
Pattern.compile( "Adv.*?<b>(.*?)</b>" ),
},
// Expanded
{
Pattern.compile( "/(?:slim)?hp\\.gif.*?<span.*?>(.*?) / (.*?)</span>" ),
Pattern.compile( "/(?:slim)?mp\\.gif.*?<span.*?>(.*?) / (.*?)</span>" ),
Pattern.compile( "/(?:slim)?meat\\.gif.*?<span.*?>(.*?)</span>" ),
Pattern.compile( "/(?:slim)?hourglass\\.gif.*?<span.*?>(.*?)</span>" ),
},
// Compact Zombiecore
{
Pattern.compile( "HP.*?<b>(.*?)/(.*?)</b>" ),
Pattern.compile( "Horde: (\\d+)" ),
Pattern.compile( "Meat.*?<b>(.*?)</b>" ),
Pattern.compile( "Adv.*?<b>(.*?)</b>" ),
},
// Expanded Zombiecore
{
Pattern.compile( "/(?:slim)?hp\\.gif.*?<span.*?>(.*?) / (.*?)</span>" ),
Pattern.compile( "/(?:slim)?zombies/horde.*?\\.gif.*?Horde: (\\d+)" ),
Pattern.compile( "/(?:slim)?meat\\.gif.*?<span.*?>(.*?)</span>" ),
Pattern.compile( "/(?:slim)?hourglass\\.gif.*?<span.*?>(.*?)</span>" ),
},
};
private static final int HP = 0;
private static final int MP = 1;
private static final int MEAT = 2;
private static final int ADV = 3;
private static final void handleMiscPoints( final String responseText, final Pattern [] patterns )
throws Exception
{
// Health and all that good stuff is complicated, has nested
// images, and lots of other weird stuff. Handle it in a
// non-modular fashion.
Pattern pattern = patterns[ HP ];
Matcher matcher = pattern == null ? null : pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int currentHP = StringUtilities.parseInt( matcher.group( 1 ).replaceAll( "<[^>]*>", "" ).replaceAll( "[^\\d]+", "" ) );
int maximumHP = StringUtilities.parseInt( matcher.group( 2 ).replaceAll( "<[^>]*>", "" ).replaceAll( "[^\\d]+", "" ) );
KoLCharacter.setHP( currentHP, maximumHP, maximumHP );
}
pattern = patterns[ MP ];
matcher = pattern == null ? null : pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int currentMP = 0;
int maximumMP = 0;
if ( KoLCharacter.inZombiecore() )
{
String currentHorde = matcher.group( 1 );
currentMP = maximumMP = StringUtilities.parseInt( currentHorde );
}
else
{
currentMP = StringUtilities.parseInt( matcher.group( 1 ).replaceAll( "<[^>]*>", "" ).replaceAll( "[^\\d]+", "" ) );
maximumMP = StringUtilities.parseInt( matcher.group( 2 ).replaceAll( "<[^>]*>", "" ).replaceAll( "[^\\d]+", "" ) );
}
KoLCharacter.setMP( currentMP, maximumMP, maximumMP );
}
pattern = patterns[ MEAT ];
matcher = pattern == null ? null : pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int availableMeat = StringUtilities.parseInt( matcher.group( 1 ).replaceAll( "<[^>]*>", "" ).replaceAll( "[^\\d]+", "" ) );
KoLCharacter.setAvailableMeat( availableMeat );
}
pattern = patterns[ ADV ];
matcher = pattern == null ? null : pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int oldAdventures = KoLCharacter.getAdventuresLeft();
int newAdventures = StringUtilities.parseInt( matcher.group( 1 ).replaceAll( "<[^>]*>", "" ).replaceAll( "[^\\d]+", "" ) );
ResultProcessor.processAdventuresLeft( newAdventures - oldAdventures );
}
if ( KoLCharacter.getClassType() == KoLCharacter.SEAL_CLUBBER )
{
pattern = Pattern.compile( ">(\\d+) gal.</span>" );
matcher = pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int fury = StringUtilities.parseInt( matcher.group( 1 ) );
KoLCharacter.setFuryNoCheck( fury );
}
else
{
KoLCharacter.setFuryNoCheck( 0 );
}
}
else if ( KoLCharacter.getClassType() == KoLCharacter.SAUCEROR )
{
pattern = Pattern.compile( "auce:(?:</small>)?</td><td align=left><b><font color=black>(?:<span>)?(\\d+)<" );
matcher = pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int soulsauce = StringUtilities.parseInt( matcher.group( 1 ) );
KoLCharacter.setSoulsauce( soulsauce );
}
else
{
KoLCharacter.setSoulsauce( 0 );
}
}
else if ( KoLCharacter.isSneakyPete() )
{
pattern = Pattern.compile( "<b>(\\d+ )?(Love|Hate|Bored)</td>" );
matcher = pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
if ( matcher.group( 2 ).equals( "Love" ) )
{
KoLCharacter.setAudience( StringUtilities.parseInt( matcher.group( 1 ) ) );
}
else if ( matcher.group( 2 ).equals( "Hate" ) )
{
KoLCharacter.setAudience( -StringUtilities.parseInt( matcher.group( 1 ) ) );
}
else if ( matcher.group( 2 ).equals( "Bored" ) )
{
KoLCharacter.setAudience( 0 );
}
}
else
{
KoLCharacter.setAudience( 0 );
}
}
else if ( KoLCharacter.inNoobcore() )
{
pattern = Pattern.compile( "<b>Absorptions:</b> (\\d+) / (\\d+)</span>" );
matcher = pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int absorbs = StringUtilities.parseInt( matcher.group( 1 ) );
KoLCharacter.setAbsorbs( absorbs );
}
}
// Path rather than class restricted matchers
if ( KoLCharacter.inRaincore() )
{
pattern = Pattern.compile( "Thunder:</td><td align=left><b><font color=black>(\\d+) dBs" );
matcher = pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int thunder = StringUtilities.parseInt( matcher.group( 1 ) );
KoLCharacter.setThunder( thunder );
}
else
{
KoLCharacter.setThunder( 0 );
}
pattern = Pattern.compile( "Rain:</td><td align=left><b><font color=black>(\\d+) drops" );
matcher = pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int rain = StringUtilities.parseInt( matcher.group( 1 ) );
KoLCharacter.setRain( rain );
}
else
{
KoLCharacter.setRain( 0 );
}
pattern = Pattern.compile( "Lightning:</td><td align=left><b><font color=black>(\\d+) bolts" );
matcher = pattern.matcher( responseText );
if ( matcher != null && matcher.find() )
{
int lightning = StringUtilities.parseInt( matcher.group( 1 ) );
KoLCharacter.setLightning( lightning );
}
else
{
KoLCharacter.setLightning( 0 );
}
}
}
private static final void handleMindControl( final String text, final Pattern [] patterns )
{
for ( int i = 0; i < patterns.length; ++i )
{
int level = CharPaneRequest.handleMindControl( text, patterns[i] );
if ( level > 0 )
{
KoLCharacter.setMindControlLevel( level );
return;
}
}
KoLCharacter.setMindControlLevel( 0 );
}
private static final Pattern makeMCPattern( final String mcString )
{
return Pattern.compile( mcString + "</a>: ?(?:</td><td>)?<b>(\\d+)</b>" );
}
private static final Pattern [] compactMCPatterns =
{
CharPaneRequest.makeMCPattern( "MC" ),
CharPaneRequest.makeMCPattern( "Radio" ),
CharPaneRequest.makeMCPattern( "AOT5K" ),
CharPaneRequest.makeMCPattern( "HH" ),
};
private static final Pattern [] expandedMCPatterns =
{
CharPaneRequest.makeMCPattern( "Mind Control" ),
CharPaneRequest.makeMCPattern( "Detuned Radio" ),
CharPaneRequest.makeMCPattern( "Annoy-o-Tron 5k" ),
CharPaneRequest.makeMCPattern( "Heartbreaker's" ),
};
private static final int handleMindControl( final String responseText, final Pattern pattern )
{
Matcher matcher = pattern.matcher( responseText );
return matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
}
private static final Pattern makeConsumptionPattern( final String consumptionString )
{
return Pattern.compile( consumptionString + ":</span></td><td(?: align=left)?><b><span class=\"(?:blur.)?\">(\\d+) / (\\d+)</span>" );
}
private static final Pattern [] compactInebrietyPatterns =
{
CharPaneRequest.makeConsumptionPattern( "Drunk" ),
};
private static final Pattern [] expandedInebrietyPatterns =
{
CharPaneRequest.makeConsumptionPattern( "Drunkenness" ),
CharPaneRequest.makeConsumptionPattern( "Inebriety" ),
CharPaneRequest.makeConsumptionPattern( "Temulency" ),
CharPaneRequest.makeConsumptionPattern( "Tipsiness" ),
};
private static final int handleConsumption( final String responseText, final Pattern pattern )
{
Matcher matcher = pattern.matcher( responseText );
return matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
}
private static final void handleInebriety( final String text, final Pattern [] patterns )
{
for ( int i = 0; i < patterns.length; ++i )
{
int level = CharPaneRequest.handleConsumption( text, patterns[i] );
if ( level > 0 )
{
KoLCharacter.setInebriety( level );
return;
}
}
KoLCharacter.setInebriety( 0 );
}
public static final AdventureResult extractEffect( final String responseText, int searchIndex )
{
String effectName = null;
int durationIndex = -1;
if ( CharPaneRequest.compactCharacterPane )
{
int startIndex = responseText.indexOf( "alt=\"", searchIndex ) + 5;
effectName = responseText.substring( startIndex, responseText.indexOf( "\"", startIndex ) );
durationIndex = responseText.indexOf( "<td>(", startIndex ) + 5;
}
else
{
int startIndex = responseText.indexOf( "<font size=2", searchIndex );
startIndex = responseText.indexOf( ">", startIndex ) + 1;
durationIndex = responseText.indexOf( "</font", startIndex );
durationIndex = responseText.lastIndexOf( "(", durationIndex ) + 1;
if ( durationIndex < 0 )
{
return null;
}
effectName = responseText.substring( startIndex, durationIndex - 1 ).trim();
}
searchIndex = responseText.indexOf( "onClick='eff", searchIndex );
searchIndex = responseText.indexOf( "(", searchIndex ) + 1;
String descId = responseText.substring( searchIndex + 1, responseText.indexOf( ")", searchIndex ) - 1 );
String durationString = responseText.substring( durationIndex, responseText.indexOf( ")", durationIndex ) );
int duration;
if ( durationString.equals( "∞" ) )
{
duration = Integer.MAX_VALUE;
}
else if ( durationString.indexOf( "&" ) != -1 || durationString.indexOf( "<" ) != -1 )
{
return null;
}
else
{
duration = StringUtilities.parseInt( durationString );
}
return CharPaneRequest.extractEffect( descId, effectName, duration );
}
public static final AdventureResult extractEffect( final String descId, String effectName, int duration )
{
int effectId = EffectDatabase.getEffectIdFromDescription( descId );
if ( effectId == -1 )
{
effectId = EffectDatabase.learnEffectId( effectName, descId );
}
else
{
effectName = EffectDatabase.getEffectName( effectId );
}
if ( duration == Integer.MAX_VALUE )
{
// Intrinsic effect
}
return EffectPool.get( effectId, duration );
}
private static final void refreshEffects( final String responseText )
{
int searchIndex = 0;
int onClickIndex = 0;
ArrayList<AdventureResult> visibleEffects = new ArrayList<AdventureResult>();
while ( onClickIndex != -1 )
{
onClickIndex = responseText.indexOf( "onClick='eff", onClickIndex + 1 );
if ( onClickIndex == -1 )
{
continue;
}
searchIndex = responseText.lastIndexOf( "<", onClickIndex );
AdventureResult effect = CharPaneRequest.extractEffect( responseText, searchIndex );
if ( effect == null )
{
continue;
}
int currentCount = effect.getCount();
if ( currentCount == 0 )
{
// This is an expired effect. We don't need to
// explicitly remove it from activeEffects,
// since we'll simply not retain it.
continue;
}
int activeCount = effect.getCount( KoLConstants.activeEffects );
if ( currentCount != activeCount )
{
ResultProcessor.processResult( effect.getInstance( currentCount - activeCount ) );
}
visibleEffects.add( effect );
}
KoLConstants.recentEffects.clear();
KoLConstants.activeEffects.clear();
KoLConstants.activeEffects.addAll( visibleEffects );
LockableListFactory.sort( KoLConstants.activeEffects );
CharPaneRequest.startCounters();
}
private static final void startCounters()
{
if ( TurnCounter.isCounting( "Wormwood" ) )
{
return;
}
int absintheCount = CharPaneRequest.ABSINTHE.getCount( KoLConstants.activeEffects );
if ( absintheCount > 8 )
{
TurnCounter.startCounting( absintheCount - 9, "Wormwood loc=151 loc=152 loc=153 place.php?whichplace=wormwood", "tinybottle.gif" );
}
else if ( absintheCount > 4 )
{
TurnCounter.startCounting( absintheCount - 5, "Wormwood loc=151 loc=152 loc=153 place.php?whichplace=wormwood", "tinybottle.gif" );
}
else if ( absintheCount > 0 )
{
TurnCounter.startCounting( absintheCount - 1, "Wormwood loc=151 loc=152 loc=153 place.php?whichplace=wormwood", "tinybottle.gif" );
}
}
private static final Pattern compactLastAdventurePattern =
Pattern.compile( "<td align=right><a onclick=[^<]+ title=\"Last Adventure: ([^\"]+)\" target=mainpane href=\"([^\"]*)\">.*?</a>:</td>" );
private static final Pattern expandedLastAdventurePattern =
Pattern.compile( "<a.*href=\"([^\"]*)\".*>Last Adventure:</a>.*?<a.*?href=\"([^\"]*)\">([^<]*)</a>.*?</table>" );
private static final void setLastAdventure( final String responseText )
{
if ( ChoiceManager.handlingChoice || FightRequest.currentRound != 0 || FightRequest.inMultiFight || FightRequest.choiceFollowsFight )
{
return;
}
String adventureName = null;
String adventureURL = null;
String container = null;
if ( CharPaneRequest.compactCharacterPane )
{
Matcher matcher = CharPaneRequest.compactLastAdventurePattern.matcher( responseText );
if ( matcher.find() )
{
adventureName = matcher.group( 1 );
adventureURL = matcher.group( 2 );
}
}
else
{
Matcher matcher = CharPaneRequest.expandedLastAdventurePattern.matcher( responseText );
if ( matcher.find() )
{
adventureName = matcher.group( 3 );
adventureURL = matcher.group( 2 );
container = matcher.group( 1 );
}
}
if ( adventureName == null || adventureName.equals( "The Naughty Sorceress' Tower" ) )
{
return;
}
CharPaneRequest.setLastAdventure( "", adventureName, adventureURL, container );
}
private static final void setLastAdventure( final String adventureId, final String adventureName, final String adventureURL, final String container )
{
if ( ChoiceManager.handlingChoice || FightRequest.currentRound != 0 || FightRequest.inMultiFight || FightRequest.choiceFollowsFight )
{
return;
}
if ( adventureName == null || adventureName.equals( "The Naughty Sorceress' Tower" ) )
{
return;
}
KoLAdventure adventure = KoLAdventure.setLastAdventure( adventureId, adventureName, adventureURL, container );
if ( KoLmafia.isRefreshing() )
{
KoLAdventure.setNextAdventure( adventure );
}
if ( AdventureSpentDatabase.getNoncombatEncountered() && KoLCharacter.getCurrentRun() > AdventureSpentDatabase.getLastTurnUpdated() )
{
AdventureSpentDatabase.addTurn( KoLAdventure.lastLocationName );
}
AdventureSpentDatabase.setNoncombatEncountered( false );
AdventureSpentDatabase.setLastTurnUpdated( KoLCharacter.getCurrentRun() );
}
private static final Pattern compactFamiliarWeightPattern =
Pattern.compile( "<br>([\\d]+) lb" );
private static final Pattern expandedFamiliarWeightPattern =
Pattern.compile( "<b>([\\d]+)</b> pound" );
private static final Pattern familiarImagePattern =
Pattern.compile( "<a.*?class=\"familiarpick\"><img.*?itemimages/(.*?\\.gif)" );
private static final AdventureResult somePigs = EffectPool.get( EffectPool.SOME_PIGS );
private static final void checkFamiliar( final String responseText )
{
if ( KoLConstants.activeEffects.contains( CharPaneRequest.somePigs ) )
{
KoLCharacter.setFamiliarImage( "somepig.gif" );
return;
}
Pattern pattern = CharPaneRequest.compactCharacterPane ?
CharPaneRequest.compactFamiliarWeightPattern :
CharPaneRequest.expandedFamiliarWeightPattern;
Matcher matcher = pattern.matcher( responseText );
if ( matcher.find() )
{
int weight = StringUtilities.parseInt( matcher.group(1) );
boolean feasted = responseText.contains( "well-fed" );
KoLCharacter.getFamiliar().checkWeight( weight, feasted );
}
pattern = CharPaneRequest.familiarImagePattern;
matcher = pattern.matcher( responseText );
String image = matcher.find() ? new String( matcher.group( 1 ) ) : null;
if ( image != null )
{
if ( image.startsWith( "snow" ) )
{
CharPaneRequest.checkSnowsuit( image );
}
else
{
KoLCharacter.setFamiliarImage( image );
CharPaneRequest.checkMedium( responseText );
CharPaneRequest.checkMiniAdventurer( image );
if ( image.startsWith( "commacha" ) )
{
CharPaneRequest.checkComma( responseText );
}
}
}
}
private static final Pattern compactClancyPattern =
Pattern.compile( "otherimages/clancy_([123])(_att)?.gif.*?L\\. (\\d+)", Pattern.DOTALL );
private static final Pattern expandedClancyPattern =
Pattern.compile( "<b>Clancy</b>.*?Level <b>(\\d+)</b>.*?otherimages/clancy_([123])(_att)?.gif", Pattern.DOTALL );
public static AdventureResult SACKBUT = ItemPool.get( ItemPool.CLANCY_SACKBUT, 1 );
public static AdventureResult CRUMHORN = ItemPool.get( ItemPool.CLANCY_CRUMHORN, 1 );
public static AdventureResult LUTE = ItemPool.get( ItemPool.CLANCY_LUTE, 1 );
private static final void checkClancy( final String responseText )
{
Pattern pattern = CharPaneRequest.compactCharacterPane ?
CharPaneRequest.compactClancyPattern :
CharPaneRequest.expandedClancyPattern;
Matcher clancyMatcher = pattern.matcher( responseText );
if ( clancyMatcher.find() )
{
String level = clancyMatcher.group( CharPaneRequest.compactCharacterPane ? 3 : 1 );
String image = clancyMatcher.group( CharPaneRequest.compactCharacterPane ? 1 : 2 );
boolean att = clancyMatcher.group( CharPaneRequest.compactCharacterPane ? 2 : 3 ) != null;
AdventureResult instrument =
image.equals( "1" ) ? CharPaneRequest.SACKBUT :
image.equals( "2" ) ? CharPaneRequest.CRUMHORN :
image.equals( "3" ) ? CharPaneRequest.LUTE :
null;
KoLCharacter.setClancy( StringUtilities.parseInt( level ), instrument, att );
}
}
private static final Pattern compactServantPattern =
Pattern.compile( "<b>Servant:</b>.*?target=\"mainpane\">(.*?) \\(lvl (\\d+)\\).*?edserv(\\d+).gif", Pattern.DOTALL );
private static final Pattern expandedServantPattern =
Pattern.compile( "<b>Servant:</b>.*?target=\"mainpane\">(.*?) the (\\d+) level.*?edserv(\\d+).gif" , Pattern.DOTALL );
private static final void checkServant( final String responseText )
{
Pattern pattern = CharPaneRequest.compactCharacterPane ?
CharPaneRequest.compactServantPattern :
CharPaneRequest.expandedServantPattern;
Matcher servantMatcher = pattern.matcher( responseText );
if ( servantMatcher.find() )
{
EdServantData.setEdServant( servantMatcher );
}
}
public enum Companion
{
EGGMAN( "Eggman", "jarl_eggman.gif" ),
RADISH( "Radish Horse", "jarl_horse.gif" ),
HIPPO( "Hippotatomous", "jarl_hippo.gif" ),
CREAM( "Cream Puff", "jarl_creampuff.gif" );
private final String name;
private final String image;
private Companion( String name, String image )
{
this.name = name;
this.image = image;
}
@Override
public String toString()
{
return this.name;
}
public String imageName()
{
return this.image;
}
}
private static final void checkCompanion( final String responseText )
{
if ( responseText.contains( "the Eggman" ) )
{
KoLCharacter.setCompanion( Companion.EGGMAN );
}
else if ( responseText.contains( "the Radish Horse" ) )
{
KoLCharacter.setCompanion( Companion.RADISH );
}
else if ( responseText.contains( "the Hippotatomous" ) )
{
KoLCharacter.setCompanion( Companion.HIPPO );
}
else if ( responseText.contains( "the Cream Puff" ) )
{
KoLCharacter.setCompanion( Companion.CREAM );
}
else
{
KoLCharacter.setCompanion( null );
}
}
// <font size=2><b>VYKEA Companion</b></font><br><font size=2><b>ÅVOBÉ</b> the level 5 lamp<br>
private static final Pattern VYKEACompanionPattern =
Pattern.compile( "<b>VYKEA Companion</b></font><br><font size=2>(.*?)<br>", Pattern.DOTALL );
private static final void checkVYKEACompanion( final String responseText )
{
// Since you can't change companions once you have built one,
// no need to parse the charpane if we know the companion.
if ( VYKEACompanionData.currentCompanion() != VYKEACompanionData.NO_COMPANION )
{
return;
}
Pattern pattern = CharPaneRequest.VYKEACompanionPattern;
Matcher matcher = pattern.matcher( responseText );
if ( matcher.find() )
{
VYKEACompanionData.parseCharpaneCompanion( matcher.group( 1 ) );
}
}
private static final Pattern pastaThrallPattern =
Pattern.compile( "desc_guardian.php.*?itemimages/(.*?.gif).*?<b>(.*?)</b>.*?the Lvl. (\\d+) (.*?)</font>", Pattern.DOTALL );
private static final void checkPastaThrall( final String responseText )
{
if ( KoLCharacter.getClassType() != KoLCharacter.PASTAMANCER )
{
return;
}
Pattern pattern = CharPaneRequest.pastaThrallPattern;
Matcher matcher = pattern.matcher( responseText );
if ( matcher.find() )
{
//String image = matcher.group( 1 );
String name = matcher.group( 2 );
String levelString = matcher.group( 3 );
String type = matcher.group( 4 );
PastaThrallData thrall = KoLCharacter.findPastaThrall( type );
if ( thrall != null && thrall != PastaThrallData.NO_THRALL )
{
KoLCharacter.setPastaThrall( thrall );
thrall.update( StringUtilities.parseInt( levelString ), name );
}
}
else
{
KoLCharacter.setPastaThrall( PastaThrallData.NO_THRALL );
}
}
private static final Pattern radSicknessPattern =
Pattern.compile( "Rad(?:iation| Sickness):</td><td align=left><b><font color=black><span alt=\"-(\\d+) to All Stats" );
private static final void checkRadSickness( final String responseText )
{
if ( !KoLCharacter.inNuclearAutumn() )
{
return;
}
Pattern pattern = CharPaneRequest.radSicknessPattern;
Matcher matcher = pattern.matcher( responseText );
if ( matcher.find() )
{
KoLCharacter.setRadSickness( StringUtilities.parseInt( matcher.group( 1 ) ) );
}
else
{
KoLCharacter.setRadSickness( 0 );
}
}
private static final void checkAbsorbs( final String responseText )
{
if ( !KoLCharacter.inNoobcore() )
{
return;
}
TagNode doc;
try
{
doc = cleaner.clean( responseText );
}
catch( IOException e )
{
StaticEntity.printStackTrace( e );
return;
}
Object[] result;
String xpath = "//div[@class='gnoob small']/font/text()";
try
{
result = doc.evaluateXPath( xpath );
}
catch ( XPatherException e )
{
StaticEntity.printStackTrace( e );
return;
}
if ( result.length == 0 )
{
return;
}
ModifierList modList = new ModifierList();
for ( Object res : result )
{
String mod = Modifiers.parseModifier( res.toString() );
if ( mod == null )
{
// this shouldn't happen...
continue;
}
// Split into modifiers as some, like regeneration, get two values from one mod string
ModifierList newModList = Modifiers.splitModifiers( mod );
// Iterate over modifiers
for ( Modifier modifier : newModList )
{
String key = modifier.getName();
String value = modifier.getValue();
int modVal = StringUtilities.parseInt( value );
// If modifier exists in ModList, get modifier value, add to it and replace
if ( modList.containsModifier( key ) )
{
int oldVal = StringUtilities.parseInt( modList.getModifierValue( key ) );
modList.removeModifier( key );
modList.addModifier( key, Integer.toString( oldVal + modVal ) );
}
// Otherwise just add it
else
{
modList.addModifier( modifier );
}
}
}
Modifiers.overrideModifier( "Generated:Enchantments Absorbed", modList.toString() );
}
private static final Pattern commaPattern =
Pattern.compile( "pound (.*?), Chameleon", Pattern.DOTALL );
private static final void checkComma( final String responseText )
{
Pattern pattern = CharPaneRequest.commaPattern;
Matcher commaMatcher = pattern.matcher( responseText );
if ( commaMatcher.find() )
{
String newRace = commaMatcher.group( 1 );
if ( !newRace.equals( Preferences.getString( "commaFamiliar" ) ) )
{
Preferences.setString( "commaFamiliar", commaMatcher.group( 1 ) );
KoLCharacter.recalculateAdjustments();
}
}
else
{
if ( !Preferences.getString( "commaFamiliar" ).equals( "" ) )
{
Preferences.setString( "commaFamiliar", "" );
KoLCharacter.recalculateAdjustments();
}
}
}
private static final Pattern mediumPattern =
Pattern.compile( "images/medium_([0123]).gif", Pattern.DOTALL );
private static final void checkMedium( final String responseText )
{
Pattern pattern = CharPaneRequest.mediumPattern;
Matcher mediumMatcher = pattern.matcher( responseText );
if ( mediumMatcher.find() )
{
int aura = StringUtilities.parseInt( mediumMatcher.group( 1 ) );
FamiliarData fam = KoLCharacter.findFamiliar( FamiliarPool.HAPPY_MEDIUM );
if ( fam == null )
{
// Another familiar has turned into a Happy Medium
return;
}
fam.setCharges( aura );
}
}
public static void checkMiniAdventurer( final String image )
{
if ( image.startsWith( "miniadv" ) )
{
String miniAdvClass = image.substring( 7, 8 );
if ( !miniAdvClass.equals( Preferences.getString( "miniAdvClass" ) ) )
{
Preferences.setString( "miniAdvClass", miniAdvClass );
KoLCharacter.recalculateAdjustments();
}
}
}
private static final Pattern snowsuitPattern =
Pattern.compile( "snowface([1-5]).gif" );
private static final void checkSnowsuit( final String responseText )
{
Matcher matcher = CharPaneRequest.snowsuitPattern.matcher( responseText );
if ( matcher.find() )
{
int id = StringUtilities.parseInt( matcher.group( 1 ) ) - 1;
Preferences.setString( "snowsuit", SnowsuitCommand.DECORATION[ id ][ 0 ] );
}
}
public static final void parseStatus( final JSONObject JSON )
throws JSONException
{
int turnsThisRun = JSON.getInt( "turnsthisrun" );
CharPaneRequest.turnsThisRun = turnsThisRun;
int turnsPlayed = JSON.getInt( "turnsplayed" );
KoLCharacter.setTurnsPlayed( turnsPlayed );
if ( KoLmafia.isRefreshing() )
{
// If we are refreshing status, simply set turns used
KoLCharacter.setCurrentRun( turnsThisRun );
}
else
{
// Otherwise, increment them
int mafiaTurnsThisRun = KoLCharacter.getCurrentRun();
ResultProcessor.processAdventuresUsed( turnsThisRun - mafiaTurnsThisRun );
}
KoLCharacter.setLimitmode( JSON.getString( "limitmode" ) );
JSONObject lastadv = JSON.getJSONObject( "lastadv" );
String adventureId = lastadv.getString( "id" );
String adventureName = lastadv.getString( "name" );
String adventureURL = lastadv.getString( "link" );
String container = lastadv.getString( "container" );
CharPaneRequest.setLastAdventure( adventureId, adventureName, adventureURL, container );
int fury = JSON.getInt( "fury" );
KoLCharacter.setFuryNoCheck( fury );
int soulsauce = JSON.getInt( "soulsauce" );
KoLCharacter.setSoulsauce( soulsauce );
if( KoLCharacter.isSneakyPete() )
{
int audience = 0;
audience += JSON.getInt( "petelove" );
audience -= JSON.getInt( "petehate" );
KoLCharacter.setAudience( audience );
}
int hp = JSON.getInt( "hp" );
int maxhp = JSON.getInt( "maxhp" );
KoLCharacter.setHP( hp, maxhp, maxhp );
if ( KoLCharacter.inZombiecore() )
{
int horde = JSON.getInt( "horde" );
KoLCharacter.setMP( horde, horde, horde );
}
else
{
int mp = JSON.getInt( "mp" );
int maxmp = JSON.getInt( "maxmp" );
KoLCharacter.setMP( mp, maxmp, maxmp );
}
int meat = JSON.getInt( "meat" );
KoLCharacter.setAvailableMeat( meat );
int drunk = JSON.getInt( "drunk" );
KoLCharacter.setInebriety( drunk );
int full = JSON.getInt( "full" );
KoLCharacter.setFullness( full );
int spleen = JSON.getInt( "spleen" );
KoLCharacter.setSpleenUse( spleen );
int adventures = JSON.getInt( "adventures" );
KoLCharacter.setAdventuresLeft( adventures );
int mcd = JSON.getInt( "mcd" );
KoLCharacter.setMindControlLevel( mcd );
int classType = JSON.getInt( "class" );
KoLCharacter.setClassType( classType );
int pvpFights = JSON.getInt( "pvpfights" );
KoLCharacter.setAttacksLeft( pvpFights );
CharPaneRequest.refreshEffects( JSON );
boolean hardcore = JSON.getInt( "hardcore" ) == 1;
KoLCharacter.setHardcore( hardcore );
//boolean casual = JSON.getInt( "casual" ) == 1;
int roninLeft = JSON.getInt( "roninleft" );
if ( KoLCharacter.inRaincore() )
{
int thunder = JSON.getInt( "thunder" );
KoLCharacter.setThunder( thunder );
int rain = JSON.getInt( "rain" );
KoLCharacter.setRain( rain );
int lightning = JSON.getInt( "lightning" );
KoLCharacter.setLightning( lightning );
}
// *** Assume that roninleft always equals 0 if casual
KoLCharacter.setRonin( roninLeft > 0 );
CharPaneRequest.setInteraction();
if ( Limitmode.limitFamiliars() )
{
// No familiar
}
else if ( KoLCharacter.inAxecore() )
{
int level = JSON.getInt( "clancy_level" );
int itype = JSON.getInt( "clancy_instrument" );
boolean att = JSON.getBoolean( "clancy_wantsattention" );
AdventureResult instrument =
itype == 1 ? CharPaneRequest.SACKBUT :
itype == 2 ? CharPaneRequest.CRUMHORN :
itype == 3 ? CharPaneRequest.LUTE :
null;
KoLCharacter.setClancy( level, instrument, att );
}
else if ( KoLCharacter.isJarlsberg() )
{
if ( JSON.has( "jarlcompanion" ) )
{
int companion = JSON.getInt( "jarlcompanion" );
switch ( companion )
{
case 1:
KoLCharacter.setCompanion( Companion.EGGMAN );
break;
case 2:
KoLCharacter.setCompanion( Companion.RADISH );
break;
case 3:
KoLCharacter.setCompanion( Companion.HIPPO );
break;
case 4:
KoLCharacter.setCompanion( Companion.CREAM );
break;
}
}
else
{
KoLCharacter.setCompanion( null );
}
}
else
{
int famId = JSON.getInt( "familiar" );
int famExp = JSON.getInt( "familiarexp" );
FamiliarData familiar = FamiliarData.registerFamiliar( famId, famExp );
KoLCharacter.setFamiliar( familiar );
String image = JSON.getString( "familiarpic" );
KoLCharacter.setFamiliarImage( image.equals( "" ) ? null : image + ".gif" );
int weight = JSON.getInt( "famlevel" );
boolean feasted = JSON.getInt( "familiar_wellfed" ) == 1;
familiar.checkWeight( weight, feasted );
// Set charges from the Medium's image
if ( famId == FamiliarPool.HAPPY_MEDIUM )
{
int aura = StringUtilities.parseInt( image.substring( 7, 8 ) );
FamiliarData medium = KoLCharacter.findFamiliar( FamiliarPool.HAPPY_MEDIUM );
medium.setCharges( aura );
}
}
int thrallId = JSON.getInt( "pastathrall" );
int thrallLevel = JSON.getInt( "pastathralllevel" );
PastaThrallData thrall = KoLCharacter.findPastaThrall( thrallId );
if ( thrall != null )
{
KoLCharacter.setPastaThrall( thrall );
if ( thrall != PastaThrallData.NO_THRALL )
{
thrall.update( thrallLevel, null );
}
}
if ( KoLCharacter.inNuclearAutumn() )
{
if ( JSON.has( "radsickness" ) )
{
int rads = JSON.getInt( "radsickness" );
KoLCharacter.setRadSickness( rads );
}
else
{
KoLCharacter.setRadSickness( 0 );
}
}
}
private static final void refreshEffects( final JSONObject JSON )
throws JSONException
{
ArrayList<AdventureResult> visibleEffects = new ArrayList<AdventureResult>();
Object o = JSON.get( "effects" );
if ( o instanceof JSONObject )
{
// KoL returns an empty JSON array if there are no effects
JSONObject effects = (JSONObject) o;
Iterator keys = effects.keys();
while ( keys.hasNext() )
{
String descId = (String) keys.next();
JSONArray data = effects.getJSONArray( descId );
String effectName = data.getString( 0 );
int count = data.getInt( 1 );
AdventureResult effect = CharPaneRequest.extractEffect( descId, effectName, count );
if ( effect != null )
{
visibleEffects.add( effect );
}
}
}
o = JSON.get( "intrinsics" );
if ( o instanceof JSONObject )
{
JSONObject intrinsics = (JSONObject) o;
Iterator keys = intrinsics.keys();
while ( keys.hasNext() )
{
String descId = (String) keys.next();
JSONArray data = intrinsics.getJSONArray( descId );
String effectName = data.getString( 0 );
AdventureResult effect = CharPaneRequest.extractEffect( descId, effectName, Integer.MAX_VALUE );
if ( effect != null )
{
visibleEffects.add( effect );
}
}
}
KoLConstants.recentEffects.clear();
KoLConstants.activeEffects.clear();
KoLConstants.activeEffects.addAll( visibleEffects );
LockableListFactory.sort( KoLConstants.activeEffects );
// If we are Absinthe Minded, start absinthe counters
CharPaneRequest.startCounters();
// Do this now so that familiar weight effects are accounted for
KoLCharacter.recalculateAdjustments();
}
}