/** * 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 net.sourceforge.kolmafia.AdventureResult; import net.sourceforge.kolmafia.KoLCharacter; import net.sourceforge.kolmafia.RequestLogger; import net.sourceforge.kolmafia.objectpool.EffectPool; import net.sourceforge.kolmafia.preferences.Preferences; public abstract class BadMoonManager { public final static String STAT1 = "+20 to one stat, -5 to others"; public final static String STAT2 = "+40 to one stat, -50% Familiar Weight"; public final static String STAT3 = "+50% to one stat, -50% to another"; public final static String DAMAGE1 = "+10 damage, Damage Reduction -2"; public final static String DAMAGE2 = "+20 damage, 1-3 damage/round to self"; public final static String RESIST1 = "So-So resistance to one, Vulnerability to opposites"; public final static String RESIST2 = "Resistance to all, -attributes"; public final static String ITEM_DROP = "Item Drop"; public final static String MEAT_DROP = "Meat Drop"; public final static String DAMAGE_REDUCTION = "+ Damage Reduction, - Weapon Damage"; public final static String MEAT = "Meat"; public final static String ITEMS = "Items"; public static final String [] TYPES = { STAT1, STAT2, STAT3, DAMAGE1, DAMAGE2, RESIST1, RESIST2, ITEM_DROP, MEAT_DROP, DAMAGE_REDUCTION, MEAT, ITEMS, }; public static final Object [][] SPECIAL_ENCOUNTERS = { // Encounter Name // Adventure Zone // Prerequisites // Status Effect // Description // Type // Setting // Effects that grant +20 to one stat and -5 to the others { "O Goblin, Where Art Thou?", "Outskirts of Cobb's Knob", "receiving Knob Goblin encryption key", EffectPool.get( EffectPool.MINIONED, 10 ), "Muscle +20, Mysticality -5, Moxie -5", BadMoonManager.STAT1, "badMoonEncounter01", }, { "Pantry Raid!", "The Haunted Pantry", "opening Spookyraven Manor", EffectPool.get( EffectPool.ENHANCED_ARCHAEOLOGIST, 10 ), "Mysticality +20, Muscle -5, Moxie -5", BadMoonManager.STAT1, "badMoonEncounter02", }, { "Sandwiched in the Club", "The Sleazy Back Alley", null, EffectPool.get( EffectPool.CHRONOLOGICALLY_PUMMELLED, 10 ), "Moxie +20, Muscle -5, Mysticality -5", BadMoonManager.STAT1, "badMoonEncounter03", }, // Effects that grant +40 to one stat and -50% Familiar weight { "It's So Heavy", "Cobb's Knob Treasury", null, EffectPool.get( EffectPool.ANIMAL_EXPLOITER, 10 ), "Muscle +40, Familiar Weight -50%", BadMoonManager.STAT2, "badMoonEncounter04", }, { "KELF! I Need Somebody!", "Cobb's Knob Kitchens", null, EffectPool.get( EffectPool.SCENT_OF_A_KITCHEN_ELF, 10 ), "Mysticality +40, Familiar Weight -50%", BadMoonManager.STAT2, "badMoonEncounter05", }, { "On The Whole, the Bark is Better", "Cobb's Knob Harem", null, EffectPool.get( EffectPool.ONCE_BITTEN_TWICE_SHY, 10 ), "Moxie +40, Familiar Weight -50%", BadMoonManager.STAT2, "badMoonEncounter06", }, // Effects that adjust one stat by +50% and another by -50% { "It's All The Rage", "Orcish Frat House (Undisguised)", null, EffectPool.get( EffectPool.THE_RAGE, 10 ), "Muscle +50%, Mysticality -50%", BadMoonManager.STAT3, "badMoonEncounter07", }, { "Double-Secret Initiation", "Orcish Frat House (In Disguise)", null, EffectPool.get( EffectPool.SHAMED_AND_MANIPULATED, 10 ), "Muscle +50%, Moxie -50%", BadMoonManager.STAT3, "badMoonEncounter08", }, { "Better Dread Than Dead", "The Hippy Camp (Undisguised)", null, EffectPool.get( EffectPool.DREADLOCKED, 10 ), "Mysticality +50%, Moxie -50%", BadMoonManager.STAT3, "badMoonEncounter09", }, { "Drumroll, Please", "The Hippy Camp (In Disguise)", null, EffectPool.get( EffectPool.DRUMMED_OUT, 10 ), "Mysticality +50%, Muscle -50%", BadMoonManager.STAT3, "badMoonEncounter10", }, { "How Far Down Do You Want To Go?", "The Obligatory Pirate's Cove (Undisguised)", null, EffectPool.get( EffectPool.HORNSWAGGLED, 10 ), "Moxie +50%, Muscle -50%", BadMoonManager.STAT3, "badMoonEncounter11", }, { "Mind Your Business", "The Obligatory Pirate's Cove (In Disguise)", null, EffectPool.get( EffectPool.THIRD_EYE_BLIND, 10 ), "Moxie +50%, Mysticality -50%", BadMoonManager.STAT3, "badMoonEncounter12", }, // Effects that grant +10 damage and Damage Reduction -2 { "Vole Call!", "The Haunted Billiards Room", "opening Haunted Library", EffectPool.get( EffectPool.RE_POSSESSED, 10 ), "Bonus Weapon Damage +10, Damage Reduction -2", BadMoonManager.DAMAGE1, "badMoonEncounter13", }, { "Frost Bitten, Twice Shy", "The Goatlet", "opening The eXtreme Slope", EffectPool.get( EffectPool.FROSTBITTEN, 10 ), "+10 Cold Damage, Damage Reduction -2", BadMoonManager.DAMAGE1, "badMoonEncounter14", }, { "If You Smell Something Burning, It's My Heart", "The Haunted Kitchen", null, EffectPool.get( EffectPool.BURNING_HEART, 10 ), "+10 Hot Damage, Damage Reduction -2", BadMoonManager.DAMAGE1, "badMoonEncounter15", }, { "Oil Be Seeing You", "The Deep Fat Friars' Gate", null, EffectPool.get( EffectPool.BASTED, 10 ), "+10 Sleaze Damage, Damage Reduction -2", BadMoonManager.DAMAGE1, "badMoonEncounter16", }, { "Back Off, Man. I'm a Scientist.", "The Haunted Library", null, EffectPool.get( EffectPool.FREAKED_OUT, 10 ), "+10 Spooky Damage, Damage Reduction -2", BadMoonManager.DAMAGE1, "badMoonEncounter17", }, { "Oh Guanoes!", "Guano Junction", null, EffectPool.get( EffectPool.GUANIFIED, 10 ), "+10 Stench Damage, Damage Reduction -2", BadMoonManager.DAMAGE1, "badMoonEncounter18", }, // Effects that grant +20 damage at the cost of taking the // same kind of damage yourself every round. { "Do You Think You're Better Off Alone", "The Castle in the Clouds in the Sky", "completed Giant Trash Quest", EffectPool.get( EffectPool.RAVING_LUNATIC, 10 ), "Melee Damage +20, Lose 1-3 HP per combat round", BadMoonManager.DAMAGE2, "badMoonEncounter19", }, { "The Big Chill", "The Icy Peak", null, EffectPool.get( EffectPool.HYPERBOLIC_HYPOTHERMIA, 10 ), "+20 Cold Damage, Lose 1-3 HP (cold damage) per combat round", BadMoonManager.DAMAGE2, "badMoonEncounter20", }, { "Mr. Sun Is Not Your Friend", "An Oasis", "receiving worm-riding hooks", EffectPool.get( EffectPool.SOLAR_FLAIR, 10 ), "+20 Hot Damage, Lose 1-3 HP (hot damage) per combat round", BadMoonManager.DAMAGE2, "badMoonEncounter21", }, { "Pot Jacked", "The Hole in the Sky", "made Richard's star key", EffectPool.get( EffectPool.GREASED, 10 ), "+20 Sleaze Damage, Lose 1-3 HP (sleaze damage) per combat round", BadMoonManager.DAMAGE2, "badMoonEncounter22", }, { "Party Crasher", "The Haunted Ballroom", "opening Haunted Wine Cellar", EffectPool.get( EffectPool.SLIMED, 10 ), "+20 Spooky Damage, Lose 1-3 HP (spooky damage) per combat round", BadMoonManager.DAMAGE2, "badMoonEncounter23", }, { "A Potentially Offensive Reference Has Been Carefully Avoided Here", "The Black Forest", "opening The Black Market", EffectPool.get( EffectPool.TAR_STRUCK, 10 ), "+20 Stench Damage, Lose 1-3 HP (stench damage) per combat round", BadMoonManager.DAMAGE2, "badMoonEncounter24", }, // Effects that grant resistance to one element and // vulnerability to the opposite elements { "Strategy: Get Arts", "Inside the Palindome", "defeating Dr. Awkward", EffectPool.get( EffectPool.PAW_SWAP, 10 ), "So-So Cold Resistance. Double damage from Hot and Spooky", BadMoonManager.RESIST1, "badMoonEncounter25", }, { "Pot-Unlucky", "The Hidden City", "opening A Smallish Temple", EffectPool.get( EffectPool.DEEP_FRIED, 10 ), "So-So Hot Resistance, Double damage from Stench and Sleaze", BadMoonManager.RESIST1, "badMoonEncounter26", }, { "Mistaken Identity, LOL", "The Valley of Rof L'm Fao", "receiving facsimile dictionary", EffectPool.get( EffectPool.SCARED_STIFF, 10 ), "So-So Sleaze Resistance, Double damage from Cold and Spooky", BadMoonManager.RESIST1, "badMoonEncounter27", }, { "Mind the Fine Print", "Tower Ruins", null, EffectPool.get( EffectPool.SIDE_AFFECTATION, 10 ), "So-So Spooky Resistance, Double damage from Stench and Hot", BadMoonManager.RESIST1, "badMoonEncounter28", }, { "Sweatin' Like a Vet'ran", "The Arid, Extra-Dry Desert (Ultrahydrated)", "receiving worm-riding hooks", EffectPool.get( EffectPool.SHIRTLESS_IN_SEATTLE, 10 ), "So-So Stench Resistance, Double damage from Cold and Sleaze", BadMoonManager.RESIST1, "badMoonEncounter29", }, // Effects that grant elemental resistance and reduce attributes { "Elementally, My Deal Watson", "Beanbat Chamber", "opening The Beanstalk", EffectPool.get( EffectPool.BATIGUE, 10 ), "Slight Resistance to All Elements, All Attributes -10%", BadMoonManager.RESIST2, "badMoonEncounter30", }, { "Hair of the Hellhound", "The Haunted Wine Cellar", "defeating Lord Spookyraven", EffectPool.get( EffectPool.CUPSHOTTEN, 10 ), "So-So Resistance to All Elements, All Attributes -20%", BadMoonManager.RESIST2, "badMoonEncounter31", }, // Effects that improve Item Drop { "Shall We Dance", "Cobb's Knob Laboratory", null, EffectPool.get( EffectPool.THE_VITUS_VIRUS, 10 ), "+50% Items from Monsters, -5 Stats Per Fight", BadMoonManager.ITEM_DROP, "badMoonEncounter32", }, { "You Look Flushed", "The Haunted Bathroom", null, EffectPool.get( EffectPool.YOUR_NUMBER_1_PROBLEM, 10 ), "+100% Items from Monsters, All Attributes -20", BadMoonManager.ITEM_DROP, "badMoonEncounter33", }, // Effects that improve Meat Drop { "What Do We Want?", "The Misspelled Cemetary (Pre-Cyrpt)", null, EffectPool.get( EffectPool.BRAAAINS, 10 ), "+50% Meat from Monsters, -50% Combat Initiative", BadMoonManager.MEAT_DROP, "badMoonEncounter34", }, { "When Do We Want It?", "The Misspelled Cemetary (Post-Cyrpt)", null, EffectPool.get( EffectPool.BRAAAAAAINS, 10 ), "+200% Meat from Monsters, -50% Items from Monsters", BadMoonManager.MEAT_DROP, "badMoonEncounter35", }, // Effects that grant Damage Reduction but reduce Weapon Damage { "Getting Hammered", "The Inexplicable Door", "receiving digital key", EffectPool.get( EffectPool.MIDGETIZED, 10 ), "Damage Reduction: 4. Weapon Damage -8", BadMoonManager.DAMAGE_REDUCTION, "badMoonEncounter36", }, { "Obligatory Mascot Cameo", "The Penultimate Fantasy Airship", "opening The Castle in the Clouds in the Sky", EffectPool.get( EffectPool.SYNTHESIZED, 10 ), "Damage Reduction: 8, Weapon Damage -8", BadMoonManager.DAMAGE_REDUCTION, "badMoonEncounter37", }, // Encounters that grant meat { "This Doesn't Look Like Candy Mountain", "The Spooky Forest", null, EffectPool.get( EffectPool.MISSING_KIDNEY ), "1,000 Meat", BadMoonManager.MEAT, "badMoonEncounter38", }, { "Flowers For ", // (Familiar Name) "Degrassi Knoll", "returned the bitchin' meatcar to the guild.", EffectPool.get( EffectPool.DUHHH, 10 ), "2,000 Meat, Lose 12-56(?) MP, Mysticality -20", BadMoonManager.MEAT, "badMoonEncounter39", }, { "Onna Stick", "The Bat Hole Entrance", "opening The Boss Bat's Lair", EffectPool.get( EffectPool.AFFRONTED_DECENCY, 10 ), "3,000 Meat, Moxie -20", BadMoonManager.MEAT, "badMoonEncounter40", }, { "The Beaten-Senseless Man's Hand", "South of The Border", null, EffectPool.get( EffectPool.BEATEN_UP, 10 ), "4,000 Meat, All Attributes -50%", BadMoonManager.MEAT, "badMoonEncounter41", }, { "A White Lie", "Whitey's Grove", "opening The Road to the White Citadel", EffectPool.get( EffectPool.MAID_DISSERVICE, 10 ), "5,000 Meat, All Attributes -20%", BadMoonManager.MEAT, "badMoonEncounter42", }, // Encounters that grant items or skills { "Surprising!", "Noob Cave", null, null, "Familiar-Gro™ Terrarium, black kitten, 14 Drunkenness", BadMoonManager.ITEMS, "badMoonEncounter43", }, { "That's My Favorite Kind of Contraption", "The Spooky Forest", "opening The Hidden Temple", EffectPool.get( EffectPool.DANG_NEAR_CUT_IN_HALF, 5 ), "Muscle -50%, Gain Torso Awaregness", BadMoonManager.ITEMS, "badMoonEncounter44", }, { "Say Cheese!", "The Arid, Extra-Dry Desert (unhydrated)", null, null, "anticheese, lose 50 HP", BadMoonManager.ITEMS, "badMoonEncounter45", }, { "Because Stereotypes Are Awesome", "The Typical Tavern (Post-Quest)", null, null, "leprechaun hatchling, 1 Drunkenness", BadMoonManager.ITEMS, "badMoonEncounter46", }, { "Why Did It Have To Be Snake Eyes?", "The Hidden Temple", null, null, "loaded dice", BadMoonManager.ITEMS, "badMoonEncounter47", }, { "The Placebo Defect", "The Haunted Conservatory", null, null, "potato sprout, Lose 75% HP & MP", BadMoonManager.ITEMS, "badMoonEncounter48", }, }; private static String dataEncounterName( final Object[] data ) { return ( data == null ) ? null : ((String) data[0] ); } private static String dataLocation( final Object[] data ) { return ( data == null ) ? null : ((String) data[1] ); } private static String dataPrereq( final Object[] data ) { return ( data == null ) ? null : ((String) data[2] ); } private static AdventureResult dataEffect( final Object[] data ) { return ( data == null ) ? null : ((AdventureResult) data[3] ); } private static String dataDescription( final Object[] data ) { return ( data == null ) ? null : ((String) data[4] ); } private static String dataType( final Object[] data ) { return ( data == null ) ? null : ((String) data[5] ); } private static String dataSetting( final Object[] data ) { return ( data == null ) ? null : ((String) data[6] ); } private static Object[] encounterToData( final String encounter ) { for ( int i = 0; i < SPECIAL_ENCOUNTERS.length; ++i ) { Object [] data = SPECIAL_ENCOUNTERS[i]; String encounterName = dataEncounterName( data ); if ( encounter.startsWith( encounterName ) ) { return data; } } return null; } public static final void validateBadMoon() { int lastAscension = Preferences.getInteger( "lastBadMoonReset" ); if ( lastAscension < KoLCharacter.getAscensions() ) { Preferences.setInteger( "lastBadMoonReset", KoLCharacter.getAscensions() ); for ( int i = 0; i < SPECIAL_ENCOUNTERS.length; ++i ) { Object [] data = SPECIAL_ENCOUNTERS[i]; String setting = BadMoonManager.dataSetting( data ); if ( setting != null ) { Preferences.setBoolean( setting, false ); } } } } public static final boolean specialAdventure( final String encounterName ) { if ( !KoLCharacter.inBadMoon() ) { return false; } Object [] data = BadMoonManager.encounterToData( encounterName ); return data != null; } public static final void registerAdventure( final String encounterName ) { Object [] data = BadMoonManager.encounterToData( encounterName ); if ( data != null ) { BadMoonManager.validateBadMoon(); Preferences.setBoolean( dataSetting( data ), true ); } } public static final void report() { BadMoonManager.validateBadMoon(); StringBuffer output = new StringBuffer(); BadMoonManager.startReport( output ); for ( int i = 0; i < BadMoonManager.TYPES.length; ++i ) { String type = BadMoonManager.TYPES[ i ]; BadMoonManager.reportType( type, output ); } BadMoonManager.endReport( output ); RequestLogger.printLine( output.toString() ); RequestLogger.printLine(); } private static final void startReport( final StringBuffer output ) { output.append( "<table border=2 cols=2>" ); } private static final void endReport( final StringBuffer output ) { output.append( "</table>" ); } private static final void reportType( final String type, final StringBuffer output ) { // The "type" is a descriptive string output.append( "<tr><th colspan=2>" ); output.append( type ); output.append( "</th></tr>" ); for ( int i = 0; i < SPECIAL_ENCOUNTERS.length; ++i ) { Object [] data = SPECIAL_ENCOUNTERS[i]; if ( type != BadMoonManager.dataType( data ) ) { continue; } String name = BadMoonManager.dataEncounterName( data ); String location = BadMoonManager.dataLocation( data ); String prereq = BadMoonManager.dataPrereq( data ); AdventureResult effect = BadMoonManager.dataEffect( data ); String description = BadMoonManager.dataDescription( data ); String setting = BadMoonManager.dataSetting( data ); boolean value = setting != null ? Preferences.getBoolean( setting ) : false; output.append( "<tr><td rowspan=3>" ); output.append( value ); output.append( "</td><td align=left>" ); output.append( name ); output.append( "</td></tr><tr><td align=left>" ); output.append( location ); if ( prereq != null ) { output.append( " after " ); output.append( prereq ); } output.append( "</td></tr><tr><td align=left>" ); if ( effect != null ) { output.append( effect.toString() ); output.append( ": " ); } output.append( description ); output.append( "</td></tr>" ); } } }