/**
* 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.util.regex.Matcher;
import net.sourceforge.kolmafia.AdventureResult;
import net.sourceforge.kolmafia.KoLAdventure;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants;
import net.sourceforge.kolmafia.KoLConstants.CraftingType;
import net.sourceforge.kolmafia.KoLConstants.MafiaState;
import net.sourceforge.kolmafia.KoLmafia;
import net.sourceforge.kolmafia.KoLmafiaCLI;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.SpecialOutfit;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.persistence.AdventureDatabase;
import net.sourceforge.kolmafia.persistence.ConcoctionDatabase;
import net.sourceforge.kolmafia.persistence.ItemDatabase;
import net.sourceforge.kolmafia.persistence.QuestDatabase;
import net.sourceforge.kolmafia.persistence.QuestDatabase.Quest;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.session.GoalManager;
import net.sourceforge.kolmafia.session.InventoryManager;
import net.sourceforge.kolmafia.session.ResultProcessor;
import net.sourceforge.kolmafia.swingui.GenericFrame;
import net.sourceforge.kolmafia.utilities.InputFieldUtilities;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class UntinkerRequest
extends GenericRequest
{
private static final GenericRequest AVAILABLE_CHECKER = new PlaceRequest( "forestvillage", "fv_untinker", true );
private static boolean canUntinker;
private static int lastUserId = -1;
private static final AdventureResult SCREWDRIVER = ItemPool.get( ItemPool.RUSTY_SCREWDRIVER, -1 );
private final int itemId;
private int iterationsNeeded;
private AdventureResult item;
public static final void reset()
{
UntinkerRequest.canUntinker = false;
UntinkerRequest.lastUserId = -1;
}
public UntinkerRequest( final int itemId )
{
this( itemId, Integer.MAX_VALUE );
}
public UntinkerRequest( final int itemId, final int itemCount )
{
super( "place.php" );
this.addFormField( "whichplace", "forestvillage" );
this.addFormField( "action", "fv_untinker" );
this.addFormField( "preaction", "untinker" );
this.addFormField( "whichitem", String.valueOf( itemId ) );
this.itemId = itemId;
this.iterationsNeeded = 1;
this.item = ItemPool.get( itemId, itemCount );
if ( itemCount == Integer.MAX_VALUE )
{
this.item = this.item.getInstance( this.item.getCount( KoLConstants.inventory ) );
}
if ( itemCount > 5 || this.item.getCount( KoLConstants.inventory ) == itemCount )
{
this.addFormField( "untinkerall", "on" );
}
else
{
this.iterationsNeeded = itemCount;
}
}
@Override
protected boolean retryOnTimeout()
{
return true;
}
@Override
public void run()
{
// Check to see if the item can be constructed using meat
// paste, and only execute the request if it is known to be
// creatable through combination.
CraftingType mixMethod = ConcoctionDatabase.getMixingMethod( this.itemId );
if ( mixMethod != CraftingType.COMBINE && mixMethod != CraftingType.JEWELRY )
{
KoLmafia.updateDisplay( MafiaState.ERROR, "You cannot untinker that item." );
return;
}
// Retrieving item to untinker may need an outfit change
try
{
SpecialOutfit.createImplicitCheckpoint();
if ( !InventoryManager.retrieveItem( this.item ) )
{
return;
}
}
finally
{
SpecialOutfit.restoreImplicitCheckpoint();
}
KoLmafia.updateDisplay( "Untinkering " + this.item + "..." );
super.run();
if ( !this.responseText.contains( "You acquire" ) )
{
UntinkerRequest.AVAILABLE_CHECKER.run();
if ( !UntinkerRequest.AVAILABLE_CHECKER.responseText.contains( "<select" ) )
{
UntinkerRequest.canUntinker = UntinkerRequest.completeQuest();
if ( !UntinkerRequest.canUntinker )
{
return;
}
UntinkerRequest.AVAILABLE_CHECKER.run();
}
super.run();
}
for ( int i = 1; i < this.iterationsNeeded; ++i )
{
super.run();
}
KoLmafia.updateDisplay( "Successfully untinkered " + this.item );
}
public static final void parseResponse( final String location, final String responseText )
{
if ( !location.contains( "fv_untinker" ) && !location.contains( "screwquest" ) )
{
return;
}
// "Thanks! I'll tell ya, I'm just lost without my screwdriver. Here, lemme mark the Knoll on your map."
if ( responseText.contains( "I'm just lost without my screwdriver" ) ||
responseText.contains( "I'll go find your screwdriver for you" ) // Zombie Slayer
)
{
QuestDatabase.setQuestProgress( Quest.UNTINKER, QuestDatabase.STARTED );
}
// If the quest is still in progross, no need to check anything else
if ( location.contains( "fv_untinker_quest") )
{
return;
}
// Visiting the untinker removes screwdriver from inventory.
if ( KoLConstants.inventory.contains( UntinkerRequest.SCREWDRIVER ) )
{
ResultProcessor.processResult( UntinkerRequest.SCREWDRIVER );
QuestDatabase.setQuestProgress( Quest.UNTINKER, QuestDatabase.FINISHED );
}
UntinkerRequest.lastUserId = KoLCharacter.getUserId();
UntinkerRequest.canUntinker = responseText.contains( "you don't have anything like that" ) || responseText.contains( "<select name=whichitem>" );
if ( responseText.contains( "You acquire" ) )
{
Matcher matcher = TransferItemRequest.ITEMID_PATTERN.matcher( location );
if ( !matcher.find() )
{
return;
}
int itemId = StringUtilities.parseInt( matcher.group( 1 ) );
AdventureResult result = ItemPool.get( itemId, -1 );
if ( location.contains( "untinkerall=on" ) )
{
result = result.getInstance( 0 - result.getCount( KoLConstants.inventory ) );
}
ResultProcessor.processResult( result );
}
}
public static final boolean canUntinker()
{
if ( UntinkerRequest.lastUserId == KoLCharacter.getUserId() )
{
return UntinkerRequest.canUntinker;
}
UntinkerRequest.lastUserId = KoLCharacter.getUserId();
// If the person does not have the accomplishment, visit
// the untinker to ensure that they get the quest.
UntinkerRequest.AVAILABLE_CHECKER.run();
// "I can take apart anything that's put together with meat
// paste, but you don't have anything like that..."
UntinkerRequest.canUntinker =
UntinkerRequest.AVAILABLE_CHECKER.responseText.contains( "you don't have anything like that" ) ||
UntinkerRequest.AVAILABLE_CHECKER.responseText.contains( "<select name=whichitem>" );
return UntinkerRequest.canUntinker;
}
public static final boolean completeQuest()
{
// If they are in a muscle sign, this is a trivial task;
// just have them visit Innabox.
if ( KoLCharacter.knollAvailable() )
{
PlaceRequest tinkVisit = new PlaceRequest( "forestvillage", "fv_untinker_quest", true );
tinkVisit.addFormField( "preaction", "screwquest" );
tinkVisit.run();
PlaceRequest knollVisit = new PlaceRequest( "knoll_friendly", "dk_innabox" );
knollVisit.run();
return true;
}
if ( GenericFrame.instanceExists() )
{
if ( !InputFieldUtilities.confirm( "KoLmafia thinks you haven't completed the screwdriver quest. Would you like to have KoLmafia automatically complete it now?" ) )
{
return false;
}
}
// Okay, so they don't have one yet. Complete the
// untinkerer's quest automatically.
PlaceRequest tinkVisit = new PlaceRequest( "forestvillage", "fv_untinker_quest", true );
tinkVisit.addFormField( "preaction", "screwquest" );
tinkVisit.run();
KoLAdventure sideTripLocation = AdventureDatabase.getAdventureByURL( "adventure.php?snarfblat=354" );
AdventureResult sideTripItem = UntinkerRequest.SCREWDRIVER.getNegation();
String action = Preferences.getString( "battleAction" );
if ( action.contains( "dictionary" ) )
{
KoLmafiaCLI.DEFAULT_SHELL.executeCommand( "set", "battleAction=attack" );
}
GoalManager.makeSideTrip( sideTripLocation, sideTripItem );
if ( KoLmafia.refusesContinue() )
{
KoLmafiaCLI.DEFAULT_SHELL.executeCommand( "set", "battleAction=" + action );
return false;
}
KoLmafiaCLI.DEFAULT_SHELL.executeCommand( "set", "battleAction=" + action );
// You should now have a screwdriver in your inventory.
// Go ahead and rerun the untinker request and you will
// have the needed accomplishment.
UntinkerRequest.AVAILABLE_CHECKER.run();
return !UntinkerRequest.AVAILABLE_CHECKER.responseText.contains( "Degrassi Knoll" );
}
private static final String [] UNTINKER_STRINGS =
{
"Here, lemme mark the Knoll on your map."",
"I lost it at Degrassi Knoll, you'll recall."",
// Zombiecore
"Sure, no problem."",
"Oh right, Degrassi Knoll. Okay, I'll be right back.""
};
public static void decorate( final StringBuffer buffer )
{
String test = "";
int index = -1;
for ( int i = 0; index == -1 && i < UNTINKER_STRINGS.length; ++i )
{
test = UNTINKER_STRINGS[ i ];
index = buffer.indexOf( test );
}
if ( index == -1 )
{
return;
}
String link;
if ( KoLCharacter.knollAvailable() )
{
link = "<font size=1>[<a href=\"place.php?whichplace=knoll_friendly&action=dk_innabox\">visit Innabox</a>]</font>";
}
else
{
link = "<font size=1>[<a href=\"adventure.php?snarfblat=354\">Degrassi Knoll Garage</a>]</font>";
}
buffer.insert( index + test.length(), link );
}
public static final boolean registerRequest( final String urlString )
{
// Either place=untinker or action=untinker
if ( !urlString.startsWith( "place.php" ) || !urlString.contains( "whichplace=forestvillage" ) )
{
return false;
}
String message;
if ( urlString.contains( "preaction=screwquest" ) )
{
message = "Accepting quest to find the Untinker's screwdriver";
}
else if ( urlString.contains( "action=fv_untinker" ) )
{
Matcher matcher = TransferItemRequest.ITEMID_PATTERN.matcher( urlString );
if ( !matcher.find() )
{
RequestLogger.printLine( "" );
RequestLogger.updateSessionLog();
message = "Visiting the Untinker";
}
else
{
String name = ItemDatabase.getItemName( StringUtilities.parseInt( matcher.group( 1 ) ) );
message = "untinker " + ( urlString.contains( "untinkerall=on" ) ? "*" : "1" ) + " " + name;
}
}
else
{
return false;
}
RequestLogger.printLine( message );
RequestLogger.updateSessionLog( message );
return true;
}
}