/**
* 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.lang.StringBuilder;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.kolmafia.KoLAdventure;
import net.sourceforge.kolmafia.KoLCharacter;
import net.sourceforge.kolmafia.KoLConstants.MafiaState;
import net.sourceforge.kolmafia.KoLmafia;
import net.sourceforge.kolmafia.RequestLogger;
import net.sourceforge.kolmafia.RequestThread;
import net.sourceforge.kolmafia.objectpool.EffectPool;
import net.sourceforge.kolmafia.objectpool.IntegerPool;
import net.sourceforge.kolmafia.persistence.AdventureDatabase;
import net.sourceforge.kolmafia.persistence.QuestDatabase;
import net.sourceforge.kolmafia.persistence.QuestDatabase.Quest;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.GenericRequest;
import net.sourceforge.kolmafia.request.TavernRequest;
import net.sourceforge.kolmafia.swingui.CouncilFrame;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class HaciendaManager
{
private static final String[][] CLUES =
{
{ "a potato peeler", "0" },
{ "an empty sardine can", "1" },
{ "an apple core", "2" },
{ "a silver pepper-mill", "3" },
{ "the lid from a can of sterno", "4" },
{ "an empty teacup", "5" },
{ "a small crowbar", "6" },
{ "a pair of needle-nose pliers", "7" },
{ "an empty rifle cartridge", "8" },
{ "a long nightcap with a pom-pom on the end", "9" },
{ "a dirty sock", "10" },
{ "a toothbrush", "11" },
};
private static final String[] REWARDS =
{
"silver cheese-slicer",
"taco shells",
"fettucini Inconnu",
"silver salt-shaker",
"cans of sterno",
"silver paté knife",
"fancy beef jerky",
"pipe wrench",
"gun cleaning kit",
"sleep mask",
"sock garters",
"mariachi toothpaste",
"heavy leather-bound tome",
"large handful of meat",
"leather bookmark",
"ivory cue ball",
"decanter of fine Scotch",
"expensive cigar"
};
public static void parseRoom( final int lastChoice, final int lastDecision, final String text )
{
String haciendaLayout = Preferences.getString( "haciendaLayout" );
StringBuffer newLayout = new StringBuffer( haciendaLayout );
int currentSearch = lastChoice*3 + lastDecision - 1240;
int clueTo = HaciendaManager.returnClue( text );
// If a fight, mark F
if ( text.contains( "Fight!" ) )
{
newLayout.setCharAt( currentSearch, 'F' );
}
// If a key, mark K
else if ( text.contains( "hacienda key" ) )
{
newLayout.setCharAt( currentSearch, 'K' );
}
// If a clue, mark C, and mark clue location k if not already K
else if ( clueTo != -1 )
{
newLayout.setCharAt( currentSearch, 'C' );
if ( haciendaLayout.charAt( clueTo ) != 'K' )
{
newLayout.setCharAt( clueTo, 'k' );
}
String clue = "You have found a clue: " + HaciendaManager.getClue( text );
KoLmafia.updateDisplay( clue );
RequestLogger.updateSessionLog( clue );
}
// If a reward, mark R
else if ( text.contains( "You acquire" ) || text.contains( "large handful of meat" ) )
{
// Verify that it's an reward from here, not elsewhere
if ( HaciendaManager.verifyReward( text ) )
{
newLayout.setCharAt( currentSearch, 'R' );
}
}
else
{
// Not sure if this will ever happen, but nothing found, so mark X
if ( haciendaLayout.charAt( currentSearch ) == '0' )
{
newLayout.setCharAt( currentSearch, 'X' );
}
}
// Record layout
haciendaLayout = newLayout.toString();
Preferences.setString( "haciendaLayout", haciendaLayout );
// Check if quest completion was properly completed, and if not, update Hacienda layout
if ( QuestDatabase.isQuestFinished( Quest.NEMESIS ) )
{
if ( HaciendaManager.countString( haciendaLayout.toLowerCase(), "f" ) > 0 )
{
HaciendaManager.questCompleted();
haciendaLayout = Preferences.getString( "haciendaLayout" );
newLayout = new StringBuffer( haciendaLayout );
}
}
// See if we can now learn things ?
for ( int i=0 ; i < 6 ; i++ )
{
String room = haciendaLayout.substring( i*3, i*3+3 );
// Nemesis quest complete, so no fights encountered, and pattern is now two rewards and one Key/clue
if ( QuestDatabase.isQuestFinished( Quest.NEMESIS ) )
{
for ( int j=0 ; j < 3 ; j++ )
{
int currentCheck = i*3+j;
if ( haciendaLayout.charAt( currentCheck ) == '0' )
{
// If we have got a Key or Clue in the Room remaining one is a Reward
if ( room.contains( "K" ) || room.contains( "C" ) )
{
newLayout.setCharAt( currentCheck, 'r' );
}
// If there are two Rewards, remaining one is a Clue
else if ( HaciendaManager.countString( room.toLowerCase(), "r" ) == 2 )
{
newLayout.setCharAt( currentCheck, 'C' );
}
}
}
}
else
{
// Do if Nemesis quest incomplete
for ( int j=0 ; j < 3 ; j++ )
{
int currentCheck = i*3+j;
if ( haciendaLayout.charAt( currentCheck ) == '0' )
{
// If we have got a Key or Clue and a Fight in the Room remaining one is a Reward
if ( ( room.toLowerCase().contains( "k" ) || room.toLowerCase().contains( "c" ) || room.toLowerCase().contains( "u" ) ) &&
room.contains( "F" ) )
{
newLayout.setCharAt( currentCheck, 'r' );
}
// If we have got a Key or Clue and a Reward in the Room remaining one is a Fight
else if ( ( room.toLowerCase().contains( "k" ) || room.toLowerCase().contains( "c" ) || room.toLowerCase().contains( "u" ) ) &&
room.contains( "R" ) )
{
newLayout.setCharAt( currentCheck, 'f' );
}
// If we have got a Fight and a Reward in the Room remaining one is a Key or Clue
else if ( room.contains( "F" ) && room.contains( "R" ) )
{
// If we have found 4 keys, it's a clue
if( HaciendaManager.countString( haciendaLayout.toLowerCase(), "k" ) == 4 )
{
newLayout.setCharAt( currentCheck, 'c' );
}
// If we have found 2 clues, it's a key
else if ( HaciendaManager.countString( haciendaLayout.toLowerCase(), "c" ) == 2 )
{
newLayout.setCharAt( currentCheck, 'k' );
}
else
{
newLayout.setCharAt( currentCheck, 'u' );
}
}
}
}
}
}
// Record layout
Preferences.setString( "haciendaLayout", newLayout.toString() );
}
public static void questCompleted()
{
String haciendaLayout = Preferences.getString( "haciendaLayout" );
StringBuffer newLayout = new StringBuffer( haciendaLayout );
for ( int i=0 ; i < 6 ; i++ )
{
String room = haciendaLayout.substring( i*3, i*3+3 );
// Replace any u's with C's (as you must have found all keys), and all F's with r's
for ( int j=0 ; j < 3 ; j++ )
{
int currentCheck = i*3+j;
if ( haciendaLayout.charAt( currentCheck ) == 'u' )
{
newLayout.setCharAt( currentCheck, 'C' );
}
else if ( haciendaLayout.charAt( currentCheck ) == 'F' || haciendaLayout.charAt( currentCheck ) == 'f' )
{
newLayout.setCharAt( currentCheck, 'r' );
}
}
// Record layout
haciendaLayout = newLayout.toString();
Preferences.setString( "haciendaLayout", haciendaLayout );
// Make deductions based on any updates
for ( int j=0 ; j < 3 ; j++ )
{
int currentCheck = i*3+j;
if ( haciendaLayout.charAt( currentCheck ) == '0' )
{
// If we have got a Key or Clue in the Room remaining one is a Reward
if ( room.contains( "K" ) || room.contains( "C" ) )
{
newLayout.setCharAt( currentCheck, 'r' );
}
// If there are two Rewards, remaining one is a Clue
else if ( HaciendaManager.countString( room.toLowerCase(), "r" ) == 2 )
{
newLayout.setCharAt( currentCheck, 'C' );
}
}
}
}
// Record layout
Preferences.setString( "haciendaLayout", newLayout.toString() );
}
private static int returnClue( final String text )
{
for ( String[] s : CLUES )
{
if ( text.contains( s[ 0 ] ) )
{
return Integer.parseInt( s[1] );
}
}
return -1;
}
private static String getClue( final String text )
{
for ( String[] s : CLUES )
{
if ( text.contains( s[ 0 ] ) )
{
return s[ 0 ];
}
}
return null;
}
private static boolean verifyReward( final String text )
{
for ( String s : REWARDS )
{
if ( text.contains( s ) )
{
return true;
}
}
return false;
}
private static String returnReward( final int location )
{
return REWARDS[location];
}
public static String[] getSpoilers( final int choice )
{
String[] result = new String[ 4 ];
switch ( choice )
{
case 410:
// choice of hallways
result[ 0 ] = HaciendaManager.getWingSpoilers( 0 );
result[ 1 ] = HaciendaManager.getWingSpoilers( 9 );
result[ 2 ] = "leave barracks";
break;
case 411:
case 412:
// choice of rooms
for ( int i=0 ; i < 3 ; i++ )
{
StringBuilder buffer = new StringBuilder();
buffer.append( HaciendaManager.getSpoiler( choice * 9 + i * 3 - 3699 ) );
buffer.append( " / " );
buffer.append( HaciendaManager.getSpoiler( choice * 9 + i * 3 - 3698 ) );
buffer.append( " / " );
buffer.append( HaciendaManager.getSpoiler( choice * 9 + i * 3 - 3697 ) );
result[ i ] = buffer.toString();
}
result[ 3 ] = "leave barracks";
break;
default:
// choice of locations in rooms
for ( int i=0 ; i < 3 ; i++ )
{
result[ i ] = HaciendaManager.getSpoiler( choice * 3 + i - 1239 );
}
result[ 3 ] = "leave barracks";
break;
}
return result;
}
private static String getSpoiler( final int spoiler )
{
String haciendaLayout = Preferences.getString( "haciendaLayout" );
Boolean questComplete = QuestDatabase.isQuestFinished( Quest.NEMESIS );
String result = "";
int roomNumber = spoiler/3;
String room = haciendaLayout.substring( roomNumber*3, roomNumber*3+3 );
if ( haciendaLayout.charAt( spoiler ) == 'K' )
{
result = "empty";
}
else if ( haciendaLayout.charAt( spoiler ) == 'u' )
{
result = "gain hacienda key or clue";
}
else if ( haciendaLayout.charAt( spoiler ) == 'k' )
{
result = "gain hacienda key";
}
else if ( haciendaLayout.charAt( spoiler ) == 'c' )
{
result = "gain clue";
}
else if ( haciendaLayout.charAt( spoiler ) == 'F' || haciendaLayout.charAt( spoiler ) == 'f' )
{
result = "fight mariachi";
}
else if ( haciendaLayout.charAt( spoiler ) == 'R' )
{
result = "empty";
}
else if ( haciendaLayout.charAt( spoiler ) == 'r' )
{
StringBuilder buffer = new StringBuilder();
buffer.append( "gain " );
buffer.append( HaciendaManager.returnReward( spoiler ) );
result = buffer.toString();
}
else if ( haciendaLayout.charAt( spoiler ) == 'C' )
{
result = "empty";
}
else if ( haciendaLayout.charAt( spoiler ) == 'X' )
{
result = "empty";
}
else if ( haciendaLayout.charAt( spoiler ) == '0' )
{
if ( room.contains( "F" ) )
{
result = "key, clue or reward";
}
else if ( room.toLowerCase().contains( "k" ) || room.toLowerCase().contains( "c" ) || room.toLowerCase().contains( "u" ) )
{
result = "fight or reward";
}
else if ( room.contains( "R" ) || room.contains( "r" ) )
{
result = questComplete ? "reward or clue" : "key, clue or fight";
}
else
{
result = questComplete ? "reward or clue" : "unknown";
}
}
else
{
result = "unknown result";
}
if ( questComplete && spoiler == 17 )
{
return ( result + " make recordings" );
}
return result;
}
private static String getWingSpoilers( final int spoiler )
{
String haciendaLayout = Preferences.getString( "haciendaLayout" );
Boolean questComplete = QuestDatabase.isQuestFinished( Quest.NEMESIS );
int wingNumber = spoiler/9;
String wing = haciendaLayout.substring( wingNumber*9, wingNumber*9+9 );
int keysFound = HaciendaManager.countString( wing, "K" );
int keysLocated = HaciendaManager.countString( wing, "k" );
int cluesLocated = HaciendaManager.countString( wing.toLowerCase(), "c" );
int rewardsFound = HaciendaManager.countString( wing, "R" );
int rewardsLocated = HaciendaManager.countString( wing, "r" );
StringBuilder result = new StringBuilder();
if ( questComplete )
{
result.append( 6 - rewardsFound );
result.append( " rewards left, " );
result.append( rewardsLocated );
result.append( " located" );
if ( spoiler == 9 )
{
result.append( ", make recordings" );
}
result.append( "." );
}
else
{
result.append( 3 - keysFound - cluesLocated );
result.append( " keys or clues left, " );
result.append( keysLocated );
result.append( " keys located." );
}
return result.toString();
}
private static int countString( String inString, String lookFor )
{
int result = 0;
int currentIndex = 0;
currentIndex = inString.indexOf( lookFor );
while ( currentIndex != -1 )
{
currentIndex = inString.indexOf( lookFor, currentIndex + 1 );
result++;
}
return result;
}
// <option value="530" >The Ballad of Richie Thingfinder (0/10)</option>
private static final Pattern OPTION_PATTERN = Pattern.compile( "<option value=\"?(\\d+)\"? *>(.*?) \\((\\d+)/(\\d+)\\)</option>" );
private static final Object [][] RECORDINGS =
{
{
IntegerPool.get( EffectPool.THE_BALLAD_OF_RICHIE_THINGFINDER ),
"_thingfinderCasts",
},
{
IntegerPool.get( EffectPool.BENETTONS_MEDLEY_OF_DIVERSITY ),
"_benettonsCasts",
},
{
IntegerPool.get( EffectPool.ELRONS_EXPLOSIVE_ETUDE ),
"_elronsCasts",
},
{
IntegerPool.get( EffectPool.CHORALE_OF_COMPANIONSHIP ),
"_companionshipCasts",
},
{
IntegerPool.get( EffectPool.PRELUDE_OF_PRECISION ),
"_precisionCasts",
},
{
IntegerPool.get( EffectPool.DONHOS_BUBBLY_BALLAD ),
"_donhosCasts",
},
{
IntegerPool.get( EffectPool.INIGOS ),
"_inigosCasts",
},
};
private static String effectIdToSetting( final int effectId )
{
for ( int i = 0; i < HaciendaManager.RECORDINGS.length; ++i )
{
Object [] recording = HaciendaManager.RECORDINGS[ i ];
if ( effectId == ((Integer)recording[0]).intValue() )
{
return (String)recording[1];
}
}
return null;
}
public static void preRecording( final String text )
{
Matcher matcher = HaciendaManager.OPTION_PATTERN.matcher( text );
while ( matcher.find() )
{
int effectId = StringUtilities.parseInt( matcher.group( 1 ) );
String effect = matcher.group( 1 );
int used = StringUtilities.parseInt( matcher.group( 3 ) );
int max = StringUtilities.parseInt( matcher.group( 4 ) );
String setting = HaciendaManager.effectIdToSetting( effectId );
if ( setting != null )
{
Preferences.setInteger( setting, used );
}
}
}
// choice.php?whicheffect=530×=3&pwd&whichchoice=440&option=1
private static final Pattern WHICHEFFECT_PATTERN = Pattern.compile( "whicheffect=(\\d+)" );
private static final Pattern TIMES_PATTERN = Pattern.compile( "times=(\\d+)" );
public static void parseRecording( final String urlString, final String text )
{
if ( !text.contains( "You acquire" ) )
{
return;
}
Matcher matcher = HaciendaManager.WHICHEFFECT_PATTERN.matcher( urlString );
int effectId = matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
matcher = HaciendaManager.TIMES_PATTERN.matcher( urlString );
int times = matcher.find() ? StringUtilities.parseInt( matcher.group( 1 ) ) : 0;
String setting = HaciendaManager.effectIdToSetting( effectId );
if ( setting != null )
{
Preferences.increment( setting, times );
}
HaciendaManager.preRecording( text );
}
}