using System; using Server; using Server.Misc; using Server.Items; using Server.Mobiles; using System.Collections.Generic; namespace Server.Engines.Harvest { public class Fishing : HarvestSystem { private static Fishing m_System; public static Fishing System { get { if ( m_System == null ) m_System = new Fishing(); return m_System; } } private HarvestDefinition m_Definition; public HarvestDefinition Definition { get{ return m_Definition; } } private Fishing() { HarvestResource[] res = new HarvestResource[]{ new HarvestResource( 00.0, 00.0, 100.0, 1043297, typeof( Fish ) ) }; HarvestVein[] veins = new HarvestVein[]{ new HarvestVein( 100.0, 0.0, res[0], null ) }; #region Fishing HarvestDefinition fish = new HarvestDefinition(); // Resource banks are every 8x8 tiles fish.BankWidth = 8; fish.BankHeight = 8; // Every bank holds from 5 to 15 fish fish.MinTotal = 5; fish.MaxTotal = 15; // A resource bank will respawn its content every 10 to 20 minutes fish.MinRespawn = TimeSpan.FromMinutes( 10.0 ); fish.MaxRespawn = TimeSpan.FromMinutes( 20.0 ); fish.Trade = Trades.Fishing; // Set the list of harvestable tiles fish.Tiles = m_WaterTiles; fish.RangedTiles = true; // Players must be within 4 tiles to harvest fish.MaxRange = 4; // One fish per harvest action fish.ConsumedPerHarvest = 1; // The fishing fish.EffectActions = new int[]{ 12 }; fish.EffectSounds = new int[0]; fish.EffectCounts = new int[]{ 1 }; fish.EffectDelay = TimeSpan.Zero; fish.EffectSoundDelay = TimeSpan.FromSeconds( 8.0 ); fish.NoResourcesMessage = 503172; // The fish don't seem to be biting here. fish.FailMessage = 503171; // You fish a while, but fail to catch anything. fish.TimedOutOfRangeMessage = 500976; // You need to be closer to the water to fish! fish.OutOfRangeMessage = 500976; // You need to be closer to the water to fish! fish.PackFullMessage = 503176; // You do not have room in your backpack for a fish. fish.ToolBrokeMessage = 503174; // You broke your fishing pole. fish.Resources = res; fish.Veins = veins; m_Definition = fish; Definitions.Add( fish ); #endregion } public override void OnConcurrentHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) { from.SendLocalizedMessage( 500972 ); // You are already fishing. } private class MutateEntry { public double m_ReqSkill, m_MinSkill, m_MaxSkill; public bool m_DeepWater; public Type[] m_Types; public MutateEntry( double reqSkill, double minSkill, double maxSkill, bool deepWater, params Type[] types ) { m_ReqSkill = reqSkill; m_MinSkill = minSkill; m_MaxSkill = maxSkill; m_DeepWater = deepWater; m_Types = types; } } private static MutateEntry[] m_MutateTable = new MutateEntry[] { new MutateEntry( 80.0, 80.0, 4080.0, true, typeof( SpecialFishingNet ) ), new MutateEntry( 80.0, 80.0, 4080.0, true, typeof( BigFish ) ), new MutateEntry( 90.0, 80.0, 4080.0, true, typeof( TreasureMap ) ), new MutateEntry( 100.0, 80.0, 4080.0, true, typeof( MessageInABottle ) ), new MutateEntry( 0.0, 125.0, -2375.0, false, typeof( PrizedFish ), typeof( WondrousFish ), typeof( TrulyRareFish ), typeof( PeculiarFish ) ), new MutateEntry( 0.0, 105.0, -420.0, false, typeof( Boots ), typeof( Shoes ), typeof( Sandals ), typeof( ThighBoots ) ), new MutateEntry( 0.0, 200.0, -200.0, false, new Type[1]{ null } ) }; public override Type MutateType( Type type, Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestResource resource ) { if ( !IsOnBoat( from ) ) return type; bool deepWater = SpecialFishingNet.FullValidation( map, loc.X, loc.Y ); if ( !IsOnBoat( from ) ) deepWater = false; double skillBase = SkillCheck.TradeSkill( from, Trades.Fishing, false ); double skillValue = skillBase; for ( int i = 0; i < m_MutateTable.Length; ++i ) { MutateEntry entry = m_MutateTable[i]; if ( !deepWater && entry.m_DeepWater ) continue; if ( skillBase >= entry.m_ReqSkill ) { double chance = (skillValue - entry.m_MinSkill) / (entry.m_MaxSkill - entry.m_MinSkill); if ( chance > Utility.RandomDouble() ) return entry.m_Types[Utility.Random( entry.m_Types.Length )]; } } return type; } private static Map SafeMap( Map map ) { if ( map == null || map == Map.Internal ) return Map.Britannia; return map; } public override bool CheckResources( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, bool timed ) { Container pack = from.Backpack; if ( pack != null ) { List messages = pack.FindItemsByType(); for ( int i = 0; i < messages.Count; ++i ) { SOS sos = messages[i]; if ( from.Map == Map.Britannia && from.InRange( sos.TargetLocation, 60 ) ) return true; } } return base.CheckResources( from, tool, def, map, loc, timed ); } public static bool IsOnBoat( Mobile m ) { if ( m.Z != -2 ) return false; bool KeepSearching = true; bool IsOnShip = false; foreach ( Item boatman in m.GetItemsInRange( 15 ) ) { if ( KeepSearching ) { if ( boatman is TillerMan ) { IsOnShip = true; if ( IsOnShip == true ){ KeepSearching = false; } } } } return IsOnShip; } public override Item Construct( Type type, Mobile from ) { if ( type == typeof( TreasureMap ) ) { int level = 1; return new TreasureMap( level, Map.Britannia ); } else if ( type == typeof( MessageInABottle ) ) { return new MessageInABottle(); } Container pack = from.Backpack; if ( pack != null ) { List messages = pack.FindItemsByType(); for ( int i = 0; i < messages.Count; ++i ) { SOS sos = messages[i]; if ( from.Map == Map.Britannia && from.InRange( sos.TargetLocation, 60 ) ) { Item preLoot = null; switch ( Utility.Random( 8 ) ) { case 0: // Body parts { int[] list = new int[] { 0x1CDD, 0x1CE5, // arm 0x1CE0, 0x1CE8, // torso 0x1CE1, 0x1CE9, // head 0x1CE2, 0x1CEC // leg }; preLoot = new ShipwreckedItem( Utility.RandomList( list ) ); break; } case 1: // Bone parts { int[] list = new int[] { 0x1AE0, 0x1AE1, 0x1AE2, 0x1AE3, 0x1AE4, // skulls 0x1B09, 0x1B0A, 0x1B0B, 0x1B0C, 0x1B0D, 0x1B0E, 0x1B0F, 0x1B10, // bone piles 0x1B15, 0x1B16 // pelvis bones }; preLoot = new ShipwreckedItem( Utility.RandomList( list ) ); break; } case 2: // Paintings and portraits { preLoot = new ShipwreckedItem( Utility.RandomPainting() ); break; } case 3: // Pillows { preLoot = new ShipwreckedItem( Utility.Random( 0x13A4, 11 ) ); break; } case 4: // Shells { preLoot = new ShipwreckedItem( Utility.Random( 0xFC4, 9 ) ); break; } case 5: //Hats { if ( Utility.RandomBool() ) preLoot = new SkullCap(); else preLoot = new TricorneHat(); break; } case 6: // Misc { int[] list = new int[] { 0x1EB5, // unfinished barrel 0xA2A, // stool 0xC1F, // broken clock 0x1047, 0x1048, // globe 0x1EB1, 0x1EB2, 0x1EB3, 0x1EB4 // barrel staves }; if ( Utility.Random( list.Length + 1 ) == 0 ) preLoot = new Candelabra(); else preLoot = new ShipwreckedItem( Utility.RandomList( list ) ); break; } } if ( preLoot != null ) { if ( preLoot is IShipwreckedItem ) ( (IShipwreckedItem)preLoot ).IsShipwreckedItem = true; return preLoot; } LockableContainer chest; if ( sos.IsAncient ) chest = new AncientChest(); else chest = new SunkenChest(); TreasureMapChest.Fill( chest, Math.Max( 1, Math.Max( 4, sos.Level ) ) ); if ( sos.IsAncient ) chest.DropItem( new FabledFishingNet() ); else chest.DropItem( new SpecialFishingNet() ); chest.Movable = true; chest.Locked = false; chest.TrapType = TrapType.None; chest.TrapPower = 0; chest.TrapLevel = 0; sos.Delete(); return chest; } } } return base.Construct( type, from ); } public override bool Give( Mobile m, Item item, bool placeAtFeet ) { if ( item is TreasureMap || item is MessageInABottle || item is SpecialFishingNet ) { BaseCreature serp; if ( 0.25 > Utility.RandomDouble() ) serp = new DeepSeaSerpent(); else serp = new SeaSerpent(); int x = m.X, y = m.Y; Map map = m.Map; for ( int i = 0; map != null && i < 20; ++i ) { int tx = m.X - 10 + Utility.Random( 21 ); int ty = m.Y - 10 + Utility.Random( 21 ); LandTile t = map.Tiles.GetLandTile( tx, ty ); if ( t.Z == -5 && ( (t.ID >= 0xA8 && t.ID <= 0xAB) || (t.ID >= 0x136 && t.ID <= 0x137) ) && !Spells.SpellHelper.CheckMulti( new Point3D( tx, ty, -5 ), map ) ) { x = tx; y = ty; break; } } serp.MoveToWorld( new Point3D( x, y, -5 ), map ); serp.Home = serp.Location; serp.RangeHome = 10; serp.PackItem( item ); m.SendLocalizedMessage( 503170 ); // Uh oh! That doesn't look like a fish! return true; // we don't want to give the item to the player, it's on the serpent } if ( item is BigFish || item is WoodenChest || item is MetalGoldenChest ) placeAtFeet = true; return base.Give( m, item, placeAtFeet ); } public override void SendSuccessTo( Mobile from, Item item, HarvestResource resource ) { if ( item is BigFish ) { from.SendLocalizedMessage( 1042635 ); // Your fishing pole bends as you pull a big fish from the depths! ((BigFish)item).Fisher = from; } else if ( item is WoodenChest || item is MetalGoldenChest ) { from.SendLocalizedMessage( 503175 ); // You pull up a heavy chest from the depths of the ocean! } else { int number; string name; if ( item is BaseMagicFish ) { number = 1008124; name = "a mess of small fish"; } else if ( item is Fish ) { number = 1008124; name = "a fish"; } else if ( item is BaseShoes ) { number = 1008124; name = item.ItemData.Name; } else if ( item is TreasureMap ) { number = 1008125; name = "a sodden piece of parchment"; } else if ( item is MessageInABottle ) { number = 1008125; name = "a bottle, with a message in it"; } else if ( item is SpecialFishingNet ) { number = 1008125; name = "a special fishing net"; // TODO: this is just a guess--what should it really be named? } else { number = 1043297; if ( (item.ItemData.Flags & TileFlag.ArticleA) != 0 ) name = "a " + item.ItemData.Name; else if ( (item.ItemData.Flags & TileFlag.ArticleAn) != 0 ) name = "an " + item.ItemData.Name; else name = item.ItemData.Name; } if ( number == 1043297 ) from.SendLocalizedMessage( number, name ); else from.SendLocalizedMessage( number, true, name ); } } public override void OnHarvestStarted( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) { base.OnHarvestStarted( from, tool, def, toHarvest ); int tileID; Map map; Point3D loc; if ( GetHarvestDetails( from, tool, toHarvest, out tileID, out map, out loc ) ) Timer.DelayCall( TimeSpan.FromSeconds( 1.5 ), delegate { Effects.SendLocationEffect( loc, map, 0x352D, 16, 4 ); Effects.PlaySound( loc, map, 0x364 ); } ); } public override void OnHarvestFinished( Mobile from, Item tool, HarvestDefinition def, HarvestVein vein, HarvestBank bank, HarvestResource resource, object harvested ) { base.OnHarvestFinished( from, tool, def, vein, bank, resource, harvested ); } public override object GetLock( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) { return this; } public override bool BeginHarvesting( Mobile from, Item tool ) { if ( !base.BeginHarvesting( from, tool ) ) return false; from.SendLocalizedMessage( 500974 ); // What water do you want to fish in? return true; } public override bool CheckHarvest( Mobile from, Item tool ) { if ( !base.CheckHarvest( from, tool ) ) return false; if ( from.Mounted ) { from.SendLocalizedMessage( 500971 ); // You can't fish while riding! return false; } return true; } public override bool CheckHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) { if ( !base.CheckHarvest( from, tool, def, toHarvest ) ) return false; if ( from.Mounted ) { from.SendLocalizedMessage( 500971 ); // You can't fish while riding! return false; } return true; } public static int[] m_WaterTiles = new int[] { 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x0136, 0x0137, 0x5797, 0x5798, 0x5799, 0x579A, 0x579B, 0x579C, 0x746E, 0x746F, 0x7470, 0x7471, 0x7472, 0x7473, 0x7474, 0x7475, 0x7476, 0x7477, 0x7478, 0x7479, 0x747A, 0x747B, 0x747C, 0x747ED, 0x747E, 0x747F, 0x7480, 0x7481, 0x7482, 0x7483, 0x7484, 0x7485, 0x7494, 0x7495, 0x7496, 0x7497, 0x7498, 0x7499, 0x749A, 0x749B, 0x749C, 0x749D, 0x749E, 0x74A0, 0x74A1, 0x74A2, 0x74A3, 0x74A4, 0x74A5, 0x74A6, 0x74A7, 0x74A8, 0x74A9, 0x74AA, 0x74AB, 0x74B8, 0x74BA, 0x74BB, 0x74BD, 0x74BE, 0x74BF, 0x74C0, 0x74C2, 0x74C3, 0x74C4, 0x74C5, 0x74C7, 0x74C8, 0x74C9, 0x74CA }; } }