ModernUO/Projects/Scripts/Engines/Harvest/Fishing.cs
Kamron Batman 179cb50557 Updates Packets & Randomizer (#43)
* Fixes a bug with the main loop. Removes unnecessary optimizations for RDRand.

* WIP - Rewriting packets.

* Cleanup and updates README

* Converts more packets

* Fixes header

* Converts Effects packets.

* Forgot the send command

* Adds the start of containers packets.

* Adds message packets with caching

* Extends the send methods

* Starts to add Acquire methods

* Converted the packets

* Cleanup

* Cleanup

* Adds more packets

* Adds more packets

* Fixes clearing arrays from pool. Adds Mobile Incoming

* Converts more packets.

* Moves more packets

* Moves more packets

* Test compression

* Merges

* Migrating to an idiomatic syntax that also supports compression, and proxying.

* Optimize the stack alloc. Changes attributes

* Converted container packets

* Visual Studio doesn't auto save files. I am still getting used to subpar IDEs.

* Adds static packet caching. Will profile later. Converts more packets

* Fixes packets and changes how compression is configured

* WIP - Adds basics for Gumps. Not finished though.

* Fix file

* Fixes formatting

* Changed SpanWriter to be more idiomatic.

* Fixes Span vs RawSpan and missing stackallocs

* Converts over some more gumps

* WIP - Deletes 32bit support.

* Drops RDRand32 support.

* Fixes gump compilation

* Converting gump components

* Removes old huffman compression function

* Revert signature for backwards compatibility

* WIP - Converting more gump components

* Creates ArraySet for the strings. Updates AppendTo to reference that.

* Converts the maining gump components

* Cleans up gump components

* Cleans up directives

* Cleans up ArraySet and moves it. Adds null-coalescing-assignment

* Cleanup, Target Packets, and C# 8 changes.

* Removed OPL Packet

* World packets

* Fixing packet uses

* Cleans up code. Fixes packet uses in various places.

* More cleanup for packets

* Code cleanup

* Converts more packet uses and cleans up more code

* More code cleanup

* Finishes fixing the packets in Item

* Updates secure trade packets

* Updates core and gets it to compile.

* Moved packets to scripts. Fixed account handler use of packets

* Code cleanup

* Updates chat packets

* Code cleanuo

* Adds party packets, but need to implement them.

* Party packets WIP

* Finishes party packets

* Rearrange movement namespaces and classes

* Finishes plant packets

* Code Formatting

* Fixes moving effects

* Code cleanup, eliminates equipinfo

* Adds more packets. Fixes bugs with various packets.

* Finishes mahjon packets

* Fixes mahjong packet

* Code cleanup

* Finishes mahjong packets

* Adds Map packets

* Add multifacet maps and charts

* Cleans up some packets with UTF8

* Optimizes packets

* Cleans up more packets. Moves the MessageHelper

* Removes assistant support. Removes extended protocol. Incorporates MapUO packets as normal packets.

* Updates protocol extensions packet receiver

* Fixes a few bugs. Fixes a few more packets.

* Code cleanup and fixing more packets

* Fixes packet effects

* Cleaned up more code

* Buff Icon cleanup

* Removed unused constructors

* Code Cleanup. Adds BoatHS Packets

* Moves house files. Updates house foundation packets.

* Deployment cleanup

* Fixes:

* Code cleanup

* More code cleanup

* More code cleanup

* Cleaned up BaseHouse

* Enforces styling

* Converts foreach to linq where possible.

* Dont need that

* Goals/Readme updates

* Removes 32bit support at the highest level. Turns on HRT by default.

* Code cleanup. Fixes extended features packet.

* Fixes various bugs

* Code cleanup

* Code cleanup

* Code cleanup. Fixes gump X/Y assignment.

* Code cleanup using |= operator

* More code cleanup

* Cleanup

* Fixes spacing issues. Thanks Visual Studio. You suck.

* Compiler error

* Fixes NPE from RunUO 2.7

* Renames ScriptCompiler to AssemblyHandler. Fixes packets. Updates README

* Fixes more packets. Stupid trailing nulls.

* Fixes various bugs.

* Fixes for gumps

* Fixes more gump stuff. Going to split it out later since it is getting insane

* Recoded the gump writing

* WIP

* *Added output path of scripts project to dev branch
*Activated debugging in code
2019-11-11 12:40:16 +01:00

502 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Server.Engines.Quests;
using Server.Engines.Quests.Collector;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Spells;
namespace Server.Engines.Harvest
{
public class Fishing : HarvestSystem
{
private static Fishing m_System;
private static MutateEntry[] m_MutateTable =
{
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[] { null })
};
private static int[] m_WaterTiles =
{
0x00A8, 0x00AB,
0x0136, 0x0137,
0x5797, 0x579C,
0x746E, 0x7485,
0x7490, 0x74AB,
0x74B5, 0x75D5
};
private Fishing()
{
HarvestDefinition fish = new HarvestDefinition
{
BankWidth = 8,
BankHeight = 8,
MinTotal = 5,
MaxTotal = 15,
MinRespawn = TimeSpan.FromMinutes(10.0),
MaxRespawn = TimeSpan.FromMinutes(20.0),
Skill = SkillName.Fishing,
Tiles = m_WaterTiles,
RangedTiles = true,
MaxRange = 4,
ConsumedPerHarvest = 1,
ConsumedPerFeluccaHarvest = 1,
EffectActions = new[] { 12 },
EffectSounds = new int[0],
EffectCounts = new[] { 1 },
EffectDelay = TimeSpan.Zero,
EffectSoundDelay = TimeSpan.FromSeconds(8.0),
NoResourcesMessage = 503172, // The fish don't seem to be biting here.
FailMessage = 503171, // You fish a while, but fail to catch anything.
TimedOutOfRangeMessage = 500976, // You need to be closer to the water to fish!
OutOfRangeMessage = 500976, // You need to be closer to the water to fish!
PackFullMessage = 503176, // You do not have room in your backpack for a fish.
ToolBrokeMessage = 503174 // You broke your fishing pole.
};
HarvestResource[] res = {
new HarvestResource(00.0, 00.0, 100.0, 1043297, typeof(Fish))
};
HarvestVein[] veins = {
new HarvestVein(100.0, 0.0, res[0], null)
};
fish.Resources = res;
fish.Veins = veins;
if (Core.ML)
fish.BonusResources = new[]
{
new BonusHarvestResource(0, 99.4, null, null), //set to same chance as mining ml gems
new BonusHarvestResource(80.0, .6, 1072597, typeof(WhitePearl))
};
Definition = fish;
Definitions.Add(fish);
}
public static Fishing System => m_System ??= new Fishing();
public HarvestDefinition Definition{ get; }
public override void OnConcurrentHarvest(Mobile from, Item tool, HarvestDefinition def, object toHarvest)
{
from.SendLocalizedMessage(500972); // You are already fishing.
}
public override bool SpecialHarvest(Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc)
{
if (from is PlayerMobile player)
{
QuestSystem qs = player.Quest;
if (qs is CollectorQuest)
{
QuestObjective obj = qs.FindObjective<FishPearlsObjective>();
if (obj?.Completed == false)
{
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;
}
}
}
return false;
}
public override Type MutateType(Type type, Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc,
HarvestResource resource)
{
bool deepWater = SpecialFishingNet.FullValidation(map, loc.X, loc.Y);
double skillBase = from.Skills.Fishing.Base;
double skillValue = from.Skills.Fishing.Value;
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) => map == null || map == Map.Internal ? Map.Trammel : map;
public override bool CheckResources(Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, bool timed)
{
return from?.Backpack?.FindItemsByType<SOS>().Any(sos =>
(from.Map == Map.Felucca || from.Map == Map.Trammel) && from.InRange(sos.TargetLocation, 60)) ??
base.CheckResources(from, tool, def, map, loc, timed);
}
public override Item Construct(Type type, Mobile from)
{
if (type == typeof(TreasureMap))
{
int level;
if (from is PlayerMobile mobile && mobile.Young && mobile.Map == Map.Trammel &&
TreasureMap.IsInHavenIsland(from))
level = 0;
else
level = 1;
return new TreasureMap(level, from.Map == Map.Felucca ? Map.Felucca : Map.Trammel);
}
if (type == typeof(MessageInABottle))
return new MessageInABottle(from.Map == Map.Felucca ? Map.Felucca : Map.Trammel);
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;
switch (Utility.Random(8))
{
case 0: // Body parts
{
int[] list =
{
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 =
{
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.Random(0xE9F, 10));
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 =
{
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)
{
((IShipwreckedItem)preLoot).IsShipwreckedItem = true;
return preLoot;
}
LockableContainer chest;
if (Utility.RandomBool())
chest = new MetalGoldenChest();
else
chest = new WoodenChest();
if (sos.IsAncient)
chest.Hue = 0x481;
TreasureMapChest.Fill(chest, Math.Max(1, Math.Min(4, sos.Level)));
chest.DropItem(sos.IsAncient ? new FabledFishingNet() : 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) &&
!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
}
return base.Give(m, item, placeAtFeet || item is BigFish || item is WoodenChest || item is MetalGoldenChest);
}
public override void SendSuccessTo(Mobile from, Item item, HarvestResource resource)
{
if (item is BigFish fish)
{
from.SendLocalizedMessage(1042635); // Your fishing pole bends as you pull a big fish from the depths!
fish.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 = 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
{
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 OnHarvestStarted(Mobile from, Item tool, HarvestDefinition def, object toHarvest)
{
base.OnHarvestStarted(from, tool, def, toHarvest);
if (GetHarvestDetails(from, tool, toHarvest, out _, out Map map, out Point3D loc))
Timer.DelayCall(TimeSpan.FromSeconds(1.5),
delegate
{
if (Core.ML)
from.RevealingAction();
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);
if (Core.ML)
from.RevealingAction();
}
public override object GetLock(Mobile from, Item tool, HarvestDefinition def, object toHarvest) => 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;
}
private class MutateEntry
{
public bool m_DeepWater;
public double m_ReqSkill, m_MinSkill, m_MaxSkill;
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;
}
}
}
}