/**
* 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.session;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.kolmafia.FamiliarData;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.listener.PreferenceListenerRegistry;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.pages.PageRegistry;
import net.sourceforge.kolmafia.persistence.ConcoctionDatabase;
import net.sourceforge.kolmafia.persistence.ItemDatabase;
import net.sourceforge.kolmafia.persistence.SkillDatabase;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.AWOLQuartermasterRequest;
import net.sourceforge.kolmafia.request.AccountRequest;
import net.sourceforge.kolmafia.request.AltarOfBonesRequest;
import net.sourceforge.kolmafia.request.AltarOfLiteracyRequest;
import net.sourceforge.kolmafia.request.ApiRequest;
import net.sourceforge.kolmafia.request.AscensionHistoryRequest;
import net.sourceforge.kolmafia.request.AutoMallRequest;
import net.sourceforge.kolmafia.request.AutoSellRequest;
import net.sourceforge.kolmafia.request.BasementRequest;
import net.sourceforge.kolmafia.request.BeerPongRequest;
import net.sourceforge.kolmafia.request.BigBrotherRequest;
import net.sourceforge.kolmafia.request.BountyHunterHunterRequest;
import net.sourceforge.kolmafia.request.BURTRequest;
import net.sourceforge.kolmafia.request.CakeArenaRequest;
import net.sourceforge.kolmafia.request.CampgroundRequest;
import net.sourceforge.kolmafia.request.CharSheetRequest;
import net.sourceforge.kolmafia.request.ChezSnooteeRequest;
import net.sourceforge.kolmafia.request.ClanHallRequest;
import net.sourceforge.kolmafia.request.ClanLoungeRequest;
import net.sourceforge.kolmafia.request.ClanLoungeSwimmingPoolRequest;
import net.sourceforge.kolmafia.request.ClanRumpusRequest;
import net.sourceforge.kolmafia.request.ClanStashRequest;
import net.sourceforge.kolmafia.request.ClosetRequest;
import net.sourceforge.kolmafia.request.ContactListRequest;
import net.sourceforge.kolmafia.request.CreateItemRequest;
import net.sourceforge.kolmafia.request.Crimbo09Request;
import net.sourceforge.kolmafia.request.Crimbo10Request;
import net.sourceforge.kolmafia.request.Crimbo11Request;
import net.sourceforge.kolmafia.request.CurseRequest;
import net.sourceforge.kolmafia.request.CustomOutfitRequest;
import net.sourceforge.kolmafia.request.DigRequest;
import net.sourceforge.kolmafia.request.DisplayCaseRequest;
import net.sourceforge.kolmafia.request.DreadsylvaniaRequest;
import net.sourceforge.kolmafia.request.DwarfContraptionRequest;
import net.sourceforge.kolmafia.request.DwarfFactoryRequest;
import net.sourceforge.kolmafia.request.EquipmentRequest;
import net.sourceforge.kolmafia.request.FamiliarRequest;
import net.sourceforge.kolmafia.request.FriarRequest;
import net.sourceforge.kolmafia.request.FudgeWandRequest;
import net.sourceforge.kolmafia.request.GameShoppeRequest;
import net.sourceforge.kolmafia.request.GenericRequest;
import net.sourceforge.kolmafia.request.GnomeTinkerRequest;
import net.sourceforge.kolmafia.request.GourdRequest;
import net.sourceforge.kolmafia.request.GuildRequest;
import net.sourceforge.kolmafia.request.HermitRequest;
import net.sourceforge.kolmafia.request.HeyDezeRequest;
import net.sourceforge.kolmafia.request.IslandRequest;
import net.sourceforge.kolmafia.request.LeafletRequest;
import net.sourceforge.kolmafia.request.MallPurchaseRequest;
import net.sourceforge.kolmafia.request.ManageStoreRequest;
import net.sourceforge.kolmafia.request.MicroBreweryRequest;
import net.sourceforge.kolmafia.request.MomRequest;
import net.sourceforge.kolmafia.request.MoneyMakingGameRequest;
import net.sourceforge.kolmafia.request.MonsterManuelRequest;
import net.sourceforge.kolmafia.request.MrStoreRequest;
import net.sourceforge.kolmafia.request.MushroomRequest;
import net.sourceforge.kolmafia.request.NPCPurchaseRequest;
import net.sourceforge.kolmafia.request.NemesisRequest;
import net.sourceforge.kolmafia.request.PandamoniumRequest;
import net.sourceforge.kolmafia.request.PeeVPeeRequest;
import net.sourceforge.kolmafia.request.PhineasRequest;
import net.sourceforge.kolmafia.request.PlaceRequest;
import net.sourceforge.kolmafia.request.QuestLogRequest;
import net.sourceforge.kolmafia.request.RaffleRequest;
import net.sourceforge.kolmafia.request.SeaMerkinRequest;
import net.sourceforge.kolmafia.request.SendGiftRequest;
import net.sourceforge.kolmafia.request.SendMailRequest;
import net.sourceforge.kolmafia.request.ShowClanRequest;
import net.sourceforge.kolmafia.request.ShrineRequest;
import net.sourceforge.kolmafia.request.SkateParkRequest;
import net.sourceforge.kolmafia.request.SpaaaceRequest;
import net.sourceforge.kolmafia.request.StorageRequest;
import net.sourceforge.kolmafia.request.SuburbanDisRequest;
import net.sourceforge.kolmafia.request.SummoningChamberRequest;
import net.sourceforge.kolmafia.request.SushiRequest;
import net.sourceforge.kolmafia.request.TavernRequest;
import net.sourceforge.kolmafia.request.TravelingTraderRequest;
import net.sourceforge.kolmafia.request.TrendyRequest;
import net.sourceforge.kolmafia.request.TrophyHutRequest;
import net.sourceforge.kolmafia.request.UseItemRequest;
import net.sourceforge.kolmafia.request.UseSkillRequest;
import net.sourceforge.kolmafia.request.VolcanoIslandRequest;
import net.sourceforge.kolmafia.request.VolcanoMazeRequest;
import net.sourceforge.kolmafia.request.WaxGlobRequest;
import net.sourceforge.kolmafia.request.WitchessRequest;
import net.sourceforge.kolmafia.request.ZapRequest;
import net.sourceforge.kolmafia.utilities.LockableListFactory;
import net.sourceforge.kolmafia.utilities.StringUtilities;
import net.sourceforge.kolmafia.webui.DiscoCombatHelper;
import net.sourceforge.kolmafia.webui.MineDecorator;
public class ResponseTextParser
{
private static final Pattern NEWSKILL1_PATTERN =
Pattern.compile( "<td>You (have learned|learn) a new skill: <b>(.*?)</b>" );
private static final Pattern NEWSKILL2_PATTERN = Pattern.compile( "whichskill=(\\d+)" );
// You acquire a skill: </td><td><img src="http://images.kingdomofloathing.com/itemimages/wosp_stink.gif" onClick='javascript:poop("desc_skill.php?whichskill=67&self=true","skill", 350, 300)' width=30 height=30></td><td><b><a onClick='javascript:poop("desc_skill.php?whichskill=67&self=true","skill", 350, 300)'>Stinkpalm</a></b>
private static final Pattern NEWSKILL3_PATTERN =
Pattern.compile( "You (?:gain|acquire) a skill:.*?<[bB]>(?:<a[^>]*>)?(.*?)(?:</a>)?</[bB]>" );
private static final Pattern DESCITEM_PATTERN = Pattern.compile( "whichitem=(\\d+)" );
private static final Pattern DESCEFFECT_PATTERN = Pattern.compile( "whicheffect=([0-9a-zA-Z]+)" );
public static boolean hasResult( final String location )
{
if ( location == null )
{
return false;
}
int queryStringBegin = location.indexOf( '?' );
String path = location;
String queryString = "";
if ( queryStringBegin != -1 )
{
path = location.substring( 0, queryStringBegin );
queryString = location.substring( queryStringBegin + 1 );
}
if ( !PageRegistry.isGameAction( path, queryString ) )
{
return false;
}
if ( location.startsWith( "lchat.php" ) ||
location.startsWith( "mchat.php" ) ||
location.startsWith( "newchatmessages.php" ) ||
location.startsWith( "submitnewchat.php" ) )
{
return false;
}
if ( location.startsWith( "showplayer.php" ) )
{
// We want to register new items from Equipment and Familiar
return true;
}
if ( location.startsWith( "displaycollection.php" ) )
{
// We want to register new items in display cases
return true;
}
if ( location.endsWith( "menu.php" ) ||
location.startsWith( "actionbar" ) )
{
return false;
}
if ( location.startsWith( "api.php" ) ||
location.startsWith( "game.php" ) ||
location.startsWith( "desc" ) ||
location.startsWith( "quest" ) ||
location.startsWith( "static" ) )
{
return false;
}
if ( location.startsWith( "makeoffer" ) ||
location.startsWith( "message" ) ||
location.startsWith( "display" ) ||
location.startsWith( "managecollectionshelves" ) ||
location.startsWith( "search" ) ||
location.startsWith( "show" ) )
{
return false;
}
if ( location.startsWith( "valhalla" ) )
{
return false;
}
if ( location.startsWith( "clan" ) )
{
return location.startsWith( "clan_stash" ) ||
location.startsWith( "clan_hall" ) ||
location.startsWith( "clan_rumpus" ) ||
location.startsWith( "clan_viplounge" ) ||
location.startsWith( "clan_hobopolis" ) ||
location.startsWith( "clan_slimetube" ) ||
location.startsWith( "clan_dreadsylvania" );
}
if ( location.startsWith( "login.php" ) ||
location.startsWith( "logout.php" ) )
{
return false;
}
if ( location.startsWith( "dev" ) ||
location.startsWith( "ilovebugs.php" ) )
{
return false;
}
return true;
}
public static final void externalUpdate( final GenericRequest request )
{
ResponseTextParser.externalUpdate( request.getURLString(), request.responseText );
}
public static final void externalUpdate( final String location, final String responseText )
{
if ( responseText == null || responseText.length() == 0 )
{
return;
}
if ( location.startsWith( "account.php" ) )
{
AccountRequest.parseAccountData( location, responseText );
}
else if ( location.startsWith( "account_contactlist.php" ) )
{
ContactListRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "account_manageoutfits.php" ) )
{
CustomOutfitRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "adventure.php" ) )
{
SeaMerkinRequest.parseColosseumResponse( location, responseText );
}
else if ( location.startsWith( "api.php" ) )
{
ApiRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "ascensionhistory.php" ) )
{
AscensionHistoryRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "arena.php" ) )
{
CakeArenaRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "backoffice.php" ) )
{
ManageStoreRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "basement.php" ) )
{
BasementRequest.checkBasement( responseText );
}
else if ( location.startsWith( "bedazzle.php" ) )
{
EquipmentRequest.parseBedazzlements( responseText );
}
else if ( location.startsWith( "beerpong.php" ) )
{
BeerPongRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "bet.php" ) )
{
MoneyMakingGameRequest.parseResponse( location, responseText, false );
}
else if ( location.startsWith( "bigisland.php" ) || location.startsWith( "postwarisland.php" ) )
{
IslandRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "bone_altar.php" ) )
{
AltarOfBonesRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "bounty.php" ) )
{
BountyHunterHunterRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "campground.php" ) )
{
CampgroundRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "cafe.php" ) )
{
ChezSnooteeRequest.parseResponse( location, responseText );
MicroBreweryRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "cave.php" ) )
{
NemesisRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "charsheet.php" ) && !location.contains( "ajax=1" ) )
{
CharSheetRequest.parseStatus( responseText );
}
else if ( location.startsWith( "choice.php" ) )
{
if ( location.contains( "whichchoice=562" ) )
{
FudgeWandRequest.parseResponse( location, responseText );
}
else if ( location.contains( "whichchoice=585" ) )
{
ClanLoungeSwimmingPoolRequest.parseResponse( location, responseText );
}
else if ( location.contains( "whichchoice=922" ) )
{
SummoningChamberRequest.parseResponse( location, responseText );
}
else if ( location.contains( "whichchoice=1218" ) )
{
WaxGlobRequest.parseResponse( location, responseText );
}
}
else if ( location.startsWith( "clan_hall.php" ) )
{
ClanHallRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "clan_rumpus.php" ) )
{
ClanRumpusRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "clan_stash.php" ) )
{
ClanStashRequest.parseTransfer( location, responseText );
}
else if ( location.startsWith( "clan_dreadsylvania.php" ) )
{
DreadsylvaniaRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "clan_viplounge.php" ) )
{
ClanLoungeRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "closet.php" ) || location.startsWith( "fillcloset.php" ) )
{
ClosetRequest.parseTransfer( location, responseText );
}
else if ( location.startsWith( "craft.php" ) )
{
CreateItemRequest.parseCrafting( location, responseText );
}
else if ( location.startsWith( "crimbo09.php" ) )
{
Crimbo09Request.parseResponse( location, responseText );
}
else if ( location.startsWith( "crimbo10.php" ) )
{
Crimbo10Request.parseResponse( location, responseText );
}
else if ( location.startsWith( "crimbo11.php" ) )
{
Crimbo11Request.parseResponse( location, responseText );
}
else if ( location.startsWith( "curse.php" ) )
{
CurseRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "da.php" ) )
{
ShrineRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "desc_skill.php" ) && location.contains( "self=true" ) )
{
Matcher m = ResponseTextParser.NEWSKILL2_PATTERN.matcher( location );
if ( m.find() )
{
int skill = StringUtilities.parseInt( m.group( 1 ) );
ConsequenceManager.parseSkillDesc( skill, responseText );
}
}
else if ( location.startsWith( "desc_item.php" ) && !location.contains( "otherplayer=" ) )
{
Matcher m = ResponseTextParser.DESCITEM_PATTERN.matcher( location );
if ( m.find() )
{
String descid = m.group( 1 );
ConsequenceManager.parseItemDesc( descid, responseText );
int itemId = ItemDatabase.getItemIdFromDescription( descid );
if ( itemId == ItemPool.YEARBOOK_CAMERA )
{
ItemDatabase.parseYearbookCamera( responseText );
}
}
}
else if ( location.startsWith( "desc_effect.php" ) )
{
Matcher m = ResponseTextParser.DESCEFFECT_PATTERN.matcher( location );
if ( m.find() )
{
ConsequenceManager.parseEffectDesc( m.group( 1 ), responseText );
}
}
else if ( location.startsWith( "diary.php" ) )
{
UseItemRequest.handleDiary( responseText );
}
else if ( location.startsWith( "dig.php" ) )
{
DigRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "dwarfcontraption.php" ) )
{
DwarfContraptionRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "dwarffactory.php" ) )
{
DwarfFactoryRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "familiar.php" ) )
{
FamiliarRequest.parseResponse( location, responseText );
if ( !location.contains( "ajax=1" ) )
{
FamiliarData.registerFamiliarData( responseText );
}
}
else if ( location.startsWith( "familiarbinger.php" ) )
{
UseItemRequest.parseBinge( location, responseText );
}
else if ( location.startsWith( "gamestore.php" ) )
{
GameShoppeRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "guild.php" ) )
{
GuildRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "hermit.php" ) )
{
HermitRequest.parseHermitTrade( location, responseText );
}
else if ( location.startsWith( "heydeze.php" ) )
{
HeyDezeRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "friars.php" ) )
{
FriarRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "gamestore" ) )
{
GameShoppeRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "gnomes.php" ) )
{
GnomeTinkerRequest.parseCreation( location, responseText );
}
// Keep your current equipment and familiars updated, if you
// visit the appropriate pages.
else if ( location.startsWith( "inventory.php" ) )
{
// If KoL is showing us our current equipment, parse it.
if ( location.contains( "which=2" ) || location.contains( "curequip=1" ) )
{
EquipmentRequest.parseEquipment( location, responseText );
// Slimeling binge requests come here, too
if ( location.contains( "action=slime" ) )
{
UseItemRequest.parseBinge( location, responseText );
}
// Certain requests, like inserting cards into
// an El Vibrato helmet, have a usage message,
// not an equipment page. Check for that, too.
else
{
UseItemRequest.parseConsumption( responseText, false );
}
}
// If there is a consumption message, parse it
else if ( location.contains( "action=message" ) )
{
UseItemRequest.parseConsumption( responseText, false );
AWOLQuartermasterRequest.parseResponse( location, responseText );
BURTRequest.parseResponse( location, responseText );
}
// If there is a bricko message, parse it
else if ( location.contains( "action=breakbricko" ) )
{
UseItemRequest.parseBricko( responseText );
}
// If there is a binge message, parse it
else if ( location.contains( "action=ghost" ) || location.contains( "action=hobo" ) ||
location.contains( "action=slime" ) || location.contains( "action=candy" ) )
{
UseItemRequest.parseBinge( location, responseText );
}
// Robortender consumption
else if ( location.contains( "action=robooze" ) )
{
UseItemRequest.parseRobortenderBinge( location, responseText );
}
// If there is an absorb message, parse it
else if ( location.contains( "absorb=" ) )
{
UseItemRequest.parseAbsorb( location, responseText );
}
// Closet transfers can come via inventory.php
else if ( location.contains( "action=closetpush" ) || location.contains( "action=closetpull" ) )
{
ClosetRequest.parseTransfer( location, responseText );
}
// Emptying storage can come via inventory.php
else if ( location.contains( "action=pullall" ) )
{
StorageRequest.parseTransfer( location, responseText );
}
}
else if ( location.startsWith( "inv_equip.php" ) && location.contains( "ajax=1" ) )
{
// If we are changing equipment via a chat command,
// try to deduce what changed.
EquipmentRequest.parseEquipmentChange( location, responseText );
}
else if ( ( location.startsWith( "inv_eat.php" ) ||
location.startsWith( "inv_booze.php" ) ||
location.startsWith( "inv_spleen.php" ) ||
location.startsWith( "inv_use.php" ) ||
location.startsWith( "inv_familiar.php" ) )
&& location.contains( "whichitem" ) )
{
UseItemRequest.parseConsumption( responseText, false );
}
else if ( location.startsWith( "knoll_mushrooms.php" ) )
{
MushroomRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "leaflet.php" ) )
{
LeafletRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "mallstore.php" ) )
{
MallPurchaseRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "managecollection.php" ) )
{
DisplayCaseRequest.parseDisplayTransfer( location, responseText );
}
else if ( location.startsWith( "managecollectionshelves.php" ) )
{
DisplayCaseRequest.parseDisplayArrangement( location, responseText );
}
else if ( location.startsWith( "managestore.php" ) )
{
AutoMallRequest.parseTransfer( location, responseText );
}
else if ( location.startsWith( "mining.php" ) )
{
MineDecorator.parseResponse( location, responseText );
}
else if ( location.startsWith( "monkeycastle.php" ) )
{
if ( location.contains( "who=2" ) || location.contains( "action=buyitem" ) )
{
BigBrotherRequest.parseResponse( location, responseText );
}
else if ( location.contains( "who=4" ) )
{
MomRequest.parseResponse( location, responseText );
}
}
else if ( location.startsWith( "mrstore.php" ) )
{
MrStoreRequest.parseResponse( location, responseText );
}
else if ( ( location.startsWith( "multiuse.php" ) || location.startsWith( "skills.php" ) ) && location.contains( "useitem" ) )
{
UseItemRequest.parseConsumption( responseText, false );
}
else if ( location.startsWith( "pandamonium.php" ) )
{
PandamoniumRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "peevpee.php" ) )
{
PeeVPeeRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "place.php" ) )
{
PlaceRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "questlog.php" ) )
{
MonsterManuelRequest.parseResponse( location, responseText );
QuestLogRequest.registerQuests( true, location, responseText );
}
else if ( location.startsWith( "raffle.php" ) )
{
RaffleRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "runskillz.php" ) || location.startsWith( "skillz.php" ) )
{
UseSkillRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "sea_merkin.php" ) )
{
SeaMerkinRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "sea_skatepark.php" ) )
{
SkateParkRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "sellstuff.php" ) )
{
AutoSellRequest.parseCompactAutoSell( location, responseText );
}
else if ( location.startsWith( "sellstuff_ugly.php" ) )
{
AutoSellRequest.parseDetailedAutoSell( location, responseText );
}
else if ( location.startsWith( "sendmessage.php" ) )
{
SendMailRequest.parseTransfer( location, responseText );
}
else if ( location.startsWith( "shop.php" ) )
{
NPCPurchaseRequest.parseShopResponse( location, responseText );
}
else if ( location.startsWith( "showclan.php" ) )
{
ShowClanRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "skills.php" ) )
{
if ( location.contains( "action=useditem" ) )
{
UseItemRequest.parseConsumption( responseText, false );
}
}
else if ( location.startsWith( "spaaace.php" ) )
{
SpaaaceRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "storage.php" ) )
{
StorageRequest.parseTransfer( location, responseText );
}
else if ( location.startsWith( "suburbandis.php" ) )
{
SuburbanDisRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "sushi.php" ) )
{
SushiRequest.parseConsumption( location, responseText, true );
}
else if ( location.startsWith( "tavern.php" ) )
{
TavernRequest.parseResponse( location, responseText );
}
if ( location.startsWith( "tiles.php" ) )
{
DvorakManager.parseResponse( location, responseText );
}
else if ( location.startsWith( "topmenu.php" ) )
{
if ( KoLCharacter.getLimitmode() == Limitmode.BATMAN )
{
BatManager.parseTopMenu( responseText );
}
}
else if ( location.startsWith( "town_altar.php" ) )
{
AltarOfLiteracyRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "town_right.php" ) )
{
GourdRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "town_sendgift.php" ) )
{
SendGiftRequest.parseTransfer( location, responseText );
}
else if ( location.startsWith( "traveler.php" ) )
{
TravelingTraderRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "trophy.php" ) )
{
TrophyHutRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "typeii.php" ) )
{
TrendyRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "volcanoisland.php" ) )
{
PhineasRequest.parseResponse( location, responseText );
VolcanoIslandRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "volcanomaze.php" ) )
{
VolcanoMazeRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "wand.php" ) )
{
ZapRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "witchess.php" ) )
{
WitchessRequest.parseResponse( location, responseText );
}
else if ( location.startsWith( "crypt.php" ) )
{
// Check if crypt areas have unexpectedly vanished and correct if so
if ( !responseText.contains( "The Defiled Alcove" ) && Preferences.getInteger( "cyrptAlcoveEvilness" ) > 0 ||
!responseText.contains( "The Defiled Cranny" ) && Preferences.getInteger( "cyrptCrannyEvilness" ) > 0 ||
!responseText.contains( "The Defiled Niche" ) && Preferences.getInteger( "cyrptNicheEvilness" ) > 0 ||
!responseText.contains( "The Defiled Nook" ) && Preferences.getInteger( "cyrptNookEvilness" ) > 0 )
{
if ( InventoryManager.hasItem( ItemPool.EVILOMETER ) )
{
RequestThread.postRequest( UseItemRequest.getInstance( ItemPool.EVILOMETER ) );
}
else
{
// Must have completed quest and already used and lost Evilometer
Preferences.setInteger( "cyrptAlcoveEvilness", 0 );
Preferences.setInteger( "cyrptCrannyEvilness", 0 );
Preferences.setInteger( "cyrptNicheEvilness", 0 );
Preferences.setInteger( "cyrptNookEvilness", 0 );
Preferences.setInteger( "cyrptTotalEvilness", 0 );
}
}
}
// You can learn a skill on many pages.
ResponseTextParser.learnSkill( location, responseText );
// Currently, required recipes can only be learned via using an
// item, but that's probably not guaranteed to be true forever.
// Update: you can now learn them from the April Shower
ResponseTextParser.learnRecipe( location, responseText );
}
private static final Pattern DIV_LINK_PATTERN = Pattern.compile( "<div id=([^ ]+)[^>]*><a .*?</a></div>", Pattern.DOTALL );
public static String parseDivLabel( final String label, final String responseText )
{
Matcher matcher = ResponseTextParser.DIV_LINK_PATTERN.matcher( responseText );
while ( matcher.find() )
{
if ( matcher.group( 1 ).equals( label ) )
{
return parseDivLabel( matcher.group( 0 ) );
}
}
return "";
}
// <img src="http://images.kingdomofloathing.com/otherimages/zonefont/percent.gif" height="10" border="0" style="margin-right: 4px"/>
private static final Pattern DIV_CHAR_PATTERN = Pattern.compile( "otherimages/zonefont/(.*?)\\.gif" );
public static String parseDivLabel( final String divText )
{
StringBuilder string = new StringBuilder();
Matcher matcher = ResponseTextParser.DIV_CHAR_PATTERN.matcher( divText );
while ( matcher.find() )
{
String c = matcher.group( 1 );
if ( c.length() == 1 )
{
string.append( c.charAt( 0 ) );
}
else if ( c.equals( "lparen" ) )
{
string.append( "(" );
}
else if ( c.equals( "percent" ) )
{
string.append( "%" );
}
else if ( c.equals( "rparen" ) )
{
string.append( ")" );
}
}
return string.toString();
}
private static final Pattern [] RECIPE_PATTERNS =
{
Pattern.compile( "You learn to .*?craft.*? a new item:.*?<b>(.*?)</b>" ),
Pattern.compile( "You (?:have|just) .*?discovered.*? a new recipe.*?<b>(.*?)</b>" )
};
public static void learnRecipe( String location, String responseText )
{
if ( !ResponseTextParser.hasResult( location ) )
{
return;
}
String itemName = null;
for ( int i = 0; i < RECIPE_PATTERNS.length; ++i )
{
Matcher matcher = RECIPE_PATTERNS[i].matcher( responseText );
if ( matcher.find() )
{
itemName = matcher.group( 1 );
break;
}
}
if ( itemName == null )
{
return;
}
int id = ItemDatabase.getItemId( itemName, 1, false );
if ( id <= 0 )
{
return;
}
String message = "Learned recipe: " + itemName + " (" + id + ")";
RequestLogger.printLine( message );
RequestLogger.updateSessionLog( message );
Preferences.setBoolean( "unknownRecipe" + id, false );
ConcoctionDatabase.setRefreshNeeded( false );
}
public static void learnSkill( final String location, final String responseText )
{
if ( !ResponseTextParser.hasResult( location ) )
{
return;
}
// Don't parse skill acquisition via item use here, since
// UseItemRequest will detect it.
// Don't parse steel margarita/lasagna here, either.
if ( location.startsWith( "inv_use.php" ) ||
location.startsWith( "inv_eat.php" ) ||
location.startsWith( "inv_booze.php" ) ||
location.startsWith( "inv_spleen.php" ) ||
location.startsWith( "showplayer.php" ) )
{
return;
}
// Unfortunately, if you learn a new skill from Frank
// the Regnaissance Gnome at the Gnomish Gnomads
// Camp, it doesn't tell you the name of the skill.
// It simply says: "You leargn a new skill. Whee!"
if ( responseText.contains( "You leargn a new skill." ) )
{
Matcher matcher = ResponseTextParser.NEWSKILL2_PATTERN.matcher( location );
if ( matcher.find() )
{
int skillId = StringUtilities.parseInt( matcher.group( 1 ) );
String skillName = SkillDatabase.getSkillName( skillId );
ResponseTextParser.learnSkill( skillName );
return;
}
}
ResponseTextParser.learnSkillFromResponse( responseText );
}
public static void learnSkillFromResponse( final String responseText )
{
boolean skillFound = false;
Matcher matcher = ResponseTextParser.NEWSKILL1_PATTERN.matcher( responseText );
while ( matcher.find() )
{
ResponseTextParser.learnSkill( matcher.group( 2 ) );
skillFound = true;
}
if ( skillFound )
{
return;
}
matcher = ResponseTextParser.NEWSKILL3_PATTERN.matcher( responseText );
while ( matcher.find() )
{
ResponseTextParser.learnSkill( matcher.group( 1 ) );
skillFound = true;
}
if ( skillFound )
{
return;
}
}
public static final void learnSkill( final String skillName )
{
// The following skills are found in battle and result in
// losing an item from inventory.
if ( skillName.equals( "Snarl of the Timberwolf" ) )
{
if ( InventoryManager.hasItem( ItemPool.TATTERED_WOLF_STANDARD ) )
{
ResultProcessor.processItem( ItemPool.TATTERED_WOLF_STANDARD, -1 );
}
}
else if ( skillName.equals( "Spectral Snapper" ) )
{
if ( InventoryManager.hasItem( ItemPool.TATTERED_SNAKE_STANDARD ) )
{
ResultProcessor.processItem( ItemPool.TATTERED_SNAKE_STANDARD, -1 );
}
}
else if ( skillName.equals( "Scarysauce" ) || skillName.equals( "Fearful Fettucini" ) )
{
if ( InventoryManager.hasItem( ItemPool.ENGLISH_TO_A_F_U_E_DICTIONARY ) )
{
ResultProcessor.processItem( ItemPool.ENGLISH_TO_A_F_U_E_DICTIONARY, -1 );
}
}
else if ( skillName.equals( "Tango of Terror" ) || skillName.equals( "Dirge of Dreadfulness" ) )
{
if ( InventoryManager.hasItem( ItemPool.BIZARRE_ILLEGIBLE_SHEET_MUSIC ) )
{
ResultProcessor.processItem( ItemPool.BIZARRE_ILLEGIBLE_SHEET_MUSIC, -1 );
}
}
else if ( skillName.equals( "Belch The Rainbow" ) )
{
Preferences.increment( "skillLevel117", 1, 11, false );
}
else if ( skillName.equals( "Toggle Optimality" ) )
{
Preferences.increment( "skillLevel7254", 1 );
}
else if ( skillName.equals( "Bear Essence" ) )
{
Preferences.increment( "skillLevel134", 1 );
}
else if ( skillName.equals( "Calculate the Universe" ) )
{
Preferences.increment( "skillLevel144" );
}
else if ( KoLCharacter.inNuclearAutumn() )
{
if ( skillName.equals( "Boiling Tear Ducts" ) ||
skillName.equals( "Projectile Salivary Glands" ) ||
skillName.equals( "Translucent Skin" ) ||
skillName.equals( "Skunk Glands" ) ||
skillName.equals( "Throat Refrigerant" ) ||
skillName.equals( "Internal Soda Machine" ) )
{
ResultProcessor.processResult( ItemPool.get( ItemPool.RAD, -30 ) );
}
else if ( skillName.equals( "Steroid Bladder" ) ||
skillName.equals( "Magic Sweat" ) ||
skillName.equals( "Flappy Ears" ) ||
skillName.equals( "Self-Combing Hair" ) ||
skillName.equals( "Intracranial Eye" ) ||
skillName.equals( "Mind Bullets" ) ||
skillName.equals( "Extra Kidney" ) ||
skillName.equals( "Extra Gall Bladder" ) )
{
ResultProcessor.processResult( ItemPool.get( ItemPool.RAD, -60 ) );
}
else if ( skillName.equals( "Extra Muscles" ) ||
skillName.equals( "Adipose Polymers" ) ||
skillName.equals( "Metallic Skin" ) ||
skillName.equals( "Hypno-Eyes" ) ||
skillName.equals( "Extra Brain" ) ||
skillName.equals( "Magnetic Ears" ) ||
skillName.equals( "Extremely Punchable Face" ) ||
skillName.equals( "Firefly Abdomen" ) ||
skillName.equals( "Bone Springs" ) ||
skillName.equals( "Squid Glands" ) )
{
ResultProcessor.processResult( ItemPool.get( ItemPool.RAD, -90 ) );
}
else if ( skillName.equals( "Sucker Fingers" ) ||
skillName.equals( "Backwards Knees" ) )
{
ResultProcessor.processResult( ItemPool.get( ItemPool.RAD, -120 ) );
}
}
String message = "You learned a new skill: " + skillName;
RequestLogger.printLine( message );
RequestLogger.updateSessionLog( message );
KoLCharacter.addAvailableSkill( skillName );
KoLCharacter.updateStatus();
LockableListFactory.sort( KoLConstants.usableSkills );
DiscoCombatHelper.learnSkill( skillName );
ConcoctionDatabase.setRefreshNeeded( true );
if ( SkillDatabase.isBookshelfSkill( skillName ) )
{
KoLCharacter.setBookshelf( true );
}
PreferenceListenerRegistry.firePreferenceChanged( "(skill)" );
}
public static final String[][] COMBAT_MOVE_DATA =
{
{
"gladiatorBallMovesKnown",
"Ball Bust",
"Ball Sweat",
"Ball Sack",
},
{
"gladiatorBladeMovesKnown",
"Blade Sling",
"Blade Roller",
"Blade Runner",
},
{
"gladiatorNetMovesKnown",
"Net Gain",
"Net Loss",
"Net Neutrality",
},
};
public static final void learnCombatMove( final String skillName )
{
for ( int type = 0; type < COMBAT_MOVE_DATA.length; ++type )
{
String [] moves = COMBAT_MOVE_DATA[ type ];
for ( int index= 1; index < moves.length; ++index )
{
if ( skillName.equals( moves[ index ] ) )
{
String setting = moves[ 0 ];
Preferences.setInteger( setting, index );
String message = "You learned a new special combat move: " + skillName;
RequestLogger.printLine( message );
RequestLogger.updateSessionLog( message );
// KoLCharacter.addCombatSkill( skillName );
// PreferenceListenerRegistry.firePreferenceChanged( "(skill)" );
return;
}
}
}
}
}