/**
* 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.webui;
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.MonsterData;
import net.sourceforge.kolmafia.RequestEditorKit;
import net.sourceforge.kolmafia.combat.MonsterStatusTracker;
import net.sourceforge.kolmafia.objectpool.AdventurePool;
import net.sourceforge.kolmafia.objectpool.ItemPool;
import net.sourceforge.kolmafia.persistence.ItemDatabase;
import net.sourceforge.kolmafia.persistence.MonsterDatabase;
import net.sourceforge.kolmafia.preferences.Preferences;
import net.sourceforge.kolmafia.request.IslandRequest;
import net.sourceforge.kolmafia.session.InventoryManager;
import net.sourceforge.kolmafia.session.IslandManager;
import net.sourceforge.kolmafia.session.IslandManager.Quest;
import net.sourceforge.kolmafia.utilities.StringUtilities;
public class IslandDecorator
{
private static final String progressLineStyle = "<td style=\"color: red;font-size: 80%\" align=center>";
// KoLmafia images showing each quest area on bigisland.php
// JHunz's replacement images for Big Island sidequest areas from his
// BattlefieldCounter Greasemonkey script, used with his permission.
//
// http://userscripts.org/scripts/show/11720
private static final String LOCAL_ROOT = "/images/otherimages/bigisland/";
private static final Object[][] IMAGES =
{
{
Quest.JUNKYARD,
IslandDecorator.LOCAL_ROOT + "2.gif",
IslandDecorator.LOCAL_ROOT + "2F.gif",
IslandDecorator.LOCAL_ROOT + "2H.gif",
},
{
Quest.ORCHARD,
IslandDecorator.LOCAL_ROOT + "3.gif",
IslandDecorator.LOCAL_ROOT + "3F.gif",
IslandDecorator.LOCAL_ROOT + "3H.gif",
},
{
Quest.ARENA,
IslandDecorator.LOCAL_ROOT + "6.gif",
IslandDecorator.LOCAL_ROOT + "6F.gif",
IslandDecorator.LOCAL_ROOT + "6H.gif",
},
{
Quest.FARM,
IslandDecorator.LOCAL_ROOT + "15.gif",
IslandDecorator.LOCAL_ROOT + "15F.gif",
IslandDecorator.LOCAL_ROOT + "15H.gif",
},
{
Quest.LIGHTHOUSE,
IslandDecorator.LOCAL_ROOT + "17.gif",
IslandDecorator.LOCAL_ROOT + "17F.gif",
IslandDecorator.LOCAL_ROOT + "17H.gif",
},
{
Quest.NUNS,
IslandDecorator.LOCAL_ROOT + "19.gif",
IslandDecorator.LOCAL_ROOT + "19F.gif",
IslandDecorator.LOCAL_ROOT + "19H.gif",
},
};
private static final Object[] findImages( final Quest quest )
{
for ( int i = 0; i < IslandDecorator.IMAGES.length; ++i )
{
Object[] row = IslandDecorator.IMAGES[ i ];
if ( (Quest)( row[ 0 ] ) == quest )
{
return row;
}
}
return null;
}
private static final String originalImage( final Quest quest )
{
Object[] row = IslandDecorator.findImages( quest );
return row == null ? "" : (String)( row[ 1 ] );
}
private static final String fratImage( final Quest quest )
{
Object[] row = IslandDecorator.findImages( quest );
return row == null ? "" : (String)( row[ 2 ] );
}
private static final String hippyImage( final Quest quest )
{
Object[] row = IslandDecorator.findImages( quest );
return row == null ? "" : (String)( row[ 3 ] );
}
private static final String sidequestImage( final String setting, final Quest quest )
{
String status = Preferences.getString( setting );
return status.equals( "fratboy" ) ?
IslandDecorator.fratImage( quest) :
status.equals( "hippy" ) ?
IslandDecorator.hippyImage( quest) :
null;
}
/*
* Methods to decorate the Fight page
*/
public static final void decorateThemtharFight( final StringBuffer buffer )
{
int index = buffer.indexOf( "<!--WINWINWIN-->" );
if ( index == -1 )
{
return;
}
String message = "<p><center>" + IslandDecorator.meatMessage() + "<br>";
buffer.insert( index, message );
}
// Meat drops from dirty thieving brigands
private static final MonsterData BRIGAND = MonsterDatabase.findMonster( "dirty thieving brigand", false );
private static final int BRIGAND_MIN = BRIGAND.getMinMeat();
private static final int BRIGAND_MAX = BRIGAND.getMaxMeat();
private static final String meatMessage()
{
StringBuilder message = new StringBuilder();
int current = IslandManager.currentNunneryMeat();
message.append( KoLConstants.COMMA_FORMAT.format( current ) );
message.append( " meat recovered, " );
double left = 100000 - current;
message.append( KoLConstants.COMMA_FORMAT.format( left ) );
message.append( " left (" );
double mod = ( KoLCharacter.currentNumericModifier( Modifiers.MEATDROP ) + 100.0f ) / 100.0f;
double min = BRIGAND_MIN * mod;
double max = BRIGAND_MAX * mod;
int minTurns = (int) Math.ceil( left / max );
int maxTurns = (int) Math.ceil( left / min );
message.append( String.valueOf( minTurns ) );
if ( minTurns != maxTurns )
{
message.append( "-" );
message.append( String.valueOf( maxTurns ) );
}
message.append( " turns)." );
return message.toString();
}
private static final String[] GREMLIN_TOOLS =
{
"It whips out a hammer",
"He whips out a crescent wrench",
"It whips out a pair of pliers",
"It whips out a screwdriver",
};
private static final Object[][] TOOL_MONSTERS =
{
{
"batwinged gremlin",
AdventurePool.JUNKYARD_BARREL,
ItemPool.MOLYBDENUM_HAMMER
},
{
"erudite gremlin",
AdventurePool.JUNKYARD_TIRES,
ItemPool.MOLYBDENUM_WRENCH
},
{
"spider gremlin",
AdventurePool.JUNKYARD_REFRIGERATOR,
ItemPool.MOLYBDENUM_PLIERS
},
{
"vegetable gremlin",
AdventurePool.JUNKYARD_CAR,
ItemPool.MOLYBDENUM_SCREWDRIVER
}
};
public static final void decorateGremlinFight( final String monster, final StringBuffer buffer )
{
// Color the tool in the monster spoiler text
int loc = KoLAdventure.lastAdventureId();
if ( IslandManager.missingGremlinTool() == null )
{
for ( int i = 0; i < IslandDecorator.TOOL_MONSTERS.length; ++i )
{
if ( !monster.startsWith( (String) IslandDecorator.TOOL_MONSTERS[i][0] ) )
{
continue;
}
if ( loc != 0 && loc != (Integer) IslandDecorator.TOOL_MONSTERS[i][1] )
{
break;
}
if ( KoLConstants.inventory.contains( ItemPool.get( (Integer) IslandDecorator.TOOL_MONSTERS[i][2], 1 ) ) )
{
break;
}
String zoneTool = ItemDatabase.getItemName( (Integer) IslandDecorator.TOOL_MONSTERS[i][2] );
StringUtilities.singleStringReplace( buffer,
zoneTool,
"<font color=#DD00FF>" + zoneTool + "</font>" );
break;
}
}
for ( int i = 0; i < IslandDecorator.GREMLIN_TOOLS.length; ++i )
{
String tool = IslandDecorator.GREMLIN_TOOLS[ i ];
if ( buffer.indexOf( tool ) != -1 )
{
// Make the message pink
StringUtilities.singleStringReplace( buffer, tool, "<font color=#DD00FF>" + tool + "</font>" );
String select1 = "<option picurl=magnet2 selected value=2497>";
String select2 = "<option selected value=2497>";
// If we already have the molybdenum magnet
// selected (which should only be possible if
// we are funkslinging), cool. Otherwise, get
// rid of current selection(s) and select the
// magnet on the first combat item dropdown.
if ( buffer.indexOf( select1 ) == -1 && buffer.indexOf( select2 ) == -1 )
{
// Unselect battle actions in dropdowns on the fight page
StringUtilities.globalStringReplace( buffer, " selected ", " " );
// Select the molybdenum magnet
// <option picurl=magnet2 selected value=2497>molybdenum magnet (1)</option>
String search = "<option picurl=magnet2 value=2497>";
StringUtilities.singleStringReplace( buffer, search, select1 );
}
break;
}
}
}
public static final void appendMissingGremlinTool( final StringBuffer buffer )
{
if ( IslandManager.missingGremlinTool() != null )
{
buffer.append( "<br />This gremlin does <b>NOT</b> have a " ).append( IslandManager.missingGremlinTool() );
}
}
private static final String victoryMessageHTML( final int last, final int current )
{
String message = IslandManager.victoryMessage( last, current );
return message == null ? "" : message + "<br>";
}
private static final String areaMessageHTML( final int last, final int current )
{
String message = IslandManager.areaMessage( last, current );
return message == null ? "" : "<b>" + message + "</b><br>";
}
private static final String heroMessageHTML( final int last, final int current )
{
String message = IslandManager.heroMessage( last, current );
return message == null ? "" : "<b>" + message + "</b><br>";
}
public static final void decorateBattlefieldFight( final StringBuffer buffer )
{
int index = buffer.indexOf( "<!--WINWINWIN-->" );
if ( index == -1 )
{
return;
}
// Don't bother showing progress of the war if you've just won
MonsterData monster = MonsterStatusTracker.getLastMonster();
String monsterName = "";
if ( monster != null )
{
monsterName = monster.getName();
}
if ( monsterName.equals( "The Big Wisniewski" ) || monsterName.equals( "The Man" ) )
{
return;
}
int last;
int current;
if ( IslandManager.fratboy() )
{
last = IslandManager.lastFratboysDefeated();
current = IslandManager.fratboysDefeated();
}
else
{
last = IslandManager.lastHippiesDefeated();
current = IslandManager.hippiesDefeated();
}
if ( last == current )
{
return;
}
String message =
"<p><center>" +
victoryMessageHTML( last, current ) +
areaMessageHTML( last, current ) +
heroMessageHTML( last, current ) +
"</center>";
buffer.insert( index, message );
}
/*
* Method to decorate the Big Island map
*/
// Decorate the HTML with custom goodies
public static final void decorateBigIsland( final String url, final StringBuffer buffer )
{
// Quest-specific page decorations
IslandDecorator.decorateJunkyard( buffer );
IslandDecorator.decorateArena( url, buffer );
IslandDecorator.decorateNunnery( url, buffer );
// Find the table that contains the map.
int tableIndex = buffer.indexOf( "<tr><td style=\"color: white;\" align=center bgcolor=blue><b>The Mysterious Island of Mystery</b></td>" );
if ( tableIndex != -1 )
{
String fratboyMessage = IslandManager.sideSummary( "frat boys" );
String hippyMessage = IslandManager.sideSummary( "hippies" );
String row =
"<tr><td><center><table width=100%><tr>" + IslandDecorator.progressLineStyle +
fratboyMessage +
"</td>" + IslandDecorator.progressLineStyle +
hippyMessage +
"</td>" + "</tr></table></td></tr>";
buffer.insert( tableIndex, row );
}
// Replace all KoL image servers with KoLmafia image cache locations
StringUtilities.globalStringReplace( buffer, KoLmafia.AMAZON_IMAGE_SERVER, "/images" );
StringUtilities.globalStringReplace( buffer, KoLmafia.KOL_IMAGE_SERVER, "/images" );
// Replace sidequest location images for completed quests
IslandDecorator.sidequestImage( buffer, "sidequestArenaCompleted", Quest.ARENA );
IslandDecorator.sidequestImage( buffer, "sidequestFarmCompleted", Quest.FARM );
IslandDecorator.sidequestImage( buffer, "sidequestJunkyardCompleted", Quest.JUNKYARD );
IslandDecorator.sidequestImage( buffer, "sidequestLighthouseCompleted", Quest.LIGHTHOUSE );
IslandDecorator.sidequestImage( buffer, "sidequestNunsCompleted", Quest.NUNS );
IslandDecorator.sidequestImage( buffer, "sidequestOrchardCompleted", Quest.ORCHARD );
}
private static final void sidequestImage( final StringBuffer buffer, final String setting, final Quest quest )
{
String image = IslandDecorator.sidequestImage( setting, quest );
if ( image == null )
{
return;
}
String old = IslandDecorator.originalImage( quest);
StringUtilities.singleStringReplace( buffer, old, image );
}
public static final void decorateJunkyard( final StringBuffer buffer )
{
if ( IslandManager.currentJunkyardLocation().equals( "" ) )
{
return;
}
int tableIndex =
buffer.indexOf( "<tr><td style=\"color: white;\" align=center bgcolor=blue><b>The Junkyard</b></td>" );
if ( tableIndex == -1 )
{
return;
}
String message;
if ( !InventoryManager.hasItem( ItemPool.MOLYBDENUM_MAGNET ) )
{
message = "Visit Yossarian in uniform to get a molybdenum magnet";
}
else if ( IslandManager.currentJunkyardTool().equals( "" ) )
{
message = "Visit Yossarian for your next assignment";
}
else if ( InventoryManager.hasItem( ItemPool.MOLYBDENUM_HAMMER ) &&
InventoryManager.hasItem( ItemPool.MOLYBDENUM_SCREWDRIVER ) &&
InventoryManager.hasItem( ItemPool.MOLYBDENUM_PLIERS ) &&
InventoryManager.hasItem( ItemPool.MOLYBDENUM_WRENCH ) )
{
message = "Visit Yossarian in uniform to receive your reward for finding all four molybdenum tools";
}
else
{
message = "Look for the " + IslandManager.currentJunkyardTool() + " " + IslandManager.currentJunkyardLocation();
}
String row = "<tr><td><center><table width=100%><tr>" + IslandDecorator.progressLineStyle + message + ".</td>" + "</tr></table></td></tr>";
buffer.insert( tableIndex, row );
}
public static final void decorateArena( final String urlString, final StringBuffer buffer )
{
// If he's not visiting the arena, punt
if ( !urlString.contains( "place=concert" ) )
{
return;
}
// If there's no concert available, see if quest is in progress
if ( buffer.indexOf( "value=\"concert\"" ) == -1 )
{
if ( Preferences.getString( "warProgress" ).equals( "finished" ) ||
!Preferences.getString( "sidequestArenaCompleted" ).equals( "none" ) )
{
// War is over or quest is finished. Punt.
return;
}
int tableIndex =
buffer.indexOf( "<tr><td style=\"color: white;\" align=center bgcolor=blue><b>Mysterious Island Arena</b></td>" );
if ( tableIndex != -1 )
{
String message = RequestEditorKit.advertisingMessage();
String row = "<tr><td><center><table width=100%><tr>" + IslandDecorator.progressLineStyle + message + "</td></tr></table></td></tr>";
buffer.insert( tableIndex, row );
}
return;
}
String quest = Preferences.getString( "sidequestArenaCompleted" );
String [][] array =
quest.equals( "hippy" ) ?
IslandRequest.HIPPY_CONCERTS :
IslandRequest.FRATBOY_CONCERTS;
String text = buffer.toString();
buffer.setLength( 0 );
int index1 = 0, index2;
// Add first choice spoiler
String choice = array[0][0] + ": " + array[0][1];
index2 = text.indexOf( "</form>", index1 );
buffer.append( text.substring( index1, index2 ) );
buffer.append( "<br><font size=-1>(" ).append( choice ).append( ")</font><br/></form>" );
index1 = index2 + 7;
// Add second choice spoiler
choice = array[1][0] + ": " + array[1][1];
index2 = text.indexOf( "</form>", index1 );
buffer.append( text.substring( index1, index2 ) );
buffer.append( "<br><font size=-1>(" ).append( choice ).append( ")</font><br/></form>" );
index1 = index2 + 7;
// Add third choice spoiler
choice = array[2][0] + ": " + array[2][1];
index2 = text.indexOf( "</form>", index1 );
buffer.append( text.substring( index1, index2 ) );
buffer.append( "<br><font size=-1>(" ).append( choice ).append( ")</font><br/></form>" );
index1 = index2 + 7;
// Append remainder of buffer
buffer.append( text.substring( index1 ) );
}
public static final void decorateNunnery( final String urlString, final StringBuffer buffer )
{
// If he's not visiting the nunnery, punt
if ( !urlString.contains( "place=nunnery" ) )
{
return;
}
// See if quest is in progress
if ( Preferences.getString( "warProgress" ).equals( "finished" ) ||
!Preferences.getString( "sidequestNunsCompleted" ).equals( "none" ) )
{
// Either the war or quest is over. Punt
return;
}
int tableIndex =
buffer.indexOf( "<tr><td style=\"color: white;\" align=center bgcolor=blue><b>Our Lady of Perpetual Indecision</b></td>" );
if ( tableIndex == -1 )
{
return;
}
String message = IslandDecorator.meatMessage();
String row = "<tr><td><center><table width=100%><tr>" + IslandDecorator.progressLineStyle + message + "</td></tr></table></td></tr>";
buffer.insert( tableIndex, row );
}
public static final void decoratePostwarIsland( final String url, final StringBuffer buffer )
{
// Quest-specific page decorations
IslandDecorator.decorateArena( url, buffer );
// Replace all KoL image servers with KoLmafia image cache locations
StringUtilities.globalStringReplace( buffer, KoLmafia.AMAZON_IMAGE_SERVER, "/images" );
StringUtilities.globalStringReplace( buffer, KoLmafia.KOL_IMAGE_SERVER, "/images" );
// Replace sidequest location images for completed quests
// The arena is available after the war only if the fans of the
// concert you promoted won the war.
String arena = IslandManager.questCompleter( "sidequestArenaCompleted" );
String winner = IslandManager.warWinner();
if ( arena.equals( winner ) )
{
IslandDecorator.sidequestImage( buffer, "sidequestArenaCompleted", Quest.ARENA );
}
// If you aided the nuns during the war, they will help you
// after the war, regardless of who won.
IslandDecorator.sidequestImage( buffer, "sidequestNunsCompleted", Quest.NUNS );
}
}