527 lines
No EOL
14 KiB
C#
527 lines
No EOL
14 KiB
C#
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<SOS> messages = pack.FindItemsByType<SOS>();
|
|
|
|
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<SOS> messages = pack.FindItemsByType<SOS>();
|
|
|
|
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
|
|
};
|
|
}
|
|
} |