mirror of
https://github.com/ServUO/ServUO
synced 2026-08-11 20:23:04 -04:00
FIXED: the server was crashing when using old versions of tiledata for HouseTeleporterTile as it is hardcoded. You may check all all the posts about this error by searching "HouseTeleporterTile" in servuo forum. The fix is obvious.
710 lines
21 KiB
C#
710 lines
21 KiB
C#
using Server;
|
|
using System;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
using Server.Spells;
|
|
using Server.Gumps;
|
|
using System.Collections.Generic;
|
|
using Server.ContextMenus;
|
|
using Server.Targeting;
|
|
|
|
namespace Server.Multis
|
|
{
|
|
public class HouseTeleporterTile : HouseTeleporter, IFlipable
|
|
{
|
|
public static void Initialize()
|
|
{
|
|
if(TileData.ItemTable.Length >= 0x574A)
|
|
TileData.ItemTable[0x574A].Flags = TileFlag.None;
|
|
}
|
|
|
|
public static int MaxCharges = 1000;
|
|
|
|
private int _Charges;
|
|
|
|
public override int ItemID
|
|
{
|
|
get { return base.ItemID; }
|
|
set
|
|
{
|
|
base.ItemID = value;
|
|
|
|
HueChange();
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public HouseTeleporterTile Link
|
|
{
|
|
get
|
|
{
|
|
if(Target != null && Target.Deleted)
|
|
Target = null;
|
|
|
|
return Target as HouseTeleporterTile;
|
|
}
|
|
set
|
|
{
|
|
Target = value;
|
|
}
|
|
}
|
|
|
|
private bool IsMoveOver { get { return ItemID == 0x574A || ItemID == 0xA1CB || ItemID == 0xA1CC || ItemID == 0x40BB; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int Charges
|
|
{
|
|
get { return _Charges; }
|
|
set
|
|
{
|
|
_Charges = value;
|
|
|
|
HueChange();
|
|
|
|
InvalidateProperties();
|
|
}
|
|
}
|
|
|
|
public void HueChange()
|
|
{
|
|
if (UsesCharges && ItemID == 0x574A)
|
|
{
|
|
if (_Charges == 0)
|
|
{
|
|
Hue = 340;
|
|
}
|
|
else if (_Charges >= 1 && Hue != 541)
|
|
{
|
|
Hue = 541;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Hue = 0;
|
|
}
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool UsesCharges { get; set; }
|
|
|
|
public override int LabelNumber { get { return Link == null ? 1114916 : 1113917; } } // house teleporter (unlinked) -or- House Teleporter
|
|
|
|
public HouseTeleporterTile(bool vetReward)
|
|
: base(vetReward ? 0x40BB : 0x574A, null)
|
|
{
|
|
UsesCharges = !vetReward;
|
|
Movable = true;
|
|
Weight = 1.0;
|
|
LootType = LootType.Blessed;
|
|
|
|
if (vetReward)
|
|
{
|
|
UsesCharges = false;
|
|
}
|
|
else
|
|
{
|
|
UsesCharges = true;
|
|
Charges = MaxCharges;
|
|
}
|
|
}
|
|
|
|
public void OnFlip(Mobile from)
|
|
{
|
|
bool flip = false;
|
|
|
|
switch (ItemID)
|
|
{
|
|
case 0x108C:
|
|
ItemID = 0x1093;
|
|
flip = true;
|
|
break;
|
|
case 0x1093:
|
|
ItemID = 0x108C;
|
|
flip = true;
|
|
break;
|
|
case 0x108D:
|
|
ItemID = 0x1094;
|
|
flip = true;
|
|
break;
|
|
case 0x1094:
|
|
ItemID = 0x108D;
|
|
flip = true;
|
|
break;
|
|
case 0x108E:
|
|
ItemID = 0x1095;
|
|
flip = true;
|
|
break;
|
|
case 0x1095:
|
|
ItemID = 0x108E;
|
|
flip = true;
|
|
break;
|
|
case 0x1090:
|
|
case 0x108F:
|
|
ItemID = 0x1091;
|
|
flip = true;
|
|
break;
|
|
case 0x1091:
|
|
ItemID = 0x1090;
|
|
flip = true;
|
|
break;
|
|
case 0xA1CB:
|
|
ItemID = 0xA1CC;
|
|
flip = true;
|
|
break;
|
|
case 0xA1CC:
|
|
ItemID = 0xA1CB;
|
|
flip = true;
|
|
break;
|
|
case 0xA2BA:
|
|
ItemID = 0xA2BC;
|
|
flip = true;
|
|
break;
|
|
case 0xA2BC:
|
|
ItemID = 0xA2BA;
|
|
flip = true;
|
|
break;
|
|
case 0xA2BB:
|
|
ItemID = 0xA2BD;
|
|
flip = true;
|
|
break;
|
|
case 0xA2BD:
|
|
ItemID = 0xA2BB;
|
|
flip = true;
|
|
break;
|
|
}
|
|
|
|
if (!flip)
|
|
from.SendLocalizedMessage(1042273); // You cannot turn that.
|
|
}
|
|
|
|
public override bool OnMoveOver(Mobile m)
|
|
{
|
|
if (IsMoveOver)
|
|
{
|
|
base.OnMoveOver(m);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
|
|
{
|
|
if (from.InRange(Location, 2) || IsChildOf(from.Backpack))
|
|
{
|
|
if (UsesCharges)
|
|
{
|
|
list.Add(new RechargeEntry(from, this));
|
|
list.Add(new ChangeTypeEntry(from, this));
|
|
}
|
|
}
|
|
|
|
base.GetContextMenuEntries(from, list);
|
|
}
|
|
|
|
private class RechargeEntry : ContextMenuEntry
|
|
{
|
|
private readonly Mobile Mobile;
|
|
private readonly HouseTeleporterTile Item;
|
|
|
|
public RechargeEntry(Mobile mobile, HouseTeleporterTile item)
|
|
: base(1076197, 2)
|
|
{
|
|
Mobile = mobile;
|
|
Item = item;
|
|
|
|
BaseHouse house = BaseHouse.FindHouseAt(item);
|
|
|
|
Enabled = Item.IsLockedDown && house != null && house.IsOwner(Mobile);
|
|
}
|
|
|
|
public override void OnClick()
|
|
{
|
|
if (Item == null || Item.Deleted)
|
|
return;
|
|
|
|
Mobile.SendLocalizedMessage(1158897); // Target the gate scrolls you wish to recharge this item with...
|
|
Mobile.Target = new InternalTarget(Item);
|
|
}
|
|
}
|
|
|
|
private class InternalTarget : Target
|
|
{
|
|
private readonly HouseTeleporterTile Item;
|
|
|
|
public InternalTarget(HouseTeleporterTile item)
|
|
: base(2, false, TargetFlags.None)
|
|
{
|
|
Item = item;
|
|
}
|
|
|
|
protected override void OnTarget(Mobile from, object targeted)
|
|
{
|
|
if (from == null || Item == null || Item.Deleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (targeted is Item)
|
|
{
|
|
Item item = targeted as Item;
|
|
|
|
if (!item.IsChildOf(from.Backpack))
|
|
{
|
|
from.SendLocalizedMessage(1054107); // This item must be in your backpack.
|
|
return;
|
|
}
|
|
|
|
if (item is GateTravelScroll)
|
|
{
|
|
GateTravelScroll scroll = item as GateTravelScroll;
|
|
|
|
if (Item.Charges >= MaxCharges)
|
|
{
|
|
from.SendLocalizedMessage(1115126); // The House Teleporter cannot be charged any further.
|
|
}
|
|
else
|
|
{
|
|
int left = MaxCharges - Item.Charges;
|
|
int scrollsNeeded = Math.Max(1, left / 5);
|
|
|
|
if (scroll.Amount <= scrollsNeeded)
|
|
{
|
|
Item.Charges = Math.Min(MaxCharges, Item.Charges + (scroll.Amount * 5));
|
|
scroll.Delete();
|
|
}
|
|
else
|
|
{
|
|
scroll.Amount -= scrollsNeeded;
|
|
Item.Charges = MaxCharges;
|
|
}
|
|
|
|
from.SendLocalizedMessage(1115127); // The Gate Travel scroll crumbles to dust as it strengthens the House Teleporter.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(1158898); // Target gate scroll to recharge the teleporter.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private class ChangeTypeEntry : ContextMenuEntry
|
|
{
|
|
private readonly Mobile Mobile;
|
|
private readonly Item Item;
|
|
|
|
public ChangeTypeEntry(Mobile mobile, Item item)
|
|
: base(1158896, 2)
|
|
{
|
|
Mobile = mobile;
|
|
Item = item;
|
|
|
|
BaseHouse house = BaseHouse.FindHouseAt(item);
|
|
|
|
Enabled = Item.IsLockedDown && house != null && house.IsOwner(Mobile);
|
|
}
|
|
|
|
public override void OnClick()
|
|
{
|
|
if (Item == null || Item.Deleted)
|
|
return;
|
|
|
|
if (!Mobile.HasGump(typeof(HouseTeleporterTypeGump)))
|
|
{
|
|
BaseGump.SendGump(new HouseTeleporterTypeGump((PlayerMobile)Mobile, Item));
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void GetProperties(ObjectPropertyList list)
|
|
{
|
|
base.GetProperties(list);
|
|
|
|
if (UsesCharges)
|
|
{
|
|
list.Add(1060741, _Charges.ToString()); // charges: ~1_val~
|
|
}
|
|
}
|
|
|
|
public bool CheckBaseAccess(Mobile m)
|
|
{
|
|
return base.CheckAccess(m);
|
|
}
|
|
|
|
public override bool CheckAccess(Mobile m)
|
|
{
|
|
BaseHouse house = BaseHouse.FindHouseAt(this);
|
|
BaseHouse linkHouse = Link == null ? null : BaseHouse.FindHouseAt(Link);
|
|
|
|
if (house == null || Link == null || !IsLockedDown || !Link.IsLockedDown || linkHouse == null) // TODO: Messages for these?
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (UsesCharges && _Charges == 0)
|
|
{
|
|
m.SendLocalizedMessage(1115121); // There are no charges left in this teleporter.
|
|
return false;
|
|
}
|
|
|
|
if (UsesCharges && Link.Charges == 0)
|
|
{
|
|
m.SendLocalizedMessage(1115120); // There are no more charges left in the remote teleporter.
|
|
return false;
|
|
}
|
|
|
|
if (CheckBaseAccess(m) && Link.CheckBaseAccess(m))
|
|
{
|
|
return CheckTravel(m, Link.Location, Link.Map);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool CheckTravel(Mobile from, Point3D dest, Map destMap)
|
|
{
|
|
if (Factions.Sigil.ExistsOn(from))
|
|
{
|
|
from.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil.
|
|
return false;
|
|
}
|
|
else if (from.Criminal)
|
|
{
|
|
from.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily.
|
|
return false;
|
|
}
|
|
else if (SpellHelper.CheckCombat(from))
|
|
{
|
|
from.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle??
|
|
return false;
|
|
}
|
|
else if (destMap == Map.Felucca && from is PlayerMobile && ((PlayerMobile)from).Young)
|
|
{
|
|
from.SendLocalizedMessage(1049543); // You decide against traveling to Felucca while you are still young.
|
|
return false;
|
|
}
|
|
else if (SpellHelper.RestrictRedTravel && from.Murderer && destMap.Rules != MapRules.FeluccaRules && !Siege.SiegeShard)
|
|
{
|
|
from.SendLocalizedMessage(1019004); // You are not allowed to travel there.
|
|
return false;
|
|
}
|
|
else if (Server.Engines.CityLoyalty.CityTradeSystem.HasTrade(from))
|
|
{
|
|
from.SendLocalizedMessage(1151733); // You cannot do that while carrying a Trade Order.
|
|
return false;
|
|
}
|
|
else if (from.Holding != null)
|
|
{
|
|
from.SendLocalizedMessage(1071955); // You cannot teleport while dragging an object.
|
|
return false;
|
|
}
|
|
else if (from.Target != null)
|
|
{
|
|
from.SendLocalizedMessage(500310); // You are too busy with something else.
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void OnDoubleClick(Mobile m)
|
|
{
|
|
if(IsChildOf(m.Backpack))
|
|
{
|
|
m.SendLocalizedMessage(1114918); // Select a House Teleporter to link to.
|
|
m.BeginTarget(-1, false, Server.Targeting.TargetFlags.None, (from, targeted) =>
|
|
{
|
|
if(targeted is HouseTeleporterTile)
|
|
{
|
|
var tile = targeted as HouseTeleporterTile;
|
|
|
|
if(tile.IsChildOf(m.Backpack))
|
|
{
|
|
tile.Link = this;
|
|
Link = tile;
|
|
|
|
if (UsesCharges && tile.UsesCharges) //TODO: Can you link non-charged with charged?
|
|
{
|
|
from.SendLocalizedMessage(1115119); // The two House Teleporters are now linked and the charges remaining have been rebalanced.
|
|
|
|
if (!UsesCharges)
|
|
UsesCharges = true;
|
|
|
|
if (!tile.UsesCharges)
|
|
tile.UsesCharges = true;
|
|
|
|
int charges = _Charges + tile.Charges;
|
|
Charges = charges / 2;
|
|
tile.Charges = charges / 2;
|
|
}
|
|
else if (!UsesCharges && !tile.UsesCharges)
|
|
{
|
|
from.SendLocalizedMessage(1114919); // The two House Teleporters are now linked.
|
|
}
|
|
else
|
|
{
|
|
from.SendMessage("Those cannot be linked."); // TODO: Message?
|
|
}
|
|
}
|
|
else
|
|
{
|
|
from.SendLocalizedMessage(1114917); // This must be in your backpack to link it.
|
|
}
|
|
}
|
|
});
|
|
}
|
|
else if (!IsMoveOver)
|
|
{
|
|
if (Target != null && !Target.Deleted && InRange(m, 1))
|
|
{
|
|
if (CheckAccess(m))
|
|
{
|
|
if (!m.Hidden || m.IsPlayer())
|
|
new EffectTimer(m.Location, m.Map, 2023, 0x1F0, TimeSpan.FromSeconds(0.4)).Start();
|
|
|
|
new DelayTimer(this, m).Start();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m.SendLocalizedMessage(1114917); // This must be in your backpack to link it.
|
|
}
|
|
}
|
|
|
|
private class DelayTimer : Timer
|
|
{
|
|
private readonly HouseTeleporter m_Teleporter;
|
|
private readonly Mobile m_Mobile;
|
|
|
|
public DelayTimer(HouseTeleporter tp, Mobile m)
|
|
: base(TimeSpan.FromSeconds(1.0))
|
|
{
|
|
m_Teleporter = tp;
|
|
m_Mobile = m;
|
|
}
|
|
|
|
protected override void OnTick()
|
|
{
|
|
Item target = m_Teleporter.Target;
|
|
|
|
if (target != null && !target.Deleted)
|
|
{
|
|
Mobile m = m_Mobile;
|
|
|
|
Point3D p = target.GetWorldTop();
|
|
Map map = target.Map;
|
|
|
|
Server.Mobiles.BaseCreature.TeleportPets(m, p, map);
|
|
|
|
m.MoveToWorld(p, map);
|
|
|
|
if (!m.Hidden || m.IsPlayer())
|
|
{
|
|
Effects.PlaySound(target.Location, target.Map, 0x1FE);
|
|
|
|
Effects.SendLocationParticles(EffectItem.Create(m_Teleporter.Location, m_Teleporter.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023, 0);
|
|
Effects.SendLocationParticles(EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 5023, 0);
|
|
|
|
new EffectTimer(target.Location, target.Map, 2023, -1, TimeSpan.FromSeconds(0.4)).Start();
|
|
}
|
|
|
|
m_Teleporter.OnAfterTeleport(m);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void OnAfterTeleport(Mobile m)
|
|
{
|
|
if (UsesCharges)
|
|
{
|
|
Charges = Math.Max(0, _Charges - 1);
|
|
|
|
if (Link != null)
|
|
{
|
|
Link.Charges = Math.Max(0, Link.Charges - 1);
|
|
|
|
if (!Link.UsesCharges)
|
|
{
|
|
Link.UsesCharges = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public HouseTeleporterTile(Serial serial) : base(serial)
|
|
{
|
|
}
|
|
|
|
public override void Serialize(GenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
writer.Write(0);
|
|
|
|
writer.Write(_Charges);
|
|
writer.Write(UsesCharges);
|
|
}
|
|
|
|
public override void Deserialize(GenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
int version = reader.ReadInt();
|
|
|
|
_Charges = reader.ReadInt();
|
|
UsesCharges = reader.ReadBool();
|
|
|
|
if (ItemID == 0x40B9)
|
|
ItemID = 0x574A;
|
|
}
|
|
}
|
|
|
|
public class HouseTeleporterTypeGump : BaseGump
|
|
{
|
|
public Item Teleporter { get; set; }
|
|
|
|
public HouseTeleporterTypeGump(PlayerMobile pm, Item item)
|
|
: base(pm, 100, 100)
|
|
{
|
|
Teleporter = item;
|
|
}
|
|
|
|
public override void AddGumpLayout()
|
|
{
|
|
AddPage(0);
|
|
|
|
AddBackground(0, 0, 310, 400, 0x6DB);
|
|
|
|
AddImage(54, 0, 0x6E4);
|
|
AddHtmlLocalized(10, 10, 290, 18, 1114513, "#1113917", 0x0, false, false); // <DIV ALIGN=CENTER>~1_TOKEN~</DIV>
|
|
AddItem(35, 80, 0x574A);
|
|
AddButton(105, 80, 0x845, 0x846, 22346, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(35, 140, 0x108C);
|
|
AddButton(105, 140, 0x845, 0x846, 4236, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(35, 200, 0x108D);
|
|
AddButton(105, 200, 0x845, 0x846, 4237, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(35, 260, 0x108E);
|
|
AddButton(105, 260, 0x845, 0x846, 4238, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(35, 320, 0x108F);
|
|
AddButton(105, 320, 0x845, 0x846, 4239, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(235, 80, 0x1090);
|
|
AddButton(195, 80, 0x845, 0x846, 4240, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(235, 140, 0x9CDE);
|
|
AddButton(195, 140, 0x845, 0x846, 40158, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(235, 200, 0xA1CB);
|
|
AddButton(195, 200, 0x845, 0x846, 41419, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(235, 260, 0xA2BA);
|
|
AddButton(195, 260, 0x845, 0x846, 41658, GumpButtonType.Reply, 0);
|
|
|
|
AddItem(235, 320, 0xA2BB);
|
|
AddButton(195, 320, 0x845, 0x846, 41659, GumpButtonType.Reply, 0);
|
|
}
|
|
|
|
public override void OnResponse(RelayInfo info)
|
|
{
|
|
if (info.ButtonID != 0)
|
|
{
|
|
Teleporter.ItemID = info.ButtonID;
|
|
Refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class HouseTeleporterTileBag : Bag
|
|
{
|
|
public override int LabelNumber { get { return 1113917; } }
|
|
|
|
[Constructable]
|
|
public HouseTeleporterTileBag()
|
|
: this(false)
|
|
{
|
|
}
|
|
|
|
[Constructable]
|
|
public HouseTeleporterTileBag(bool reward)
|
|
{
|
|
Hue = 1336;
|
|
|
|
var tele1 = new HouseTeleporterTile(reward);
|
|
var tele2 = new HouseTeleporterTile(reward);
|
|
|
|
tele1.Link = tele2;
|
|
tele2.Link = tele1;
|
|
|
|
DropItem(tele1);
|
|
DropItem(tele2);
|
|
DropItem(new HouseTeleporterInstructions(reward));
|
|
}
|
|
|
|
public HouseTeleporterTileBag(Serial serial)
|
|
: base(serial)
|
|
{
|
|
}
|
|
|
|
public override void Serialize(GenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
writer.Write(0);
|
|
}
|
|
|
|
public override void Deserialize(GenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
int version = reader.ReadInt();
|
|
}
|
|
}
|
|
|
|
public class HouseTeleporterInstructions : Item
|
|
{
|
|
public override int LabelNumber { get { return 1115122; } } // Care Instructions
|
|
|
|
public bool VetReward { get; set; }
|
|
|
|
public HouseTeleporterInstructions(bool reward)
|
|
: base(0xFF4)
|
|
{
|
|
VetReward = reward;
|
|
Hue = 195;
|
|
}
|
|
|
|
public override void GetProperties(ObjectPropertyList list)
|
|
{
|
|
base.GetProperties(list);
|
|
|
|
list.Add(1115123); // Congratulations on becoming the<br> owner of your very own house<br> teleporter set!
|
|
list.Add(1115124); // To use them, lock one down in your<br> home then lock the other down in<br> the home of a trusted friend.
|
|
|
|
if (!VetReward)
|
|
{
|
|
list.Add(1115125); // Drop Gate Travel scrolls onto these<br> to recharge them.
|
|
}
|
|
}
|
|
|
|
public HouseTeleporterInstructions(Serial serial)
|
|
: base(serial)
|
|
{
|
|
}
|
|
|
|
public override void Serialize(GenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
writer.Write(0);
|
|
writer.Write(VetReward);
|
|
}
|
|
|
|
public override void Deserialize(GenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
int version = reader.ReadInt();
|
|
VetReward = reader.ReadBool();
|
|
}
|
|
}
|
|
}
|