The fishing mutate table offers every special catch in every era, so a pre-T2A shard fishes up boots, magic fish, treasure maps and bottles (added in the March 1999 fishing update), and a T2A shard gets the special fishing net and big fish, which no T2A publish or guide lists.
Each entry now carries the expansion that added it; the chances are unchanged. The nets in SOS chests and on krakens need UO:R as well, and before SE ancient SOS roll 1 in 40 and their chests aren't hued white, since Publish 28 changed both.
Two fixes from the same notes come with it. An SOS now only works in the facet it was found in, so kraken and leviathan bottles are made at death with the creature's facet. Big fish, their trophy deed and their trophy show the fisherman's mark and weight only from SE.
## Why each change
### The rule
- `Core.T2A`, `Core.UOR`, `Core.SE`… mean "the shard is this expansion **or newer**".
- An expansion includes every publish that came out while it was the newest one. Publish 27 (September 2004) came out before Samurai Empire (November 2004), so it belongs to AOS.
- An item can't drop on a shard older than the expansion that added it.
- When the sources only narrow it down to a window that spans two expansions, the item takes the older one, so no shard loses something it may really have had.
### When each fishing item arrived
| Expansion | Released | What it added to fishing | Sources |
|---|---|---|---|
| T2A | Oct 1, 1998 | Boots, magic fish, treasure maps, bottles (update of March 17, 1999) | [1] |
| UO:R | May 4, 2000 | Special fishing net (first listed in August 2000) | [2], [6], [7] |
| UO:R or Third Dawn | | Big fish (first listed between November 2000 and March 2001) | [3], [8], [9] |
| AOS | Feb 11, 2003 | Ancient SOS at 1 in 40, fabled fishing net (Publish 27, September 14, 2004) | [4] |
| SE | Nov 2, 2004 | Ancient SOS at 1 in 25, white ancient chests, the fisherman's mark on big fish (Publish 28, January 12, 2005) | [5] |
Release dates: [13].
### `Fishing.cs`
**`MutateEntry` gets an `Expansion` field and constructor argument.**
Each row has to know which expansion added it. `MutateEntry` is private to `Fishing`, so no other code is affected.
**`MutateType` skips rows newer than the shard:**
```csharp
if (Core.Expansion < entry.m_Expansion)
{
continue;
}
```
A skipped row behaves as if it weren't in the table. Every other row rolls exactly as before.
**The rows:**
| Row | Expansion | Why |
|---|---|---|
| Boots, shoes, sandals, thigh boots | T2A | The March 17, 1999 update is the first time fishing gives anything but fish: "you now have a chance of pulling up … One of any of several types of boots". [1] |
| Magic fish (prized, wondrous, truly rare, peculiar) | T2A | Same update: "Magical fish, which can boost stamina, strength, intelligence, or dexterity". [1] |
| Treasure map | T2A | Same update: "Treasure maps". [1] |
| Message in a bottle | T2A | Same update: "Messages in bottles". [1] |
| Special fishing net | UO:R | Missing from the 1999 list [1] and from the March 2000 fishing changes, which only mention treasure maps and SOS bottles [2]. Stratics' fishing guide doesn't have it from July 1999 to July 8, 2000 [6] and has it on August 10, 2000 [7], after UO:R came out. |
| Big fish | UO:R | Stratics' fishing guide doesn't have it from July 1999 [6] to November 7, 2000 [8] and has it on May 24, 2001 [9]. Publish 11 (March 14, 2001) already lets taxidermy kits use it [3]. So it is certainly not T2A. It came at the end of UO:R or with Third Dawn (March 7, 2001); the sources can't tell which, so it takes UO:R, the older one. |
| Nothing (the empty row) | None | Exists in every expansion; unchanged. |
**SOS chest, white hue: `if (sos.IsAncient && Core.SE)`**
Publish 28: "Hued level 4 fishing chests white." [5] It came out after SE, so before SE the ancient chest keeps its normal colour.
**SOS chest, net: `if (Core.UOR) { chest.DropItem(...); }`**
You can fish up an SOS chest from T2A on, because bottles are T2A [1]. The net inside it is UO:R (see the table), so before UO:R the chest comes without a net. The fabled net only goes in ancient chests, and those already need AOS [4].
**SOS: `from.Map == sos.TargetMap`, in `CheckResources` and `Construct`**
Both accepted an SOS whenever the fisher was in Felucca or Trammel, without comparing the SOS's `TargetMap`, so a Trammel SOS paid out in Felucca at the same spot. Publish 5: "SOS bottles and treasure maps will only work in the land they are found in (for instance, a map found in Felucca will only work in Felucca)." [14] Treasure maps already check their facet.
### `MessageInABottle.cs`
**`GetRandomLevel`: `Utility.Random(Core.SE ? 25 : 40) < 1`**
Publish 27 added ancient SOS at "a 1 in 40 chance" [4]. Publish 28 "Changed Ancient SoS spawn chance from 1 in 40 to 1 in 25" [5]. So AOS rolls 1 in 40, SE and newer 1 in 25. The `Core.AOS` check was already there.
### `Kraken.cs`
**Bottle, now made in `OnBeforeDeath`: `if (Core.T2A && Utility.RandomDouble() < .05)`**
Bottles don't exist before T2A [1], so a kraken can't carry one there. The 5% is unchanged; no official source gives a number. The kraken is in Stratics' 1999 creature list [10]; its kraken page says "Loot: Unknown" in January 2000 [11] and "Loot: Messages in a Bottle, Treasure Maps, 300 - 600 gold" in October 2000 [12].
The constructor packed the bottle before the kraken had a map, so it always pointed to Trammel; with the SOS check above, a kraken killed in Felucca would drop an SOS that only works in Trammel. It is now made at death with the kraken's facet, as `BaseCreature.OnBeforeDeath` does for treasure maps; the net already does the same for the kraken it brings up.
**Net: `if (Core.UOR) { PackItem(new SpecialFishingNet()); // Confirm? }`**
Nets are UO:R [6], [7]. The `// Confirm?` stays: in 2000 Stratics says the net was "loot on Sea Serpents" [7], [12], not on krakens. Which creature drops the net is out of scope; this PR only fixes the expansion.
### `Leviathan.cs`
**Bottle, now made in `OnBeforeDeath`**
Same as the kraken: it was packed in the constructor and pointed to Trammel. It is now made at death with the leviathan's facet, and still drops every time.
### `BigFish.cs` and `TaxidermyKit.cs`
**Mark and weight: `if (Core.SE && Weight >= 20)`, and the same in the trophy and its deed**
Publish 28: "Added variable weight and fisherman's mark on big fish, big fish trophy deed, and big fish trophy. Any big fish caught that is below 20 stones will not display weight or fisherman's mark." [5] It came out after SE, so before SE none of the three shows them.
### What this PR doesn't change
No chance, skill threshold or row order changes. The open questions (which creature drops the net, the exact expansion of big fish, its weight before Publish 28, the rates) are in #2687.
## References
1. Origin Update Center, update of March 17, 1999: the fishing overhaul that adds boots, magic fish, treasure maps and bottles. https://web.archive.org/web/19990417083713/http://update.owo.com/latest.html
2. Publish 4, March 8, 2000: "Every time you successfully fish up a treasure map or SOS bottle a sea serpent will surface and attack." https://uo.com/wiki/ultima-online-wiki/technical/previous-publishes/2000-2/2000-publish-04-8th-march/ (copy from the time: https://web.archive.org/web/20000408162342/http://update.uo.com/design_180.html)
3. Publish 11, March 14, 2001: taxidermy kits accept "Big Fish". https://uo.com/wiki/ultima-online-wiki/technical/previous-publishes/2001-2/2001-publish-11-14th-march/ (copy from the time: https://web.archive.org/web/20010331072129/http://update.uo.com/design_321.html)
4. Publish 27, September 14, 2004: "There is a 1 in 40 chance that any message in a bottle becomes 'an ancient SOS'", "Added fabled fishing nets and ancient sos treasure". https://uo.com/wiki/ultima-online-wiki/technical/previous-publishes/2004-2/publish-27/
5. Publish 28, January 12, 2005: "Hued level 4 fishing chests white", "Changed Ancient SoS spawn chance from 1 in 40 to 1 in 25". https://uo.com/wiki/ultima-online-wiki/technical/previous-publishes/2005-2/publish-28-12th-january/
6. Stratics fishing guide without the net or big fish, the same text from July 24, 1999 to July 8, 2000: last modified July 24, 1999, https://web.archive.org/web/19991009203653/http://uo.stratics.com:80/fishing.htm ; last modified July 8, 2000, https://web.archive.org/web/20000711071050/http://uo.stratics.com:80/fishing.shtml
7. Stratics fishing guide, last modified August 10, 2000: lists the special fishing net, "found as loot on sea serpents". https://web.archive.org/web/20000831173915/http://uo.stratics.com:80/fishing.shtml
8. Stratics fishing guide, last modified November 7, 2000: still no big fish. https://web.archive.org/web/20001209013100/http://uo.stratics.com:80/fishing.shtml
9. Stratics fishing guide, last modified May 24, 2001: lists big fish. https://web.archive.org/web/20010608153326/http://uo.stratics.com:80/content/skills/fishing.shtml
10. Stratics Hunter's Guide menu, last modified July 4, 1999: the kraken is in the creature list. https://web.archive.org/web/19991013090543/http://uo.stratics.com:80/hunters/huntmenu.htm
11. Stratics kraken page, last modified January 1, 2000: "Loot: Unknown". https://web.archive.org/web/20000119061647/http://uo.stratics.com:80/hunters/kraken.html
12. Stratics kraken page, last modified October 15, 2000: "Loot: Messages in a Bottle, Treasure Maps, 300 - 600 gold"; the net "can be found as loot on Sea Serpents". https://web.archive.org/web/20001017190252/http://uo.stratics.com:80/hunters/kraken.shtml
13. Expansion release dates: https://en.wikipedia.org/wiki/Ultima_Online#Expansions_and_follow-up_releases
14. Publish 5, April 27, 2000: "SOS bottles and treasure maps will only work in the land they are found in". https://uo.com/wiki/ultima-online-wiki/technical/previous-publishes/2000-2/2000-publish-05-27th-april/ (copy from the time: https://web.archive.org/web/20000510032101/http://update.uo.com/design_196.html)
562 lines
19 KiB
C#
562 lines
19 KiB
C#
using System;
|
|
using Server.Engines.Quests.Collector;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
using Server.Spells;
|
|
|
|
namespace Server.Engines.Harvest
|
|
{
|
|
public class Fishing : HarvestSystem
|
|
{
|
|
private static Fishing _system;
|
|
|
|
private static readonly MutateEntry[] _mutateTable =
|
|
{
|
|
new(80.0, 80.0, 4080.0, true, Expansion.UOR, typeof(SpecialFishingNet)),
|
|
new(80.0, 80.0, 4080.0, true, Expansion.UOR, typeof(BigFish)),
|
|
new(90.0, 80.0, 4080.0, true, Expansion.T2A, typeof(TreasureMap)),
|
|
new(100.0, 80.0, 4080.0, true, Expansion.T2A, typeof(MessageInABottle)),
|
|
new(
|
|
0.0,
|
|
125.0,
|
|
-2375.0,
|
|
false,
|
|
Expansion.T2A,
|
|
typeof(PrizedFish),
|
|
typeof(WondrousFish),
|
|
typeof(TrulyRareFish),
|
|
typeof(PeculiarFish)
|
|
),
|
|
new(0.0, 105.0, -420.0, false, Expansion.T2A, typeof(Boots), typeof(Shoes), typeof(Sandals), typeof(ThighBoots)),
|
|
new(0.0, 200.0, -200.0, false, Expansion.None, new Type[] { null })
|
|
};
|
|
|
|
private static readonly int[] _waterLandTiles =
|
|
{
|
|
0x00A8, 0x00AB,
|
|
0x0136, 0x0137
|
|
};
|
|
|
|
private static readonly int[] waterStaticTiles =
|
|
{
|
|
0x1797, 0x179C,
|
|
0x346E, 0x3485,
|
|
0x3490, 0x34AB,
|
|
0x34B5, 0x35D5
|
|
};
|
|
|
|
private static readonly int[] bodyParts = {
|
|
0x1CDD, 0x1CE5, // arm
|
|
0x1CE0, 0x1CE8, // torso
|
|
0x1CE1, 0x1CE9, // head
|
|
0x1CE2, 0x1CEC // leg
|
|
};
|
|
|
|
private static readonly int[] boneParts = {
|
|
0x1AE0, 0x1AE1, 0x1AE2, 0x1AE3, 0x1AE4, // skulls
|
|
0x1B09, 0x1B0A, 0x1B0B, 0x1B0C, 0x1B0D, 0x1B0E, 0x1B0F, 0x1B10, // bone piles
|
|
0x1B15, 0x1B16 // pelvis bones
|
|
};
|
|
|
|
private static readonly int[] miscItems = {
|
|
0x1EB5, // unfinished barrel
|
|
0xA2A, // stool
|
|
0xC1F, // broken clock
|
|
0x1047, 0x1048, // globe
|
|
0x1EB1, 0x1EB2, 0x1EB3, 0x1EB4 // barrel staves
|
|
};
|
|
|
|
private Fishing()
|
|
{
|
|
var fish = new HarvestDefinition
|
|
{
|
|
BankWidth = 8,
|
|
BankHeight = 8,
|
|
MinTotal = 5,
|
|
MaxTotal = 15,
|
|
MinRespawn = TimeSpan.FromMinutes(10.0),
|
|
MaxRespawn = TimeSpan.FromMinutes(20.0),
|
|
Skill = SkillName.Fishing,
|
|
LandTiles = _waterLandTiles,
|
|
StaticTiles = waterStaticTiles,
|
|
RangedTiles = true,
|
|
MaxRange = 4,
|
|
ConsumedPerHarvest = 1,
|
|
ConsumedPerFeluccaHarvest = 1,
|
|
EffectActions = new[] { 12 },
|
|
EffectSounds = Array.Empty<int>(),
|
|
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(00.0, 00.0, 100.0, 1043297, typeof(Fish))
|
|
};
|
|
|
|
HarvestVein[] veins =
|
|
{
|
|
new(1000, 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))
|
|
};
|
|
}
|
|
|
|
Definitions = new[] { fish };
|
|
}
|
|
|
|
public static Fishing System => _system ??= new Fishing();
|
|
|
|
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)
|
|
{
|
|
var qs = player.Quest;
|
|
|
|
if (qs is CollectorQuest)
|
|
{
|
|
var obj = qs.FindObjective<FishPearlsObjective>();
|
|
|
|
if (obj?.Completed == false)
|
|
{
|
|
if (Utility.RandomBool())
|
|
{
|
|
// You pull a shellfish out of the water, and find a rainbow pearl inside of it.
|
|
player.SendLocalizedMessage(1055086, "", 0x59);
|
|
obj.CurProgress++;
|
|
}
|
|
else
|
|
{
|
|
// You pull a shellfish out of the water, but it doesn't have a rainbow pearl.
|
|
player.SendLocalizedMessage(1055087, "", 0x2C);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override Type MutateType(
|
|
Type type, Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc,
|
|
HarvestResource resource
|
|
)
|
|
{
|
|
var deepWater = SpecialFishingNet.FullValidation(map, loc.X, loc.Y);
|
|
|
|
var skillBase = from.Skills.Fishing.Base;
|
|
var skillValue = from.Skills.Fishing.Value;
|
|
|
|
for (var i = 0; i < _mutateTable.Length; ++i)
|
|
{
|
|
var entry = _mutateTable[i];
|
|
|
|
if (Core.Expansion < entry.m_Expansion)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!deepWater && entry.m_DeepWater)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (skillBase >= entry.m_ReqSkill)
|
|
{
|
|
var chance = (skillValue - entry.m_MinSkill) / (entry.m_MaxSkill - entry.m_MinSkill);
|
|
|
|
if (chance > Utility.RandomDouble())
|
|
{
|
|
return entry.m_Types.RandomElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
public override bool CheckResources(Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, bool timed)
|
|
{
|
|
var pack = from.Backpack;
|
|
|
|
if (pack != null)
|
|
{
|
|
foreach (var sos in pack.FindItemsByType<SOS>())
|
|
{
|
|
if (from.Map == sos.TargetMap && from.InRange(sos.TargetLocation, 60))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 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);
|
|
}
|
|
|
|
var pack = from.Backpack;
|
|
|
|
if (pack != null)
|
|
{
|
|
// We don't have to queue since we are returning on the first SOS.
|
|
foreach (var sos in pack.FindItemsByType<SOS>())
|
|
{
|
|
if (from.Map == sos.TargetMap && from.InRange(sos.TargetLocation, 60))
|
|
{
|
|
Item preLoot = null;
|
|
|
|
switch (Utility.Random(8))
|
|
{
|
|
case 0: // Body parts
|
|
{
|
|
preLoot = new ShipwreckedItem(bodyParts.RandomElement());
|
|
break;
|
|
}
|
|
case 1: // Bone parts
|
|
{
|
|
preLoot = new ShipwreckedItem(boneParts.RandomElement());
|
|
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
|
|
{
|
|
preLoot = Utility.RandomBool() ? new SkullCap() : new TricorneHat();
|
|
break;
|
|
}
|
|
case 6: // Misc
|
|
{
|
|
var rand = Utility.Random(miscItems.Length + 1);
|
|
|
|
preLoot = rand == miscItems.Length
|
|
? new Candelabra()
|
|
: new ShipwreckedItem(miscItems[rand]);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (preLoot != null)
|
|
{
|
|
((IShipwreckedItem)preLoot).IsShipwreckedItem = true;
|
|
return preLoot;
|
|
}
|
|
|
|
LockableContainer chest = Utility.RandomBool() ? new MetalGoldenChest() : new WoodenChest();
|
|
|
|
if (sos.IsAncient && Core.SE)
|
|
{
|
|
chest.Hue = 0x481;
|
|
}
|
|
|
|
TreasureMapChest.Fill(chest, Math.Max(1, Math.Min(4, sos.Level)));
|
|
|
|
if (Core.UOR)
|
|
{
|
|
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 or MessageInABottle or SpecialFishingNet)
|
|
{
|
|
BaseCreature serp;
|
|
|
|
if (Utility.RandomDouble() < 0.25)
|
|
{
|
|
serp = new DeepSeaSerpent();
|
|
}
|
|
else
|
|
{
|
|
serp = new SeaSerpent();
|
|
}
|
|
|
|
int x = m.X, y = m.Y;
|
|
|
|
var map = m.Map;
|
|
|
|
for (var i = 0; map != null && i < 20; ++i)
|
|
{
|
|
var tx = m.X - 10 + Utility.Random(21);
|
|
var ty = m.Y - 10 + Utility.Random(21);
|
|
|
|
var 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 or WoodenChest or 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 or 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;
|
|
}
|
|
}
|
|
|
|
var ns = from.NetState;
|
|
|
|
if (number == 1043297 || ns?.HighSeas == true)
|
|
{
|
|
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 var map, out var loc, out _))
|
|
{
|
|
Timer.StartTimer(
|
|
TimeSpan.FromSeconds(1.5),
|
|
() =>
|
|
{
|
|
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 readonly bool m_DeepWater;
|
|
public readonly Expansion m_Expansion;
|
|
public readonly double m_MaxSkill;
|
|
public readonly double m_MinSkill;
|
|
public readonly double m_ReqSkill;
|
|
public readonly Type[] m_Types;
|
|
|
|
public MutateEntry(
|
|
double reqSkill, double minSkill, double maxSkill, bool deepWater, Expansion expansion, params Type[] types
|
|
)
|
|
{
|
|
m_ReqSkill = reqSkill;
|
|
m_MinSkill = minSkill;
|
|
m_MaxSkill = maxSkill;
|
|
m_DeepWater = deepWater;
|
|
m_Expansion = expansion;
|
|
m_Types = types;
|
|
}
|
|
}
|
|
}
|
|
}
|