/** * 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.swingui.panel; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JProgressBar; import javax.swing.SwingConstants; import net.java.dev.spellcast.utilities.JComponentUtilities; import net.sourceforge.kolmafia.AdventureResult; import net.sourceforge.kolmafia.EdServantData; import net.sourceforge.kolmafia.FamiliarData; import net.sourceforge.kolmafia.KoLCharacter; import net.sourceforge.kolmafia.KoLConstants; import net.sourceforge.kolmafia.KoLmafia; import net.sourceforge.kolmafia.Modifiers; import net.sourceforge.kolmafia.listener.Listener; import net.sourceforge.kolmafia.listener.NamedListenerRegistry; import net.sourceforge.kolmafia.objectpool.EffectPool; import net.sourceforge.kolmafia.objectpool.ItemPool; import net.sourceforge.kolmafia.persistence.FamiliarDatabase; import net.sourceforge.kolmafia.persistence.ItemDatabase; import net.sourceforge.kolmafia.preferences.Preferences; import net.sourceforge.kolmafia.request.ApiRequest; import net.sourceforge.kolmafia.request.CharPaneRequest; import net.sourceforge.kolmafia.request.CharPaneRequest.Companion; import net.sourceforge.kolmafia.request.SpelunkyRequest; import net.sourceforge.kolmafia.session.InventoryManager; import net.sourceforge.kolmafia.session.Limitmode; import net.sourceforge.kolmafia.swingui.CommandDisplayFrame; import net.sourceforge.kolmafia.swingui.button.InvocationButton; import net.sourceforge.kolmafia.swingui.listener.ThreadedListener; import net.sourceforge.kolmafia.swingui.menu.ThreadedMenuItem; import net.sourceforge.kolmafia.utilities.FileUtilities; import net.sourceforge.kolmafia.webui.CharPaneDecorator; public class CompactSidePane extends JPanel implements Runnable { private final JPanel levelPanel; private final JProgressBar levelMeter; private final JLabel levelLabel, roninLabel, mcdLabel; private final int STAT_LABELS = 3; private final JLabel[] statLabel = new JLabel[ STAT_LABELS ]; private final JLabel[] statValueLabel = new JLabel[ STAT_LABELS ]; private final int STATUS_LABELS = 6; private final JLabel[] statusLabel = new JLabel[ STATUS_LABELS ]; private final JLabel[] statusValueLabel = new JLabel[ STATUS_LABELS ]; private final int CONSUMPTION_LABELS = 3; private final JLabel[] consumptionLabel = new JLabel[ CONSUMPTION_LABELS ]; private final JLabel[] consumptionValueLabel = new JLabel[ CONSUMPTION_LABELS ]; private final FamiliarLabel familiarLabel; private final int BONUS_LABELS = 10; private final JLabel[] bonusLabel = new JLabel[ BONUS_LABELS ]; private final JLabel[] bonusValueLabel = new JLabel[ BONUS_LABELS ]; private final JPopupMenu modPopup; private final JLabel modPopLabel; // Sneaky Pete's Motorcycle private final JPopupMenu motPopup; private final JLabel motPopLabel; private static final AdventureResult CLUMSY = EffectPool.get( EffectPool.CLUMSY ); private static final AdventureResult SLIMED = EffectPool.get( EffectPool.COATED_IN_SLIME ); public CompactSidePane() { super( new BorderLayout() ); JPanel labelPanel, valuePanel; JPanel[] panels = new JPanel[ 6 ]; int panelCount = -1; panels[ ++panelCount ] = new JPanel( new BorderLayout() ); this.levelPanel = panels[ 0 ]; panels[ panelCount ].add( this.levelLabel = new JLabel( " ", JLabel.CENTER ), BorderLayout.NORTH ); panels[ panelCount ].add( this.levelMeter = new JProgressBar(), BorderLayout.CENTER ); this.levelMeter.setOpaque( true ); this.levelMeter.setStringPainted( true ); JComponentUtilities.setComponentSize( this.levelMeter, 40, 6 ); panels[ panelCount ].add( Box.createHorizontalStrut( 10 ), BorderLayout.WEST ); panels[ panelCount ].add( Box.createHorizontalStrut( 10 ), BorderLayout.EAST ); panels[ panelCount ].setOpaque( false ); JPanel holderPanel = new JPanel( new GridLayout( 2, 1 ) ); holderPanel.add( this.roninLabel = new JLabel( " ", JLabel.CENTER ) ); holderPanel.add( this.mcdLabel = new JLabel( " ", JLabel.CENTER ) ); holderPanel.setOpaque( false ); panels[ panelCount ].add( holderPanel, BorderLayout.SOUTH ); panels[ ++panelCount ] = new JPanel( new BorderLayout() ); panels[ panelCount ].setOpaque( false ); labelPanel = new JPanel( new GridLayout( this.STAT_LABELS, 1 ) ); labelPanel.setOpaque( false ); for ( int i = 0; i < this.STAT_LABELS ; i++ ) { labelPanel.add( this.statLabel[ i ] = new JLabel( " ", JLabel.RIGHT ) ); } valuePanel = new JPanel( new GridLayout( this.STAT_LABELS, 1 ) ); valuePanel.setOpaque( false ); for ( int i = 0; i < this.STAT_LABELS ; i++ ) { valuePanel.add( this.statValueLabel[ i ] = new JLabel( " ", JLabel.LEFT ) ); } panels[ panelCount ].add( labelPanel, BorderLayout.WEST ); panels[ panelCount ].add( valuePanel, BorderLayout.CENTER ); panels[ ++panelCount ] = new JPanel( new BorderLayout() ); panels[ panelCount ].setOpaque( false ); labelPanel = new JPanel( new GridLayout( this.STATUS_LABELS, 1 ) ); labelPanel.setOpaque( false ); for ( int i = 0; i < this.STATUS_LABELS ; i++ ) { labelPanel.add( this.statusLabel[ i ] = new JLabel( " ", JLabel.RIGHT ) ); } valuePanel = new JPanel( new GridLayout( this.STATUS_LABELS, 1 ) ); valuePanel.setOpaque( false ); for ( int i = 0; i < this.STATUS_LABELS ; i++ ) { valuePanel.add( this.statusValueLabel[ i ] = new JLabel( " ", JLabel.LEFT ) ); } panels[ panelCount ].add( labelPanel, BorderLayout.WEST ); panels[ panelCount ].add( valuePanel, BorderLayout.CENTER ); panels[ ++panelCount ] = new JPanel( new BorderLayout() ); panels[ panelCount ].setOpaque( false ); labelPanel = new JPanel( new GridLayout( this.CONSUMPTION_LABELS, 1 ) ); labelPanel.setOpaque( false ); for ( int i = 0; i < this.CONSUMPTION_LABELS ; i++ ) { labelPanel.add( this.consumptionLabel[ i ] = new JLabel( " ", JLabel.RIGHT ) ); } valuePanel = new JPanel( new GridLayout( this.CONSUMPTION_LABELS, 1 ) ); valuePanel.setOpaque( false ); for ( int i = 0; i < this.CONSUMPTION_LABELS ; i++ ) { valuePanel.add( this.consumptionValueLabel[ i ] = new JLabel( " ", JLabel.LEFT ) ); } panels[ panelCount ].add( labelPanel, BorderLayout.WEST ); panels[ panelCount ].add( valuePanel, BorderLayout.CENTER ); panels[ ++panelCount ] = new JPanel( new GridLayout( 1, 1 ) ); panels[ panelCount ].add( this.familiarLabel = new FamiliarLabel() ); panels[ panelCount ].addMouseListener( new FamPopListener() ); // Make a popup label for Sneaky Pete's motorcycle. Clicking on // the motorcycle image (which replaces the familiar icon) // activates it. this.motPopLabel = new JLabel(); this.motPopup = new JPopupMenu(); this.motPopup.insert( this.motPopLabel, 0 ); panels[ ++panelCount ] = new JPanel( new GridLayout( this.BONUS_LABELS , 2 ) ); for ( int i = 0; i < this.BONUS_LABELS ; i++ ) { panels[ panelCount ].add( this.bonusLabel[ i ] = new JLabel( " ", JLabel.RIGHT ) ); panels[ panelCount ].add( this.bonusValueLabel[ i ] = new JLabel( " ", JLabel.LEFT ) ); } this.modPopLabel = new JLabel(); this.modPopup = new JPopupMenu(); this.modPopup.insert( this.modPopLabel, 0 ); panels[ panelCount ].addMouseListener( new ModPopListener() ); JPanel compactContainer = new JPanel(); compactContainer.setOpaque( false ); compactContainer.setLayout( new BoxLayout( compactContainer, BoxLayout.Y_AXIS ) ); for ( int i = 0; i < panels.length; ++i ) { panels[ i ].setOpaque( false ); compactContainer.add( panels[ i ] ); compactContainer.add( Box.createVerticalStrut( 20 ) ); } compactContainer.add( Box.createHorizontalStrut( 110 ) ); JPanel compactCard = new JPanel( new CardLayout( 8, 8 ) ); compactCard.setOpaque( false ); compactCard.add( compactContainer, "" ); JPanel refreshPanel = new JPanel(); refreshPanel.setOpaque( false ); refreshPanel.add( new InvocationButton( "Refresh Status", "refresh.gif", ApiRequest.class, "updateStatus" ) ); this.add( refreshPanel, BorderLayout.SOUTH ); this.add( compactCard, BorderLayout.NORTH ); this.levelLabel.setForeground( Color.BLACK ); this.roninLabel.setForeground( Color.BLACK ); this.mcdLabel.setForeground( Color.BLACK ); for ( int i = 0; i < this.STAT_LABELS ; i++ ) { this.statLabel[ i ].setForeground( Color.BLACK ); this.statValueLabel[ i ].setForeground( Color.BLACK ); } for ( int i = 0; i < this.STATUS_LABELS ; i++ ) { this.statusLabel[ i ].setForeground( Color.BLACK ); this.statusValueLabel[ i ].setForeground( Color.BLACK ); } for ( int i = 0; i < this.CONSUMPTION_LABELS ; i++ ) { this.consumptionLabel[ i ].setForeground( Color.BLACK ); this.consumptionValueLabel[ i ].setForeground( Color.BLACK ); } for ( int i = 0; i < this.BONUS_LABELS ; i++ ) { this.bonusLabel[ i ].setForeground( Color.BLACK ); this.bonusValueLabel[ i ].setForeground( Color.BLACK ); } } private class ModPopListener extends MouseAdapter { @Override public void mousePressed( MouseEvent e ) { CompactSidePane.this.modPopup.show( e.getComponent(), e.getX(), e.getY() ); } } private class FamPopListener extends MouseAdapter { @Override public void mousePressed( MouseEvent e ) { if ( KoLCharacter.isSneakyPete() ) { CompactSidePane.this.motPopup.show( e.getComponent(), e.getX(), e.getY() ); return; } JPopupMenu famPopup = new JPopupMenu(); if ( KoLCharacter.inAxecore() ) { this.addInstruments( famPopup ); } else if ( KoLCharacter.isEd() ) { this.addServants( famPopup ); } else { this.addFamiliars( famPopup ); } famPopup.show( e.getComponent(), e.getX(), e.getY() ); } private void addInstruments( JPopupMenu famPopup ) { AdventureResult item = CharPaneRequest.SACKBUT; if ( item.getCount( KoLConstants.inventory ) > 0 ) { famPopup.add( new InstrumentMenuItem( item ) ); } item = CharPaneRequest.CRUMHORN; if ( item.getCount( KoLConstants.inventory ) > 0 ) { famPopup.add( new InstrumentMenuItem( item ) ); } item = CharPaneRequest.LUTE; if ( item.getCount( KoLConstants.inventory ) > 0 ) { famPopup.add( new InstrumentMenuItem( item ) ); } } private void addServants( JPopupMenu famPopup ) { EdServantData current = EdServantData.currentServant(); for ( EdServantData servant : EdServantData.getServants() ) { if ( servant != current && servant != EdServantData.NO_SERVANT ) { famPopup.add( new ServantMenuItem( servant ) ); } } } private void addFamiliars( JPopupMenu famPopup ) { JMenu stat = new JMenu( "stat gain" ); JMenu item = new JMenu( "item drop" ); JMenu meat = new JMenu( "meat drop" ); JMenu drops = new JMenu( "special drops" ); // Combat submenus JMenu combat0 = new JMenu( "physical only" ); JMenu combat1 = new JMenu( "elemental only" ); JMenu combat01 = new JMenu( "physical and elemental" ); JMenu block = new JMenu( "block" ); JMenu delevel = new JMenu( "delevel" ); JMenu hp0 = new JMenu( "restore HP" ); JMenu mp0 = new JMenu( "restore MP" ); JMenu stat2 = new JMenu( "stats" ); JMenu meat1 = new JMenu( "meat" ); JMenu other0 = new JMenu( "anything else" ); // After Combat submenu JMenu hp1 = new JMenu( "restore HP" ); JMenu mp1 = new JMenu( "restore MP" ); JMenu stat3 = new JMenu( "stats" ); JMenu other1 = new JMenu( "anything else" ); JMenu passive = new JMenu( "passive" ); JMenu underwater = new JMenu( "underwater" ); JMenu variable = new JMenu( "configurable" ); // None of the above JMenu other = new JMenu( "other" ); String custom[] = new String[9]; JMenu customMenu[] = new JMenu[9]; for ( int i = 0; i < 9; ++i ) { String pref = Preferences.getString( "familiarCategory" + (i + 1) ); if ( pref.length() > 0 ) { custom[ i ] = pref.toLowerCase(); customMenu[ i ] = new JMenu( pref.split( "\\|", 2 )[ 0 ] ); } } for ( FamiliarData fam : KoLCharacter.getFamiliarList() ) { if ( fam == FamiliarData.NO_FAMILIAR ) { continue; // no menu item for this one } // If we cannot equip this familiar for some reason, skip it. if ( !fam.canEquip() ) { continue; } if ( fam.equals( KoLCharacter.getFamiliar() ) ) { continue; // no menu item for this one } if ( fam.getFavorite() ) { famPopup.add( new FamiliarMenuItem( fam ) ); continue; } int id = fam.getId(); Modifiers mods = Modifiers.getModifiers( "Familiar", fam.getRace() ); boolean added = false; // Stat Gain if ( FamiliarDatabase.isVolleyType( id ) || FamiliarDatabase.isSombreroType( id ) || (mods != null && mods.get( Modifiers.VOLLEYBALL_WEIGHT ) != 0.0) ) { stat.add( new FamiliarMenuItem( fam ) ); added = true; } // Item Drop if ( FamiliarDatabase.isFairyType( id ) ) { item.add( new FamiliarMenuItem( fam ) ); added = true; } // Meat Drop if ( FamiliarDatabase.isMeatDropType( id ) ) { meat.add( new FamiliarMenuItem( fam ) ); added = true; } // Special drops if ( FamiliarDatabase.isDropType( id ) ) { drops.add( new FamiliarMenuItem( fam ) ); added = true; } // Combat submenus boolean is0 = FamiliarDatabase.isCombat0Type( id ); boolean is1 = FamiliarDatabase.isCombat1Type( id ); if ( is0 && !is1 ) { combat0.add( new FamiliarMenuItem( fam ) ); added = true; } if ( is1 && !is0 ) { combat1.add( new FamiliarMenuItem( fam ) ); added = true; } if ( is0 && is1 ) { combat01.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isBlockType( id ) ) { block.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isDelevelType( id ) ) { delevel.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isHp0Type( id ) ) { hp0.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isMp0Type( id ) ) { mp0.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isStat2Type( id ) ) { stat2.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isMeat1Type( id ) ) { meat1.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isOther0Type( id ) ) { other0.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isHp1Type( id ) ) { hp1.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isMp1Type( id ) ) { mp1.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isStat3Type( id ) ) { stat3.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isOther1Type( id ) ) { other1.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isPassiveType( id ) ) { passive.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isUnderwaterType( id ) ) { underwater.add( new FamiliarMenuItem( fam ) ); added = true; } if ( FamiliarDatabase.isVariableType( id ) ) { variable.add( new FamiliarMenuItem( fam ) ); added = true; } String key = "|" + fam.getRace().toLowerCase(); for ( int i = 0; i < 9; ++i ) { if ( custom[ i ] != null && custom[ i ].contains( key ) ) { customMenu[ i ].add( new FamiliarMenuItem( fam ) ); added = true; } } if ( !added ) { other.add( new FamiliarMenuItem( fam ) ); } } if ( stat.getMenuComponentCount() > 0 ) { famPopup.add( stat ); } if ( item.getMenuComponentCount() > 0 ) { famPopup.add( item ); } if ( meat.getMenuComponentCount() > 0 ) { famPopup.add( meat ); } if ( drops.getMenuComponentCount() > 0 ) { famPopup.add( drops ); } if ( combat0.getMenuComponentCount() > 0 || combat1.getMenuComponentCount() > 0 || combat01.getMenuComponentCount() > 0 || block.getMenuComponentCount() > 0 || delevel.getMenuComponentCount() > 0 || hp0.getMenuComponentCount() > 0 || mp0.getMenuComponentCount() > 0 || stat2.getMenuComponentCount() > 0 || meat1.getMenuComponentCount() > 0 || other0.getMenuComponentCount() > 0 ) { JMenu combat = new JMenu( "combat" ); if ( combat0.getMenuComponentCount() > 0 ) { combat.add( combat0 ); } if ( combat1.getMenuComponentCount() > 0 ) { combat.add( combat1 ); } if ( combat01.getMenuComponentCount() > 0 ) { combat.add( combat01 ); } if ( block.getMenuComponentCount() > 0 ) { combat.add( block ); } if ( delevel.getMenuComponentCount() > 0 ) { combat.add( delevel ); } if ( hp0.getMenuComponentCount() > 0 ) { combat.add( hp0 ); } if ( mp0.getMenuComponentCount() > 0 ) { combat.add( mp0 ); } if ( stat2.getMenuComponentCount() > 0 ) { combat.add( stat2 ); } if ( meat1.getMenuComponentCount() > 0 ) { combat.add( meat1 ); } if ( other0.getMenuComponentCount() > 0 ) { combat.add( other0 ); } famPopup.add( combat ); } if ( hp1.getMenuComponentCount() > 0 || mp1.getMenuComponentCount() > 0 || stat3.getMenuComponentCount() > 0 || other1.getMenuComponentCount() > 0 ) { JMenu aftercombat = new JMenu( "after combat" ); if ( hp1.getMenuComponentCount() > 0 ) { aftercombat.add( hp1 ); } if ( mp1.getMenuComponentCount() > 0 ) { aftercombat.add( mp1 ); } if ( stat3.getMenuComponentCount() > 0 ) { aftercombat.add( stat3 ); } if ( other1.getMenuComponentCount() > 0 ) { aftercombat.add( other1 ); } famPopup.add( aftercombat ); } if ( passive.getMenuComponentCount() > 0 ) { famPopup.add( passive ); } if ( underwater.getMenuComponentCount() > 0 ) { famPopup.add( underwater ); } if ( variable.getMenuComponentCount() > 0 ) { famPopup.add( variable ); } for ( int i = 0; i < 9; ++i ) { JMenu menu = customMenu[ i ]; if ( menu != null && menu.getMenuComponentCount() > 0 ) { famPopup.add( menu ); } } if ( other.getMenuComponentCount() > 0 ) { famPopup.add( other ); } } } private static class FamiliarMenuItem extends ThreadedMenuItem { public FamiliarMenuItem( final FamiliarData fam ) { super( fam.getRace(), new FamiliarListener( fam ) ); if ( fam.getFavorite() ) { ImageIcon icon = FamiliarDatabase.getFamiliarImage( fam.getId() ); this.setIcon( icon ); icon.setImageObserver( this ); } } } private static class FamiliarListener extends ThreadedListener { private final FamiliarData familiar; public FamiliarListener( FamiliarData familiar ) { this.familiar = familiar; } @Override protected void execute() { CommandDisplayFrame.executeCommand( "familiar " + this.familiar.getRace() ); } } private static class InstrumentMenuItem extends ThreadedMenuItem { public InstrumentMenuItem( final AdventureResult item ) { super( item.getName(), new UseItemListener( item ) ); ImageIcon icon = ItemDatabase.getItemImage( item.getItemId() ); this.setIcon( icon ); icon.setImageObserver( this ); } } private static class UseItemListener extends ThreadedListener { private final String command; public UseItemListener( AdventureResult item ) { this.command = "use " + item.getName(); } @Override protected void execute() { CommandDisplayFrame.executeCommand( this.command ); } } private static class ServantMenuItem extends ThreadedMenuItem { public ServantMenuItem( final EdServantData servant ) { super( servant.getType(), new ChangeServantListener( servant ) ); ImageIcon icon = FileUtilities.downloadIcon( servant.getImage(), "itemimages", "debug.gif" ); this.setIcon( icon ); icon.setImageObserver( this ); } } private static class ChangeServantListener extends ThreadedListener { private final EdServantData servant; public ChangeServantListener( EdServantData servant ) { this.servant = servant; } @Override protected void execute() { CommandDisplayFrame.executeCommand( "servant " + this.servant.getType() ); } } public String getStatText( final int adjusted, final int base ) { return adjusted == base ? "<html>" + Integer.toString( base ) : adjusted > base ? "<html><font color=blue>" + Integer.toString( adjusted ) + "</font> (" + Integer.toString( base ) + ")" : "<html><font color=red>" + Integer.toString( adjusted ) + "</font> (" + Integer.toString( base ) + ")"; } public void run() { String limitmode = KoLCharacter.getLimitmode(); if ( limitmode != Limitmode.SPELUNKY ) { this.levelLabel.setText( "Level " + KoLCharacter.getLevel() ); } else { this.levelLabel.setText( " " ); } if ( limitmode == Limitmode.SPELUNKY ) { this.roninLabel.setText( "(Spelunkin')" ); } else if ( CharPaneRequest.inValhalla() ) { this.roninLabel.setText( "(Valhalla)" ); } else if ( KoLCharacter.inBadMoon() ) { this.roninLabel.setText( "(Bad Moon)" ); } else if ( KoLCharacter.isHardcore() ) { this.roninLabel.setText( "(Hardcore)" ); } else if ( KoLCharacter.canInteract() ) { this.roninLabel.setText( "(Ronin Clear)" ); } else { this.roninLabel.setText( "(Ronin for " + ( 1000 - KoLCharacter.getCurrentRun() ) + ")" ); } if ( limitmode != Limitmode.SPELUNKY ) { this.mcdLabel.setText( "ML @ " + KoLCharacter.getMindControlLevel() ); } else { this.mcdLabel.setText( "" ); } int count = 0; this.statLabel[ count ].setText( " Mus: " ); this.statValueLabel[ count ].setText( this.getStatText( KoLCharacter.getAdjustedMuscle(), KoLCharacter.getBaseMuscle() ) ); count++; if ( limitmode != Limitmode.SPELUNKY ) { this.statLabel[ count ].setText( " Mys: " ); this.statValueLabel[ count ].setText( this.getStatText( KoLCharacter.getAdjustedMysticality(), KoLCharacter.getBaseMysticality() ) ); count++; } this.statLabel[ count ].setText( " Mox: " ); this.statValueLabel[ count ].setText( this.getStatText( KoLCharacter.getAdjustedMoxie(), KoLCharacter.getBaseMoxie() ) ); count++; for( int i = count ; i < STAT_LABELS ; i++ ) { this.statLabel[ i ].setText( "" ); this.statValueLabel[ i ].setText( "" ); } count = 0; int limit = KoLCharacter.getFullnessLimit(); if ( limit > 0 ) { this.consumptionLabel[ count ].setText( " Full: " ); this.consumptionValueLabel[ count ].setText( KoLCharacter.getFullness() + " / " + limit ); count++; } limit = KoLCharacter.getInebrietyLimit(); if ( limit > 0 ) { this.consumptionLabel[ count ].setText( " Drunk: " ); this.consumptionValueLabel[ count ].setText( KoLCharacter.getInebriety() + " / " + limit ); count++; } limit = KoLCharacter.getSpleenLimit(); if ( limit > 0 ) { this.consumptionLabel[ count ].setText( "Spleen: " ); this.consumptionValueLabel[ count ].setText( KoLCharacter.getSpleenUse() + " / " + limit ); count++; } for( int i = count ; i < CONSUMPTION_LABELS ; i++ ) { this.consumptionLabel[ i ].setText( "" ); this.consumptionValueLabel[ i ].setText( "" ); } count = 0; this.statusLabel[ count ].setText( " HP: " ); this.statusValueLabel[ count ].setText( KoLConstants.COMMA_FORMAT.format( KoLCharacter.getCurrentHP() ) + " / " + KoLConstants.COMMA_FORMAT.format( KoLCharacter.getMaximumHP() ) ); count++; if ( limitmode != Limitmode.SPELUNKY ) { if ( KoLCharacter.inZombiecore() ) { this.statusLabel[ count ].setText( " Horde: " ); this.statusValueLabel[ count ].setText( String.valueOf( KoLCharacter.getCurrentMP() ) ); count++; } else { this.statusLabel[ count ].setText( " MP: " ); this.statusValueLabel[ count ].setText( KoLConstants.COMMA_FORMAT.format( KoLCharacter.getCurrentMP() ) + " / " + KoLConstants.COMMA_FORMAT.format( KoLCharacter.getMaximumMP() ) ); count++; } if ( KoLCharacter.getFuryLimit() > 0 ) { this.statusLabel[ count ].setText( " Fury: " ); this.statusValueLabel[ count ].setText( KoLCharacter.getFury() + " / " + KoLCharacter.getFuryLimit() ); count++; } else if ( KoLCharacter.getClassType() == KoLCharacter.SAUCEROR && !KoLCharacter.inNuclearAutumn() ) { this.statusLabel[ count ].setText( "Soulsauce: "); this.statusValueLabel[ count ].setText( KoLCharacter.getSoulsauce() + " / 100" ); count++; } else if ( KoLCharacter.getClassType() == KoLCharacter.DISCO_BANDIT && !KoLCharacter.inNuclearAutumn() ) { this.statusLabel[ count ].setText( " Disco: " ); this.statusValueLabel[ count ].setText( KoLCharacter.getDiscoMomentum() + " / 3" ); count++; } else if ( KoLCharacter.isSneakyPete() ) { limit = KoLCharacter.getAudienceLimit(); this.statusLabel[ count ].setText( " Aud: " ); this.statusValueLabel[ count ].setText( KoLCharacter.getAudience() + " / " + limit ); count++; } else if ( KoLCharacter.inNoobcore() ) { limit = KoLCharacter.getAbsorbsLimit(); this.statusLabel[ count ].setText( " Abs: " ); this.statusValueLabel[ count ].setText( KoLCharacter.getAbsorbs() + " / " + limit ); count++; } this.statusLabel[ count ].setText( " Meat: " ); this.statusValueLabel[ count ].setText( KoLConstants.COMMA_FORMAT.format( KoLCharacter.getAvailableMeat() ) ); this.statusValueLabel[ count ].setToolTipText( "Closet: " + KoLConstants.COMMA_FORMAT.format( KoLCharacter.getClosetMeat() ) ); count++; if ( KoLCharacter.getHippyStoneBroken() ) { this.statusLabel[ count ].setText( " PvP: " ); this.statusValueLabel[ count ].setText( String.valueOf( KoLCharacter.getAttacksLeft() ) ); count++; } this.statusLabel[ count ].setText( " Adv: " ); this.statusValueLabel[ count ].setText( String.valueOf( KoLCharacter.getAdventuresLeft() ) ); count++; if ( KoLCharacter.isEd() ) { this.statusLabel[ count ].setText( " Ka: " ); this.statusValueLabel[ count ].setText( String.valueOf( InventoryManager.getCount( ItemPool.KA_COIN ) ) ); count++; } } else { this.statusLabel[ count ].setText( " Gold: " ); this.statusValueLabel[ count ].setText( String.valueOf( SpelunkyRequest.getGold() ) ); count++; this.statusLabel[ count ].setText( " Bomb: " ); this.statusValueLabel[ count ].setText( String.valueOf( SpelunkyRequest.getBomb() ) ); count++; this.statusLabel[ count ].setText( " Rope: " ); this.statusValueLabel[ count ].setText( String.valueOf( SpelunkyRequest.getRope() ) ); count++; this.statusLabel[ count ].setText( " Key: " ); this.statusValueLabel[ count ].setText( String.valueOf( SpelunkyRequest.getKey() ) ); count++; this.statusLabel[ count ].setText( " Turns: " ); this.statusValueLabel[ count ].setText( String.valueOf( SpelunkyRequest.getTurnsLeft() ) ); count++; } for( int i = count ; i < STATUS_LABELS ; i++ ) { this.statusLabel[ i ].setText( "" ); this.statusValueLabel[ i ].setText( "" ); } count = 0; if ( limitmode != Limitmode.SPELUNKY ) { // Remove this if/when KoL supports Water Level effect on Oil Peak/Tavern if ( KoLCharacter.inRaincore() ) { this.bonusLabel[ count ].setText( " ML: " ); this.bonusValueLabel[ count ].setText( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.getMonsterLevelAdjustment() ) + " (" + KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.MONSTER_LEVEL ) ) + ")" ); count++; } else { this.bonusLabel[ count ].setText( " ML: " ); this.bonusValueLabel[ count ].setText( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.getMonsterLevelAdjustment() ) ); count++; } this.bonusLabel[ count ].setText( " Enc: " ); this.bonusValueLabel[ count ].setText( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( KoLCharacter.getCombatRateAdjustment() ) + "%" ); count++; this.bonusLabel[ count ].setText( " Init: " ); this.bonusValueLabel[ count ].setText( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( KoLCharacter.getInitiativeAdjustment() ) + "%" ); count++; this.bonusLabel[ count ].setText( " Exp: " ); this.bonusValueLabel[ count ].setText( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( KoLCharacter.getExperienceAdjustment() ) ); count++; this.bonusLabel[ count ].setText( " Meat: " ); this.bonusValueLabel[ count ].setText( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( KoLCharacter.getMeatDropPercentAdjustment() ) + "%" ); count++; this.bonusLabel[ count ].setText( " Item: " ); this.bonusValueLabel[ count ].setText( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( KoLCharacter.getItemDropPercentAdjustment() ) + "%" ); count++; int hobo = KoLCharacter.getHoboPower(); if ( hobo != 0 && count < this.BONUS_LABELS ) { this.bonusLabel[ count ].setText( "Hobo: " ); this.bonusValueLabel[ count ].setText( KoLConstants.MODIFIER_FORMAT.format( hobo ) ); count++; } int smithsness = KoLCharacter.getSmithsness(); if ( smithsness != 0 && count < this.BONUS_LABELS ) { this.bonusLabel[ count ].setText( "Smithsness: " ); this.bonusValueLabel[ count ].setText( KoLConstants.MODIFIER_FORMAT.format( smithsness ) ); count++; } if ( KoLCharacter.inBeecore() && count < this.BONUS_LABELS ) { int bee = KoLCharacter.getBeeosity(); this.bonusLabel[ count ].setText( "Bees: " ); this.bonusValueLabel[ count ].setText( String.valueOf( bee ) ); count++; } int surgeon = (int) KoLCharacter.currentNumericModifier( Modifiers.SURGEONOSITY ); if ( surgeon != 0 && count < this.BONUS_LABELS ) { this.bonusLabel[ count ].setText( "Surgeon: " ); this.bonusValueLabel[ count ].setText( surgeon + " / 5" ); count++; } int rave = KoLCharacter.currentBitmapModifier( Modifiers.RAVEOSITY ); if ( rave != 0 && count < this.BONUS_LABELS ) { this.bonusLabel[ count ].setText( "Rave: " ); this.bonusValueLabel[ count ].setText( rave + " / 7" ); count++; } int clown = KoLCharacter.getClownosity(); if ( clown != 0 && count < this.BONUS_LABELS ) { this.bonusLabel[ count ].setText( "Clown: " ); this.bonusValueLabel[ count ].setText( clown + " / 4" ); count++; } } else { this.bonusLabel[ count ].setText( "DR: " ); this.bonusValueLabel[ count ].setText( String.valueOf( (int)KoLCharacter.currentNumericModifier( Modifiers.DAMAGE_REDUCTION ) ) ); count++; this.bonusLabel[ count ].setText( "Luck: " ); this.bonusValueLabel[ count ].setText( String.valueOf( (int)KoLCharacter.currentNumericModifier( Modifiers.LUCK ) ) ); count++; } for( int i = count ; i < BONUS_LABELS ; i++ ) { this.bonusLabel[ i ].setText( "" ); this.bonusValueLabel[ i ].setText( "" ); } try { String popText = CompactSidePane.modifierPopupText(); this.modPopLabel.setText( popText ); } catch ( Exception e ) { // Ignore errors - there seems to be a Java bug that // occasionally gets triggered during the setText(). } if ( limitmode != Limitmode.SPELUNKY ) { long currentLevel = KoLCharacter.calculateLastLevel(); long nextLevel = KoLCharacter.calculateNextLevel(); long totalPrime = KoLCharacter.getTotalPrime(); this.levelMeter.setMaximum( (int) (nextLevel - currentLevel) ); this.levelMeter.setValue( (int) (totalPrime - currentLevel) ); this.levelMeter.setString( " " ); this.levelPanel.setToolTipText( "<html>  " + KoLCharacter.getAdvancement() + "  <br>  (" + KoLConstants.COMMA_FORMAT.format( nextLevel - totalPrime ) + " subpoints needed)  </html>" ); } else { this.levelMeter.setMaximum( 1 ); this.levelMeter.setValue( 1 ); this.levelMeter.setString( " " ); this.levelPanel.setToolTipText( "" ); } if ( limitmode == Limitmode.SPELUNKY ) { String imageName = SpelunkyRequest.getBuddyImageName(); if ( imageName == null ) { this.familiarLabel.setNoIcon(); return; } this.familiarLabel.setIcon( imageName, "otherimages/" ); this.familiarLabel.setText( SpelunkyRequest.getBuddyName() ); } else if ( KoLCharacter.inAxecore() ) { AdventureResult item = KoLCharacter.getCurrentInstrument(); if ( item == null ) { this.familiarLabel.setNoIcon(); return; } this.familiarLabel.setIcon( ItemDatabase.getItemImageLocation( item.getItemId() ), "itemimages/" ); this.familiarLabel.setText( "Level " + KoLCharacter.getMinstrelLevel() ); } else if ( KoLCharacter.isJarlsberg() ) { Companion companion = KoLCharacter.getCompanion(); if ( companion == null ) { this.familiarLabel.setNoIcon(); return; } this.familiarLabel.setIcon( companion.imageName(), "itemimages/" ); } else if ( KoLCharacter.isSneakyPete() ) { this.familiarLabel.setIcon( "motorbike.gif", "itemimages/" ); String popText = CompactSidePane.motorcyclePopupText(); try { this.motPopLabel.setText( popText ); } catch ( Exception e ) { // Ignore errors - there seems to be a Java bug that // occasionally gets triggered during the setText(). } } else if ( KoLCharacter.isEd() ) { EdServantData servant = EdServantData.currentServant(); if ( servant == null ) { this.familiarLabel.setNoIcon(); return; } this.familiarLabel.setIcon( servant.getImage(), "itemimages/" ); this.familiarLabel.setText( "<HTML><center>level " + servant.getLevel() + "</center></HTML>" ); } else { this.familiarLabel.update(); } } private class FamiliarLabel extends JLabel implements Listener { private final ImageIcon noFamiliarImage = FamiliarDatabase.getNoFamiliarImage(); public FamiliarLabel() { super( " ", null, SwingConstants.CENTER ); this.setForeground( Color.BLACK ); this.setVerticalTextPosition( JLabel.BOTTOM ); this.setHorizontalTextPosition( JLabel.CENTER ); NamedListenerRegistry.registerNamedListener( "(familiar image)", this ); } private void setNoIcon() { this.setIcon( this.noFamiliarImage ); this.setText( "" ); } public void setIcon( final String image, final String prefix ) { if ( image == null ) { this.setNoIcon(); return; } String path = prefix + image; FileUtilities.downloadImage( KoLmafia.imageServerPath() + path ); ImageIcon icon = JComponentUtilities.getImage( path ); super.setIcon( icon ); icon.setImageObserver( this ); } public void update() { FamiliarData current = KoLCharacter.getFamiliar(); FamiliarData effective = KoLCharacter.getEffectiveFamiliar(); int id = effective == null ? -1 : effective.getId(); if ( id == -1 ) { this.setNoIcon(); return; } this.setIcon( KoLCharacter.getFamiliarImage(), "itemimages/" ); StringBuffer anno = CharPaneDecorator.getFamiliarAnnotation(); int weight = current.getModifiedWeight(); this.setText( "<HTML><center>" + weight + ( weight == 1 ? " lb." : " lbs." ) + ( anno == null ? "" : "<br>" + anno.toString() ) + "</center></HTML>" ); } } private static String motorcyclePopupText() { String tires = Preferences.getString( "peteMotorbikeTires" ); String gasTank = Preferences.getString( "peteMotorbikeGasTank" ); String headlight = Preferences.getString( "peteMotorbikeHeadlight" ); String cowling = Preferences.getString( "peteMotorbikeCowling" ); String muffler = Preferences.getString( "peteMotorbikeMuffler" ); String seat = Preferences.getString( "peteMotorbikeSeat" ); StringBuilder buf = new StringBuilder( "<html><table border=1>" ); buf.append( "<tr><td>Tires</td><td>" ); buf.append( tires ); buf.append( "</td></tr>" ); buf.append( "<tr><td>Gas Tank</td><td>" ); buf.append( gasTank ); buf.append( "</td></tr>" ); buf.append( "<tr><td>Headlight</td><td>" ); buf.append( headlight ); buf.append( "</td></tr>" ); buf.append( "<tr><td>Cowling</td><td>" ); buf.append( cowling ); buf.append( "</td></tr>" ); buf.append( "<tr><td>Muffler</td><td>" ); buf.append( muffler ); buf.append( "</td></tr>" ); buf.append( "<tr><td>Seat</td><td>" ); buf.append( seat ); buf.append( "</td></tr>" ); buf.append( "</table></html>" ); return buf.toString(); } private static String modifierPopupText() { StringBuffer buf = new StringBuffer( "<html><table border=1>" ); int[] predicted = KoLCharacter.getCurrentModifiers().predict(); int mus = Math.max( 1, predicted[ Modifiers.BUFFED_MUS ] ); int mys = Math.max( 1, predicted[ Modifiers.BUFFED_MYS ] ); int mox = Math.max( 1, predicted[ Modifiers.BUFFED_MOX ] ); int dmus = KoLCharacter.getAdjustedMuscle() - mus; int dmys = KoLCharacter.getAdjustedMysticality() - mys; int dmox = KoLCharacter.getAdjustedMoxie() - mox; if ( dmus != 0 || dmys != 0 || dmox != 0 ) { buf.append( "<tr><td colspan=4>Predicted: Mus " ); buf.append( mus ); buf.append( " (" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( dmus ) ); buf.append( "), Mys " ); buf.append( mys ); buf.append( " (" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( dmys ) ); buf.append( "), Mox " ); buf.append( mox ); buf.append( " (" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( dmox ) ); buf.append( ")</td></tr>" ); } int hp = Math.max( 1, predicted[ Modifiers.BUFFED_HP ] ); int mp = Math.max( 1, predicted[ Modifiers.BUFFED_MP ] ); int dhp = KoLCharacter.getMaximumHP() - hp; int dmp = KoLCharacter.getMaximumMP() - mp; if ( dhp != 0 || dmp != 0 ) { buf.append( "<tr><td colspan=4>Predicted: Max HP " ); buf.append( hp ); buf.append( " (" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( dhp ) ); buf.append( "), Max MP " ); buf.append( mp ); buf.append( " (" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( dmp ) ); buf.append( ")</td></tr>" ); } buf.append( "<tr><td></td><td>Damage</td><td>Spell dmg</td><td>Resistance</td></tr>" ); CompactSidePane.addElement( buf, "Hot", Modifiers.HOT_DAMAGE ); CompactSidePane.addElement( buf, "Cold", Modifiers.COLD_DAMAGE ); CompactSidePane.addElement( buf, "Stench", Modifiers.STENCH_DAMAGE ); CompactSidePane.addElement( buf, "Spooky", Modifiers.SPOOKY_DAMAGE ); CompactSidePane.addElement( buf, "Sleaze", Modifiers.SLEAZE_DAMAGE ); CompactSidePane.addSlime( buf ); CompactSidePane.addSupercold( buf ); buf.append( "<tr><td>Weapon</td><td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.WEAPON_DAMAGE ) ) ); buf.append( "<br>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.WEAPON_DAMAGE_PCT ) ) ); buf.append( "%</td><td rowspan=2>General<br>spell dmg:<br>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.SPELL_DAMAGE ) ) ); buf.append( "<br>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.SPELL_DAMAGE_PCT ) ) ); buf.append( "%</td><td rowspan=2>DA: " ); buf.append( KoLConstants.COMMA_FORMAT.format( KoLCharacter.getDamageAbsorption() ) ); buf.append( "<br>(" ); buf.append( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( Math.max( 0.0, ( (double) Math.sqrt( Math.min( 10000.0, KoLCharacter.getDamageAbsorption() * 10.0 ) ) - 10.0 ) ) ) ); buf.append( "%)<br>DR: " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.getDamageReduction() ) ); buf.append( "</td></tr><tr><td>Ranged</td><td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.RANGED_DAMAGE ) ) ); buf.append( "<br>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.RANGED_DAMAGE_PCT ) ) ); buf.append( "%</td></tr><tr><td>Critical</td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.CRITICAL_PCT ) ) ); buf.append( "%</td><td rowspan=2>MP cost:<br>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.getManaCostAdjustment() ) ); int hpmin = (int) KoLCharacter.currentNumericModifier( Modifiers.HP_REGEN_MIN ); int hpmax = (int) KoLCharacter.currentNumericModifier( Modifiers.HP_REGEN_MAX ); int mpmin = (int) KoLCharacter.currentNumericModifier( Modifiers.MP_REGEN_MIN ); int mpmax = (int) KoLCharacter.currentNumericModifier( Modifiers.MP_REGEN_MAX ); if ( hpmax != 0 || mpmax != 0 ) { buf.append( "<br>Regenerate:<br>HP " ); buf.append( hpmin ); if ( hpmin != hpmax ) { buf.append( "-" ); buf.append( hpmax ); } buf.append( "<br>MP " ); buf.append( mpmin ); if ( mpmin != mpmax ) { buf.append( "-" ); buf.append( mpmax ); } } buf.append( "</td><td rowspan=2>Rollover:<br>Adv " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.ADVENTURES ) + Preferences.getInteger( "extraRolloverAdventures" ) ) ); buf.append( "<br>PvP " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.PVP_FIGHTS ) ) ); buf.append( "<br>HP ~" ); buf.append( KoLCharacter.getRestingHP() ); buf.append( "<br>MP " ); buf.append( KoLCharacter.getRestingMP() ); buf.append( "</td></tr><tr><td>Fumble</td><td>" ); if ( KoLConstants.activeEffects.contains( CompactSidePane.CLUMSY ) ) { buf.append( "always" ); } else if ( KoLCharacter.currentBooleanModifier( Modifiers.NEVER_FUMBLE ) ) { buf.append( "never" ); } else { buf.append( KoLConstants.MODIFIER_FORMAT.format( KoLCharacter.currentNumericModifier( Modifiers.FUMBLE ) ) ); buf.append( " X" ); } buf.append( "</td></tr>" ); double food = KoLCharacter.currentNumericModifier( Modifiers.FOODDROP ); double booze = KoLCharacter.currentNumericModifier( Modifiers.BOOZEDROP ); double hat = KoLCharacter.currentNumericModifier( Modifiers.HATDROP ); double weapon = KoLCharacter.currentNumericModifier( Modifiers.WEAPONDROP ); double offhand = KoLCharacter.currentNumericModifier( Modifiers.OFFHANDDROP ); double shirt = KoLCharacter.currentNumericModifier( Modifiers.SHIRTDROP ); double pants = KoLCharacter.currentNumericModifier( Modifiers.PANTSDROP ); double acc = KoLCharacter.currentNumericModifier( Modifiers.ACCESSORYDROP ); if ( food != 0 || booze != 0 || hat != 0 || weapon != 0 || offhand != 0 || shirt != 0 || pants != 0 || acc != 0 ) { buf.append( "<tr><td colspan=4>Special drops:" ); if ( food != 0 ) { buf.append( " Food " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( food ) ); buf.append( '%' ); } if ( booze != 0 ) { buf.append( " Booze " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( booze ) ); buf.append( '%' ); } if ( hat != 0 ) { buf.append( " Hat " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( hat ) ); buf.append( '%' ); } if ( weapon != 0 ) { buf.append( " Weapon " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( weapon ) ); buf.append( '%' ); } if ( offhand != 0 ) { buf.append( " Offhand " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( offhand ) ); buf.append( '%' ); } if ( shirt != 0 ) { buf.append( " Shirt " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( shirt ) ); buf.append( '%' ); } if ( pants != 0 ) { buf.append( " Pants " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( pants ) ); buf.append( '%' ); } if ( acc != 0 ) { buf.append( " Accessory " ); buf.append( KoLConstants.MODIFIER_FORMAT.format( acc ) ); buf.append( '%' ); } buf.append( "</td></tr>" ); } buf.append( "</table></html>" ); return buf.toString(); } private static void addElement( StringBuffer buf, String name, int dmgModifier ) { double wdmg = KoLCharacter.currentNumericModifier( dmgModifier ); double sdmg = KoLCharacter.currentNumericModifier( dmgModifier - Modifiers.COLD_DAMAGE + Modifiers.COLD_SPELL_DAMAGE ); int resist = (int) KoLCharacter.currentNumericModifier( dmgModifier - Modifiers.COLD_DAMAGE + Modifiers.COLD_RESISTANCE ); if ( wdmg == 0.0 && sdmg == 0.0 && resist == 0 ) { return; // skip this row entirely, it's all zeros } buf.append( "<tr><td>" ); buf.append( name ); buf.append( "</td><td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( wdmg ) ); buf.append( "</td><td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( sdmg ) ); buf.append( "</td><td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( resist ) ); buf.append( " (" ); buf.append( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( KoLCharacter.elementalResistanceByLevel( resist ) ) ); buf.append( "%)</td></tr>" ); } private static void addSlime( StringBuffer buf ) { int resist = (int) KoLCharacter.currentNumericModifier( Modifiers.SLIME_RESISTANCE ); double percent = KoLCharacter.elementalResistanceByLevel( resist, false ); int turns = CompactSidePane.SLIMED.getCount( KoLConstants.activeEffects ); if ( resist == 0 && turns == 0 ) { return; // skip this row entirely, it's all zeros } buf.append( "<tr><td>Slime</td><td colspan=2>" ); if ( turns > 0 ) { buf.append( "Expected dmg " ); buf.append( KoLConstants.COMMA_FORMAT.format( Math.ceil( Math.pow( Math.max( 0, 11 - turns ), 2.727 ) * ( 100.0 - percent ) * KoLCharacter.getMaximumHP() / 10000.0 ) ) ); } buf.append( "</td><td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( resist ) ); buf.append( " (" ); buf.append( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( percent ) ); buf.append( "%)</td></tr>" ); } private static void addSupercold( StringBuffer buf ) { int resist = (int) KoLCharacter.currentNumericModifier( Modifiers.SUPERCOLD_RESISTANCE ); double percent = KoLCharacter.elementalResistanceByLevel( resist, false ); if ( resist == 0 ) { return; // skip this row entirely, it's all zeros } buf.append( "<tr><td>Supercold</td><td colspan=2>" ); buf.append( "</td><td>" ); buf.append( KoLConstants.MODIFIER_FORMAT.format( resist ) ); buf.append( " (" ); buf.append( KoLConstants.ROUNDED_MODIFIER_FORMAT.format( percent ) ); buf.append( "%)</td></tr>" ); } }