1087 lines
40 KiB
C#
1087 lines
40 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Server.Engines.Quests;
|
|
using Server.Engines.Quests.Collector;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
using Server.Network;
|
|
using Server.Targeting;
|
|
|
|
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 readonly HarvestDefinition m_Definition;
|
|
|
|
public HarvestDefinition Definition
|
|
{
|
|
get
|
|
{
|
|
return this.m_Definition;
|
|
}
|
|
}
|
|
|
|
private Fishing()
|
|
{
|
|
HarvestResource[] res;
|
|
HarvestVein[] veins;
|
|
|
|
#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);
|
|
|
|
// Skill checking is done on the Fishing skill
|
|
fish.Skill = SkillName.Fishing;
|
|
|
|
// Set the list of harvestable tiles
|
|
fish.Tiles = m_WaterTiles;
|
|
fish.SpecialTiles = m_LavaTiles;
|
|
fish.RangedTiles = true;
|
|
|
|
// Players must be within 4 tiles to harvest
|
|
fish.MaxRange = 4;
|
|
|
|
// One fish per harvest action
|
|
fish.ConsumedPerHarvest = 1;
|
|
fish.ConsumedPerFeluccaHarvest = 1;
|
|
|
|
// The fishing
|
|
fish.EffectActions = new int[] { Core.SA ? 6 : 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.
|
|
|
|
res = new HarvestResource[]
|
|
{
|
|
new HarvestResource(00.0, 00.0, 120.0, 1043297, typeof(Fish))
|
|
};
|
|
|
|
veins = new HarvestVein[]
|
|
{
|
|
new HarvestVein(100.0, 0.0, res[0], null)
|
|
};
|
|
|
|
fish.Resources = res;
|
|
fish.Veins = veins;
|
|
|
|
if (Core.ML)
|
|
{
|
|
fish.BonusResources = new BonusHarvestResource[]
|
|
{
|
|
new BonusHarvestResource(0, 97.0, null, null), //set to same chance as mining ml gems
|
|
new BonusHarvestResource(80.0, 2.0, 1113764, typeof(DelicateScales)),
|
|
new BonusHarvestResource(80.0, 1.0, 1072597, typeof(WhitePearl))
|
|
};
|
|
}
|
|
|
|
this.m_Definition = fish;
|
|
this.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, 1865.0, true, typeof( SpecialFishingNet ) ),
|
|
new MutateEntry( 90.0, 80.0, 1875.0, true, typeof( TreasureMap ) ),
|
|
new MutateEntry( 100.0, 80.0, 750.0, true, typeof( MessageInABottle ) ),
|
|
new MutateEntry( 80.0, 80.0, 4080.0, true, typeof( BigFish ) ),
|
|
new MutateEntry( 0.0, 125.0, -2375.0, false, typeof( PrizedFish ), typeof( WondrousFish ), typeof( TrulyRareFish ), typeof( PeculiarFish ) ),
|
|
new MutateEntry( 0.0, 125.0, -420.0, false, typeof( Boots ), typeof( Shoes ), typeof( Sandals ), typeof( ThighBoots ) ),
|
|
new MutateEntry( 80.0, 80.0, 2500.0, false, typeof( MudPuppy ), typeof( RedHerring) ),
|
|
new MutateEntry( 0.0, 200.0, -200.0, false, new Type[1]{ null } )
|
|
};
|
|
|
|
private static MutateEntry[] m_SiegeMutateTable = new MutateEntry[]
|
|
{
|
|
new MutateEntry( 80.0, 80.0, 1865.0, true, typeof( SpecialFishingNet ) ),
|
|
new MutateEntry( 0.0, 200.0, -200.0, false, new Type[1]{ null } ),
|
|
new MutateEntry( 100.0, 80.0, 1865.0, true, typeof( MessageInABottle ) ),
|
|
new MutateEntry( 80.0, 80.0, 4080.0, true, typeof( BigFish ) ),
|
|
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( 80.0, 80.0, 2500.0, false, typeof( MudPuppy ), typeof( RedHerring) ),
|
|
new MutateEntry( 0.0, 200.0, -200.0, false, new Type[1]{ null } )
|
|
};
|
|
|
|
private static MutateEntry[] m_LavaMutateTable = new MutateEntry[]
|
|
{
|
|
new MutateEntry( 0.0, 80.0, 333, false, typeof(StoneFootwear)),
|
|
new MutateEntry( 80.0, 80.0, 333, false, typeof(CrackedLavaRockEast), typeof(CrackedLavaRockSouth)),
|
|
new MutateEntry( 85.0, 80.0, 333, false, typeof(StonePaver)),
|
|
new MutateEntry( 80.0, 80.0, 4080, false, typeof(BaseWeapon))
|
|
};
|
|
|
|
public override bool SpecialHarvest(Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc)
|
|
{
|
|
PlayerMobile player = from as PlayerMobile;
|
|
|
|
Container pack = from.Backpack;
|
|
|
|
if (player != null)
|
|
{
|
|
QuestSystem qs = player.Quest;
|
|
|
|
if (qs is CollectorQuest)
|
|
{
|
|
QuestObjective obj = qs.FindObjective(typeof(FishPearlsObjective));
|
|
|
|
if (obj != null && !obj.Completed)
|
|
{
|
|
if (Utility.RandomDouble() < 0.5)
|
|
{
|
|
player.SendLocalizedMessage(1055086, "", 0x59); // You pull a shellfish out of the water, and find a rainbow pearl inside of it.
|
|
|
|
obj.CurProgress++;
|
|
}
|
|
else
|
|
{
|
|
player.SendLocalizedMessage(1055087, "", 0x2C); // You pull a shellfish out of the water, but it doesn't have a rainbow pearl.
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (from.Region.IsPartOf("Underworld"))
|
|
{
|
|
foreach (BaseQuest quest in player.Quests)
|
|
{
|
|
if (quest is SomethingFishy && Utility.RandomDouble() < 0.1)
|
|
{
|
|
Item red = new RedHerring();
|
|
from.AddToBackpack(red);
|
|
player.SendLocalizedMessage(1095047, "", 0x23); // You pull a shellfish out of the water, but it doesn't have a rainbow pearl.
|
|
return true;
|
|
}
|
|
|
|
if (quest is ScrapingtheBottom && Utility.RandomDouble() < 0.1)
|
|
{
|
|
Item mug = new MudPuppy();
|
|
from.AddToBackpack(mug);
|
|
player.SendLocalizedMessage(1095064, "", 0x23); // You pull a shellfish out of the water, but it doesn't have a rainbow pearl.
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
#region High Seas Charydbis
|
|
if (Core.HS && tool is FishingPole && CharydbisSpawner.SpawnInstance != null && CharydbisSpawner.SpawnInstance.IsSummoned)
|
|
{
|
|
Item oracle = from.Backpack.FindItemByType(typeof(OracleOfTheSea));
|
|
FishingPole pole = tool as FishingPole;
|
|
CharydbisSpawner sp = CharydbisSpawner.SpawnInstance;
|
|
|
|
if (oracle != null && sp != null)
|
|
{
|
|
if (from.Map != sp.Map)
|
|
from.SendLocalizedMessage(1150861); //Charybdis have never been seen in these waters, try somewhere else.
|
|
|
|
else if (pole.BaitType == typeof(Charydbis) && from.Skills[SkillName.Fishing].Value >= 100)
|
|
{
|
|
if (sp.Charydbis == null && !sp.HasSpawned && sp.CurrentLocation.Contains(loc))
|
|
{
|
|
Server.Multis.BaseBoat boat = Server.Multis.BaseBoat.FindBoatAt(from, from.Map);
|
|
sp.SpawnCharydbis(from, loc, sp.Map, boat);
|
|
sp.HasSpawned = true;
|
|
pole.OnFishedHarvest(from, true);
|
|
return true;
|
|
}
|
|
else if (sp.LastLocation.Contains(loc))
|
|
{
|
|
from.SendLocalizedMessage(1150862); //The charybdis has moved on from this location, consult Oracle Of The Seas again.
|
|
}
|
|
}
|
|
else
|
|
from.SendLocalizedMessage(1150858); //You see a few bubbles, but no charybdis.
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override Type MutateType(Type type, Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestResource resource)
|
|
{
|
|
if (FishInfo.IsRareFish(type))
|
|
return type;
|
|
|
|
bool deepWater = IsDeepWater(loc, map);
|
|
bool junkproof = HasTypeHook(tool, HookType.JunkProof);
|
|
|
|
double skillBase = from.Skills[SkillName.Fishing].Base;
|
|
double skillValue = from.Skills[SkillName.Fishing].Value;
|
|
|
|
var table = Siege.SiegeShard ? m_SiegeMutateTable : m_MutateTable;
|
|
|
|
for (int i = 0; i < table.Length; ++i)
|
|
{
|
|
MutateEntry entry = m_MutateTable[i];
|
|
|
|
// RedHerring / MudPuppy
|
|
if (i == 6 && (from.Region == null || !from.Region.IsPartOf("Underworld")))
|
|
continue;
|
|
|
|
if (junkproof && i == 5 && 0.80 >= Utility.RandomDouble())
|
|
continue;
|
|
|
|
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 bool IsDeepWater(Point3D p, Map map)
|
|
{
|
|
return Items.SpecialFishingNet.ValidateDeepWater(map, p.X, p.Y) && (map == Map.Trammel || map == Map.Felucca || map == Map.Tokuno);
|
|
}
|
|
|
|
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.Felucca || from.Map == Map.Trammel) && from.InRange(sos.TargetLocation, 60))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return base.CheckResources(from, tool, def, map, loc, timed);
|
|
}
|
|
|
|
public override Item Construct(Type type, Mobile from, Item tool)
|
|
{
|
|
// Searing Weapon Support
|
|
if (type == typeof(BaseWeapon))
|
|
return null;
|
|
|
|
if (type == typeof(TreasureMap))
|
|
{
|
|
int level;
|
|
if (from is PlayerMobile && ((PlayerMobile)from).Young && from.Map == Map.Trammel && TreasureMap.IsInHavenIsland(from))
|
|
level = 0;
|
|
else
|
|
level = 1;
|
|
|
|
return new TreasureMap(level, from.Map == Map.Felucca ? Map.Felucca : Map.Trammel);
|
|
}
|
|
else if (type == typeof(MessageInABottle))
|
|
{
|
|
return new MessageInABottle(from.Map == Map.Felucca ? Map.Felucca : Map.Trammel);
|
|
}
|
|
else if (type == typeof(WhitePearl))
|
|
{
|
|
return new WhitePearl();
|
|
}
|
|
|
|
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.Felucca || from.Map == Map.Trammel) && from.InRange(sos.TargetLocation, 60))
|
|
{
|
|
Item preLoot = null;
|
|
bool dredge = HasTypeHook(tool, HookType.Dredging);
|
|
|
|
switch (Utility.Random(Core.HS ? 17 : 16))
|
|
{
|
|
case 0: // Body parts
|
|
case 1:
|
|
{
|
|
int[] list = new int[]
|
|
{
|
|
0x1CDD, 0x1CE5, // arm
|
|
0x1CE0, 0x1CE8, // torso
|
|
0x1CE1, 0x1CE9, // head
|
|
0x1CE2, 0x1CEC // leg
|
|
};
|
|
|
|
preLoot = new ShipwreckedItem(Utility.RandomList(list), dredge);
|
|
break;
|
|
}
|
|
case 2: // Bone parts
|
|
case 3:
|
|
{
|
|
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), dredge);
|
|
break;
|
|
}
|
|
case 4: // Paintings and portraits
|
|
case 5:
|
|
{
|
|
preLoot = new ShipwreckedItem(Utility.Random(0xE9F, 10), dredge);
|
|
break;
|
|
}
|
|
case 6: // Pillows
|
|
case 7:
|
|
{
|
|
preLoot = new ShipwreckedItem(Utility.Random(0x13A4, 11), dredge);
|
|
break;
|
|
}
|
|
case 8: // Shells
|
|
case 9:
|
|
{
|
|
preLoot = new ShipwreckedItem(Utility.Random(0xFC4, 9), dredge);
|
|
break;
|
|
}
|
|
case 10: //Hats
|
|
case 11:
|
|
{
|
|
if (Utility.RandomBool())
|
|
preLoot = new SkullCap();
|
|
else
|
|
preLoot = new TricorneHat();
|
|
|
|
break;
|
|
}
|
|
case 12: // Misc
|
|
case 13:
|
|
{
|
|
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), dredge);
|
|
|
|
break;
|
|
}
|
|
#region High Seas
|
|
case 14:
|
|
{
|
|
int[] list = new int[]
|
|
{
|
|
0x1E19, 0x1E1A, 0x1E1B, //Fish heads
|
|
0x1E2A, 0x1E2B, //Oars
|
|
0x1E71, 0x1E7A, //Unfinished drawers
|
|
0x1E75, //Unfinished legs
|
|
};
|
|
|
|
double ran = Utility.RandomDouble();
|
|
|
|
if (ran < 0.05)
|
|
preLoot = new YellowPolkaDotBikini();
|
|
else if (ran < 0.25)
|
|
preLoot = new ShipwreckedItem(list[Utility.RandomMinMax(3, 7)], dredge);
|
|
else
|
|
preLoot = new ShipwreckedItem(list[Utility.Random(3)], dredge);
|
|
break;
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
if (preLoot != null)
|
|
{
|
|
if (preLoot is IShipwreckedItem)
|
|
((IShipwreckedItem)preLoot).IsShipwreckedItem = true;
|
|
|
|
return preLoot;
|
|
}
|
|
|
|
LockableContainer chest;
|
|
|
|
if (0.01 > Utility.RandomDouble())
|
|
{
|
|
chest = new ShipsStrongbox(sos.Level);
|
|
}
|
|
else
|
|
{
|
|
if (Utility.RandomBool())
|
|
chest = new MetalGoldenChest();
|
|
else
|
|
chest = new WoodenChest();
|
|
}
|
|
|
|
if (sos.IsAncient)
|
|
{
|
|
chest.Hue = 0x481;
|
|
}
|
|
|
|
TreasureMapChest.Fill(from, chest, Math.Max(1, Math.Min(4, sos.Level)), true);
|
|
sos.OnSOSComplete(chest);
|
|
|
|
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;
|
|
|
|
chest.IsShipwreckedItem = true;
|
|
|
|
sos.Delete();
|
|
|
|
return chest;
|
|
}
|
|
}
|
|
}
|
|
|
|
return base.Construct(type, from, tool);
|
|
}
|
|
|
|
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;
|
|
|
|
#region High Seas
|
|
if (item is RareFish)
|
|
{
|
|
RareFish fish = (RareFish)item;
|
|
|
|
if (FishInfo.IsRareFish(fish.GetType()))
|
|
{
|
|
fish.Fisher = m;
|
|
fish.DateCaught = DateTime.Now;
|
|
fish.Stackable = false;
|
|
|
|
fish.Weight = Math.Max(1, 200 - (int)Math.Sqrt(Utility.RandomMinMax(0, 40000)));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
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;
|
|
((BigFish)item).DateCaught = DateTime.Now;
|
|
}
|
|
|
|
#region Stygian Abyss
|
|
else if (item is RedHerring)
|
|
from.SendLocalizedMessage(1095047, null, 0x23); // You take the Red Herring and put it into your pack. The only thing more surprising than the fact that there is a fish called the Red Herring is the fact that you fished for it!
|
|
else if (item is MudPuppy)
|
|
from.SendLocalizedMessage(1095064, null, 0x23); // You take the Mud Puppy and put it into your pack. Not surprisingly, it is very muddy.
|
|
#endregion
|
|
|
|
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 = item.ItemData.Name;
|
|
}
|
|
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 if (item is BaseHighseasFish)
|
|
{
|
|
if (FishInfo.IsRareFish(item.GetType()))
|
|
{
|
|
from.SendLocalizedMessage(1043297, "a rare fish");
|
|
}
|
|
else if (item.LabelNumber < 1)
|
|
{
|
|
from.SendLocalizedMessage(1043297, "a fish");
|
|
}
|
|
else
|
|
from.SendLocalizedMessage(1043297, String.Format("#{0}", item.LabelNumber));
|
|
|
|
return;
|
|
}
|
|
else if (item.LabelNumber > 0)
|
|
{
|
|
from.SendLocalizedMessage(1043297, String.Format("#{0}", item.LabelNumber));
|
|
return;
|
|
}
|
|
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;
|
|
}
|
|
|
|
NetState ns = from.NetState;
|
|
|
|
if (ns == null)
|
|
return;
|
|
|
|
if (number == 1043297 || ns.HighSeas)
|
|
from.SendLocalizedMessage(number, name);
|
|
else
|
|
from.SendLocalizedMessage(number, true, name);
|
|
}
|
|
}
|
|
|
|
public override void StartHarvesting(Mobile from, Item tool, object toHarvest)
|
|
{
|
|
if (from != null && tool != null && tool.IsChildOf(from.Backpack))
|
|
{
|
|
Item item = from.FindItemOnLayer(Layer.OneHanded);
|
|
Item item2 = from.FindItemOnLayer(Layer.TwoHanded);
|
|
|
|
if (item != null)
|
|
from.AddToBackpack(item);
|
|
|
|
if (item2 != null)
|
|
from.AddToBackpack(item2);
|
|
|
|
Timer.DelayCall(TimeSpan.FromMilliseconds(250), () =>
|
|
{
|
|
from.EquipItem(tool);
|
|
});
|
|
}
|
|
|
|
base.StartHarvesting(from, tool, toHarvest);
|
|
}
|
|
|
|
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 (this.GetHarvestDetails(from, tool, toHarvest, out tileID, out map, out loc))
|
|
Timer.DelayCall(TimeSpan.FromSeconds(1.5),
|
|
delegate
|
|
{
|
|
if (Core.ML)
|
|
from.RevealingAction();
|
|
|
|
int sound = 0x364;
|
|
int effect = 0x352D;
|
|
|
|
if (IsLavaHarvest(tool, toHarvest))
|
|
{
|
|
sound = 0x60A;
|
|
effect = 0x1A75;
|
|
}
|
|
|
|
Effects.SendLocationEffect(loc, map, effect, 16, 4);
|
|
Effects.PlaySound(loc, map, sound);
|
|
});
|
|
}
|
|
|
|
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);
|
|
|
|
if (Core.ML)
|
|
from.RevealingAction();
|
|
}
|
|
|
|
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.Flying)
|
|
{
|
|
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.Flying)
|
|
{
|
|
from.SendLocalizedMessage(500971); // You can't fish while riding!
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static readonly int[] m_WaterTiles = new int[]
|
|
{
|
|
0x00A8, 0x00AB,
|
|
0x0136, 0x0137,
|
|
0x5797, 0x579C,
|
|
0x746E, 0x7485,
|
|
0x7490, 0x74AB,
|
|
0x74B5, 0x75D5
|
|
};
|
|
|
|
#region HighSeas
|
|
public static int[] LavaTiles { get { return m_LavaTiles; } }
|
|
private static int[] m_LavaTiles = new int[]
|
|
{
|
|
0x1F4, 0x1F5,
|
|
0x1F6, 0x1F7,
|
|
|
|
4846, 4847, 4848, 4849, 4850,
|
|
4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, 4560, 4561, 4562,
|
|
4864, 4865, 4866, 4867, 4868,
|
|
4870, 4871, 4872, 4873, 4874,
|
|
4876, 4877, 4878, 4879, 4880,
|
|
4882, 4883, 4884, 4885, 4886,
|
|
4888, 4889, 4890, 4891, 4892,
|
|
|
|
};
|
|
|
|
public override bool GetHarvestDetails(Mobile from, Item tool, object toHarvest, out int tileID, out Map map, out Point3D loc)
|
|
{
|
|
bool lava = HasTypeHook(tool, HookType.Lava);
|
|
|
|
if (toHarvest is Static && !((Static)toHarvest).Movable)
|
|
{
|
|
Static obj = (Static)toHarvest;
|
|
|
|
if (lava)
|
|
tileID = obj.ItemID;
|
|
else
|
|
tileID = (obj.ItemID & 0x3FFF) | 0x4000;
|
|
|
|
map = obj.Map;
|
|
loc = obj.GetWorldLocation();
|
|
}
|
|
else if (toHarvest is StaticTarget)
|
|
{
|
|
StaticTarget obj = (StaticTarget)toHarvest;
|
|
|
|
if (lava)
|
|
tileID = obj.ItemID;
|
|
else
|
|
tileID = (obj.ItemID & 0x3FFF) | 0x4000;
|
|
|
|
map = from.Map;
|
|
loc = obj.Location;
|
|
}
|
|
else if (toHarvest is LandTarget)
|
|
{
|
|
LandTarget obj = (LandTarget)toHarvest;
|
|
|
|
tileID = obj.TileID;
|
|
map = from.Map;
|
|
loc = obj.Location;
|
|
}
|
|
else
|
|
{
|
|
tileID = 0;
|
|
map = null;
|
|
loc = Point3D.Zero;
|
|
return false;
|
|
}
|
|
|
|
//Lava tile, no lava hook
|
|
if (ValidateSpecialTile(tileID) && !lava)
|
|
return false;
|
|
|
|
return (map != null && map != Map.Internal);
|
|
}
|
|
|
|
public override HarvestDefinition GetDefinition(int tileID, Item tool)
|
|
{
|
|
if (tool is FishingPole)
|
|
{
|
|
FishingPole pole = (FishingPole)tool;
|
|
bool usingLavaHook = HasTypeHook(pole, HookType.Lava);
|
|
|
|
if (usingLavaHook && ValidateSpecialTile(tileID))
|
|
return GetDefinitionFromSpecialTile(tileID);
|
|
}
|
|
|
|
return base.GetDefinition(tileID, tool);
|
|
}
|
|
|
|
public bool ValidateSpecialTile(int tileID)
|
|
{
|
|
foreach (int id in m_LavaTiles)
|
|
{
|
|
if (tileID == id)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool IsLavaHarvest(Item tool, object toHarvest)
|
|
{
|
|
int id = 0;
|
|
|
|
if (!HasTypeHook(tool, HookType.Lava))
|
|
return false;
|
|
|
|
if (toHarvest is StaticTarget)
|
|
id = ((StaticTarget)toHarvest).ItemID;
|
|
else if (toHarvest is LandTarget)
|
|
id = ((LandTarget)toHarvest).TileID;
|
|
else if (toHarvest is Static && !((Static)toHarvest).Movable)
|
|
id = ((Static)toHarvest).ItemID;
|
|
|
|
return ValidateSpecialTile(id);
|
|
}
|
|
|
|
public bool IsLavaHarvest(Item tool, int id)
|
|
{
|
|
if (!HasTypeHook(tool, HookType.Lava))
|
|
return false;
|
|
|
|
return ValidateSpecialTile(id);
|
|
}
|
|
|
|
public override void OnToolUsed(Mobile from, Item tool, bool caughtsomething)
|
|
{
|
|
if (tool is FishingPole)
|
|
((FishingPole)tool).OnFishedHarvest(from, caughtsomething);
|
|
}
|
|
|
|
public static bool HasTypeHook(Item tool, HookType type)
|
|
{
|
|
if (tool is FishingPole)
|
|
return ((FishingPole)tool).HookType == type;
|
|
return false;
|
|
}
|
|
|
|
public override Type GetResourceType(Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestResource resource)
|
|
{
|
|
Type type = FishInfo.GetSpecialItem(from, tool, loc, false);
|
|
|
|
if (type == null)
|
|
type = base.GetResourceType(from, tool, def, map, loc, resource);
|
|
|
|
return type;
|
|
}
|
|
|
|
public override void FinishHarvesting(Mobile from, Item tool, HarvestDefinition def, object toHarvest, object locked)
|
|
{
|
|
//Lava fishing needs to have its own set of rules.
|
|
if (IsLavaHarvest(tool, toHarvest))
|
|
{
|
|
from.EndAction(locked);
|
|
|
|
if (!CheckHarvest(from, tool))
|
|
return;
|
|
|
|
int tileID;
|
|
Map map;
|
|
Point3D loc;
|
|
|
|
if (!GetHarvestDetails(from, tool, toHarvest, out tileID, out map, out loc))
|
|
{
|
|
OnBadHarvestTarget(from, tool, toHarvest);
|
|
return;
|
|
}
|
|
else if (!def.Validate(tileID) && !def.ValidateSpecial(tileID))
|
|
{
|
|
OnBadHarvestTarget(from, tool, toHarvest);
|
|
return;
|
|
}
|
|
|
|
if (!CheckRange(from, tool, def, map, loc, true))
|
|
return;
|
|
else if (!CheckResources(from, tool, def, map, loc, true))
|
|
return;
|
|
else if (!CheckHarvest(from, tool, def, toHarvest))
|
|
return;
|
|
|
|
HarvestBank bank = def.GetBank(map, loc.X, loc.Y);
|
|
|
|
if (bank == null)
|
|
return;
|
|
|
|
HarvestVein vein = bank.Vein;
|
|
|
|
if (vein == null)
|
|
return;
|
|
|
|
Type type = null;
|
|
|
|
HarvestResource resource = MutateResource(from, tool, def, map, loc, vein, vein.PrimaryResource, vein.FallbackResource);
|
|
|
|
if (from.CheckSkill(def.Skill, resource.MinSkill, resource.MaxSkill))
|
|
{
|
|
//Special eye candy item
|
|
type = GetSpecialLavaItem(from, tool, map, loc, toHarvest);
|
|
|
|
//Special fish
|
|
if (type == null)
|
|
type = FishInfo.GetSpecialItem(from, tool, loc, IsLavaHarvest(tool, tileID));
|
|
|
|
if (type != null)
|
|
{
|
|
Item item = Construct(type, from, tool);
|
|
|
|
if (item == null)
|
|
{
|
|
type = null;
|
|
}
|
|
else
|
|
{
|
|
if (from.AccessLevel == AccessLevel.Player)
|
|
bank.Consume(Convert.ToInt32(map != null && map.Rules == MapRules.FeluccaRules ? Math.Ceiling(item.Amount / 2.0) : item.Amount), from);
|
|
|
|
if (Give(from, item, true))
|
|
{
|
|
SendSuccessTo(from, item, null);
|
|
}
|
|
else
|
|
{
|
|
SendPackFullTo(from, item, def, null);
|
|
item.Delete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type == null)
|
|
{
|
|
def.SendMessageTo(from, def.FailMessage);
|
|
|
|
double skill = (double)from.Skills[SkillName.Fishing].Value / 50;
|
|
|
|
if (0.5 / skill > Utility.RandomDouble())
|
|
OnToolUsed(from, tool, false);
|
|
}
|
|
else
|
|
OnToolUsed(from, tool, true);
|
|
|
|
OnHarvestFinished(from, tool, def, vein, bank, null, null);
|
|
}
|
|
else
|
|
base.FinishHarvesting(from, tool, def, toHarvest, locked);
|
|
}
|
|
|
|
public override bool CheckHarvestSkill(Map map, Point3D loc, Mobile from, HarvestResource res, HarvestDefinition def)
|
|
{
|
|
bool deepWater = IsDeepWater(loc, map);
|
|
double value = from.Skills[SkillName.Fishing].Value;
|
|
|
|
if (deepWater && value < 75.0) // can't fish here yet
|
|
return from.Skills[def.Skill].Value >= res.ReqSkill;
|
|
|
|
if (!deepWater && value >= 75.0) // you can fish, but no gains!
|
|
return true;
|
|
|
|
return base.CheckHarvestSkill(map, loc, from, res, def);
|
|
}
|
|
|
|
public Type GetSpecialLavaItem(Mobile from, Item type, Map map, Point3D pnt, object toHarvest)
|
|
{
|
|
Type newType = null;
|
|
|
|
double skillBase = from.Skills[SkillName.Fishing].Base;
|
|
double skillValue = Math.Min(120.0, from.Skills[SkillName.Fishing].Value);
|
|
|
|
//Same method as mutate entries
|
|
for (int i = 0; i < m_LavaMutateTable.Length; ++i)
|
|
{
|
|
MutateEntry entry = m_LavaMutateTable[i];
|
|
|
|
if (skillBase >= entry.m_ReqSkill)
|
|
{
|
|
double chance = (skillValue - entry.m_MinSkill) / (entry.m_MaxSkill - entry.m_MinSkill);
|
|
|
|
if (map != null && map.Rules == MapRules.FeluccaRules)
|
|
chance *= 1.5;
|
|
|
|
if (chance > Utility.RandomDouble())
|
|
{
|
|
newType = entry.m_Types[Utility.Random(entry.m_Types.Length)];
|
|
|
|
if (newType == typeof(BaseWeapon))
|
|
{
|
|
BaseWeapon wep = Loot.RandomWeapon();
|
|
|
|
if (wep != null)
|
|
{
|
|
wep.AttachSocket(new SearingWeapon(wep));
|
|
|
|
from.AddToBackpack(wep);
|
|
from.SendMessage("You have pulled out an item : mysterious weapon");
|
|
return typeof(BaseWeapon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return newType;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|