v0.0.1-Alpha (#42)
This commit is contained in:
parent
d30f93c454
commit
a36796c2c1
3552 changed files with 2476 additions and 15223 deletions
28
Projects/Scripts/Engines/BulkOrders/BODTarget.cs
Normal file
28
Projects/Scripts/Engines/BulkOrders/BODTarget.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Server.Targeting;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BODTarget : Target
|
||||
{
|
||||
private BaseBOD m_Deed;
|
||||
|
||||
public BODTarget(BaseBOD deed) : base(18, false, TargetFlags.None)
|
||||
{
|
||||
m_Deed = deed;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (m_Deed.Deleted || !m_Deed.IsChildOf(from.Backpack))
|
||||
return;
|
||||
|
||||
if (!(targeted is Item item && item.IsChildOf(from.Backpack)))
|
||||
{
|
||||
from.SendLocalizedMessage( 1045158 ); // You must have the item in your backpack to target it.
|
||||
return;
|
||||
}
|
||||
|
||||
m_Deed.EndCombine(from, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
153
Projects/Scripts/Engines/BulkOrders/BaseBOD.cs
Normal file
153
Projects/Scripts/Engines/BulkOrders/BaseBOD.cs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public abstract class BaseBOD : Item
|
||||
{
|
||||
private int m_AmountMax;
|
||||
private bool m_RequireExceptional;
|
||||
private BulkMaterialType m_Material;
|
||||
|
||||
public static BulkMaterialType GetRandomMaterial(BulkMaterialType start, double[] chances)
|
||||
{
|
||||
double random = Utility.RandomDouble();
|
||||
|
||||
for ( int i = 0; i < chances.Length; ++i )
|
||||
{
|
||||
if ( random < chances[i] )
|
||||
return i == 0 ? BulkMaterialType.None : start + (i - 1);
|
||||
|
||||
random -= chances[i];
|
||||
}
|
||||
|
||||
return BulkMaterialType.None;
|
||||
}
|
||||
|
||||
public BaseBOD(int hue, int amountMax, bool requireExeptional, BulkMaterialType material) : this()
|
||||
{
|
||||
Hue = hue;
|
||||
AmountMax = amountMax;
|
||||
RequireExceptional = requireExeptional;
|
||||
Material = material;
|
||||
}
|
||||
|
||||
public BaseBOD() : base(Core.AOS ? 0x2258 : 0x14EF)
|
||||
{
|
||||
Weight = 1.0;
|
||||
LootType = LootType.Blessed;
|
||||
}
|
||||
|
||||
public BaseBOD(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract bool Complete{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public sealed override int Hue{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int AmountMax
|
||||
{
|
||||
get => m_AmountMax;
|
||||
set{ m_AmountMax = value; InvalidateProperties(); }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public bool RequireExceptional
|
||||
{
|
||||
get => m_RequireExceptional;
|
||||
set{ m_RequireExceptional = value; InvalidateProperties(); }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public BulkMaterialType Material
|
||||
{
|
||||
get => m_Material;
|
||||
set{ m_Material = value; InvalidateProperties(); }
|
||||
}
|
||||
|
||||
public abstract RewardGroup GetRewardGroup();
|
||||
|
||||
public abstract int ComputeGold();
|
||||
public abstract int ComputeFame();
|
||||
public abstract void EndCombine(Mobile from, Item item);
|
||||
|
||||
public virtual void GetRewards(out Item reward, out int gold, out int fame)
|
||||
{
|
||||
gold = ComputeGold();
|
||||
fame = ComputeFame();
|
||||
|
||||
List<RewardItem> rewards = ComputeRewards(false);
|
||||
|
||||
reward = rewards.Count <= 0 ? null : rewards[Utility.Random(rewards.Count)].Construct();
|
||||
}
|
||||
|
||||
public virtual List<RewardItem> ComputeRewards(bool full)
|
||||
{
|
||||
RewardGroup rewardGroup = GetRewardGroup();
|
||||
|
||||
List<RewardItem> list = new List<RewardItem>();
|
||||
|
||||
if (full)
|
||||
{
|
||||
for (int i = 0; i < rewardGroup?.Items.Length; ++i)
|
||||
{
|
||||
RewardItem reward = rewardGroup.Items[i];
|
||||
|
||||
if (reward != null)
|
||||
list.Add(reward);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RewardItem reward = rewardGroup.AcquireItem();
|
||||
|
||||
if (reward != null)
|
||||
list.Add(reward);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public virtual void BeginCombine(Mobile from)
|
||||
{
|
||||
if (Complete)
|
||||
from.SendLocalizedMessage(1045166); // The maximum amount of requested items have already been combined to this deed.
|
||||
else
|
||||
from.Target = new BODTarget(this);
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
|
||||
writer.WriteEncodedInt( 0 ); // version
|
||||
|
||||
writer.Write( m_AmountMax );
|
||||
writer.Write( m_RequireExceptional );
|
||||
writer.Write( (int) m_Material );
|
||||
}
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch ( version )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_AmountMax = reader.ReadInt();
|
||||
m_RequireExceptional = reader.ReadBool();
|
||||
m_Material = (BulkMaterialType)reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( Parent == null && Map == Map.Internal && Location == Point3D.Zero )
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Projects/Scripts/Engines/BulkOrders/Books/BOBFilter.cs
Normal file
62
Projects/Scripts/Engines/BulkOrders/Books/BOBFilter.cs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BOBFilter
|
||||
{
|
||||
public BOBFilter()
|
||||
{
|
||||
}
|
||||
|
||||
public BOBFilter(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Type = reader.ReadEncodedInt();
|
||||
Quality = reader.ReadEncodedInt();
|
||||
Material = reader.ReadEncodedInt();
|
||||
Quantity = reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDefault => Type == 0 && Quality == 0 && Material == 0 && Quantity == 0;
|
||||
|
||||
public int Type{ get; set; }
|
||||
|
||||
public int Quality{ get; set; }
|
||||
|
||||
public int Material{ get; set; }
|
||||
|
||||
public int Quantity{ get; set; }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Type = 0;
|
||||
Quality = 0;
|
||||
Material = 0;
|
||||
Quantity = 0;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
if (IsDefault)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteEncodedInt(1); // version
|
||||
|
||||
writer.WriteEncodedInt(Type);
|
||||
writer.WriteEncodedInt(Quality);
|
||||
writer.WriteEncodedInt(Material);
|
||||
writer.WriteEncodedInt(Quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
220
Projects/Scripts/Engines/BulkOrders/Books/BOBFilterGump.cs
Normal file
220
Projects/Scripts/Engines/BulkOrders/Books/BOBFilterGump.cs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BOBFilterGump : Gump
|
||||
{
|
||||
private const int LabelColor = 0x7FFF;
|
||||
|
||||
private static int[,] m_MaterialFilters =
|
||||
{
|
||||
{ 1044067, 1 }, // Blacksmithy
|
||||
{ 1062226, 3 }, // Iron
|
||||
{ 1018332, 4 }, // Dull Copper
|
||||
{ 1018333, 5 }, // Shadow Iron
|
||||
{ 1018334, 6 }, // Copper
|
||||
{ 1018335, 7 }, // Bronze
|
||||
|
||||
{ 0, 0 }, // --Blank--
|
||||
{ 1018336, 8 }, // Golden
|
||||
{ 1018337, 9 }, // Agapite
|
||||
{ 1018338, 10 }, // Verite
|
||||
{ 1018339, 11 }, // Valorite
|
||||
{ 0, 0 }, // --Blank--
|
||||
|
||||
{ 1044094, 2 }, // Tailoring
|
||||
{ 1044286, 12 }, // Cloth
|
||||
{ 1062235, 13 }, // Leather
|
||||
{ 1062236, 14 }, // Spined
|
||||
{ 1062237, 15 }, // Horned
|
||||
{ 1062238, 16 } // Barbed
|
||||
};
|
||||
|
||||
private static int[,] m_TypeFilters =
|
||||
{
|
||||
{ 1062229, 0 }, // All
|
||||
{ 1062224, 1 }, // Small
|
||||
{ 1062225, 2 } // Large
|
||||
};
|
||||
|
||||
private static int[,] m_QualityFilters =
|
||||
{
|
||||
{ 1062229, 0 }, // All
|
||||
{ 1011542, 1 }, // Normal
|
||||
{ 1060636, 2 } // Exceptional
|
||||
};
|
||||
|
||||
private static int[,] m_AmountFilters =
|
||||
{
|
||||
{ 1062229, 0 }, // All
|
||||
{ 1049706, 1 }, // 10
|
||||
{ 1016007, 2 }, // 15
|
||||
{ 1062239, 3 } // 20
|
||||
};
|
||||
|
||||
private static int[][,] m_Filters =
|
||||
{
|
||||
m_TypeFilters,
|
||||
m_QualityFilters,
|
||||
m_MaterialFilters,
|
||||
m_AmountFilters
|
||||
};
|
||||
|
||||
private static int[] m_XOffsets_Type = { 0, 75, 170 };
|
||||
private static int[] m_XOffsets_Quality = { 0, 75, 170 };
|
||||
private static int[] m_XOffsets_Amount = { 0, 75, 180, 275 };
|
||||
private static int[] m_XOffsets_Material = { 0, 105, 210, 305, 390, 485 };
|
||||
|
||||
private static int[] m_XWidths_Small = { 50, 50, 70, 50 };
|
||||
private static int[] m_XWidths_Large = { 80, 50, 50, 50, 50, 50 };
|
||||
private BulkOrderBook m_Book;
|
||||
private PlayerMobile m_From;
|
||||
|
||||
public BOBFilterGump(PlayerMobile from, BulkOrderBook book) : base(12, 24)
|
||||
{
|
||||
from.CloseGump<BOBGump>();
|
||||
from.CloseGump<BOBFilterGump>();
|
||||
|
||||
m_From = from;
|
||||
m_Book = book;
|
||||
|
||||
BOBFilter f = from.UseOwnFilter ? from.BOBFilter : book.Filter;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(10, 10, 600, 439, 5054);
|
||||
|
||||
AddImageTiled(18, 20, 583, 420, 2624);
|
||||
AddAlphaRegion(18, 20, 583, 420);
|
||||
|
||||
AddImage(5, 5, 10460);
|
||||
AddImage(585, 5, 10460);
|
||||
AddImage(5, 424, 10460);
|
||||
AddImage(585, 424, 10460);
|
||||
|
||||
AddHtmlLocalized(270, 32, 200, 32, 1062223, LabelColor); // Filter Preference
|
||||
|
||||
AddHtmlLocalized(26, 64, 120, 32, 1062228, LabelColor); // Bulk Order Type
|
||||
AddFilterList(25, 96, m_XOffsets_Type, 40, m_TypeFilters, m_XWidths_Small, f.Type, 0);
|
||||
|
||||
AddHtmlLocalized(320, 64, 50, 32, 1062215, LabelColor); // Quality
|
||||
AddFilterList(320, 96, m_XOffsets_Quality, 40, m_QualityFilters, m_XWidths_Small, f.Quality, 1);
|
||||
|
||||
AddHtmlLocalized(26, 160, 120, 32, 1062232, LabelColor); // Material Type
|
||||
AddFilterList(25, 192, m_XOffsets_Material, 40, m_MaterialFilters, m_XWidths_Large, f.Material, 2);
|
||||
|
||||
AddHtmlLocalized(26, 320, 120, 32, 1062217, LabelColor); // Amount
|
||||
AddFilterList(25, 352, m_XOffsets_Amount, 40, m_AmountFilters, m_XWidths_Small, f.Quantity, 3);
|
||||
|
||||
AddHtmlLocalized(75, 416, 120, 32, 1062477, from.UseOwnFilter ? LabelColor : 16927); // Set Book Filter
|
||||
AddButton(40, 416, 4005, 4007, 1);
|
||||
|
||||
AddHtmlLocalized(235, 416, 120, 32, 1062478, from.UseOwnFilter ? 16927 : LabelColor); // Set Your Filter
|
||||
AddButton(200, 416, 4005, 4007, 2);
|
||||
|
||||
AddHtmlLocalized(405, 416, 120, 32, 1062231, LabelColor); // Clear Filter
|
||||
AddButton(370, 416, 4005, 4007, 3);
|
||||
|
||||
AddHtmlLocalized(540, 416, 50, 32, 1011046, LabelColor); // APPLY
|
||||
AddButton(505, 416, 4017, 4018, 0);
|
||||
}
|
||||
|
||||
private void AddFilterList(int x, int y, int[] xOffsets, int yOffset, int[,] filters, int[] xWidths, int filterValue,
|
||||
int filterIndex)
|
||||
{
|
||||
for (int i = 0; i < filters.GetLength(0); ++i)
|
||||
{
|
||||
int number = filters[i, 0];
|
||||
|
||||
if (number == 0)
|
||||
continue;
|
||||
|
||||
bool isSelected = filters[i, 1] == filterValue ||
|
||||
i % xOffsets.Length == 0 && filterValue == 0;
|
||||
|
||||
AddHtmlLocalized(x + 35 + xOffsets[i % xOffsets.Length], y + i / xOffsets.Length * yOffset,
|
||||
xWidths[i % xOffsets.Length], 32, number, isSelected ? 16927 : LabelColor);
|
||||
AddButton(x + xOffsets[i % xOffsets.Length], y + i / xOffsets.Length * yOffset, 4005, 4007,
|
||||
4 + filterIndex + i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
BOBFilter f = m_From.UseOwnFilter ? m_From.BOBFilter : m_Book.Filter;
|
||||
|
||||
int index = info.ButtonID;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0: // Apply
|
||||
{
|
||||
m_From.SendGump(new BOBGump(m_From, m_Book));
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // Set Book Filter
|
||||
{
|
||||
m_From.UseOwnFilter = false;
|
||||
m_From.SendGump(new BOBFilterGump(m_From, m_Book));
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // Set Your Filter
|
||||
{
|
||||
m_From.UseOwnFilter = true;
|
||||
m_From.SendGump(new BOBFilterGump(m_From, m_Book));
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Clear Filter
|
||||
{
|
||||
f.Clear();
|
||||
m_From.SendGump(new BOBFilterGump(m_From, m_Book));
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
index -= 4;
|
||||
|
||||
int type = index % 4;
|
||||
index /= 4;
|
||||
|
||||
if (type >= 0 && type < m_Filters.Length)
|
||||
{
|
||||
int[,] filters = m_Filters[type];
|
||||
|
||||
if (index >= 0 && index < filters.GetLength(0))
|
||||
{
|
||||
if (filters[index, 0] == 0)
|
||||
break;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
f.Type = filters[index, 1];
|
||||
break;
|
||||
case 1:
|
||||
f.Quality = filters[index, 1];
|
||||
break;
|
||||
case 2:
|
||||
f.Material = filters[index, 1];
|
||||
break;
|
||||
case 3:
|
||||
f.Quantity = filters[index, 1];
|
||||
break;
|
||||
}
|
||||
|
||||
m_From.SendGump(new BOBFilterGump(m_From, m_Book));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
647
Projects/Scripts/Engines/BulkOrders/Books/BOBGump.cs
Normal file
647
Projects/Scripts/Engines/BulkOrders/Books/BOBGump.cs
Normal file
|
|
@ -0,0 +1,647 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Prompts;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BOBGump : Gump
|
||||
{
|
||||
private const int LabelColor = 0x7FFF;
|
||||
private BulkOrderBook m_Book;
|
||||
private PlayerMobile m_From;
|
||||
private List<IBOBEntry> m_List;
|
||||
|
||||
private int m_Page;
|
||||
|
||||
public BOBGump(PlayerMobile from, BulkOrderBook book, int page = 0, List<IBOBEntry> list = null) : base(12, 24)
|
||||
{
|
||||
from.CloseGump<BOBGump>();
|
||||
from.CloseGump<BOBFilterGump>();
|
||||
|
||||
m_From = from;
|
||||
m_Book = book;
|
||||
m_Page = page;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<IBOBEntry>(book.Entries.Count);
|
||||
|
||||
for (int i = 0; i < book.Entries.Count; ++i)
|
||||
{
|
||||
IBOBEntry entry = book.Entries[i];
|
||||
|
||||
if (CheckFilter(entry))
|
||||
list.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
m_List = list;
|
||||
|
||||
int index = GetIndexForPage(page);
|
||||
int count = GetCountForIndex(index);
|
||||
|
||||
int tableIndex = 0;
|
||||
|
||||
PlayerVendor pv = book.RootParent as PlayerVendor;
|
||||
|
||||
bool canDrop = book.IsChildOf(from.Backpack);
|
||||
bool canBuy = pv != null;
|
||||
bool canPrice = canDrop || canBuy;
|
||||
|
||||
if (canBuy)
|
||||
{
|
||||
VendorItem vi = pv.GetVendorItem(book);
|
||||
|
||||
canBuy = vi?.IsForSale == false;
|
||||
}
|
||||
|
||||
int width = 600;
|
||||
|
||||
if (!canPrice)
|
||||
width = 516;
|
||||
|
||||
X = (624 - width) / 2;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(10, 10, width, 439, 5054);
|
||||
AddImageTiled(18, 20, width - 17, 420, 2624);
|
||||
|
||||
if (canPrice)
|
||||
{
|
||||
AddImageTiled(573, 64, 24, 352, 200);
|
||||
AddImageTiled(493, 64, 78, 352, 1416);
|
||||
}
|
||||
|
||||
if (canDrop)
|
||||
AddImageTiled(24, 64, 32, 352, 1416);
|
||||
|
||||
AddImageTiled(58, 64, 36, 352, 200);
|
||||
AddImageTiled(96, 64, 133, 352, 1416);
|
||||
AddImageTiled(231, 64, 80, 352, 200);
|
||||
AddImageTiled(313, 64, 100, 352, 1416);
|
||||
AddImageTiled(415, 64, 76, 352, 200);
|
||||
|
||||
for (int i = index; i < index + count && i >= 0 && i < list.Count; ++i)
|
||||
{
|
||||
IBOBEntry entry = list[i];
|
||||
|
||||
if (!CheckFilter(entry))
|
||||
continue;
|
||||
|
||||
AddImageTiled(24, 94 + tableIndex * 32, canPrice ? 573 : 489, 2, 2624);
|
||||
tableIndex += entry is BOBLargeEntry largeEntry ? largeEntry.Entries.Length : 1;
|
||||
}
|
||||
|
||||
AddAlphaRegion(18, 20, width - 17, 420);
|
||||
AddImage(5, 5, 10460);
|
||||
AddImage(width - 15, 5, 10460);
|
||||
AddImage(5, 424, 10460);
|
||||
AddImage(width - 15, 424, 10460);
|
||||
|
||||
AddHtmlLocalized(canPrice ? 266 : 224, 32, 200, 32, 1062220, LabelColor); // Bulk Order Book
|
||||
AddHtmlLocalized(63, 64, 200, 32, 1062213, LabelColor); // Type
|
||||
AddHtmlLocalized(147, 64, 200, 32, 1062214, LabelColor); // Item
|
||||
AddHtmlLocalized(246, 64, 200, 32, 1062215, LabelColor); // Quality
|
||||
AddHtmlLocalized(336, 64, 200, 32, 1062216, LabelColor); // Material
|
||||
AddHtmlLocalized(429, 64, 200, 32, 1062217, LabelColor); // Amount
|
||||
|
||||
AddButton(35, 32, 4005, 4007, 1);
|
||||
AddHtmlLocalized(70, 32, 200, 32, 1062476, LabelColor); // Set Filter
|
||||
|
||||
BOBFilter f = from.UseOwnFilter ? from.BOBFilter : book.Filter;
|
||||
|
||||
if (f.IsDefault)
|
||||
AddHtmlLocalized(canPrice ? 470 : 386, 32, 120, 32, 1062475, 16927); // Using No Filter
|
||||
else if (from.UseOwnFilter)
|
||||
AddHtmlLocalized(canPrice ? 470 : 386, 32, 120, 32, 1062451, 16927); // Using Your Filter
|
||||
else
|
||||
AddHtmlLocalized(canPrice ? 470 : 386, 32, 120, 32, 1062230, 16927); // Using Book Filter
|
||||
|
||||
AddButton(375, 416, 4017, 4018, 0);
|
||||
AddHtmlLocalized(410, 416, 120, 20, 1011441, LabelColor); // EXIT
|
||||
|
||||
if (canDrop)
|
||||
AddHtmlLocalized(26, 64, 50, 32, 1062212, LabelColor); // Drop
|
||||
|
||||
if (canPrice)
|
||||
{
|
||||
AddHtmlLocalized(516, 64, 200, 32, 1062218, LabelColor); // Price
|
||||
|
||||
if (canBuy)
|
||||
{
|
||||
AddHtmlLocalized(576, 64, 200, 32, 1062219, LabelColor); // Buy
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtmlLocalized(576, 64, 200, 32, 1062227, LabelColor); // Set
|
||||
|
||||
AddButton(450, 416, 4005, 4007, 4);
|
||||
AddHtml(485, 416, 120, 20, "<BASEFONT COLOR=#FFFFFF>Price all</FONT>");
|
||||
}
|
||||
}
|
||||
|
||||
tableIndex = 0;
|
||||
|
||||
if (page > 0)
|
||||
{
|
||||
AddButton(75, 416, 4014, 4016, 2);
|
||||
AddHtmlLocalized(110, 416, 150, 20, 1011067, LabelColor); // Previous page
|
||||
}
|
||||
|
||||
if (GetIndexForPage(page + 1) < list.Count)
|
||||
{
|
||||
AddButton(225, 416, 4005, 4007, 3);
|
||||
AddHtmlLocalized(260, 416, 150, 20, 1011066, LabelColor); // Next page
|
||||
}
|
||||
|
||||
for (int i = index; i < index + count && i >= 0 && i < list.Count; ++i)
|
||||
{
|
||||
IBOBEntry entry = list[i];
|
||||
|
||||
if (!CheckFilter(entry))
|
||||
continue;
|
||||
|
||||
if (entry is BOBLargeEntry largeEntry)
|
||||
{
|
||||
int y = 96 + tableIndex * 32;
|
||||
|
||||
if (canDrop)
|
||||
AddButton(35, y + 2, 5602, 5606, 5 + i * 2);
|
||||
|
||||
if (canDrop || canBuy && entry.Price > 0)
|
||||
{
|
||||
AddButton(579, y + 2, 2117, 2118, 6 + i * 2);
|
||||
AddLabel(495, y, 1152, entry.Price.ToString());
|
||||
}
|
||||
|
||||
AddHtmlLocalized(61, y, 50, 32, 1062225, LabelColor); // Large
|
||||
|
||||
for (int j = 0; j < largeEntry.Entries.Length; ++j)
|
||||
{
|
||||
BOBLargeSubEntry sub = largeEntry.Entries[j];
|
||||
|
||||
AddHtmlLocalized(103, y, 130, 32, sub.Number, LabelColor);
|
||||
|
||||
if (entry.RequireExceptional)
|
||||
AddHtmlLocalized(235, y, 80, 20, 1060636, LabelColor); // exceptional
|
||||
else
|
||||
AddHtmlLocalized(235, y, 80, 20, 1011542, LabelColor); // normal
|
||||
|
||||
object name = GetMaterialName(entry.Material, entry.DeedType, sub.ItemType);
|
||||
|
||||
if (name is int intName)
|
||||
AddHtmlLocalized(316, y, 100, 20, intName, LabelColor);
|
||||
else
|
||||
AddLabel(316, y, 1152, name.ToString());
|
||||
|
||||
AddLabel(421, y, 1152, $"{sub.AmountCur} / {entry.AmountMax}");
|
||||
|
||||
++tableIndex;
|
||||
y += 32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOBSmallEntry smallEntry = (BOBSmallEntry)entry;
|
||||
|
||||
int y = 96 + tableIndex++ * 32;
|
||||
|
||||
if (canDrop)
|
||||
AddButton(35, y + 2, 5602, 5606, 5 + i * 2);
|
||||
|
||||
if (canDrop || canBuy && smallEntry.Price > 0)
|
||||
{
|
||||
AddButton(579, y + 2, 2117, 2118, 6 + i * 2);
|
||||
AddLabel(495, y, 1152, smallEntry.Price.ToString());
|
||||
}
|
||||
|
||||
AddHtmlLocalized(61, y, 50, 32, 1062224, LabelColor); // Small
|
||||
|
||||
AddHtmlLocalized(103, y, 130, 32, smallEntry.Number, LabelColor);
|
||||
|
||||
if (smallEntry.RequireExceptional)
|
||||
AddHtmlLocalized(235, y, 80, 20, 1060636, LabelColor); // exceptional
|
||||
else
|
||||
AddHtmlLocalized(235, y, 80, 20, 1011542, LabelColor); // normal
|
||||
|
||||
object name = GetMaterialName(smallEntry.Material, smallEntry.DeedType, smallEntry.ItemType);
|
||||
|
||||
if (name is int intName)
|
||||
AddHtmlLocalized(316, y, 100, 20, intName, LabelColor);
|
||||
else
|
||||
AddLabel(316, y, 1152, name.ToString());
|
||||
|
||||
AddLabel(421, y, 1152, $"{smallEntry.AmountCur} / {smallEntry.AmountMax}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckFilter(IBOBEntry entry)
|
||||
{
|
||||
if (entry is BOBLargeEntry largeEntry)
|
||||
return CheckFilter(entry.Material, entry.AmountMax, true, entry.RequireExceptional, entry.DeedType,
|
||||
largeEntry.Entries.Length > 0 ? largeEntry.Entries[0].ItemType : null);
|
||||
|
||||
if (entry is BOBSmallEntry smallEntry)
|
||||
return CheckFilter(entry.Material, entry.AmountMax, false, entry.RequireExceptional,
|
||||
entry.DeedType, smallEntry.ItemType);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CheckFilter(BulkMaterialType mat, int amountMax, bool isLarge, bool reqExc, BODType deedType,
|
||||
Type itemType)
|
||||
{
|
||||
BOBFilter f = m_From.UseOwnFilter ? m_From.BOBFilter : m_Book.Filter;
|
||||
|
||||
if (f.IsDefault)
|
||||
return true;
|
||||
|
||||
if (f.Quality == 1 && reqExc)
|
||||
return false;
|
||||
if (f.Quality == 2 && !reqExc)
|
||||
return false;
|
||||
|
||||
if (f.Quantity == 1 && amountMax != 10)
|
||||
return false;
|
||||
if (f.Quantity == 2 && amountMax != 15)
|
||||
return false;
|
||||
if (f.Quantity == 3 && amountMax != 20)
|
||||
return false;
|
||||
|
||||
if (f.Type == 1 && isLarge)
|
||||
return false;
|
||||
if (f.Type == 2 && !isLarge)
|
||||
return false;
|
||||
|
||||
switch (f.Material)
|
||||
{
|
||||
default:
|
||||
return true;
|
||||
case 1: return deedType == BODType.Smith;
|
||||
case 2: return deedType == BODType.Tailor;
|
||||
|
||||
case 3:
|
||||
return mat == BulkMaterialType.None &&
|
||||
BGTClassifier.Classify(deedType, itemType) == BulkGenericType.Iron;
|
||||
case 4: return mat == BulkMaterialType.DullCopper;
|
||||
case 5: return mat == BulkMaterialType.ShadowIron;
|
||||
case 6: return mat == BulkMaterialType.Copper;
|
||||
case 7: return mat == BulkMaterialType.Bronze;
|
||||
case 8: return mat == BulkMaterialType.Gold;
|
||||
case 9: return mat == BulkMaterialType.Agapite;
|
||||
case 10: return mat == BulkMaterialType.Verite;
|
||||
case 11: return mat == BulkMaterialType.Valorite;
|
||||
|
||||
case 12:
|
||||
return mat == BulkMaterialType.None &&
|
||||
BGTClassifier.Classify(deedType, itemType) == BulkGenericType.Cloth;
|
||||
case 13:
|
||||
return mat == BulkMaterialType.None &&
|
||||
BGTClassifier.Classify(deedType, itemType) == BulkGenericType.Leather;
|
||||
case 14: return mat == BulkMaterialType.Spined;
|
||||
case 15: return mat == BulkMaterialType.Horned;
|
||||
case 16: return mat == BulkMaterialType.Barbed;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetIndexForPage(int page)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
while (page-- > 0)
|
||||
index += GetCountForIndex(index);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public int GetCountForIndex(int index)
|
||||
{
|
||||
int slots = 0;
|
||||
int count = 0;
|
||||
|
||||
List<IBOBEntry> list = m_List;
|
||||
|
||||
for (int i = index; i >= 0 && i < list.Count; ++i)
|
||||
{
|
||||
IBOBEntry entry = list[i];
|
||||
|
||||
if (CheckFilter(entry))
|
||||
{
|
||||
int add = entry is BOBLargeEntry largeEntry ? largeEntry.Entries.Length : 1;
|
||||
|
||||
if (slots + add > 10)
|
||||
break;
|
||||
|
||||
slots += add;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public int GetPageForIndex(int index, int sizeDropped)
|
||||
{
|
||||
if (index <= 0)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
int page = 0;
|
||||
int i;
|
||||
|
||||
List<IBOBEntry> list = m_List;
|
||||
for (i = 0; i < index && i < list.Count; i++)
|
||||
{
|
||||
IBOBEntry entry = list[i];
|
||||
if (!CheckFilter(entry))
|
||||
continue;
|
||||
|
||||
int add = entry is BOBLargeEntry largeEntry ? largeEntry.Entries.Length : 1;
|
||||
count += add;
|
||||
if (count > 10)
|
||||
{
|
||||
page++;
|
||||
count = add;
|
||||
}
|
||||
}
|
||||
|
||||
/* now we are on the page of the bod preceding the dropped one.
|
||||
* next step: checking whether we have to remain where we are.
|
||||
* The counter i needs to be incremented as the bod to this very moment
|
||||
* has not yet been removed from m_List */
|
||||
i++;
|
||||
|
||||
/* if, for instance, a big bod of size 6 has been removed, smaller bods
|
||||
* might fall back into this page. Depending on their sizes, the page needs
|
||||
* to be adjusted accordingly. This is done now.
|
||||
*/
|
||||
if (count + sizeDropped > 10)
|
||||
{
|
||||
while (i < list.Count && count <= 10)
|
||||
{
|
||||
IBOBEntry entry = list[i];
|
||||
if (CheckFilter(entry))
|
||||
count += entry is BOBLargeEntry largeEntry ? largeEntry.Entries.Length : 1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (count > 10)
|
||||
page++;
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
public object GetMaterialName(BulkMaterialType mat, BODType type, Type itemType)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BODType.Smith:
|
||||
{
|
||||
switch (mat)
|
||||
{
|
||||
case BulkMaterialType.None: return 1062226;
|
||||
case BulkMaterialType.DullCopper: return 1018332;
|
||||
case BulkMaterialType.ShadowIron: return 1018333;
|
||||
case BulkMaterialType.Copper: return 1018334;
|
||||
case BulkMaterialType.Bronze: return 1018335;
|
||||
case BulkMaterialType.Gold: return 1018336;
|
||||
case BulkMaterialType.Agapite: return 1018337;
|
||||
case BulkMaterialType.Verite: return 1018338;
|
||||
case BulkMaterialType.Valorite: return 1018339;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BODType.Tailor:
|
||||
{
|
||||
switch (mat)
|
||||
{
|
||||
case BulkMaterialType.None:
|
||||
{
|
||||
if (itemType.IsSubclassOf(typeof(BaseArmor)) || itemType.IsSubclassOf(typeof(BaseShoes)))
|
||||
return 1062235;
|
||||
|
||||
return 1044286;
|
||||
}
|
||||
case BulkMaterialType.Spined: return 1062236;
|
||||
case BulkMaterialType.Horned: return 1062237;
|
||||
case BulkMaterialType.Barbed: return 1062238;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
int index = info.ButtonID;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0: // EXIT
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 1: // Set Filter
|
||||
{
|
||||
m_From.SendGump(new BOBFilterGump(m_From, m_Book));
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // Previous page
|
||||
{
|
||||
if (m_Page > 0)
|
||||
m_From.SendGump(new BOBGump(m_From, m_Book, m_Page - 1, m_List));
|
||||
|
||||
return;
|
||||
}
|
||||
case 3: // Next page
|
||||
{
|
||||
if (GetIndexForPage(m_Page + 1) < m_List.Count)
|
||||
m_From.SendGump(new BOBGump(m_From, m_Book, m_Page + 1, m_List));
|
||||
|
||||
break;
|
||||
}
|
||||
case 4: // Price all
|
||||
{
|
||||
if (m_Book.IsChildOf(m_From.Backpack))
|
||||
{
|
||||
m_From.Prompt = new SetPricePrompt(m_Book, null, m_Page, m_List);
|
||||
m_From.SendMessage("Type in a price for all deeds in the book:");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
index -= 5;
|
||||
|
||||
int type = index % 2;
|
||||
index /= 2;
|
||||
|
||||
if (index < 0 || index >= m_List.Count)
|
||||
break;
|
||||
|
||||
IBOBEntry bobEntry = m_List[index];
|
||||
|
||||
if (!m_Book.Entries.Contains(bobEntry))
|
||||
{
|
||||
m_From.SendLocalizedMessage(1062382); // The deed selected is not available.
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == 0) // Drop
|
||||
{
|
||||
if (m_Book.IsChildOf(m_From.Backpack))
|
||||
{
|
||||
Item item = bobEntry.Reconstruct();
|
||||
|
||||
Container pack = m_From.Backpack;
|
||||
if (pack?.CheckHold(m_From, item, true, true, 0,
|
||||
item.PileWeight + item.TotalWeight) != true)
|
||||
{
|
||||
m_From.SendLocalizedMessage(503204); // You do not have room in your backpack for this
|
||||
m_From.SendGump(new BOBGump(m_From, m_Book, m_Page));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Book.IsChildOf(m_From.Backpack))
|
||||
{
|
||||
int sizeOfDroppedBod = bobEntry is BOBLargeEntry entry ? entry.Entries.Length : 1;
|
||||
|
||||
m_From.AddToBackpack(item);
|
||||
m_From.SendLocalizedMessage(
|
||||
1045152); // The bulk order deed has been placed in your backpack.
|
||||
m_Book.Entries.Remove(bobEntry);
|
||||
m_Book.InvalidateProperties();
|
||||
|
||||
if (m_Book.Entries.Count / 5 < m_Book.ItemCount)
|
||||
{
|
||||
m_Book.ItemCount--;
|
||||
m_Book.InvalidateItems();
|
||||
}
|
||||
|
||||
if (m_Book.Entries.Count > 0)
|
||||
{
|
||||
m_Page = GetPageForIndex(index, sizeOfDroppedBod);
|
||||
m_From.SendGump(new BOBGump(m_From, m_Book, m_Page));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1062381); // The book is empty.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Set Price | Buy
|
||||
{
|
||||
if (m_Book.IsChildOf(m_From.Backpack))
|
||||
{
|
||||
m_From.Prompt = new SetPricePrompt(m_Book, bobEntry, m_Page, m_List);
|
||||
m_From.SendLocalizedMessage(1062383); // Type in a price for the deed:
|
||||
}
|
||||
else if (m_Book.RootParent is PlayerVendor pv)
|
||||
{
|
||||
VendorItem vi = pv.GetVendorItem(m_Book);
|
||||
|
||||
if (vi?.IsForSale != false)
|
||||
return;
|
||||
|
||||
int sizeOfDroppedBod = bobEntry is BOBLargeEntry largeEntry ? largeEntry.Entries.Length : 1;
|
||||
int price = bobEntry.Price;
|
||||
|
||||
if (price == 0)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1062382); // The deed selected is not available.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Book.Entries.Count > 0)
|
||||
{
|
||||
m_Page = GetPageForIndex(index, sizeOfDroppedBod);
|
||||
m_From.SendGump(new BODBuyGump(m_From, m_Book, bobEntry, m_Page, price));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1062381); // The book is emptz
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SetPricePrompt : Prompt
|
||||
{
|
||||
private BulkOrderBook m_Book;
|
||||
private List<IBOBEntry> m_List;
|
||||
private IBOBEntry m_Entry;
|
||||
private int m_Page;
|
||||
|
||||
public SetPricePrompt(BulkOrderBook book, IBOBEntry entry, int page, List<IBOBEntry> list)
|
||||
{
|
||||
m_Book = book;
|
||||
m_Entry = entry;
|
||||
m_Page = page;
|
||||
m_List = list;
|
||||
}
|
||||
|
||||
public override void OnResponse(Mobile from, string text)
|
||||
{
|
||||
if (m_Entry != null && !m_Book.Entries.Contains(m_Entry))
|
||||
{
|
||||
from.SendLocalizedMessage(1062382); // The deed selected is not available.
|
||||
return;
|
||||
}
|
||||
|
||||
int price = Utility.ToInt32(text);
|
||||
|
||||
if (price < 0 || price > 250000000)
|
||||
{
|
||||
from.SendLocalizedMessage(1062390); // The price you requested is outrageous!
|
||||
}
|
||||
else if (m_Entry == null)
|
||||
{
|
||||
for (int i = 0; i < m_List.Count; ++i)
|
||||
{
|
||||
IBOBEntry entry = m_List[i];
|
||||
|
||||
if (!m_Book.Entries.Contains(entry))
|
||||
continue;
|
||||
|
||||
entry.Price = price;
|
||||
}
|
||||
|
||||
from.SendMessage("Deed prices set.");
|
||||
|
||||
if (from is PlayerMobile mobile)
|
||||
mobile.SendGump(new BOBGump(mobile, m_Book, m_Page, m_List));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Entry.Price = price;
|
||||
from.SendLocalizedMessage(1062384); // Deed price set.
|
||||
if (from is PlayerMobile mobile)
|
||||
mobile.SendGump(new BOBGump(mobile, m_Book, m_Page, m_List));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
Projects/Scripts/Engines/BulkOrders/Books/BOBLargeEntry.cs
Normal file
106
Projects/Scripts/Engines/BulkOrders/Books/BOBLargeEntry.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BOBLargeEntry: IBOBEntry
|
||||
{
|
||||
public BOBLargeEntry(LargeBOD bod)
|
||||
{
|
||||
RequireExceptional = bod.RequireExceptional;
|
||||
|
||||
if (bod is LargeTailorBOD)
|
||||
DeedType = BODType.Tailor;
|
||||
else if (bod is LargeSmithBOD)
|
||||
DeedType = BODType.Smith;
|
||||
|
||||
Material = bod.Material;
|
||||
AmountMax = bod.AmountMax;
|
||||
|
||||
Entries = new BOBLargeSubEntry[bod.Entries.Length];
|
||||
|
||||
for (int i = 0; i < Entries.Length; ++i)
|
||||
Entries[i] = new BOBLargeSubEntry(bod.Entries[i]);
|
||||
}
|
||||
|
||||
public BOBLargeEntry(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
RequireExceptional = reader.ReadBool();
|
||||
|
||||
DeedType = (BODType)reader.ReadEncodedInt();
|
||||
|
||||
Material = (BulkMaterialType)reader.ReadEncodedInt();
|
||||
AmountMax = reader.ReadEncodedInt();
|
||||
Price = reader.ReadEncodedInt();
|
||||
|
||||
Entries = new BOBLargeSubEntry[reader.ReadEncodedInt()];
|
||||
|
||||
for (int i = 0; i < Entries.Length; ++i)
|
||||
Entries[i] = new BOBLargeSubEntry(reader);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool RequireExceptional{ get; }
|
||||
|
||||
public BODType DeedType{ get; }
|
||||
|
||||
public BulkMaterialType Material{ get; }
|
||||
|
||||
public int AmountMax{ get; }
|
||||
|
||||
public int Price{ get; set; }
|
||||
|
||||
public BOBLargeSubEntry[] Entries{ get; }
|
||||
|
||||
public Item Reconstruct()
|
||||
{
|
||||
LargeBOD bod = null;
|
||||
|
||||
if (DeedType == BODType.Smith)
|
||||
bod = new LargeSmithBOD(AmountMax, RequireExceptional, Material, ReconstructEntries());
|
||||
else if (DeedType == BODType.Tailor)
|
||||
bod = new LargeTailorBOD(AmountMax, RequireExceptional, Material, ReconstructEntries());
|
||||
|
||||
for (int i = 0; bod?.Entries.Length >= i; ++i)
|
||||
bod.Entries[i].Owner = bod;
|
||||
|
||||
return bod;
|
||||
}
|
||||
|
||||
private LargeBulkEntry[] ReconstructEntries()
|
||||
{
|
||||
LargeBulkEntry[] entries = new LargeBulkEntry[Entries.Length];
|
||||
|
||||
for (int i = 0; i < Entries.Length; ++i)
|
||||
{
|
||||
entries[i] = new LargeBulkEntry(null,
|
||||
new SmallBulkEntry(Entries[i].ItemType, Entries[i].Number, Entries[i].Graphic)) { Amount = Entries[i].AmountCur };
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.Write(RequireExceptional);
|
||||
|
||||
writer.WriteEncodedInt((int)DeedType);
|
||||
writer.WriteEncodedInt((int)Material);
|
||||
writer.WriteEncodedInt(AmountMax);
|
||||
writer.WriteEncodedInt(Price);
|
||||
|
||||
writer.WriteEncodedInt(Entries.Length);
|
||||
|
||||
for (int i = 0; i < Entries.Length; ++i)
|
||||
Entries[i].Serialize(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BOBLargeSubEntry
|
||||
{
|
||||
public BOBLargeSubEntry(LargeBulkEntry lbe)
|
||||
{
|
||||
ItemType = lbe.Details.Type;
|
||||
AmountCur = lbe.Amount;
|
||||
Number = lbe.Details.Number;
|
||||
Graphic = lbe.Details.Graphic;
|
||||
}
|
||||
|
||||
public BOBLargeSubEntry(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
string type = reader.ReadString();
|
||||
|
||||
if (type != null)
|
||||
ItemType = ScriptCompiler.FindTypeByFullName(type);
|
||||
|
||||
AmountCur = reader.ReadEncodedInt();
|
||||
Number = reader.ReadEncodedInt();
|
||||
Graphic = reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type ItemType{ get; }
|
||||
|
||||
public int AmountCur{ get; }
|
||||
|
||||
public int Number{ get; }
|
||||
|
||||
public int Graphic{ get; }
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.Write(ItemType == null ? null : ItemType.FullName);
|
||||
|
||||
writer.WriteEncodedInt(AmountCur);
|
||||
writer.WriteEncodedInt(Number);
|
||||
writer.WriteEncodedInt(Graphic);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Projects/Scripts/Engines/BulkOrders/Books/BOBSmallEntry.cs
Normal file
100
Projects/Scripts/Engines/BulkOrders/Books/BOBSmallEntry.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BOBSmallEntry : IBOBEntry
|
||||
{
|
||||
public BOBSmallEntry(SmallBOD bod)
|
||||
{
|
||||
ItemType = bod.Type;
|
||||
RequireExceptional = bod.RequireExceptional;
|
||||
|
||||
if (bod is SmallTailorBOD)
|
||||
DeedType = BODType.Tailor;
|
||||
else if (bod is SmallSmithBOD)
|
||||
DeedType = BODType.Smith;
|
||||
|
||||
Material = bod.Material;
|
||||
AmountCur = bod.AmountCur;
|
||||
AmountMax = bod.AmountMax;
|
||||
Number = bod.Number;
|
||||
Graphic = bod.Graphic;
|
||||
}
|
||||
|
||||
public BOBSmallEntry(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
string type = reader.ReadString();
|
||||
|
||||
if (type != null)
|
||||
ItemType = ScriptCompiler.FindTypeByFullName(type);
|
||||
|
||||
RequireExceptional = reader.ReadBool();
|
||||
|
||||
DeedType = (BODType)reader.ReadEncodedInt();
|
||||
|
||||
Material = (BulkMaterialType)reader.ReadEncodedInt();
|
||||
AmountCur = reader.ReadEncodedInt();
|
||||
AmountMax = reader.ReadEncodedInt();
|
||||
Number = reader.ReadEncodedInt();
|
||||
Graphic = reader.ReadEncodedInt();
|
||||
Price = reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type ItemType{ get; }
|
||||
|
||||
public bool RequireExceptional{ get; }
|
||||
|
||||
public BODType DeedType{ get; }
|
||||
|
||||
public BulkMaterialType Material{ get; }
|
||||
|
||||
public int AmountCur{ get; }
|
||||
|
||||
public int AmountMax{ get; }
|
||||
|
||||
public int Number{ get; }
|
||||
|
||||
public int Graphic{ get; }
|
||||
|
||||
public int Price{ get; set; }
|
||||
|
||||
public Item Reconstruct()
|
||||
{
|
||||
SmallBOD bod = null;
|
||||
|
||||
if (DeedType == BODType.Smith)
|
||||
bod = new SmallSmithBOD(AmountCur, AmountMax, ItemType, Number, Graphic, RequireExceptional, Material);
|
||||
else if (DeedType == BODType.Tailor)
|
||||
bod = new SmallTailorBOD(AmountCur, AmountMax, ItemType, Number, Graphic, RequireExceptional, Material);
|
||||
|
||||
return bod;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.Write(ItemType == null ? null : ItemType.FullName);
|
||||
|
||||
writer.Write(RequireExceptional);
|
||||
|
||||
writer.WriteEncodedInt((int)DeedType);
|
||||
writer.WriteEncodedInt((int)Material);
|
||||
writer.WriteEncodedInt(AmountCur);
|
||||
writer.WriteEncodedInt(AmountMax);
|
||||
writer.WriteEncodedInt(Number);
|
||||
writer.WriteEncodedInt(Graphic);
|
||||
writer.WriteEncodedInt(Price);
|
||||
}
|
||||
}
|
||||
}
|
||||
122
Projects/Scripts/Engines/BulkOrders/Books/BODBuyGump.cs
Normal file
122
Projects/Scripts/Engines/BulkOrders/Books/BODBuyGump.cs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BODBuyGump : Gump
|
||||
{
|
||||
private BulkOrderBook m_Book;
|
||||
private PlayerMobile m_From;
|
||||
private IBOBEntry m_Entry;
|
||||
private int m_Page;
|
||||
private int m_Price;
|
||||
|
||||
public BODBuyGump(PlayerMobile from, BulkOrderBook book, IBOBEntry entry, int page, int price) : base(100, 200)
|
||||
{
|
||||
m_From = from;
|
||||
m_Book = book;
|
||||
m_Entry = entry;
|
||||
m_Price = price;
|
||||
m_Page = page;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(100, 10, 300, 150, 5054);
|
||||
|
||||
AddHtmlLocalized(125, 20, 250, 24, 1019070); // You have agreed to purchase:
|
||||
AddHtmlLocalized(125, 45, 250, 24, 1045151); // a bulk order deed
|
||||
|
||||
AddHtmlLocalized(125, 70, 250, 24, 1019071); // for the amount of:
|
||||
AddLabel(125, 95, 0, price.ToString());
|
||||
|
||||
AddButton(250, 130, 4005, 4007, 1);
|
||||
AddHtmlLocalized(282, 130, 100, 24, 1011012); // CANCEL
|
||||
|
||||
AddButton(120, 130, 4005, 4007, 2);
|
||||
AddHtmlLocalized(152, 130, 100, 24, 1011036); // OKAY
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID != 2)
|
||||
{
|
||||
m_From.SendLocalizedMessage(503207); // Cancelled purchase.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(m_Book.RootParent is PlayerVendor pv))
|
||||
{
|
||||
m_From.SendLocalizedMessage(1062382); // The deed selected is not available.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_Book.Entries.Contains(m_Entry))
|
||||
{
|
||||
pv.SayTo(m_From, 1062382); // The deed selected is not available.
|
||||
return;
|
||||
}
|
||||
|
||||
int price = 0;
|
||||
|
||||
if (pv.GetVendorItem(m_Book)?.IsForSale == false)
|
||||
price = m_Entry.Price;
|
||||
|
||||
if (price != m_Price)
|
||||
{
|
||||
pv.SayTo(m_From,
|
||||
"The price has been been changed. If you like, you may offer to purchase the item again.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (price == 0)
|
||||
{
|
||||
pv.SayTo(m_From, 1062382); // The deed selected is not available.
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = m_Entry.Reconstruct();
|
||||
|
||||
pv.Say(m_From.Name);
|
||||
|
||||
Container pack = m_From.Backpack;
|
||||
|
||||
if (pack?.CheckHold(m_From, item, true, true, 0,
|
||||
item.PileWeight + item.TotalWeight) != true)
|
||||
{
|
||||
pv.SayTo(m_From, 503204); // You do not have room in your backpack for this
|
||||
m_From.SendGump(new BOBGump(m_From, m_Book, m_Page));
|
||||
item.Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pack.ConsumeTotal(typeof(Gold), price) || Banker.Withdraw(m_From, price))
|
||||
{
|
||||
m_Book.Entries.Remove(m_Entry);
|
||||
m_Book.InvalidateProperties();
|
||||
pv.HoldGold += price;
|
||||
m_From.AddToBackpack(item);
|
||||
m_From.SendLocalizedMessage(
|
||||
1045152); // The bulk order deed has been placed in your backpack.
|
||||
|
||||
if (m_Book.Entries.Count / 5 < m_Book.ItemCount)
|
||||
{
|
||||
m_Book.ItemCount--;
|
||||
m_Book.InvalidateItems();
|
||||
}
|
||||
|
||||
if (m_Book.Entries.Count > 0)
|
||||
m_From.SendGump(new BOBGump(m_From, m_Book, m_Page));
|
||||
else
|
||||
m_From.SendLocalizedMessage(1062381); // The book is empty.
|
||||
}
|
||||
else
|
||||
{
|
||||
pv.SayTo(m_From, 503205); // You cannot afford this item.
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Projects/Scripts/Engines/BulkOrders/Books/BODType.cs
Normal file
8
Projects/Scripts/Engines/BulkOrders/Books/BODType.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public enum BODType
|
||||
{
|
||||
Smith,
|
||||
Tailor
|
||||
}
|
||||
}
|
||||
308
Projects/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs
Normal file
308
Projects/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Multis;
|
||||
using Server.Prompts;
|
||||
using Server.Mobiles;
|
||||
using Server.ContextMenus;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class BulkOrderBook : Item, ISecurable
|
||||
{
|
||||
private string m_BookName;
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public string BookName
|
||||
{
|
||||
get => m_BookName;
|
||||
set{ m_BookName = value; InvalidateProperties(); }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public SecureLevel Level { get; set; }
|
||||
|
||||
public List<IBOBEntry> Entries { get; private set; }
|
||||
|
||||
public BOBFilter Filter { get; private set; }
|
||||
|
||||
public int ItemCount { get; set; }
|
||||
|
||||
[Constructible]
|
||||
public BulkOrderBook() : base( 0x2259 )
|
||||
{
|
||||
Weight = 1.0;
|
||||
LootType = LootType.Blessed;
|
||||
|
||||
Entries = new List<IBOBEntry>();
|
||||
Filter = new BOBFilter();
|
||||
|
||||
Level = SecureLevel.CoOwners;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick( Mobile from )
|
||||
{
|
||||
if ( !from.InRange( GetWorldLocation(), 2 ) )
|
||||
from.LocalOverheadMessage( Network.MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that.
|
||||
else if ( Entries.Count == 0 )
|
||||
from.SendLocalizedMessage( 1062381 ); // The book is empty.
|
||||
else if ( from is PlayerMobile mobile )
|
||||
mobile.SendGump( new BOBGump( mobile, this ) );
|
||||
}
|
||||
|
||||
public override void OnDoubleClickSecureTrade( Mobile from )
|
||||
{
|
||||
if ( !from.InRange( GetWorldLocation(), 2 ) )
|
||||
{
|
||||
from.SendLocalizedMessage( 500446 ); // That is too far away.
|
||||
}
|
||||
else if ( Entries.Count == 0 )
|
||||
{
|
||||
from.SendLocalizedMessage( 1062381 ); // The book is empty.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendGump( new BOBGump( (PlayerMobile)from, this ) );
|
||||
|
||||
SecureTrade trade = GetSecureTradeCont()?.Trade;
|
||||
|
||||
if (trade?.From.Mobile == from )
|
||||
trade.To.Mobile.SendGump( new BOBGump( (PlayerMobile)trade.To.Mobile, this ) );
|
||||
else if (trade?.To.Mobile == from )
|
||||
trade.From.Mobile.SendGump( new BOBGump( (PlayerMobile)trade.From.Mobile, this ) );
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnDragDrop( Mobile from, Item dropped )
|
||||
{
|
||||
if ( dropped is BaseBOD )
|
||||
{
|
||||
if ( !IsChildOf( from.Backpack ) )
|
||||
{
|
||||
from.SendLocalizedMessage( 1062385 ); // You must have the book in your backpack to add deeds to it.
|
||||
return false;
|
||||
}
|
||||
if ( !from.Backpack.CheckHold( from, dropped, true, true ) )
|
||||
return false;
|
||||
if ( Entries.Count < 500 )
|
||||
{
|
||||
if ( dropped is LargeBOD bod )
|
||||
Entries.Add( new BOBLargeEntry( bod ) );
|
||||
else
|
||||
Entries.Add( new BOBSmallEntry( (SmallBOD)dropped ) );
|
||||
|
||||
InvalidateProperties();
|
||||
|
||||
if ( Entries.Count / 5 > ItemCount )
|
||||
{
|
||||
ItemCount++;
|
||||
InvalidateItems();
|
||||
}
|
||||
|
||||
from.SendSound(0x42, GetWorldLocation());
|
||||
from.SendLocalizedMessage( 1062386 ); // Deed added to book.
|
||||
|
||||
if ( from is PlayerMobile pm )
|
||||
pm.SendGump( new BOBGump( pm, this ) );
|
||||
|
||||
dropped.Delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage( 1062387 ); // The book is full of deeds.
|
||||
return false;
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage( 1062388 ); // That is not a bulk order deed.
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetTotal( TotalType type )
|
||||
{
|
||||
int total = base.GetTotal( type );
|
||||
|
||||
if ( type == TotalType.Items )
|
||||
total = ItemCount;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
public void InvalidateItems()
|
||||
{
|
||||
if ( RootParent is Mobile m )
|
||||
{
|
||||
m.UpdateTotals();
|
||||
InvalidateContainers( Parent );
|
||||
}
|
||||
}
|
||||
|
||||
public void InvalidateContainers(IEntity parent)
|
||||
{
|
||||
if ( parent is Container c )
|
||||
{
|
||||
c.InvalidateProperties();
|
||||
InvalidateContainers( c.Parent );
|
||||
}
|
||||
}
|
||||
|
||||
public BulkOrderBook( Serial serial ) : base( serial )
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
|
||||
writer.Write( 2 ); // version
|
||||
|
||||
writer.Write( ItemCount );
|
||||
|
||||
writer.Write( (int) Level );
|
||||
|
||||
writer.Write( m_BookName );
|
||||
|
||||
Filter.Serialize( writer );
|
||||
|
||||
writer.WriteEncodedInt( Entries.Count );
|
||||
|
||||
for ( int i = 0; i < Entries.Count; ++i )
|
||||
{
|
||||
object obj = Entries[i];
|
||||
|
||||
if ( obj is BOBLargeEntry entry )
|
||||
{
|
||||
writer.WriteEncodedInt( 0 );
|
||||
entry.Serialize( writer );
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteEncodedInt( 1 );
|
||||
((BOBSmallEntry)obj).Serialize( writer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch ( version )
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
ItemCount = reader.ReadInt();
|
||||
goto case 1;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
Level = (SecureLevel)reader.ReadInt();
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
m_BookName = reader.ReadString();
|
||||
|
||||
Filter = new BOBFilter( reader );
|
||||
|
||||
int count = reader.ReadEncodedInt();
|
||||
|
||||
Entries = new List<IBOBEntry>( count );
|
||||
|
||||
for ( int i = 0; i < count; ++i )
|
||||
{
|
||||
int v = reader.ReadEncodedInt();
|
||||
|
||||
switch ( v )
|
||||
{
|
||||
case 0: Entries.Add( new BOBLargeEntry( reader ) ); break;
|
||||
case 1: Entries.Add( new BOBSmallEntry( reader ) ); break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetProperties( ObjectPropertyList list )
|
||||
{
|
||||
base.GetProperties( list );
|
||||
|
||||
list.Add( 1062344, Entries.Count.ToString() ); // Deeds in book: ~1_val~
|
||||
|
||||
if ( !string.IsNullOrEmpty(m_BookName) )
|
||||
list.Add( 1062481, m_BookName ); // Book Name: ~1_val~
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
base.OnSingleClick(from);
|
||||
|
||||
LabelTo(from, 1062344, Entries.Count.ToString()); // Deeds in book: ~1_val~
|
||||
|
||||
if (!string.IsNullOrEmpty(m_BookName))
|
||||
LabelTo(from, 1062481, m_BookName);
|
||||
}
|
||||
|
||||
public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
|
||||
{
|
||||
base.GetContextMenuEntries( from, list );
|
||||
|
||||
if ( from.CheckAlive() && IsChildOf( from.Backpack ) )
|
||||
list.Add( new NameBookEntry( from, this ) );
|
||||
|
||||
SetSecureLevelEntry.AddTo( from, this, list );
|
||||
}
|
||||
|
||||
private class NameBookEntry : ContextMenuEntry
|
||||
{
|
||||
private Mobile m_From;
|
||||
private BulkOrderBook m_Book;
|
||||
|
||||
public NameBookEntry( Mobile from, BulkOrderBook book ) : base( 6216 )
|
||||
{
|
||||
m_From = from;
|
||||
m_Book = book;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
if ( m_From.CheckAlive() && m_Book.IsChildOf( m_From.Backpack ) )
|
||||
{
|
||||
m_From.Prompt = new NameBookPrompt( m_Book );
|
||||
m_From.SendLocalizedMessage( 1062479 ); // Type in the new name of the book:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NameBookPrompt : Prompt
|
||||
{
|
||||
private BulkOrderBook m_Book;
|
||||
|
||||
public NameBookPrompt( BulkOrderBook book )
|
||||
{
|
||||
m_Book = book;
|
||||
}
|
||||
|
||||
public override void OnResponse( Mobile from, string text )
|
||||
{
|
||||
if ( text.Length > 40 )
|
||||
text = text.Substring( 0, 40 );
|
||||
|
||||
if ( from.CheckAlive() && m_Book.IsChildOf( from.Backpack ) )
|
||||
{
|
||||
m_Book.BookName = Utility.FixHtml( text.Trim() );
|
||||
|
||||
from.SendLocalizedMessage( 1062480 ); // The bulk order book's name has been changed.
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnCancel( Mobile from )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Projects/Scripts/Engines/BulkOrders/Books/IBOBEntry.cs
Normal file
12
Projects/Scripts/Engines/BulkOrders/Books/IBOBEntry.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public interface IBOBEntry
|
||||
{
|
||||
bool RequireExceptional{ get; }
|
||||
BODType DeedType{ get; }
|
||||
BulkMaterialType Material{ get; }
|
||||
int AmountMax{ get; }
|
||||
int Price{ get; set; }
|
||||
Item Reconstruct();
|
||||
}
|
||||
}
|
||||
40
Projects/Scripts/Engines/BulkOrders/BulkMaterialType.cs
Normal file
40
Projects/Scripts/Engines/BulkOrders/BulkMaterialType.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public enum BulkMaterialType
|
||||
{
|
||||
None,
|
||||
DullCopper,
|
||||
ShadowIron,
|
||||
Copper,
|
||||
Bronze,
|
||||
Gold,
|
||||
Agapite,
|
||||
Verite,
|
||||
Valorite,
|
||||
Spined,
|
||||
Horned,
|
||||
Barbed
|
||||
}
|
||||
|
||||
public enum BulkGenericType
|
||||
{
|
||||
Iron,
|
||||
Cloth,
|
||||
Leather
|
||||
}
|
||||
|
||||
public class BGTClassifier
|
||||
{
|
||||
public static BulkGenericType Classify(BODType deedType, Type itemType)
|
||||
{
|
||||
if (deedType != BODType.Tailor)
|
||||
return BulkGenericType.Iron;
|
||||
|
||||
return itemType == null || itemType.IsSubclassOf(typeof(BaseArmor)) || itemType.IsSubclassOf(typeof(BaseShoes))
|
||||
? BulkGenericType.Leather : BulkGenericType.Cloth;
|
||||
}
|
||||
}
|
||||
}
|
||||
175
Projects/Scripts/Engines/BulkOrders/LargeBOD.cs
Normal file
175
Projects/Scripts/Engines/BulkOrders/LargeBOD.cs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public abstract class LargeBOD : BaseBOD
|
||||
{
|
||||
private LargeBulkEntry[] m_Entries;
|
||||
|
||||
public LargeBulkEntry[] Entries
|
||||
{
|
||||
get => m_Entries;
|
||||
set{ m_Entries = value; InvalidateProperties(); }
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public override bool Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
for ( int i = 0; i < m_Entries.Length; ++i )
|
||||
if ( m_Entries[i].Amount < AmountMax )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1045151; // a bulk order deed
|
||||
|
||||
public LargeBOD(int hue, int amountMax, bool requireExeptional, BulkMaterialType material, LargeBulkEntry[] entries) :
|
||||
base(hue, amountMax, requireExeptional, material)
|
||||
{
|
||||
m_Entries = entries;
|
||||
}
|
||||
|
||||
public LargeBOD()
|
||||
{
|
||||
}
|
||||
|
||||
public override void GetProperties( ObjectPropertyList list )
|
||||
{
|
||||
base.GetProperties( list );
|
||||
|
||||
list.Add( 1060655 ); // large bulk order
|
||||
|
||||
if ( RequireExceptional )
|
||||
list.Add( 1045141 ); // All items must be exceptional.
|
||||
|
||||
if ( Material != BulkMaterialType.None )
|
||||
list.Add( LargeBODGump.GetMaterialNumberFor( Material ) ); // All items must be made with x material.
|
||||
|
||||
list.Add( 1060656, AmountMax.ToString() ); // amount to make: ~1_val~
|
||||
|
||||
for ( int i = 0; i < m_Entries.Length; ++i )
|
||||
list.Add( 1060658 + i, "#{0}\t{1}", m_Entries[i].Details.Number, m_Entries[i].Amount ); // ~1_val~: ~2_val~
|
||||
}
|
||||
|
||||
public override void OnDoubleClickNotAccessible( Mobile from )
|
||||
{
|
||||
OnDoubleClick( from );
|
||||
}
|
||||
|
||||
public override void OnDoubleClickSecureTrade( Mobile from )
|
||||
{
|
||||
OnDoubleClick( from );
|
||||
}
|
||||
|
||||
public override void OnDoubleClick( Mobile from )
|
||||
{
|
||||
if ( IsChildOf( from.Backpack ) || InSecureTrade || RootParent is PlayerVendor )
|
||||
from.SendGump( new LargeBODGump( from, this ) );
|
||||
else
|
||||
from.SendLocalizedMessage( 1045156 ); // You must have the deed in your backpack to use it.
|
||||
}
|
||||
|
||||
public override void EndCombine(Mobile from, Item item)
|
||||
{
|
||||
if (!(item is SmallBOD small))
|
||||
{
|
||||
from.SendLocalizedMessage(1045159); // That is not a bulk order.
|
||||
return;
|
||||
}
|
||||
|
||||
LargeBulkEntry entry = null;
|
||||
|
||||
for (int i = 0; i < m_Entries.Length; ++i)
|
||||
{
|
||||
if (m_Entries[i].Details.Type == small.Type)
|
||||
{
|
||||
entry = m_Entries[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1045160); // That is not a bulk order for this large request.
|
||||
}
|
||||
else if (RequireExceptional && !small.RequireExceptional)
|
||||
{
|
||||
from.SendLocalizedMessage(1045161); // Both orders must be of exceptional quality.
|
||||
}
|
||||
else if (Material >= BulkMaterialType.DullCopper && Material <= BulkMaterialType.Valorite &&
|
||||
small.Material != Material)
|
||||
{
|
||||
from.SendLocalizedMessage(1045162); // Both orders must use the same ore type.
|
||||
}
|
||||
else if (Material >= BulkMaterialType.Spined && Material <= BulkMaterialType.Barbed &&
|
||||
small.Material != Material)
|
||||
{
|
||||
from.SendLocalizedMessage(1049351); // Both orders must use the same leather type.
|
||||
}
|
||||
else if (AmountMax != small.AmountMax)
|
||||
{
|
||||
from.SendLocalizedMessage(1045163); // The two orders have different requested amounts and cannot be combined.
|
||||
}
|
||||
else if (small.AmountCur < small.AmountMax)
|
||||
{
|
||||
from.SendLocalizedMessage(1045164); // The order to combine with is not completed.
|
||||
}
|
||||
else if (entry.Amount >= AmountMax)
|
||||
{
|
||||
from.SendLocalizedMessage(
|
||||
1045166); // The maximum amount of requested items have already been combined to this deed.
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.Amount += small.AmountCur;
|
||||
small.Delete();
|
||||
|
||||
from.SendLocalizedMessage(1045165); // The orders have been combined.
|
||||
from.SendGump(new LargeBODGump(from, this));
|
||||
|
||||
if (!Complete)
|
||||
BeginCombine(from);
|
||||
}
|
||||
}
|
||||
|
||||
public LargeBOD(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
|
||||
writer.WriteEncodedInt( 0 ); // version
|
||||
|
||||
writer.Write( m_Entries.Length );
|
||||
|
||||
for ( int i = 0; i < m_Entries.Length; ++i )
|
||||
m_Entries[i].Serialize( writer );
|
||||
}
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch ( version )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Entries = new LargeBulkEntry[reader.ReadInt()];
|
||||
|
||||
for ( int i = 0; i < m_Entries.Length; ++i )
|
||||
m_Entries[i] = new LargeBulkEntry( this, reader );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
Projects/Scripts/Engines/BulkOrders/LargeBODAcceptGump.cs
Normal file
110
Projects/Scripts/Engines/BulkOrders/LargeBODAcceptGump.cs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class LargeBODAcceptGump : Gump
|
||||
{
|
||||
private LargeBOD m_Deed;
|
||||
private Mobile m_From;
|
||||
|
||||
public LargeBODAcceptGump(Mobile from, LargeBOD deed) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Deed = deed;
|
||||
|
||||
m_From.CloseGump<LargeBODAcceptGump>();
|
||||
m_From.CloseGump<SmallBODAcceptGump>();
|
||||
|
||||
LargeBulkEntry[] entries = deed.Entries;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(25, 10, 430, 240 + entries.Length * 24, 5054);
|
||||
|
||||
AddImageTiled(33, 20, 413, 221 + entries.Length * 24, 2624);
|
||||
AddAlphaRegion(33, 20, 413, 221 + entries.Length * 24);
|
||||
|
||||
AddImage(20, 5, 10460);
|
||||
AddImage(430, 5, 10460);
|
||||
AddImage(20, 225 + entries.Length * 24, 10460);
|
||||
AddImage(430, 225 + entries.Length * 24, 10460);
|
||||
|
||||
AddHtmlLocalized(180, 25, 120, 20, 1045134, 0x7FFF); // A large bulk order
|
||||
|
||||
AddHtmlLocalized(40, 48, 350, 20, 1045135, 0x7FFF); // Ah! Thanks for the goods! Would you help me out?
|
||||
|
||||
AddHtmlLocalized(40, 72, 210, 20, 1045138, 0x7FFF); // Amount to make:
|
||||
AddLabel(250, 72, 1152, deed.AmountMax.ToString());
|
||||
|
||||
AddHtmlLocalized(40, 96, 120, 20, 1045137, 0x7FFF); // Items requested:
|
||||
|
||||
int y = 120;
|
||||
|
||||
for (int i = 0; i < entries.Length; ++i, y += 24)
|
||||
AddHtmlLocalized(40, y, 210, 20, entries[i].Details.Number, 0x7FFF);
|
||||
|
||||
if (deed.RequireExceptional || deed.Material != BulkMaterialType.None)
|
||||
{
|
||||
AddHtmlLocalized(40, y, 210, 20, 1045140, 0x7FFF); // Special requirements to meet:
|
||||
y += 24;
|
||||
|
||||
if (deed.RequireExceptional)
|
||||
{
|
||||
AddHtmlLocalized(40, y, 350, 20, 1045141, 0x7FFF); // All items must be exceptional.
|
||||
y += 24;
|
||||
}
|
||||
|
||||
if (deed.Material != BulkMaterialType.None)
|
||||
{
|
||||
AddHtmlLocalized(40, y, 350, 20, GetMaterialNumberFor(deed.Material), 0x7FFF); // All items must be made with x material.
|
||||
y += 24;
|
||||
}
|
||||
}
|
||||
|
||||
AddHtmlLocalized(40, 192 + entries.Length * 24, 350, 20, 1045139, 0x7FFF); // Do you want to accept this order?
|
||||
|
||||
AddButton(100, 216 + entries.Length * 24, 4005, 4007, 1);
|
||||
AddHtmlLocalized(135, 216 + entries.Length * 24, 120, 20, 1006044, 0x7FFF); // Ok
|
||||
|
||||
AddButton(275, 216 + entries.Length * 24, 4005, 4007, 0);
|
||||
AddHtmlLocalized(310, 216 + entries.Length * 24, 120, 20, 1011012, 0x7FFF); // CANCEL
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 1) // Ok
|
||||
{
|
||||
if (m_From.PlaceInBackpack(m_Deed))
|
||||
{
|
||||
m_From.SendLocalizedMessage(1045152); // The bulk order deed has been placed in your backpack.
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1045150); // There is not enough room in your backpack for the deed.
|
||||
m_Deed.Delete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Deed.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnServerClose(NetState owner)
|
||||
{
|
||||
if (m_Deed?.Deleted == false)
|
||||
m_Deed.Delete();
|
||||
}
|
||||
|
||||
public static int GetMaterialNumberFor(BulkMaterialType material)
|
||||
{
|
||||
if (material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite)
|
||||
return 1045142 + (material - BulkMaterialType.DullCopper);
|
||||
if (material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed)
|
||||
return 1049348 + (material - BulkMaterialType.Spined);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Projects/Scripts/Engines/BulkOrders/LargeBODGump.cs
Normal file
98
Projects/Scripts/Engines/BulkOrders/LargeBODGump.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class LargeBODGump : Gump
|
||||
{
|
||||
private LargeBOD m_Deed;
|
||||
private Mobile m_From;
|
||||
|
||||
public LargeBODGump(Mobile from, LargeBOD deed) : base(25, 25)
|
||||
{
|
||||
m_From = from;
|
||||
m_Deed = deed;
|
||||
|
||||
m_From.CloseGump<LargeBODGump>();
|
||||
m_From.CloseGump<SmallBODGump>();
|
||||
|
||||
LargeBulkEntry[] entries = deed.Entries;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(50, 10, 455, 236 + entries.Length * 24, 5054);
|
||||
|
||||
AddImageTiled(58, 20, 438, 217 + entries.Length * 24, 2624);
|
||||
AddAlphaRegion(58, 20, 438, 217 + entries.Length * 24);
|
||||
|
||||
AddImage(45, 5, 10460);
|
||||
AddImage(480, 5, 10460);
|
||||
AddImage(45, 221 + entries.Length * 24, 10460);
|
||||
AddImage(480, 221 + entries.Length * 24, 10460);
|
||||
|
||||
AddHtmlLocalized(225, 25, 120, 20, 1045134, 0x7FFF); // A large bulk order
|
||||
|
||||
AddHtmlLocalized(75, 48, 250, 20, 1045138, 0x7FFF); // Amount to make:
|
||||
AddLabel(275, 48, 1152, deed.AmountMax.ToString());
|
||||
|
||||
AddHtmlLocalized(75, 72, 120, 20, 1045137, 0x7FFF); // Items requested:
|
||||
AddHtmlLocalized(275, 76, 200, 20, 1045153, 0x7FFF); // Amount finished:
|
||||
|
||||
int y = 96;
|
||||
|
||||
for (int i = 0; i < entries.Length; ++i)
|
||||
{
|
||||
LargeBulkEntry entry = entries[i];
|
||||
SmallBulkEntry details = entry.Details;
|
||||
|
||||
AddHtmlLocalized(75, y, 210, 20, details.Number, 0x7FFF);
|
||||
AddLabel(275, y, 0x480, entry.Amount.ToString());
|
||||
|
||||
y += 24;
|
||||
}
|
||||
|
||||
if (deed.RequireExceptional || deed.Material != BulkMaterialType.None)
|
||||
{
|
||||
AddHtmlLocalized(75, y, 200, 20, 1045140, 0x7FFF); // Special requirements to meet:
|
||||
y += 24;
|
||||
}
|
||||
|
||||
if (deed.RequireExceptional)
|
||||
{
|
||||
AddHtmlLocalized(75, y, 300, 20, 1045141, 0x7FFF); // All items must be exceptional.
|
||||
y += 24;
|
||||
}
|
||||
|
||||
if (deed.Material != BulkMaterialType.None)
|
||||
AddHtmlLocalized(75, y, 300, 20, GetMaterialNumberFor(deed.Material), 0x7FFF); // All items must be made with x material.
|
||||
|
||||
AddButton(125, 168 + entries.Length * 24, 4005, 4007, 2);
|
||||
AddHtmlLocalized(160, 168 + entries.Length * 24, 300, 20, 1045155, 0x7FFF); // Combine this deed with another deed.
|
||||
|
||||
AddButton(125, 192 + entries.Length * 24, 4005, 4007, 1);
|
||||
AddHtmlLocalized(160, 192 + entries.Length * 24, 120, 20, 1011441, 0x7FFF); // EXIT
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (m_Deed.Deleted || !m_Deed.IsChildOf(m_From.Backpack))
|
||||
return;
|
||||
|
||||
if (info.ButtonID == 2) // Combine
|
||||
{
|
||||
m_From.SendGump(new LargeBODGump(m_From, m_Deed));
|
||||
m_Deed.BeginCombine(m_From);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetMaterialNumberFor(BulkMaterialType material)
|
||||
{
|
||||
if (material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite)
|
||||
return 1045142 + (material - BulkMaterialType.DullCopper);
|
||||
if (material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed)
|
||||
return 1049348 + (material - BulkMaterialType.Spined);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Projects/Scripts/Engines/BulkOrders/LargeBulkEntry.cs
Normal file
120
Projects/Scripts/Engines/BulkOrders/LargeBulkEntry.cs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class LargeBulkEntry
|
||||
{
|
||||
private int m_Amount;
|
||||
|
||||
public LargeBOD Owner { get; set; }
|
||||
|
||||
public int Amount
|
||||
{
|
||||
get => m_Amount;
|
||||
set{ m_Amount = value; Owner?.InvalidateProperties(); }
|
||||
}
|
||||
public SmallBulkEntry Details { get; }
|
||||
|
||||
public static SmallBulkEntry[] LargeRing => GetEntries( "Blacksmith", "largering" );
|
||||
|
||||
public static SmallBulkEntry[] LargePlate => GetEntries( "Blacksmith", "largeplate" );
|
||||
|
||||
public static SmallBulkEntry[] LargeChain => GetEntries( "Blacksmith", "largechain" );
|
||||
|
||||
public static SmallBulkEntry[] LargeAxes => GetEntries( "Blacksmith", "largeaxes" );
|
||||
|
||||
public static SmallBulkEntry[] LargeFencing => GetEntries( "Blacksmith", "largefencing" );
|
||||
|
||||
public static SmallBulkEntry[] LargeMaces => GetEntries( "Blacksmith", "largemaces" );
|
||||
|
||||
public static SmallBulkEntry[] LargePolearms => GetEntries( "Blacksmith", "largepolearms" );
|
||||
|
||||
public static SmallBulkEntry[] LargeSwords => GetEntries( "Blacksmith", "largeswords" );
|
||||
|
||||
|
||||
public static SmallBulkEntry[] BoneSet => GetEntries( "Tailoring", "boneset" );
|
||||
|
||||
public static SmallBulkEntry[] Farmer => GetEntries( "Tailoring", "farmer" );
|
||||
|
||||
public static SmallBulkEntry[] FemaleLeatherSet => GetEntries( "Tailoring", "femaleleatherset" );
|
||||
|
||||
public static SmallBulkEntry[] FisherGirl => GetEntries( "Tailoring", "fishergirl" );
|
||||
|
||||
public static SmallBulkEntry[] Gypsy => GetEntries( "Tailoring", "gypsy" );
|
||||
|
||||
public static SmallBulkEntry[] HatSet => GetEntries( "Tailoring", "hatset" );
|
||||
|
||||
public static SmallBulkEntry[] Jester => GetEntries( "Tailoring", "jester" );
|
||||
|
||||
public static SmallBulkEntry[] Lady => GetEntries( "Tailoring", "lady" );
|
||||
|
||||
public static SmallBulkEntry[] MaleLeatherSet => GetEntries( "Tailoring", "maleleatherset" );
|
||||
|
||||
public static SmallBulkEntry[] Pirate => GetEntries( "Tailoring", "pirate" );
|
||||
|
||||
public static SmallBulkEntry[] ShoeSet => GetEntries( "Tailoring", "shoeset" );
|
||||
|
||||
public static SmallBulkEntry[] StuddedSet => GetEntries( "Tailoring", "studdedset" );
|
||||
|
||||
public static SmallBulkEntry[] TownCrier => GetEntries( "Tailoring", "towncrier" );
|
||||
|
||||
public static SmallBulkEntry[] Wizard => GetEntries( "Tailoring", "wizard" );
|
||||
|
||||
|
||||
private static Dictionary<string,Dictionary<string,SmallBulkEntry[]>> m_Cache;
|
||||
|
||||
public static SmallBulkEntry[] GetEntries( string type, string name )
|
||||
{
|
||||
if (m_Cache == null)
|
||||
m_Cache = new Dictionary<string, Dictionary<string, SmallBulkEntry[]>>();
|
||||
|
||||
if (!m_Cache.TryGetValue( type, out Dictionary<string, SmallBulkEntry[]> table ))
|
||||
m_Cache[type] = table = new Dictionary<string, SmallBulkEntry[]>();
|
||||
|
||||
if (!table.TryGetValue( name, out SmallBulkEntry[] entries ))
|
||||
table[name] = entries = SmallBulkEntry.LoadEntries(type, name);
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
public static LargeBulkEntry[] ConvertEntries( LargeBOD owner, SmallBulkEntry[] small )
|
||||
{
|
||||
LargeBulkEntry[] large = new LargeBulkEntry[small.Length];
|
||||
|
||||
for ( int i = 0; i < small.Length; ++i )
|
||||
large[i] = new LargeBulkEntry( owner, small[i] );
|
||||
|
||||
return large;
|
||||
}
|
||||
|
||||
public LargeBulkEntry( LargeBOD owner, SmallBulkEntry details )
|
||||
{
|
||||
Owner = owner;
|
||||
Details = details;
|
||||
}
|
||||
|
||||
public LargeBulkEntry( LargeBOD owner, GenericReader reader )
|
||||
{
|
||||
Owner = owner;
|
||||
m_Amount = reader.ReadInt();
|
||||
|
||||
Type realType = null;
|
||||
|
||||
string type = reader.ReadString();
|
||||
|
||||
if ( type != null )
|
||||
realType = ScriptCompiler.FindTypeByFullName( type );
|
||||
|
||||
Details = new SmallBulkEntry( realType, reader.ReadInt(), reader.ReadInt() );
|
||||
}
|
||||
|
||||
public void Serialize( GenericWriter writer )
|
||||
{
|
||||
writer.Write( m_Amount );
|
||||
writer.Write( Details.Type == null ? null : Details.Type.FullName );
|
||||
writer.Write( Details.Number );
|
||||
writer.Write( Details.Graphic );
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Projects/Scripts/Engines/BulkOrders/LargeSmithBOD.cs
Normal file
102
Projects/Scripts/Engines/BulkOrders/LargeSmithBOD.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class LargeSmithBOD : LargeBOD
|
||||
{
|
||||
public static double[] m_BlacksmithMaterialChances =
|
||||
{
|
||||
0.501953125, // None
|
||||
0.250000000, // Dull Copper
|
||||
0.125000000, // Shadow Iron
|
||||
0.062500000, // Copper
|
||||
0.031250000, // Bronze
|
||||
0.015625000, // Gold
|
||||
0.007812500, // Agapite
|
||||
0.003906250, // Verite
|
||||
0.001953125 // Valorite
|
||||
};
|
||||
|
||||
[Constructible]
|
||||
public LargeSmithBOD()
|
||||
{
|
||||
LargeBulkEntry[] entries;
|
||||
bool useMaterials = true;
|
||||
|
||||
int rand = Utility.Random(8);
|
||||
|
||||
switch (rand)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargeRing);
|
||||
break;
|
||||
case 1:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargePlate);
|
||||
break;
|
||||
case 2:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargeChain);
|
||||
break;
|
||||
case 3:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargeAxes);
|
||||
break;
|
||||
case 4:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargeFencing);
|
||||
break;
|
||||
case 5:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargeMaces);
|
||||
break;
|
||||
case 6:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargePolearms);
|
||||
break;
|
||||
case 7:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.LargeSwords);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rand > 2 && rand < 8)
|
||||
useMaterials = false;
|
||||
|
||||
int hue = 0x44E;
|
||||
int amountMax = Utility.RandomList(10, 15, 20, 20);
|
||||
bool reqExceptional = 0.825 > Utility.RandomDouble();
|
||||
|
||||
BulkMaterialType material = useMaterials ? GetRandomMaterial(BulkMaterialType.DullCopper, m_BlacksmithMaterialChances)
|
||||
: BulkMaterialType.None;
|
||||
|
||||
Hue = hue;
|
||||
AmountMax = amountMax;
|
||||
Entries = entries;
|
||||
RequireExceptional = reqExceptional;
|
||||
Material = material;
|
||||
}
|
||||
|
||||
public LargeSmithBOD(int amountMax, bool reqExceptional, BulkMaterialType mat, LargeBulkEntry[] entries)
|
||||
: base(0x44E, amountMax, reqExceptional, mat, entries)
|
||||
{
|
||||
}
|
||||
|
||||
public LargeSmithBOD(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int ComputeFame() => SmithRewardCalculator.Instance.ComputeFame(this);
|
||||
|
||||
public override int ComputeGold() => SmithRewardCalculator.Instance.ComputeGold(this);
|
||||
|
||||
public override RewardGroup GetRewardGroup() =>
|
||||
SmithRewardCalculator.Instance.LookupRewards(SmithRewardCalculator.Instance.ComputePoints(this));
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Projects/Scripts/Engines/BulkOrders/LargeTailorBOD.cs
Normal file
121
Projects/Scripts/Engines/BulkOrders/LargeTailorBOD.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class LargeTailorBOD : LargeBOD
|
||||
{
|
||||
public static double[] m_TailoringMaterialChances =
|
||||
{
|
||||
0.857421875, // None
|
||||
0.125000000, // Spined
|
||||
0.015625000, // Horned
|
||||
0.001953125 // Barbed
|
||||
};
|
||||
|
||||
[Constructible]
|
||||
public LargeTailorBOD()
|
||||
{
|
||||
LargeBulkEntry[] entries;
|
||||
bool useMaterials = false;
|
||||
|
||||
switch (Utility.Random(14))
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.Farmer);
|
||||
break;
|
||||
case 1:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.FemaleLeatherSet);
|
||||
useMaterials = true;
|
||||
break;
|
||||
case 2:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.FisherGirl);
|
||||
break;
|
||||
case 3:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.Gypsy);
|
||||
break;
|
||||
case 4:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.HatSet);
|
||||
break;
|
||||
case 5:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.Jester);
|
||||
break;
|
||||
case 6:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.Lady);
|
||||
break;
|
||||
case 7:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.MaleLeatherSet);
|
||||
useMaterials = true;
|
||||
break;
|
||||
case 8:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.Pirate);
|
||||
break;
|
||||
case 9:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.ShoeSet);
|
||||
useMaterials = Core.ML;
|
||||
break;
|
||||
case 10:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.StuddedSet);
|
||||
useMaterials = true;
|
||||
break;
|
||||
case 11:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.TownCrier);
|
||||
break;
|
||||
case 12:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.Wizard);
|
||||
break;
|
||||
case 13:
|
||||
entries = LargeBulkEntry.ConvertEntries(this, LargeBulkEntry.BoneSet);
|
||||
useMaterials = true;
|
||||
break;
|
||||
}
|
||||
|
||||
int hue = 0x483;
|
||||
int amountMax = Utility.RandomList(10, 15, 20, 20);
|
||||
bool reqExceptional = 0.825 > Utility.RandomDouble();
|
||||
|
||||
BulkMaterialType material = useMaterials ? GetRandomMaterial(BulkMaterialType.Spined, m_TailoringMaterialChances)
|
||||
: BulkMaterialType.None;
|
||||
|
||||
Hue = hue;
|
||||
AmountMax = amountMax;
|
||||
Entries = entries;
|
||||
RequireExceptional = reqExceptional;
|
||||
Material = material;
|
||||
}
|
||||
|
||||
public LargeTailorBOD(int amountMax, bool reqExceptional, BulkMaterialType mat, LargeBulkEntry[] entries)
|
||||
: base(0x483, amountMax, reqExceptional, mat, entries)
|
||||
{
|
||||
}
|
||||
|
||||
public LargeTailorBOD(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int ComputeFame()
|
||||
{
|
||||
return TailorRewardCalculator.Instance.ComputeFame(this);
|
||||
}
|
||||
|
||||
public override int ComputeGold()
|
||||
{
|
||||
return TailorRewardCalculator.Instance.ComputeGold(this);
|
||||
}
|
||||
|
||||
public override RewardGroup GetRewardGroup() =>
|
||||
TailorRewardCalculator.Instance.LookupRewards(TailorRewardCalculator.Instance.ComputePoints(this));
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
745
Projects/Scripts/Engines/BulkOrders/Rewards.cs
Normal file
745
Projects/Scripts/Engines/BulkOrders/Rewards.cs
Normal file
|
|
@ -0,0 +1,745 @@
|
|||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public delegate Item ConstructCallback(int type);
|
||||
|
||||
public sealed class RewardType
|
||||
{
|
||||
public RewardType(int points, params Type[] types)
|
||||
{
|
||||
Points = points;
|
||||
Types = types;
|
||||
}
|
||||
|
||||
public int Points{ get; }
|
||||
|
||||
public Type[] Types{ get; }
|
||||
|
||||
public bool Contains(Type type)
|
||||
{
|
||||
for (int i = 0; i < Types.Length; ++i)
|
||||
if (Types[i] == type)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RewardItem
|
||||
{
|
||||
public RewardItem(int weight, ConstructCallback constructor, int type = 0)
|
||||
{
|
||||
Weight = weight;
|
||||
Constructor = constructor;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public int Weight{ get; }
|
||||
|
||||
public ConstructCallback Constructor{ get; }
|
||||
|
||||
public int Type{ get; }
|
||||
|
||||
public Item Construct()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Constructor(Type);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RewardGroup
|
||||
{
|
||||
public RewardGroup(int points, params RewardItem[] items)
|
||||
{
|
||||
Points = points;
|
||||
Items = items;
|
||||
}
|
||||
|
||||
public int Points{ get; }
|
||||
|
||||
public RewardItem[] Items{ get; }
|
||||
|
||||
public RewardItem AcquireItem()
|
||||
{
|
||||
if (Items.Length == 0)
|
||||
return null;
|
||||
if (Items.Length == 1)
|
||||
return Items[0];
|
||||
|
||||
int totalWeight = 0;
|
||||
|
||||
for (int i = 0; i < Items.Length; ++i)
|
||||
totalWeight += Items[i].Weight;
|
||||
|
||||
int randomWeight = Utility.Random(totalWeight);
|
||||
|
||||
for (int i = 0; i < Items.Length; ++i)
|
||||
{
|
||||
RewardItem item = Items[i];
|
||||
|
||||
if (randomWeight < item.Weight)
|
||||
return item;
|
||||
|
||||
randomWeight -= item.Weight;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class RewardCalculator
|
||||
{
|
||||
public RewardGroup[] Groups{ get; set; }
|
||||
|
||||
public abstract int ComputePoints(int quantity, bool exceptional, BulkMaterialType material, int itemCount,
|
||||
Type type);
|
||||
|
||||
public abstract int ComputeGold(int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type);
|
||||
|
||||
public virtual int ComputeFame(SmallBOD bod)
|
||||
{
|
||||
int points = ComputePoints(bod) / 50;
|
||||
return points * points;
|
||||
}
|
||||
|
||||
public virtual int ComputeFame(LargeBOD bod)
|
||||
{
|
||||
int points = ComputePoints(bod) / 50;
|
||||
return points * points;
|
||||
}
|
||||
|
||||
public virtual int ComputePoints(SmallBOD bod)
|
||||
{
|
||||
return ComputePoints(bod.AmountMax, bod.RequireExceptional, bod.Material, 1, bod.Type);
|
||||
}
|
||||
|
||||
public virtual int ComputePoints(LargeBOD bod)
|
||||
{
|
||||
return ComputePoints(bod.AmountMax, bod.RequireExceptional, bod.Material, bod.Entries.Length,
|
||||
bod.Entries[0].Details.Type);
|
||||
}
|
||||
|
||||
public virtual int ComputeGold(SmallBOD bod)
|
||||
{
|
||||
return ComputeGold(bod.AmountMax, bod.RequireExceptional, bod.Material, 1, bod.Type);
|
||||
}
|
||||
|
||||
public virtual int ComputeGold(LargeBOD bod)
|
||||
{
|
||||
return ComputeGold(bod.AmountMax, bod.RequireExceptional, bod.Material, bod.Entries.Length,
|
||||
bod.Entries[0].Details.Type);
|
||||
}
|
||||
|
||||
public virtual RewardGroup LookupRewards(int points)
|
||||
{
|
||||
for (int i = Groups.Length - 1; i >= 1; --i)
|
||||
{
|
||||
RewardGroup group = Groups[i];
|
||||
|
||||
if (points >= group.Points)
|
||||
return group;
|
||||
}
|
||||
|
||||
return Groups[0];
|
||||
}
|
||||
|
||||
public virtual int LookupTypePoints(RewardType[] types, Type type)
|
||||
{
|
||||
for (int i = 0; i < types.Length; ++i)
|
||||
if (types[i].Contains(type))
|
||||
return types[i].Points;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SmithRewardCalculator : RewardCalculator
|
||||
{
|
||||
private static readonly ConstructCallback SturdyShovel = CreateSturdyShovel;
|
||||
private static readonly ConstructCallback SturdyPickaxe = CreateSturdyPickaxe;
|
||||
private static readonly ConstructCallback MiningGloves = CreateMiningGloves;
|
||||
private static readonly ConstructCallback GargoylesPickaxe = CreateGargoylesPickaxe;
|
||||
private static readonly ConstructCallback ProspectorsTool = CreateProspectorsTool;
|
||||
private static readonly ConstructCallback PowderOfTemperament = CreatePowderOfTemperament;
|
||||
private static readonly ConstructCallback RunicHammer = CreateRunicHammer;
|
||||
private static readonly ConstructCallback PowerScroll = CreatePowerScroll;
|
||||
private static readonly ConstructCallback ColoredAnvil = CreateColoredAnvil;
|
||||
private static readonly ConstructCallback AncientHammer = CreateAncientHammer;
|
||||
public static readonly SmithRewardCalculator Instance = new SmithRewardCalculator();
|
||||
|
||||
private static int[][][] m_GoldTable =
|
||||
{
|
||||
new[] // 1-part (regular)
|
||||
{
|
||||
new[] { 150, 250, 250, 400, 400, 750, 750, 1200, 1200 },
|
||||
new[] { 225, 375, 375, 600, 600, 1125, 1125, 1800, 1800 },
|
||||
new[] { 300, 500, 750, 800, 1050, 1500, 2250, 2400, 4000 }
|
||||
},
|
||||
new[] // 1-part (exceptional)
|
||||
{
|
||||
new[] { 250, 400, 400, 750, 750, 1500, 1500, 3000, 3000 },
|
||||
new[] { 375, 600, 600, 1125, 1125, 2250, 2250, 4500, 4500 },
|
||||
new[] { 500, 800, 1200, 1500, 2500, 3000, 6000, 6000, 12000 }
|
||||
},
|
||||
new[] // Ringmail (regular)
|
||||
{
|
||||
new[] { 3000, 5000, 5000, 7500, 7500, 10000, 10000, 15000, 15000 },
|
||||
new[] { 4500, 7500, 7500, 11250, 11500, 15000, 15000, 22500, 22500 },
|
||||
new[] { 6000, 10000, 15000, 15000, 20000, 20000, 30000, 30000, 50000 }
|
||||
},
|
||||
new[] // Ringmail (exceptional)
|
||||
{
|
||||
new[] { 5000, 10000, 10000, 15000, 15000, 25000, 25000, 50000, 50000 },
|
||||
new[] { 7500, 15000, 15000, 22500, 22500, 37500, 37500, 75000, 75000 },
|
||||
new[] { 10000, 20000, 30000, 30000, 50000, 50000, 100000, 100000, 200000 }
|
||||
},
|
||||
new[] // Chainmail (regular)
|
||||
{
|
||||
new[] { 4000, 7500, 7500, 10000, 10000, 15000, 15000, 25000, 25000 },
|
||||
new[] { 6000, 11250, 11250, 15000, 15000, 22500, 22500, 37500, 37500 },
|
||||
new[] { 8000, 15000, 20000, 20000, 30000, 30000, 50000, 50000, 100000 }
|
||||
},
|
||||
new[] // Chainmail (exceptional)
|
||||
{
|
||||
new[] { 7500, 15000, 15000, 25000, 25000, 50000, 50000, 100000, 100000 },
|
||||
new[] { 11250, 22500, 22500, 37500, 37500, 75000, 75000, 150000, 150000 },
|
||||
new[] { 15000, 30000, 50000, 50000, 100000, 100000, 200000, 200000, 200000 }
|
||||
},
|
||||
new[] // Platemail (regular)
|
||||
{
|
||||
new[] { 5000, 10000, 10000, 15000, 15000, 25000, 25000, 50000, 50000 },
|
||||
new[] { 7500, 15000, 15000, 22500, 22500, 37500, 37500, 75000, 75000 },
|
||||
new[] { 10000, 20000, 30000, 30000, 50000, 50000, 100000, 100000, 200000 }
|
||||
},
|
||||
new[] // Platemail (exceptional)
|
||||
{
|
||||
new[] { 10000, 25000, 25000, 50000, 50000, 100000, 100000, 100000, 100000 },
|
||||
new[] { 15000, 37500, 37500, 75000, 75000, 150000, 150000, 150000, 150000 },
|
||||
new[] { 20000, 50000, 100000, 100000, 200000, 200000, 200000, 200000, 200000 }
|
||||
},
|
||||
new[] // 2-part weapons (regular)
|
||||
{
|
||||
new[] { 3000, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 4500, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 6000, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
},
|
||||
new[] // 2-part weapons (exceptional)
|
||||
{
|
||||
new[] { 5000, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 7500, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 10000, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
},
|
||||
new[] // 5-part weapons (regular)
|
||||
{
|
||||
new[] { 4000, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 6000, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 8000, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
},
|
||||
new[] // 5-part weapons (exceptional)
|
||||
{
|
||||
new[] { 7500, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 11250, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 15000, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
},
|
||||
new[] // 6-part weapons (regular)
|
||||
{
|
||||
new[] { 4000, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 6000, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 10000, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
},
|
||||
new[] // 6-part weapons (exceptional)
|
||||
{
|
||||
new[] { 7500, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 11250, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
new[] { 15000, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
}
|
||||
};
|
||||
|
||||
private RewardType[] m_Types =
|
||||
{
|
||||
// Armors
|
||||
new RewardType(200, typeof(RingmailGloves), typeof(RingmailChest), typeof(RingmailArms), typeof(RingmailLegs)),
|
||||
new RewardType(300, typeof(ChainCoif), typeof(ChainLegs), typeof(ChainChest)),
|
||||
new RewardType(400, typeof(PlateArms), typeof(PlateLegs), typeof(PlateHelm), typeof(PlateGorget),
|
||||
typeof(PlateGloves), typeof(PlateChest)),
|
||||
|
||||
// Weapons
|
||||
new RewardType(200, typeof(Bardiche), typeof(Halberd)),
|
||||
new RewardType(300, typeof(Dagger), typeof(ShortSpear), typeof(Spear), typeof(WarFork),
|
||||
typeof(Kryss)), //OSI put the dagger in there. Odd, ain't it.
|
||||
new RewardType(350, typeof(Axe), typeof(BattleAxe), typeof(DoubleAxe), typeof(ExecutionersAxe),
|
||||
typeof(LargeBattleAxe), typeof(TwoHandedAxe)),
|
||||
new RewardType(350, typeof(Broadsword), typeof(Cutlass), typeof(Katana), typeof(Longsword),
|
||||
typeof(Scimitar), /*typeof( ThinLongsword ),*/ typeof(VikingSword)),
|
||||
new RewardType(350, typeof(WarAxe), typeof(HammerPick), typeof(Mace), typeof(Maul), typeof(WarHammer),
|
||||
typeof(WarMace))
|
||||
};
|
||||
|
||||
public SmithRewardCalculator()
|
||||
{
|
||||
Groups = new[]
|
||||
{
|
||||
new RewardGroup(0, new RewardItem(1, SturdyShovel)),
|
||||
new RewardGroup(25, new RewardItem(1, SturdyPickaxe)),
|
||||
new RewardGroup(50, new RewardItem(45, SturdyShovel), new RewardItem(45, SturdyPickaxe),
|
||||
new RewardItem(10, MiningGloves, 1)),
|
||||
new RewardGroup(200, new RewardItem(45, GargoylesPickaxe), new RewardItem(45, ProspectorsTool),
|
||||
new RewardItem(10, MiningGloves, 3)),
|
||||
new RewardGroup(400, new RewardItem(2, GargoylesPickaxe), new RewardItem(2, ProspectorsTool),
|
||||
new RewardItem(1, PowderOfTemperament)),
|
||||
new RewardGroup(450, new RewardItem(9, PowderOfTemperament), new RewardItem(1, MiningGloves, 5)),
|
||||
new RewardGroup(500, new RewardItem(1, RunicHammer, 1)),
|
||||
new RewardGroup(550, new RewardItem(3, RunicHammer, 1), new RewardItem(2, RunicHammer, 2)),
|
||||
new RewardGroup(600, new RewardItem(1, RunicHammer, 2)),
|
||||
new RewardGroup(625, new RewardItem(3, RunicHammer, 2), new RewardItem(6, PowerScroll, 5),
|
||||
new RewardItem(1, ColoredAnvil)),
|
||||
new RewardGroup(650, new RewardItem(1, RunicHammer, 3)),
|
||||
new RewardGroup(675, new RewardItem(1, ColoredAnvil), new RewardItem(6, PowerScroll, 10),
|
||||
new RewardItem(3, RunicHammer, 3)),
|
||||
new RewardGroup(700, new RewardItem(1, RunicHammer, 4)),
|
||||
new RewardGroup(750, new RewardItem(1, AncientHammer, 10)),
|
||||
new RewardGroup(800, new RewardItem(1, PowerScroll, 15)),
|
||||
new RewardGroup(850, new RewardItem(1, AncientHammer, 15)),
|
||||
new RewardGroup(900, new RewardItem(1, PowerScroll, 20)),
|
||||
new RewardGroup(950, new RewardItem(1, RunicHammer, 5)),
|
||||
new RewardGroup(1000, new RewardItem(1, AncientHammer, 30)),
|
||||
new RewardGroup(1050, new RewardItem(1, RunicHammer, 6)),
|
||||
new RewardGroup(1100, new RewardItem(1, AncientHammer, 60)),
|
||||
new RewardGroup(1150, new RewardItem(1, RunicHammer, 7)),
|
||||
new RewardGroup(1200, new RewardItem(1, RunicHammer, 8))
|
||||
};
|
||||
}
|
||||
|
||||
public override int ComputePoints(int quantity, bool exceptional, BulkMaterialType material, int itemCount,
|
||||
Type type)
|
||||
{
|
||||
int points = 0;
|
||||
|
||||
if (quantity == 10)
|
||||
points += 10;
|
||||
else if (quantity == 15)
|
||||
points += 25;
|
||||
else if (quantity == 20)
|
||||
points += 50;
|
||||
|
||||
if (exceptional)
|
||||
points += 200;
|
||||
|
||||
if (itemCount > 1)
|
||||
points += LookupTypePoints(m_Types, type);
|
||||
|
||||
if (material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite)
|
||||
points += 200 + 50 * (material - BulkMaterialType.DullCopper);
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private int ComputeType(Type type, int itemCount)
|
||||
{
|
||||
// Item count of 1 means it's a small BOD.
|
||||
if (itemCount == 1)
|
||||
return 0;
|
||||
|
||||
int typeIdx = 0;
|
||||
|
||||
// Loop through the RewardTypes defined earlier and find the correct one.
|
||||
for (; typeIdx < 7; ++typeIdx)
|
||||
if (m_Types[typeIdx].Contains(type))
|
||||
break;
|
||||
|
||||
// Types 5, 6 and 7 are Large Weapon BODs with the same rewards.
|
||||
if (typeIdx > 5)
|
||||
typeIdx = 5;
|
||||
|
||||
return (typeIdx + 1) * 2;
|
||||
}
|
||||
|
||||
public override int ComputeGold(int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type)
|
||||
{
|
||||
int[][][] goldTable = m_GoldTable;
|
||||
|
||||
int typeIndex = ComputeType(type, itemCount);
|
||||
int quanIndex = quantity == 20 ? 2 : quantity == 15 ? 1 : 0;
|
||||
int mtrlIndex = material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite
|
||||
? 1 + (material - BulkMaterialType.DullCopper)
|
||||
: 0;
|
||||
|
||||
if (exceptional)
|
||||
typeIndex++;
|
||||
|
||||
int gold = goldTable[typeIndex][quanIndex][mtrlIndex];
|
||||
|
||||
int min = gold * 9 / 10;
|
||||
int max = gold * 10 / 9;
|
||||
|
||||
return Utility.RandomMinMax(min, max);
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
|
||||
private static Item CreateSturdyShovel(int type)
|
||||
{
|
||||
return new SturdyShovel();
|
||||
}
|
||||
|
||||
private static Item CreateSturdyPickaxe(int type)
|
||||
{
|
||||
return new SturdyPickaxe();
|
||||
}
|
||||
|
||||
private static Item CreateMiningGloves(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
return new LeatherGlovesOfMining(1);
|
||||
case 3:
|
||||
return new StuddedGlovesOfMining(3);
|
||||
case 5:
|
||||
return new RingmailGlovesOfMining(5);
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static Item CreateGargoylesPickaxe(int type)
|
||||
{
|
||||
return new GargoylesPickaxe();
|
||||
}
|
||||
|
||||
private static Item CreateProspectorsTool(int type)
|
||||
{
|
||||
return new ProspectorsTool();
|
||||
}
|
||||
|
||||
private static Item CreatePowderOfTemperament(int type)
|
||||
{
|
||||
return new PowderOfTemperament();
|
||||
}
|
||||
|
||||
private static Item CreateRunicHammer(int type)
|
||||
{
|
||||
if (type >= 1 && type <= 8)
|
||||
return new RunicHammer(CraftResource.Iron + type, Core.AOS ? 55 - type * 5 : 50);
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private static Item CreatePowerScroll(int type)
|
||||
{
|
||||
if (type == 5 || type == 10 || type == 15 || type == 20)
|
||||
return new PowerScroll(SkillName.Blacksmith, 100 + type);
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private static Item CreateColoredAnvil(int type)
|
||||
{
|
||||
// Generate an anvil deed, not an actual anvil.
|
||||
//return new ColoredAnvilDeed();
|
||||
|
||||
return new ColoredAnvil();
|
||||
}
|
||||
|
||||
private static Item CreateAncientHammer(int type)
|
||||
{
|
||||
if (type == 10 || type == 15 || type == 30 || type == 60)
|
||||
return new AncientSmithyHammer(type);
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public sealed class TailorRewardCalculator : RewardCalculator
|
||||
{
|
||||
private static readonly ConstructCallback Cloth = CreateCloth;
|
||||
private static readonly ConstructCallback Sandals = CreateSandals;
|
||||
private static readonly ConstructCallback StretchedHide = CreateStretchedHide;
|
||||
private static readonly ConstructCallback RunicKit = CreateRunicKit;
|
||||
private static readonly ConstructCallback Tapestry = CreateTapestry;
|
||||
private static readonly ConstructCallback PowerScroll = CreatePowerScroll;
|
||||
private static readonly ConstructCallback BearRug = CreateBearRug;
|
||||
private static readonly ConstructCallback ClothingBlessDeed = CreateCBD;
|
||||
public static readonly TailorRewardCalculator Instance = new TailorRewardCalculator();
|
||||
|
||||
private static int[][][] m_AosGoldTable =
|
||||
{
|
||||
new[] // 1-part (regular)
|
||||
{
|
||||
new[] { 150, 150, 300, 300 },
|
||||
new[] { 225, 225, 450, 450 },
|
||||
new[] { 300, 400, 600, 750 }
|
||||
},
|
||||
new[] // 1-part (exceptional)
|
||||
{
|
||||
new[] { 300, 300, 600, 600 },
|
||||
new[] { 450, 450, 900, 900 },
|
||||
new[] { 600, 750, 1200, 1800 }
|
||||
},
|
||||
new[] // 4-part (regular)
|
||||
{
|
||||
new[] { 4000, 4000, 5000, 5000 },
|
||||
new[] { 6000, 6000, 7500, 7500 },
|
||||
new[] { 8000, 10000, 10000, 15000 }
|
||||
},
|
||||
new[] // 4-part (exceptional)
|
||||
{
|
||||
new[] { 5000, 5000, 7500, 7500 },
|
||||
new[] { 7500, 7500, 11250, 11250 },
|
||||
new[] { 10000, 15000, 15000, 20000 }
|
||||
},
|
||||
new[] // 5-part (regular)
|
||||
{
|
||||
new[] { 5000, 5000, 7500, 7500 },
|
||||
new[] { 7500, 7500, 11250, 11250 },
|
||||
new[] { 10000, 15000, 15000, 20000 }
|
||||
},
|
||||
new[] // 5-part (exceptional)
|
||||
{
|
||||
new[] { 7500, 7500, 10000, 10000 },
|
||||
new[] { 11250, 11250, 15000, 15000 },
|
||||
new[] { 15000, 20000, 20000, 30000 }
|
||||
},
|
||||
new[] // 6-part (regular)
|
||||
{
|
||||
new[] { 7500, 7500, 10000, 10000 },
|
||||
new[] { 11250, 11250, 15000, 15000 },
|
||||
new[] { 15000, 20000, 20000, 30000 }
|
||||
},
|
||||
new[] // 6-part (exceptional)
|
||||
{
|
||||
new[] { 10000, 10000, 15000, 15000 },
|
||||
new[] { 15000, 15000, 22500, 22500 },
|
||||
new[] { 20000, 30000, 30000, 50000 }
|
||||
}
|
||||
};
|
||||
|
||||
private static int[][][] m_OldGoldTable =
|
||||
{
|
||||
new[] // 1-part (regular)
|
||||
{
|
||||
new[] { 150, 150, 300, 300 },
|
||||
new[] { 225, 225, 450, 450 },
|
||||
new[] { 300, 400, 600, 750 }
|
||||
},
|
||||
new[] // 1-part (exceptional)
|
||||
{
|
||||
new[] { 300, 300, 600, 600 },
|
||||
new[] { 450, 450, 900, 900 },
|
||||
new[] { 600, 750, 1200, 1800 }
|
||||
},
|
||||
new[] // 4-part (regular)
|
||||
{
|
||||
new[] { 3000, 3000, 4000, 4000 },
|
||||
new[] { 4500, 4500, 6000, 6000 },
|
||||
new[] { 6000, 8000, 8000, 10000 }
|
||||
},
|
||||
new[] // 4-part (exceptional)
|
||||
{
|
||||
new[] { 4000, 4000, 5000, 5000 },
|
||||
new[] { 6000, 6000, 7500, 7500 },
|
||||
new[] { 8000, 10000, 10000, 15000 }
|
||||
},
|
||||
new[] // 5-part (regular)
|
||||
{
|
||||
new[] { 4000, 4000, 5000, 5000 },
|
||||
new[] { 6000, 6000, 7500, 7500 },
|
||||
new[] { 8000, 10000, 10000, 15000 }
|
||||
},
|
||||
new[] // 5-part (exceptional)
|
||||
{
|
||||
new[] { 5000, 5000, 7500, 7500 },
|
||||
new[] { 7500, 7500, 11250, 11250 },
|
||||
new[] { 10000, 15000, 15000, 20000 }
|
||||
},
|
||||
new[] // 6-part (regular)
|
||||
{
|
||||
new[] { 5000, 5000, 7500, 7500 },
|
||||
new[] { 7500, 7500, 11250, 11250 },
|
||||
new[] { 10000, 15000, 15000, 20000 }
|
||||
},
|
||||
new[] // 6-part (exceptional)
|
||||
{
|
||||
new[] { 7500, 7500, 10000, 10000 },
|
||||
new[] { 11250, 11250, 15000, 15000 },
|
||||
new[] { 15000, 20000, 20000, 30000 }
|
||||
}
|
||||
};
|
||||
|
||||
public TailorRewardCalculator()
|
||||
{
|
||||
Groups = new[]
|
||||
{
|
||||
new RewardGroup(0, new RewardItem(1, Cloth)),
|
||||
new RewardGroup(50, new RewardItem(1, Cloth, 1)),
|
||||
new RewardGroup(100, new RewardItem(1, Cloth, 2)),
|
||||
new RewardGroup(150, new RewardItem(9, Cloth, 3), new RewardItem(1, Sandals)),
|
||||
new RewardGroup(200, new RewardItem(4, Cloth, 4), new RewardItem(1, Sandals)),
|
||||
new RewardGroup(300, new RewardItem(1, StretchedHide)),
|
||||
new RewardGroup(350, new RewardItem(1, RunicKit, 1)),
|
||||
new RewardGroup(400, new RewardItem(2, PowerScroll, 5), new RewardItem(3, Tapestry)),
|
||||
new RewardGroup(450, new RewardItem(1, BearRug)),
|
||||
new RewardGroup(500, new RewardItem(1, PowerScroll, 10)),
|
||||
new RewardGroup(550, new RewardItem(1, ClothingBlessDeed)),
|
||||
new RewardGroup(575, new RewardItem(1, PowerScroll, 15)),
|
||||
new RewardGroup(600, new RewardItem(1, RunicKit, 2)),
|
||||
new RewardGroup(650, new RewardItem(1, PowerScroll, 20)),
|
||||
new RewardGroup(700, new RewardItem(1, RunicKit, 3))
|
||||
};
|
||||
}
|
||||
|
||||
public override int ComputePoints(int quantity, bool exceptional, BulkMaterialType material, int itemCount,
|
||||
Type type)
|
||||
{
|
||||
int points = 0;
|
||||
|
||||
if (quantity == 10)
|
||||
points += 10;
|
||||
else if (quantity == 15)
|
||||
points += 25;
|
||||
else if (quantity == 20)
|
||||
points += 50;
|
||||
|
||||
if (exceptional)
|
||||
points += 100;
|
||||
|
||||
if (itemCount == 4)
|
||||
points += 300;
|
||||
else if (itemCount == 5)
|
||||
points += 400;
|
||||
else if (itemCount == 6)
|
||||
points += 500;
|
||||
|
||||
if (material == BulkMaterialType.Spined)
|
||||
points += 50;
|
||||
else if (material == BulkMaterialType.Horned)
|
||||
points += 100;
|
||||
else if (material == BulkMaterialType.Barbed)
|
||||
points += 150;
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
public override int ComputeGold(int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type)
|
||||
{
|
||||
int[][][] goldTable = Core.AOS ? m_AosGoldTable : m_OldGoldTable;
|
||||
|
||||
int typeIndex = (itemCount == 6 ? 3 : itemCount == 5 ? 2 : itemCount == 4 ? 1 : 0) * 2 + (exceptional ? 1 : 0);
|
||||
int quanIndex = quantity == 20 ? 2 : quantity == 15 ? 1 : 0;
|
||||
int mtrlIndex = material == BulkMaterialType.Barbed ? 3 :
|
||||
material == BulkMaterialType.Horned ? 2 :
|
||||
material == BulkMaterialType.Spined ? 1 : 0;
|
||||
|
||||
int gold = goldTable[typeIndex][quanIndex][mtrlIndex];
|
||||
|
||||
int min = gold * 9 / 10;
|
||||
int max = gold * 10 / 9;
|
||||
|
||||
return Utility.RandomMinMax(min, max);
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
|
||||
private static int[][] m_ClothHues =
|
||||
{
|
||||
new[] { 0x483, 0x48C, 0x488, 0x48A },
|
||||
new[] { 0x495, 0x48B, 0x486, 0x485 },
|
||||
new[] { 0x48D, 0x490, 0x48E, 0x491 },
|
||||
new[] { 0x48F, 0x494, 0x484, 0x497 },
|
||||
new[] { 0x489, 0x47F, 0x482, 0x47E }
|
||||
};
|
||||
|
||||
private static Item CreateCloth(int type)
|
||||
{
|
||||
if (type >= 0 && type < m_ClothHues.Length)
|
||||
{
|
||||
UncutCloth cloth = new UncutCloth(100);
|
||||
cloth.Hue = m_ClothHues[type][Utility.Random(m_ClothHues[type].Length)];
|
||||
return cloth;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private static int[] m_SandalHues =
|
||||
{
|
||||
0x489, 0x47F, 0x482,
|
||||
0x47E, 0x48F, 0x494,
|
||||
0x484, 0x497
|
||||
};
|
||||
|
||||
private static Item CreateSandals(int type)
|
||||
{
|
||||
return new Sandals(m_SandalHues[Utility.Random(m_SandalHues.Length)]);
|
||||
}
|
||||
|
||||
private static Item CreateStretchedHide(int type)
|
||||
{
|
||||
switch (Utility.Random(4))
|
||||
{
|
||||
default:
|
||||
return new SmallStretchedHideEastDeed();
|
||||
case 1: return new SmallStretchedHideSouthDeed();
|
||||
case 2: return new MediumStretchedHideEastDeed();
|
||||
case 3: return new MediumStretchedHideSouthDeed();
|
||||
}
|
||||
}
|
||||
|
||||
private static Item CreateTapestry(int type)
|
||||
{
|
||||
switch (Utility.Random(4))
|
||||
{
|
||||
default:
|
||||
return new LightFlowerTapestryEastDeed();
|
||||
case 1: return new LightFlowerTapestrySouthDeed();
|
||||
case 2: return new DarkFlowerTapestryEastDeed();
|
||||
case 3: return new DarkFlowerTapestrySouthDeed();
|
||||
}
|
||||
}
|
||||
|
||||
private static Item CreateBearRug(int type)
|
||||
{
|
||||
switch (Utility.Random(4))
|
||||
{
|
||||
default:
|
||||
return new BrownBearRugEastDeed();
|
||||
case 1: return new BrownBearRugSouthDeed();
|
||||
case 2: return new PolarBearRugEastDeed();
|
||||
case 3: return new PolarBearRugSouthDeed();
|
||||
}
|
||||
}
|
||||
|
||||
private static Item CreateRunicKit(int type)
|
||||
{
|
||||
if (type >= 1 && type <= 3)
|
||||
return new RunicSewingKit(CraftResource.RegularLeather + type, 60 - type * 15);
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private static Item CreatePowerScroll(int type)
|
||||
{
|
||||
if (type == 5 || type == 10 || type == 15 || type == 20)
|
||||
return new PowerScroll(SkillName.Tailoring, 100 + type);
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private static Item CreateCBD(int type)
|
||||
{
|
||||
return new ClothingBlessDeed();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
213
Projects/Scripts/Engines/BulkOrders/SmallBOD.cs
Normal file
213
Projects/Scripts/Engines/BulkOrders/SmallBOD.cs
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public abstract class SmallBOD : BaseBOD
|
||||
{
|
||||
private int m_AmountCur;
|
||||
private int m_Number;
|
||||
|
||||
public SmallBOD(int hue, int amountCur, int amountMax, Type type, int number, int graphic, bool requireExeptional,
|
||||
BulkMaterialType material) : base(hue, amountMax, requireExeptional, material)
|
||||
{
|
||||
Type = type;
|
||||
Graphic = graphic;
|
||||
m_AmountCur = amountCur;
|
||||
m_Number = number;
|
||||
}
|
||||
|
||||
public SmallBOD()
|
||||
{
|
||||
}
|
||||
|
||||
public SmallBOD(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int AmountCur
|
||||
{
|
||||
get => m_AmountCur;
|
||||
set
|
||||
{
|
||||
m_AmountCur = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Type Type{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Number
|
||||
{
|
||||
get => m_Number;
|
||||
set
|
||||
{
|
||||
m_Number = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Graphic{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public override bool Complete => m_AmountCur == AmountMax;
|
||||
|
||||
public override int LabelNumber => 1045151; // a bulk order deed
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(1060654); // small bulk order
|
||||
|
||||
if (RequireExceptional)
|
||||
list.Add(1045141); // All items must be exceptional.
|
||||
|
||||
if (Material != BulkMaterialType.None)
|
||||
list.Add(SmallBODGump.GetMaterialNumberFor(Material)); // All items must be made with x material.
|
||||
|
||||
list.Add(1060656, AmountMax.ToString()); // amount to make: ~1_val~
|
||||
list.Add(1060658, "#{0}\t{1}", m_Number, m_AmountCur); // ~1_val~: ~2_val~
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (IsChildOf(from.Backpack) || InSecureTrade || RootParent is PlayerVendor)
|
||||
from.SendGump(new SmallBODGump(from, this));
|
||||
else
|
||||
from.SendLocalizedMessage(1045156); // You must have the deed in your backpack to use it.
|
||||
}
|
||||
|
||||
public override void OnDoubleClickNotAccessible(Mobile from)
|
||||
{
|
||||
OnDoubleClick(from);
|
||||
}
|
||||
|
||||
public override void OnDoubleClickSecureTrade(Mobile from)
|
||||
{
|
||||
OnDoubleClick(from);
|
||||
}
|
||||
|
||||
public static BulkMaterialType GetMaterial(CraftResource resource)
|
||||
{
|
||||
switch (resource)
|
||||
{
|
||||
case CraftResource.DullCopper: return BulkMaterialType.DullCopper;
|
||||
case CraftResource.ShadowIron: return BulkMaterialType.ShadowIron;
|
||||
case CraftResource.Copper: return BulkMaterialType.Copper;
|
||||
case CraftResource.Bronze: return BulkMaterialType.Bronze;
|
||||
case CraftResource.Gold: return BulkMaterialType.Gold;
|
||||
case CraftResource.Agapite: return BulkMaterialType.Agapite;
|
||||
case CraftResource.Verite: return BulkMaterialType.Verite;
|
||||
case CraftResource.Valorite: return BulkMaterialType.Valorite;
|
||||
case CraftResource.SpinedLeather: return BulkMaterialType.Spined;
|
||||
case CraftResource.HornedLeather: return BulkMaterialType.Horned;
|
||||
case CraftResource.BarbedLeather: return BulkMaterialType.Barbed;
|
||||
}
|
||||
|
||||
return BulkMaterialType.None;
|
||||
}
|
||||
|
||||
public override void EndCombine(Mobile from, Item item)
|
||||
{
|
||||
Type objectType = item.GetType();
|
||||
|
||||
if (m_AmountCur >= AmountMax)
|
||||
{
|
||||
from.SendLocalizedMessage(
|
||||
1045166); // The maximum amount of requested items have already been combined to this deed.
|
||||
}
|
||||
else if (Type == null || objectType != Type && !objectType.IsSubclassOf(Type) ||
|
||||
!(item is BaseWeapon) && !(item is BaseArmor) && !(item is BaseClothing))
|
||||
{
|
||||
from.SendLocalizedMessage(1045169); // The item is not in the request.
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseArmor armor = item as BaseArmor;
|
||||
BaseClothing clothing = item as BaseClothing;
|
||||
|
||||
BulkMaterialType material = GetMaterial(armor?.Resource ?? clothing?.Resource ?? CraftResource.None);
|
||||
|
||||
if (Material >= BulkMaterialType.DullCopper && Material <= BulkMaterialType.Valorite &&
|
||||
material != Material)
|
||||
{
|
||||
from.SendLocalizedMessage(1045168); // The item is not made from the requested ore.
|
||||
}
|
||||
else if (Material >= BulkMaterialType.Spined && Material <= BulkMaterialType.Barbed &&
|
||||
material != Material)
|
||||
{
|
||||
from.SendLocalizedMessage(1049352); // The item is not made from the requested leather type.
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isExceptional;
|
||||
|
||||
if (item is BaseWeapon weapon)
|
||||
isExceptional = weapon.Quality == WeaponQuality.Exceptional;
|
||||
else if (armor != null)
|
||||
isExceptional = armor.Quality == ArmorQuality.Exceptional;
|
||||
else
|
||||
isExceptional = clothing.Quality == ClothingQuality.Exceptional;
|
||||
|
||||
if (RequireExceptional && !isExceptional)
|
||||
{
|
||||
from.SendLocalizedMessage(1045167); // The item must be exceptional.
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Delete();
|
||||
++AmountCur;
|
||||
|
||||
from.SendLocalizedMessage(1045170); // The item has been combined with the deed.
|
||||
from.SendGump(new SmallBODGump(from, this));
|
||||
|
||||
if (m_AmountCur < AmountMax)
|
||||
BeginCombine(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_AmountCur);
|
||||
writer.Write(Type == null ? null : Type.FullName);
|
||||
writer.Write(m_Number);
|
||||
writer.Write(Graphic);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_AmountCur = reader.ReadInt();
|
||||
|
||||
string type = reader.ReadString();
|
||||
|
||||
if (type != null)
|
||||
Type = ScriptCompiler.FindTypeByFullName(type);
|
||||
|
||||
m_Number = reader.ReadInt();
|
||||
Graphic = reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Projects/Scripts/Engines/BulkOrders/SmallBODAcceptGump.cs
Normal file
98
Projects/Scripts/Engines/BulkOrders/SmallBODAcceptGump.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class SmallBODAcceptGump : Gump
|
||||
{
|
||||
private SmallBOD m_Deed;
|
||||
private Mobile m_From;
|
||||
|
||||
public SmallBODAcceptGump(Mobile from, SmallBOD deed) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Deed = deed;
|
||||
|
||||
m_From.CloseGump<LargeBODAcceptGump>();
|
||||
m_From.CloseGump<SmallBODAcceptGump>();
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(25, 10, 430, 264, 5054);
|
||||
|
||||
AddImageTiled(33, 20, 413, 245, 2624);
|
||||
AddAlphaRegion(33, 20, 413, 245);
|
||||
|
||||
AddImage(20, 5, 10460);
|
||||
AddImage(430, 5, 10460);
|
||||
AddImage(20, 249, 10460);
|
||||
AddImage(430, 249, 10460);
|
||||
|
||||
AddHtmlLocalized(190, 25, 120, 20, 1045133, 0x7FFF); // A bulk order
|
||||
AddHtmlLocalized(40, 48, 350, 20, 1045135, 0x7FFF); // Ah! Thanks for the goods! Would you help me out?
|
||||
|
||||
AddHtmlLocalized(40, 72, 210, 20, 1045138, 0x7FFF); // Amount to make:
|
||||
AddLabel(250, 72, 1152, deed.AmountMax.ToString());
|
||||
|
||||
AddHtmlLocalized(40, 96, 120, 20, 1045136, 0x7FFF); // Item requested:
|
||||
AddItem(385, 96, deed.Graphic);
|
||||
AddHtmlLocalized(40, 120, 210, 20, deed.Number, 0xFFFFFF);
|
||||
|
||||
if (deed.RequireExceptional || deed.Material != BulkMaterialType.None)
|
||||
{
|
||||
AddHtmlLocalized(40, 144, 210, 20, 1045140, 0x7FFF); // Special requirements to meet:
|
||||
|
||||
if (deed.RequireExceptional)
|
||||
AddHtmlLocalized(40, 168, 350, 20, 1045141, 0x7FFF); // All items must be exceptional.
|
||||
|
||||
if (deed.Material != BulkMaterialType.None)
|
||||
AddHtmlLocalized(40, deed.RequireExceptional ? 192 : 168, 350, 20, GetMaterialNumberFor(deed.Material),
|
||||
0x7FFF); // All items must be made with x material.
|
||||
}
|
||||
|
||||
AddHtmlLocalized(40, 216, 350, 20, 1045139, 0x7FFF); // Do you want to accept this order?
|
||||
|
||||
AddButton(100, 240, 4005, 4007, 1);
|
||||
AddHtmlLocalized(135, 240, 120, 20, 1006044, 0x7FFF); // Ok
|
||||
|
||||
AddButton(275, 240, 4005, 4007, 0);
|
||||
AddHtmlLocalized(310, 240, 120, 20, 1011012, 0x7FFF); // CANCEL
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 1) // Ok
|
||||
{
|
||||
if (m_From.PlaceInBackpack(m_Deed))
|
||||
{
|
||||
m_From.SendLocalizedMessage(1045152); // The bulk order deed has been placed in your backpack.
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1045150); // There is not enough room in your backpack for the deed.
|
||||
m_Deed.Delete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Deed.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnServerClose(NetState owner)
|
||||
{
|
||||
if (m_Deed?.Deleted == false)
|
||||
m_Deed.Delete();
|
||||
}
|
||||
|
||||
public static int GetMaterialNumberFor(BulkMaterialType material)
|
||||
{
|
||||
if (material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite)
|
||||
return 1045142 + (material - BulkMaterialType.DullCopper);
|
||||
if (material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed)
|
||||
return 1049348 + (material - BulkMaterialType.Spined);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Projects/Scripts/Engines/BulkOrders/SmallBODGump.cs
Normal file
82
Projects/Scripts/Engines/BulkOrders/SmallBODGump.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class SmallBODGump : Gump
|
||||
{
|
||||
private SmallBOD m_Deed;
|
||||
private Mobile m_From;
|
||||
|
||||
public SmallBODGump(Mobile from, SmallBOD deed) : base(25, 25)
|
||||
{
|
||||
m_From = from;
|
||||
m_Deed = deed;
|
||||
|
||||
m_From.CloseGump<LargeBODGump>();
|
||||
m_From.CloseGump<SmallBODGump>();
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(50, 10, 455, 260, 5054);
|
||||
AddImageTiled(58, 20, 438, 241, 2624);
|
||||
AddAlphaRegion(58, 20, 438, 241);
|
||||
|
||||
AddImage(45, 5, 10460);
|
||||
AddImage(480, 5, 10460);
|
||||
AddImage(45, 245, 10460);
|
||||
AddImage(480, 245, 10460);
|
||||
|
||||
AddHtmlLocalized(225, 25, 120, 20, 1045133, 0x7FFF); // A bulk order
|
||||
|
||||
AddHtmlLocalized(75, 48, 250, 20, 1045138, 0x7FFF); // Amount to make:
|
||||
AddLabel(275, 48, 1152, deed.AmountMax.ToString());
|
||||
|
||||
AddHtmlLocalized(275, 76, 200, 20, 1045153, 0x7FFF); // Amount finished:
|
||||
AddHtmlLocalized(75, 72, 120, 20, 1045136, 0x7FFF); // Item requested:
|
||||
|
||||
AddItem(410, 72, deed.Graphic);
|
||||
|
||||
AddHtmlLocalized(75, 96, 210, 20, deed.Number, 0x7FFF);
|
||||
AddLabel(275, 96, 0x480, deed.AmountCur.ToString());
|
||||
|
||||
if (deed.RequireExceptional || deed.Material != BulkMaterialType.None)
|
||||
AddHtmlLocalized(75, 120, 200, 20, 1045140, 0x7FFF); // Special requirements to meet:
|
||||
|
||||
if (deed.RequireExceptional)
|
||||
AddHtmlLocalized(75, 144, 300, 20, 1045141, 0x7FFF); // All items must be exceptional.
|
||||
|
||||
if (deed.Material != BulkMaterialType.None)
|
||||
AddHtmlLocalized(75, deed.RequireExceptional ? 168 : 144, 300, 20, GetMaterialNumberFor(deed.Material),
|
||||
0x7FFF); // All items must be made with x material.
|
||||
|
||||
AddButton(125, 192, 4005, 4007, 2);
|
||||
AddHtmlLocalized(160, 192, 300, 20, 1045154, 0x7FFF); // Combine this deed with the item requested.
|
||||
|
||||
AddButton(125, 216, 4005, 4007, 1);
|
||||
AddHtmlLocalized(160, 216, 120, 20, 1011441, 0x7FFF); // EXIT
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (m_Deed.Deleted || !m_Deed.IsChildOf(m_From.Backpack))
|
||||
return;
|
||||
|
||||
if (info.ButtonID == 2) // Combine
|
||||
{
|
||||
m_From.SendGump(new SmallBODGump(m_From, m_Deed));
|
||||
m_Deed.BeginCombine(m_From);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetMaterialNumberFor(BulkMaterialType material)
|
||||
{
|
||||
if (material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite)
|
||||
return 1045142 + (material - BulkMaterialType.DullCopper);
|
||||
if (material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed)
|
||||
return 1049348 + (material - BulkMaterialType.Spined);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
92
Projects/Scripts/Engines/BulkOrders/SmallBulkEntry.cs
Normal file
92
Projects/Scripts/Engines/BulkOrders/SmallBulkEntry.cs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class SmallBulkEntry
|
||||
{
|
||||
public Type Type { get; }
|
||||
|
||||
public int Number { get; }
|
||||
|
||||
public int Graphic { get; }
|
||||
|
||||
public SmallBulkEntry( Type type, int number, int graphic )
|
||||
{
|
||||
Type = type;
|
||||
Number = number;
|
||||
Graphic = graphic;
|
||||
}
|
||||
|
||||
public static SmallBulkEntry[] BlacksmithWeapons => GetEntries( "Blacksmith", "weapons" );
|
||||
|
||||
public static SmallBulkEntry[] BlacksmithArmor => GetEntries( "Blacksmith", "armor" );
|
||||
|
||||
public static SmallBulkEntry[] TailorCloth => GetEntries( "Tailoring", "cloth" );
|
||||
|
||||
public static SmallBulkEntry[] TailorLeather => GetEntries( "Tailoring", "leather" );
|
||||
|
||||
private static Dictionary<string, Dictionary<string, SmallBulkEntry[]>> m_Cache;
|
||||
|
||||
public static SmallBulkEntry[] GetEntries( string type, string name )
|
||||
{
|
||||
if ( m_Cache == null )
|
||||
m_Cache = new Dictionary<string, Dictionary<string, SmallBulkEntry[]>>();
|
||||
|
||||
if (!m_Cache.TryGetValue( type, out Dictionary<string, SmallBulkEntry[]> table ))
|
||||
m_Cache[type] = table = new Dictionary<string, SmallBulkEntry[]>();
|
||||
|
||||
if (!table.TryGetValue( name, out SmallBulkEntry[] entries ))
|
||||
table[name] = entries = LoadEntries(type, name);
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
public static SmallBulkEntry[] LoadEntries( string type, string name )
|
||||
{
|
||||
return LoadEntries($"Data/Bulk Orders/{type}/{name}.cfg");
|
||||
}
|
||||
|
||||
public static SmallBulkEntry[] LoadEntries( string path )
|
||||
{
|
||||
path = Path.Combine( Core.BaseDirectory, path );
|
||||
|
||||
List<SmallBulkEntry> list = new List<SmallBulkEntry>();
|
||||
|
||||
if ( File.Exists( path ) )
|
||||
{
|
||||
using ( StreamReader ip = new StreamReader( path ) )
|
||||
{
|
||||
string line;
|
||||
|
||||
while ( (line = ip.ReadLine()) != null )
|
||||
{
|
||||
if ( line.Length == 0 || line.StartsWith( "#" ) )
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
string[] split = line.Split( '\t' );
|
||||
|
||||
if ( split.Length >= 2 )
|
||||
{
|
||||
Type type = ScriptCompiler.FindTypeByName( split[0] );
|
||||
int graphic = Utility.ToInt32( split[split.Length - 1] );
|
||||
|
||||
if ( type != null && graphic > 0 )
|
||||
list.Add( new SmallBulkEntry( type, graphic < 0x4000 ? 1020000 + graphic : 1078872 + graphic, graphic ) );
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
195
Projects/Scripts/Engines/BulkOrders/SmallSmithBOD.cs
Normal file
195
Projects/Scripts/Engines/BulkOrders/SmallSmithBOD.cs
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.Craft;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class SmallSmithBOD : SmallBOD
|
||||
{
|
||||
public static double[] m_BlacksmithMaterialChances =
|
||||
{
|
||||
0.501953125, // None
|
||||
0.250000000, // Dull Copper
|
||||
0.125000000, // Shadow Iron
|
||||
0.062500000, // Copper
|
||||
0.031250000, // Bronze
|
||||
0.015625000, // Gold
|
||||
0.007812500, // Agapite
|
||||
0.003906250, // Verite
|
||||
0.001953125 // Valorite
|
||||
};
|
||||
|
||||
private SmallSmithBOD(SmallBulkEntry entry, BulkMaterialType mat, int amountMax, bool reqExceptional)
|
||||
: base(0x44E, 0, amountMax, entry.Type, entry.Number, entry.Graphic, reqExceptional, mat)
|
||||
{
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public SmallSmithBOD()
|
||||
{
|
||||
bool useMaterials = Utility.RandomBool();
|
||||
|
||||
SmallBulkEntry[] entries = useMaterials ? SmallBulkEntry.BlacksmithArmor :
|
||||
SmallBulkEntry.BlacksmithWeapons;
|
||||
|
||||
if (entries.Length <= 0)
|
||||
return;
|
||||
|
||||
int hue = 0x44E;
|
||||
int amountMax = Utility.RandomList(10, 15, 20);
|
||||
|
||||
BulkMaterialType material = useMaterials ? GetRandomMaterial(BulkMaterialType.DullCopper, m_BlacksmithMaterialChances)
|
||||
: BulkMaterialType.None;
|
||||
|
||||
bool reqExceptional = Utility.RandomBool() || material == BulkMaterialType.None;
|
||||
|
||||
SmallBulkEntry entry = entries[Utility.Random(entries.Length)];
|
||||
|
||||
Hue = hue;
|
||||
AmountMax = amountMax;
|
||||
Type = entry.Type;
|
||||
Number = entry.Number;
|
||||
Graphic = entry.Graphic;
|
||||
RequireExceptional = reqExceptional;
|
||||
Material = material;
|
||||
}
|
||||
|
||||
public SmallSmithBOD(int amountCur, int amountMax, Type type, int number, int graphic, bool reqExceptional,
|
||||
BulkMaterialType mat) : base(0x44E, amountCur, amountMax, type, number, graphic, reqExceptional, mat)
|
||||
{
|
||||
}
|
||||
|
||||
public SmallSmithBOD(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int ComputeFame() => SmithRewardCalculator.Instance.ComputeFame(this);
|
||||
|
||||
public override int ComputeGold() => SmithRewardCalculator.Instance.ComputeGold(this);
|
||||
|
||||
public override RewardGroup GetRewardGroup() =>
|
||||
SmithRewardCalculator.Instance.LookupRewards(SmithRewardCalculator.Instance.ComputePoints(this));
|
||||
|
||||
public static SmallSmithBOD CreateRandomFor(Mobile m)
|
||||
{
|
||||
bool useMaterials = Utility.RandomBool();
|
||||
|
||||
SmallBulkEntry[] entries = useMaterials ? SmallBulkEntry.BlacksmithArmor :
|
||||
SmallBulkEntry.BlacksmithWeapons;
|
||||
|
||||
if (entries.Length <= 0)
|
||||
return null;
|
||||
|
||||
double theirSkill = m.Skills.Blacksmith.Base;
|
||||
int amountMax;
|
||||
|
||||
if (theirSkill >= 70.1)
|
||||
amountMax = Utility.RandomList(10, 15, 20, 20);
|
||||
else if (theirSkill >= 50.1)
|
||||
amountMax = Utility.RandomList(10, 15, 15, 20);
|
||||
else
|
||||
amountMax = Utility.RandomList(10, 10, 15, 20);
|
||||
|
||||
BulkMaterialType material = BulkMaterialType.None;
|
||||
|
||||
if (useMaterials && theirSkill >= 70.1)
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
BulkMaterialType check = GetRandomMaterial(BulkMaterialType.DullCopper, m_BlacksmithMaterialChances);
|
||||
double skillReq = 0.0;
|
||||
|
||||
switch (check)
|
||||
{
|
||||
case BulkMaterialType.DullCopper:
|
||||
skillReq = 65.0;
|
||||
break;
|
||||
case BulkMaterialType.ShadowIron:
|
||||
skillReq = 70.0;
|
||||
break;
|
||||
case BulkMaterialType.Copper:
|
||||
skillReq = 75.0;
|
||||
break;
|
||||
case BulkMaterialType.Bronze:
|
||||
skillReq = 80.0;
|
||||
break;
|
||||
case BulkMaterialType.Gold:
|
||||
skillReq = 85.0;
|
||||
break;
|
||||
case BulkMaterialType.Agapite:
|
||||
skillReq = 90.0;
|
||||
break;
|
||||
case BulkMaterialType.Verite:
|
||||
skillReq = 95.0;
|
||||
break;
|
||||
case BulkMaterialType.Valorite:
|
||||
skillReq = 100.0;
|
||||
break;
|
||||
case BulkMaterialType.Spined:
|
||||
skillReq = 65.0;
|
||||
break;
|
||||
case BulkMaterialType.Horned:
|
||||
skillReq = 80.0;
|
||||
break;
|
||||
case BulkMaterialType.Barbed:
|
||||
skillReq = 99.0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (theirSkill >= skillReq)
|
||||
{
|
||||
material = check;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double excChance = theirSkill >= 70.1 ? (theirSkill + 80.0) / 200.0 : 0.0;
|
||||
|
||||
bool reqExceptional = excChance > Utility.RandomDouble();
|
||||
|
||||
CraftSystem system = DefBlacksmithy.CraftSystem;
|
||||
|
||||
List<SmallBulkEntry> validEntries = new List<SmallBulkEntry>();
|
||||
|
||||
for (int i = 0; i < entries.Length; ++i)
|
||||
{
|
||||
CraftItem item = system.CraftItems.SearchFor(entries[i].Type);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
bool allRequiredSkills = true;
|
||||
double chance = item.GetSuccessChance(m, null, system, false, ref allRequiredSkills);
|
||||
|
||||
if (allRequiredSkills && chance >= 0.0)
|
||||
{
|
||||
if (reqExceptional)
|
||||
chance = item.GetExceptionalChance(system, chance, m);
|
||||
|
||||
if (chance > 0.0)
|
||||
validEntries.Add(entries[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validEntries.Count <= 0)
|
||||
return null;
|
||||
|
||||
SmallBulkEntry entry = validEntries[Utility.Random(validEntries.Count)];
|
||||
return new SmallSmithBOD(entry, material, amountMax, reqExceptional);
|
||||
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
191
Projects/Scripts/Engines/BulkOrders/SmallTailorBOD.cs
Normal file
191
Projects/Scripts/Engines/BulkOrders/SmallTailorBOD.cs
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.Craft;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class SmallTailorBOD : SmallBOD
|
||||
{
|
||||
public static double[] m_TailoringMaterialChances =
|
||||
{
|
||||
0.857421875, // None
|
||||
0.125000000, // Spined
|
||||
0.015625000, // Horned
|
||||
0.001953125 // Barbed
|
||||
};
|
||||
|
||||
private SmallTailorBOD(SmallBulkEntry entry, BulkMaterialType mat, int amountMax, bool reqExceptional)
|
||||
: base(0x483, 0, amountMax, entry.Type, entry.Number, entry.Graphic, reqExceptional, mat)
|
||||
{
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public SmallTailorBOD()
|
||||
{
|
||||
bool useMaterials = Utility.RandomBool();
|
||||
SmallBulkEntry[] entries = useMaterials ? SmallBulkEntry.TailorLeather : SmallBulkEntry.TailorCloth;
|
||||
|
||||
if (entries.Length <= 0)
|
||||
return;
|
||||
|
||||
int hue = 0x483;
|
||||
int amountMax = Utility.RandomList(10, 15, 20);
|
||||
|
||||
BulkMaterialType material = useMaterials ? GetRandomMaterial(BulkMaterialType.Spined, m_TailoringMaterialChances)
|
||||
: BulkMaterialType.None;
|
||||
|
||||
bool reqExceptional = Utility.RandomBool() || material == BulkMaterialType.None;
|
||||
SmallBulkEntry entry = entries[Utility.Random(entries.Length)];
|
||||
|
||||
Hue = hue;
|
||||
AmountMax = amountMax;
|
||||
Type = entry.Type;
|
||||
Number = entry.Number;
|
||||
Graphic = entry.Graphic;
|
||||
RequireExceptional = reqExceptional;
|
||||
Material = material;
|
||||
}
|
||||
|
||||
public SmallTailorBOD(int amountCur, int amountMax, Type type, int number, int graphic, bool reqExceptional,
|
||||
BulkMaterialType mat) : base(0x483, amountCur, amountMax, type, number, graphic, reqExceptional, mat)
|
||||
{
|
||||
}
|
||||
|
||||
public SmallTailorBOD(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int ComputeFame() => TailorRewardCalculator.Instance.ComputeFame(this);
|
||||
|
||||
public override int ComputeGold() => TailorRewardCalculator.Instance.ComputeGold(this);
|
||||
|
||||
public override RewardGroup GetRewardGroup() =>
|
||||
TailorRewardCalculator.Instance.LookupRewards(TailorRewardCalculator.Instance.ComputePoints(this));
|
||||
|
||||
public static SmallTailorBOD CreateRandomFor(Mobile m)
|
||||
{
|
||||
SmallBulkEntry[] entries;
|
||||
bool useMaterials = Utility.RandomBool();
|
||||
|
||||
double theirSkill = m.Skills.Tailoring.Base;
|
||||
|
||||
// Ugly, but the easiest leather BOD is Leather Cap which requires at least 6.2 skill.
|
||||
if (useMaterials && theirSkill >= 6.2)
|
||||
entries = SmallBulkEntry.TailorLeather;
|
||||
else
|
||||
entries = SmallBulkEntry.TailorCloth;
|
||||
|
||||
if (entries.Length > 0)
|
||||
{
|
||||
int amountMax;
|
||||
|
||||
if (theirSkill >= 70.1)
|
||||
amountMax = Utility.RandomList(10, 15, 20, 20);
|
||||
else if (theirSkill >= 50.1)
|
||||
amountMax = Utility.RandomList(10, 15, 15, 20);
|
||||
else
|
||||
amountMax = Utility.RandomList(10, 10, 15, 20);
|
||||
|
||||
BulkMaterialType material = BulkMaterialType.None;
|
||||
|
||||
if (useMaterials && theirSkill >= 70.1)
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
BulkMaterialType check = GetRandomMaterial(BulkMaterialType.Spined, m_TailoringMaterialChances);
|
||||
double skillReq = 0.0;
|
||||
|
||||
switch (check)
|
||||
{
|
||||
case BulkMaterialType.DullCopper:
|
||||
skillReq = 65.0;
|
||||
break;
|
||||
case BulkMaterialType.Bronze:
|
||||
skillReq = 80.0;
|
||||
break;
|
||||
case BulkMaterialType.Gold:
|
||||
skillReq = 85.0;
|
||||
break;
|
||||
case BulkMaterialType.Agapite:
|
||||
skillReq = 90.0;
|
||||
break;
|
||||
case BulkMaterialType.Verite:
|
||||
skillReq = 95.0;
|
||||
break;
|
||||
case BulkMaterialType.Valorite:
|
||||
skillReq = 100.0;
|
||||
break;
|
||||
case BulkMaterialType.Spined:
|
||||
skillReq = 65.0;
|
||||
break;
|
||||
case BulkMaterialType.Horned:
|
||||
skillReq = 80.0;
|
||||
break;
|
||||
case BulkMaterialType.Barbed:
|
||||
skillReq = 99.0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (theirSkill >= skillReq)
|
||||
{
|
||||
material = check;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double excChance = 0.0;
|
||||
|
||||
if (theirSkill >= 70.1)
|
||||
excChance = (theirSkill + 80.0) / 200.0;
|
||||
|
||||
bool reqExceptional = excChance > Utility.RandomDouble();
|
||||
|
||||
|
||||
CraftSystem system = DefTailoring.CraftSystem;
|
||||
|
||||
List<SmallBulkEntry> validEntries = new List<SmallBulkEntry>();
|
||||
|
||||
for (int i = 0; i < entries.Length; ++i)
|
||||
{
|
||||
CraftItem item = system.CraftItems.SearchFor(entries[i].Type);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
bool allRequiredSkills = true;
|
||||
double chance = item.GetSuccessChance(m, null, system, false, ref allRequiredSkills);
|
||||
|
||||
if (allRequiredSkills && chance >= 0.0)
|
||||
{
|
||||
if (reqExceptional)
|
||||
chance = item.GetExceptionalChance(system, chance, m);
|
||||
|
||||
if (chance > 0.0)
|
||||
validEntries.Add(entries[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validEntries.Count > 0)
|
||||
{
|
||||
SmallBulkEntry entry = validEntries[Utility.Random(validEntries.Count)];
|
||||
return new SmallTailorBOD(entry, material, amountMax, reqExceptional);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Projects/Scripts/Engines/CannedEvil/ChampionAltar.cs
Normal file
54
Projects/Scripts/Engines/CannedEvil/ChampionAltar.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public class ChampionAltar : PentagramAddon
|
||||
{
|
||||
private ChampionSpawn m_Spawn;
|
||||
|
||||
public ChampionAltar(ChampionSpawn spawn)
|
||||
{
|
||||
m_Spawn = spawn;
|
||||
}
|
||||
|
||||
public ChampionAltar(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
m_Spawn?.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Spawn);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Spawn = reader.ReadItem() as ChampionSpawn;
|
||||
|
||||
if (m_Spawn == null)
|
||||
Delete();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Projects/Scripts/Engines/CannedEvil/ChampionPlatform.cs
Normal file
85
Projects/Scripts/Engines/CannedEvil/ChampionPlatform.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public class ChampionPlatform : BaseAddon
|
||||
{
|
||||
private ChampionSpawn m_Spawn;
|
||||
|
||||
public ChampionPlatform(ChampionSpawn spawn)
|
||||
{
|
||||
m_Spawn = spawn;
|
||||
|
||||
for (int x = -2; x <= 2; ++x)
|
||||
for (int y = -2; y <= 2; ++y)
|
||||
AddComponent(0x750, x, y, -5);
|
||||
|
||||
for (int x = -1; x <= 1; ++x)
|
||||
for (int y = -1; y <= 1; ++y)
|
||||
AddComponent(0x750, x, y, 0);
|
||||
|
||||
for (int i = -1; i <= 1; ++i)
|
||||
{
|
||||
AddComponent(0x751, i, 2, 0);
|
||||
AddComponent(0x752, 2, i, 0);
|
||||
|
||||
AddComponent(0x753, i, -2, 0);
|
||||
AddComponent(0x754, -2, i, 0);
|
||||
}
|
||||
|
||||
AddComponent(0x759, -2, -2, 0);
|
||||
AddComponent(0x75A, 2, 2, 0);
|
||||
AddComponent(0x75B, -2, 2, 0);
|
||||
AddComponent(0x75C, 2, -2, 0);
|
||||
}
|
||||
|
||||
public ChampionPlatform(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddComponent(int id, int x, int y, int z)
|
||||
{
|
||||
AddonComponent ac = new AddonComponent(id);
|
||||
|
||||
ac.Hue = 0x497;
|
||||
|
||||
AddComponent(ac, x, y, z);
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
m_Spawn?.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Spawn);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Spawn = reader.ReadItem() as ChampionSpawn;
|
||||
|
||||
if (m_Spawn == null)
|
||||
Delete();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
Projects/Scripts/Engines/CannedEvil/ChampionSkull.cs
Normal file
89
Projects/Scripts/Engines/CannedEvil/ChampionSkull.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
using Server.Engines.CannedEvil;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class ChampionSkull : Item
|
||||
{
|
||||
private ChampionSkullType m_Type;
|
||||
|
||||
[Constructible]
|
||||
public ChampionSkull(ChampionSkullType type) : base(0x1AE1)
|
||||
{
|
||||
m_Type = type;
|
||||
LootType = LootType.Cursed;
|
||||
|
||||
// TODO: All hue values
|
||||
switch (type)
|
||||
{
|
||||
case ChampionSkullType.Power:
|
||||
Hue = 0x159;
|
||||
break;
|
||||
case ChampionSkullType.Venom:
|
||||
Hue = 0x172;
|
||||
break;
|
||||
case ChampionSkullType.Greed:
|
||||
Hue = 0x1EE;
|
||||
break;
|
||||
case ChampionSkullType.Death:
|
||||
Hue = 0x025;
|
||||
break;
|
||||
case ChampionSkullType.Pain:
|
||||
Hue = 0x035;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public ChampionSkull(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ChampionSkullType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
m_Type = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049479 + (int)m_Type;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1); // version
|
||||
|
||||
writer.Write((int)m_Type);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
m_Type = (ChampionSkullType)reader.ReadInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
if (LootType != LootType.Cursed)
|
||||
LootType = LootType.Cursed;
|
||||
|
||||
if (Insured)
|
||||
Insured = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
184
Projects/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs
Normal file
184
Projects/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public class ChampionSkullBrazier : AddonComponent
|
||||
{
|
||||
private Item m_Skull;
|
||||
private ChampionSkullType m_Type;
|
||||
|
||||
public ChampionSkullBrazier(ChampionSkullPlatform platform, ChampionSkullType type) : base(0x19BB)
|
||||
{
|
||||
Hue = 0x455;
|
||||
Light = LightType.Circle300;
|
||||
|
||||
Platform = platform;
|
||||
m_Type = type;
|
||||
}
|
||||
|
||||
public ChampionSkullBrazier(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ChampionSkullPlatform Platform{ get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ChampionSkullType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
m_Type = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Item Skull
|
||||
{
|
||||
get => m_Skull;
|
||||
set
|
||||
{
|
||||
m_Skull = value;
|
||||
Platform?.Validate();
|
||||
}
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049489 + (int)m_Type;
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
Platform?.Validate();
|
||||
|
||||
BeginSacrifice(from);
|
||||
}
|
||||
|
||||
public void BeginSacrifice(Mobile from)
|
||||
{
|
||||
if (Deleted)
|
||||
return;
|
||||
|
||||
if (m_Skull?.Deleted == true)
|
||||
Skull = null;
|
||||
|
||||
if (from.Map != Map || !from.InRange(GetWorldLocation(), 3))
|
||||
{
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
}
|
||||
else if (!Harrower.CanSpawn)
|
||||
{
|
||||
from.SendMessage("The harrower has already been spawned.");
|
||||
}
|
||||
else if (m_Skull == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1049485); // What would you like to sacrifice?
|
||||
from.Target = new SacrificeTarget(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049487, ""); // I already have my champions awakening skull!
|
||||
}
|
||||
}
|
||||
|
||||
public void EndSacrifice(Mobile from, ChampionSkull skull)
|
||||
{
|
||||
if (Deleted)
|
||||
return;
|
||||
|
||||
if (m_Skull?.Deleted == true)
|
||||
Skull = null;
|
||||
|
||||
if (from.Map != Map || !from.InRange(GetWorldLocation(), 3))
|
||||
{
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
}
|
||||
else if (!Harrower.CanSpawn)
|
||||
{
|
||||
from.SendMessage("The harrower has already been spawned.");
|
||||
}
|
||||
else if (skull == null)
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049488, ""); // That is not my champions awakening skull!
|
||||
}
|
||||
else if (m_Skull != null)
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049487, ""); // I already have my champions awakening skull!
|
||||
}
|
||||
else if (!skull.IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1049486); // You can only sacrifice items that are in your backpack!
|
||||
}
|
||||
else
|
||||
{
|
||||
if (skull.Type == Type)
|
||||
{
|
||||
skull.Movable = false;
|
||||
skull.MoveToWorld(GetWorldTop(), Map);
|
||||
|
||||
Skull = skull;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendLocalizedMessageTo(from, 1049488, ""); // That is not my champions awakening skull!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write((int)m_Type);
|
||||
writer.Write(Platform);
|
||||
writer.Write(m_Skull);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Type = (ChampionSkullType)reader.ReadInt();
|
||||
Platform = reader.ReadItem() as ChampionSkullPlatform;
|
||||
m_Skull = reader.ReadItem();
|
||||
|
||||
if (Platform == null)
|
||||
Delete();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Hue == 0x497)
|
||||
Hue = 0x455;
|
||||
|
||||
if (Light != LightType.Circle300)
|
||||
Light = LightType.Circle300;
|
||||
}
|
||||
|
||||
private class SacrificeTarget : Target
|
||||
{
|
||||
private ChampionSkullBrazier m_Brazier;
|
||||
|
||||
public SacrificeTarget(ChampionSkullBrazier brazier) : base(12, false, TargetFlags.None)
|
||||
{
|
||||
m_Brazier = brazier;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
m_Brazier.EndSacrifice(from, targeted as ChampionSkull);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
128
Projects/Scripts/Engines/CannedEvil/ChampionSkullPlatform.cs
Normal file
128
Projects/Scripts/Engines/CannedEvil/ChampionSkullPlatform.cs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public class ChampionSkullPlatform : BaseAddon
|
||||
{
|
||||
private ChampionSkullBrazier m_Power, m_Enlightenment, m_Venom, m_Pain, m_Greed, m_Death;
|
||||
|
||||
[Constructible]
|
||||
public ChampionSkullPlatform()
|
||||
{
|
||||
AddComponent(new AddonComponent(0x71A), -1, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 1, -1, -1);
|
||||
AddComponent(new AddonComponent(0x709), -1, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), 1, 0, -1);
|
||||
AddComponent(new AddonComponent(0x709), -1, 1, -1);
|
||||
AddComponent(new AddonComponent(0x709), 0, 1, -1);
|
||||
AddComponent(new AddonComponent(0x71B), 1, 1, -1);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 0, -1, 4);
|
||||
AddComponent(m_Power = new ChampionSkullBrazier(this, ChampionSkullType.Power), 0, -1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 1, -1, 4);
|
||||
AddComponent(m_Enlightenment = new ChampionSkullBrazier(this, ChampionSkullType.Enlightenment), 1, -1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), -1, 0, 4);
|
||||
AddComponent(m_Venom = new ChampionSkullBrazier(this, ChampionSkullType.Venom), -1, 0, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 1, 0, 4);
|
||||
AddComponent(m_Pain = new ChampionSkullBrazier(this, ChampionSkullType.Pain), 1, 0, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), -1, 1, 4);
|
||||
AddComponent(m_Greed = new ChampionSkullBrazier(this, ChampionSkullType.Greed), -1, 1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x50F), 0, 1, 4);
|
||||
AddComponent(m_Death = new ChampionSkullBrazier(this, ChampionSkullType.Death), 0, 1, 5);
|
||||
|
||||
AddonComponent comp = new LocalizedAddonComponent(0x20D2, 1049495);
|
||||
comp.Hue = 0x482;
|
||||
AddComponent(comp, 0, 0, 5);
|
||||
|
||||
comp = new LocalizedAddonComponent(0x0BCF, 1049496);
|
||||
comp.Hue = 0x482;
|
||||
AddComponent(comp, 0, 2, -7);
|
||||
|
||||
comp = new LocalizedAddonComponent(0x0BD0, 1049497);
|
||||
comp.Hue = 0x482;
|
||||
AddComponent(comp, 2, 0, -7);
|
||||
}
|
||||
|
||||
public ChampionSkullPlatform(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Validate(m_Power) && Validate(m_Enlightenment) && Validate(m_Venom) && Validate(m_Pain) &&
|
||||
Validate(m_Greed) && Validate(m_Death))
|
||||
{
|
||||
Mobile harrower = Harrower.Spawn(new Point3D(X, Y, Z + 6), Map);
|
||||
|
||||
if (harrower == null)
|
||||
return;
|
||||
|
||||
Clear(m_Power);
|
||||
Clear(m_Enlightenment);
|
||||
Clear(m_Venom);
|
||||
Clear(m_Pain);
|
||||
Clear(m_Greed);
|
||||
Clear(m_Death);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear(ChampionSkullBrazier brazier)
|
||||
{
|
||||
if (brazier != null)
|
||||
{
|
||||
Effects.SendBoltEffect(brazier);
|
||||
|
||||
brazier.Skull?.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Validate(ChampionSkullBrazier brazier)
|
||||
{
|
||||
return brazier?.Skull?.Deleted == false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Power);
|
||||
writer.Write(m_Enlightenment);
|
||||
writer.Write(m_Venom);
|
||||
writer.Write(m_Pain);
|
||||
writer.Write(m_Greed);
|
||||
writer.Write(m_Death);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Power = reader.ReadItem() as ChampionSkullBrazier;
|
||||
m_Enlightenment = reader.ReadItem() as ChampionSkullBrazier;
|
||||
m_Venom = reader.ReadItem() as ChampionSkullBrazier;
|
||||
m_Pain = reader.ReadItem() as ChampionSkullBrazier;
|
||||
m_Greed = reader.ReadItem() as ChampionSkullBrazier;
|
||||
m_Death = reader.ReadItem() as ChampionSkullBrazier;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Projects/Scripts/Engines/CannedEvil/ChampionSkullType.cs
Normal file
12
Projects/Scripts/Engines/CannedEvil/ChampionSkullType.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public enum ChampionSkullType
|
||||
{
|
||||
Power,
|
||||
Enlightenment,
|
||||
Venom,
|
||||
Pain,
|
||||
Greed,
|
||||
Death
|
||||
}
|
||||
}
|
||||
1245
Projects/Scripts/Engines/CannedEvil/ChampionSpawn.cs
Normal file
1245
Projects/Scripts/Engines/CannedEvil/ChampionSpawn.cs
Normal file
File diff suppressed because it is too large
Load diff
133
Projects/Scripts/Engines/CannedEvil/ChampionSpawnType.cs
Normal file
133
Projects/Scripts/Engines/CannedEvil/ChampionSpawnType.cs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public enum ChampionSpawnType
|
||||
{
|
||||
Abyss,
|
||||
Arachnid,
|
||||
ColdBlood,
|
||||
ForestLord,
|
||||
VerminHorde,
|
||||
UnholyTerror,
|
||||
SleepingDragon,
|
||||
Glade,
|
||||
Pestilence
|
||||
}
|
||||
|
||||
public class ChampionSpawnInfo
|
||||
{
|
||||
public ChampionSpawnInfo(string name, Type champion, string[] levelNames, Type[][] spawnTypes)
|
||||
{
|
||||
Name = name;
|
||||
Champion = champion;
|
||||
LevelNames = levelNames;
|
||||
SpawnTypes = spawnTypes;
|
||||
}
|
||||
|
||||
public string Name{ get; }
|
||||
|
||||
public Type Champion{ get; }
|
||||
|
||||
public Type[][] SpawnTypes{ get; }
|
||||
|
||||
public string[] LevelNames{ get; }
|
||||
|
||||
public static ChampionSpawnInfo[] Table{ get; } =
|
||||
{
|
||||
new ChampionSpawnInfo("Abyss", typeof(Semidar), new[] { "Foe", "Assassin", "Conqueror" }, new[] // Abyss
|
||||
{
|
||||
// Abyss
|
||||
new[] { typeof(GreaterMongbat), typeof(Imp) }, // Level 1
|
||||
new[] { typeof(Gargoyle), typeof(Harpy) }, // Level 2
|
||||
new[] { typeof(FireGargoyle), typeof(StoneGargoyle) }, // Level 3
|
||||
new[] { typeof(Daemon), typeof(Succubus) } // Level 4
|
||||
}),
|
||||
new ChampionSpawnInfo("Arachnid", typeof(Mephitis), new[] { "Bane", "Killer", "Vanquisher" }, new[] // Arachnid
|
||||
{
|
||||
// Arachnid
|
||||
new[] { typeof(Scorpion), typeof(GiantSpider) }, // Level 1
|
||||
new[] { typeof(TerathanDrone), typeof(TerathanWarrior) }, // Level 2
|
||||
new[] { typeof(DreadSpider), typeof(TerathanMatriarch) }, // Level 3
|
||||
new[] { typeof(PoisonElemental), typeof(TerathanAvenger) } // Level 4
|
||||
}),
|
||||
new ChampionSpawnInfo("Cold Blood", typeof(Rikktor), new[] { "Blight", "Slayer", "Destroyer" },
|
||||
new[] // Cold Blood
|
||||
{
|
||||
// Cold Blood
|
||||
new[] { typeof(Lizardman), typeof(Snake) }, // Level 1
|
||||
new[] { typeof(LavaLizard), typeof(OphidianWarrior) }, // Level 2
|
||||
new[] { typeof(Drake), typeof(OphidianArchmage) }, // Level 3
|
||||
new[] { typeof(Dragon), typeof(OphidianKnight) } // Level 4
|
||||
}),
|
||||
new ChampionSpawnInfo("Forest Lord", typeof(LordOaks), new[] { "Enemy", "Curse", "Slaughterer" },
|
||||
new[] // Forest Lord
|
||||
{
|
||||
// Forest Lord
|
||||
new[] { typeof(Pixie), typeof(ShadowWisp) }, // Level 1
|
||||
new[] { typeof(Kirin), typeof(Wisp) }, // Level 2
|
||||
new[] { typeof(Centaur), typeof(Unicorn) }, // Level 3
|
||||
new[] { typeof(EtherealWarrior), typeof(SerpentineDragon) } // Level 4
|
||||
}),
|
||||
new ChampionSpawnInfo("Vermin Horde", typeof(Barracoon), new[] { "Adversary", "Subjugator", "Eradicator" },
|
||||
new[] // Vermin Horde
|
||||
{
|
||||
// Vermin Horde
|
||||
new[] { typeof(GiantRat), typeof(Slime) }, // Level 1
|
||||
new[] { typeof(DireWolf), typeof(Ratman) }, // Level 2
|
||||
new[] { typeof(HellHound), typeof(RatmanMage) }, // Level 3
|
||||
new[] { typeof(RatmanArcher), typeof(SilverSerpent) } // Level 4
|
||||
}),
|
||||
new ChampionSpawnInfo("Unholy Terror", typeof(Neira), new[] { "Scourge", "Punisher", "Nemesis" },
|
||||
new[] // Unholy Terror
|
||||
{
|
||||
// Unholy Terror
|
||||
Core.AOS
|
||||
? new[]
|
||||
{
|
||||
typeof(Bogle), typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith)
|
||||
} // Level 1 (Pre-AoS)
|
||||
: new[] { typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) }, // Level 1
|
||||
|
||||
new[] { typeof(BoneMagi), typeof(Mummy), typeof(SkeletalMage) }, // Level 2
|
||||
new[] { typeof(BoneKnight), typeof(Lich), typeof(SkeletalKnight) }, // Level 3
|
||||
new[] { typeof(LichLord), typeof(RottingCorpse) } // Level 4
|
||||
}),
|
||||
new ChampionSpawnInfo("Sleeping Dragon", typeof(Serado), new[] { "Rival", "Challenger", "Antagonist" }, new[]
|
||||
{
|
||||
// Unholy Terror
|
||||
new[] { typeof(DeathwatchBeetleHatchling), typeof(Lizardman) },
|
||||
new[] { typeof(DeathwatchBeetle), typeof(Kappa) },
|
||||
new[] { typeof(LesserHiryu), typeof(RevenantLion) },
|
||||
new[] { typeof(Hiryu), typeof(Oni) }
|
||||
}),
|
||||
new ChampionSpawnInfo("Glade", typeof(Twaulo), new[] { "Banisher", "Enforcer", "Eradicator" }, new[]
|
||||
{
|
||||
// Glade
|
||||
new[] { typeof(Pixie), typeof(ShadowWisp) },
|
||||
new[] { typeof(Centaur), typeof(MLDryad) },
|
||||
new[] { typeof(Satyr), typeof(CuSidhe) },
|
||||
new[] { typeof(FeralTreefellow), typeof(RagingGrizzlyBear) }
|
||||
}),
|
||||
new ChampionSpawnInfo("The Corrupt", typeof(Ilhenir), new[] { "Cleanser", "Expunger", "Depurator" }, new[]
|
||||
{
|
||||
// Unholy Terror
|
||||
new[] { typeof(PlagueSpawn), typeof(Bogling) },
|
||||
new[] { typeof(PlagueBeast), typeof(BogThing) },
|
||||
new[] { typeof(PlagueBeastLord), typeof(InterredGrizzle) },
|
||||
new[] { typeof(FetidEssence), typeof(PestilentBandage) }
|
||||
})
|
||||
};
|
||||
|
||||
public static ChampionSpawnInfo GetInfo(ChampionSpawnType type)
|
||||
{
|
||||
int v = (int)type;
|
||||
|
||||
if (v < 0 || v >= Table.Length)
|
||||
v = 0;
|
||||
|
||||
return Table[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Projects/Scripts/Engines/CannedEvil/HarrowerGate.cs
Normal file
56
Projects/Scripts/Engines/CannedEvil/HarrowerGate.cs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
public class HarrowerGate : Moongate
|
||||
{
|
||||
private Mobile m_Harrower;
|
||||
|
||||
public HarrowerGate(Mobile harrower, Point3D loc, Map map, Point3D targLoc, Map targMap) : base(targLoc, targMap)
|
||||
{
|
||||
m_Harrower = harrower;
|
||||
|
||||
Dispellable = false;
|
||||
ItemID = 0x1FD4;
|
||||
Light = LightType.Circle300;
|
||||
|
||||
MoveToWorld(loc, map);
|
||||
}
|
||||
|
||||
public HarrowerGate(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049498; // dark moongate
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Harrower);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Harrower = reader.ReadMobile();
|
||||
|
||||
if (m_Harrower == null)
|
||||
Delete();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Light != LightType.Circle300)
|
||||
Light = LightType.Circle300;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Projects/Scripts/Engines/CannedEvil/RestartTimer.cs
Normal file
20
Projects/Scripts/Engines/CannedEvil/RestartTimer.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public class RestartTimer : Timer
|
||||
{
|
||||
private ChampionSpawn m_Spawn;
|
||||
|
||||
public RestartTimer(ChampionSpawn spawn, TimeSpan delay) : base(delay)
|
||||
{
|
||||
m_Spawn = spawn;
|
||||
Priority = TimerPriority.FiveSeconds;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Spawn.EndRestart();
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Projects/Scripts/Engines/CannedEvil/SliceTimer.cs
Normal file
20
Projects/Scripts/Engines/CannedEvil/SliceTimer.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public class SliceTimer : Timer
|
||||
{
|
||||
private ChampionSpawn m_Spawn;
|
||||
|
||||
public SliceTimer(ChampionSpawn spawn) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
|
||||
{
|
||||
m_Spawn = spawn;
|
||||
Priority = TimerPriority.OneSecond;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Spawn.OnSlice();
|
||||
}
|
||||
}
|
||||
}
|
||||
99
Projects/Scripts/Engines/CannedEvil/StarRoomGate.cs
Normal file
99
Projects/Scripts/Engines/CannedEvil/StarRoomGate.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class StarRoomGate : Moongate
|
||||
{
|
||||
private bool m_Decays;
|
||||
private DateTime m_DecayTime;
|
||||
private Timer m_Timer;
|
||||
|
||||
[Constructible]
|
||||
public StarRoomGate(Point3D loc, Map map, bool decays) : this(decays)
|
||||
{
|
||||
MoveToWorld(loc, map);
|
||||
Effects.PlaySound(loc, map, 0x20E);
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public StarRoomGate(bool decays = false) : base(new Point3D(5143, 1774, 0), Map.Felucca)
|
||||
{
|
||||
Dispellable = false;
|
||||
ItemID = 0x1FD4;
|
||||
|
||||
if (decays)
|
||||
{
|
||||
m_Decays = true;
|
||||
m_DecayTime = DateTime.UtcNow + TimeSpan.FromMinutes(2.0);
|
||||
|
||||
m_Timer = new InternalTimer(this, m_DecayTime);
|
||||
m_Timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public StarRoomGate(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1049498; // dark moongate
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
m_Timer?.Stop();
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Decays);
|
||||
|
||||
if (m_Decays)
|
||||
writer.WriteDeltaTime(m_DecayTime);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Decays = reader.ReadBool();
|
||||
|
||||
if (m_Decays)
|
||||
{
|
||||
m_DecayTime = reader.ReadDeltaTime();
|
||||
|
||||
m_Timer = new InternalTimer(this, m_DecayTime);
|
||||
m_Timer.Start();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Item m_Item;
|
||||
|
||||
public InternalTimer(Item item, DateTime end) : base(end - DateTime.UtcNow)
|
||||
{
|
||||
m_Item = item;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
448
Projects/Scripts/Engines/Chat/Channel.cs
Normal file
448
Projects/Scripts/Engines/Chat/Channel.cs
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.Chat
|
||||
{
|
||||
public class Channel
|
||||
{
|
||||
private string m_Name;
|
||||
private string m_Password;
|
||||
private List<ChatUser> m_Users, m_Banned, m_Moderators, m_Voices;
|
||||
private bool m_VoiceRestricted;
|
||||
|
||||
public Channel(string name)
|
||||
{
|
||||
m_Name = name;
|
||||
|
||||
m_Users = new List<ChatUser>();
|
||||
m_Banned = new List<ChatUser>();
|
||||
m_Moderators = new List<ChatUser>();
|
||||
m_Voices = new List<ChatUser>();
|
||||
}
|
||||
|
||||
public Channel(string name, string password) : this(name)
|
||||
{
|
||||
m_Password = password;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => m_Name;
|
||||
set
|
||||
{
|
||||
SendCommand(ChatCommand.RemoveChannel, m_Name);
|
||||
m_Name = value;
|
||||
SendCommand(ChatCommand.AddChannel, m_Name);
|
||||
SendCommand(ChatCommand.JoinedChannel, m_Name);
|
||||
}
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get => m_Password;
|
||||
set
|
||||
{
|
||||
string newValue = null;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
newValue = value.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(newValue))
|
||||
newValue = null;
|
||||
}
|
||||
|
||||
m_Password = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public bool VoiceRestricted
|
||||
{
|
||||
get => m_VoiceRestricted;
|
||||
set
|
||||
{
|
||||
m_VoiceRestricted = value;
|
||||
|
||||
if (value)
|
||||
SendMessage(56); // From now on, only moderators will have speaking privileges in this conference by default.
|
||||
else
|
||||
SendMessage(55); // From now on, everyone in the conference will have speaking privileges by default.
|
||||
}
|
||||
}
|
||||
|
||||
public bool AlwaysAvailable{ get; set; }
|
||||
|
||||
public static List<Channel> Channels{ get; } = new List<Channel>();
|
||||
|
||||
public bool Contains(ChatUser user)
|
||||
{
|
||||
return m_Users.Contains(user);
|
||||
}
|
||||
|
||||
public bool IsBanned(ChatUser user)
|
||||
{
|
||||
return m_Banned.Contains(user);
|
||||
}
|
||||
|
||||
public bool CanTalk(ChatUser user)
|
||||
{
|
||||
return !m_VoiceRestricted || m_Voices.Contains(user) || m_Moderators.Contains(user);
|
||||
}
|
||||
|
||||
public bool IsModerator(ChatUser user)
|
||||
{
|
||||
return m_Moderators.Contains(user);
|
||||
}
|
||||
|
||||
public bool IsVoiced(ChatUser user)
|
||||
{
|
||||
return m_Voices.Contains(user);
|
||||
}
|
||||
|
||||
public bool ValidatePassword(string password)
|
||||
{
|
||||
return m_Password == null || Insensitive.Equals(m_Password, password);
|
||||
}
|
||||
|
||||
public bool ValidateModerator(ChatUser user)
|
||||
{
|
||||
if (user != null && !IsModerator(user))
|
||||
{
|
||||
user.SendMessage(29); // You must have operator status to do this.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ValidateAccess(ChatUser from, ChatUser target)
|
||||
{
|
||||
if (from == null || target == null || from.Mobile.AccessLevel >= target.Mobile.AccessLevel)
|
||||
return true;
|
||||
|
||||
from.Mobile.SendMessage("Your access level is too low to do this.");
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public bool AddUser(ChatUser user, string password = null)
|
||||
{
|
||||
if (Contains(user))
|
||||
{
|
||||
user.SendMessage(46, m_Name); // You are already in the conference '%1'.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsBanned(user))
|
||||
{
|
||||
user.SendMessage(64); // You have been banned from this conference.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidatePassword(password))
|
||||
{
|
||||
user.SendMessage(34); // That is not the correct password.
|
||||
return false;
|
||||
}
|
||||
|
||||
user.CurrentChannel?.RemoveUser(user); // Remove them from their current channel first
|
||||
|
||||
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.JoinedChannel, m_Name);
|
||||
|
||||
SendCommand(ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username);
|
||||
|
||||
m_Users.Add(user);
|
||||
user.CurrentChannel = this;
|
||||
|
||||
if (user.Mobile.AccessLevel >= AccessLevel.GameMaster || !AlwaysAvailable && m_Users.Count == 1)
|
||||
AddModerator(user);
|
||||
|
||||
SendUsersTo(user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveUser(ChatUser user)
|
||||
{
|
||||
if (Contains(user))
|
||||
{
|
||||
m_Users.Remove(user);
|
||||
user.CurrentChannel = null;
|
||||
|
||||
if (m_Moderators.Contains(user))
|
||||
m_Moderators.Remove(user);
|
||||
|
||||
if (m_Voices.Contains(user))
|
||||
m_Voices.Remove(user);
|
||||
|
||||
SendCommand(ChatCommand.RemoveUserFromChannel, user, user.Username);
|
||||
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.LeaveChannel);
|
||||
|
||||
if (m_Users.Count == 0 && !AlwaysAvailable)
|
||||
RemoveChannel(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBan(ChatUser user, ChatUser moderator = null)
|
||||
{
|
||||
if (!ValidateModerator(moderator) || !ValidateAccess(moderator, user))
|
||||
return;
|
||||
|
||||
if (!m_Banned.Contains(user))
|
||||
m_Banned.Add(user);
|
||||
|
||||
Kick(user, moderator, true);
|
||||
}
|
||||
|
||||
public void RemoveBan(ChatUser user)
|
||||
{
|
||||
if (m_Banned.Contains(user))
|
||||
m_Banned.Remove(user);
|
||||
}
|
||||
|
||||
public void Kick(ChatUser user, ChatUser moderator = null)
|
||||
{
|
||||
Kick(user, moderator, false);
|
||||
}
|
||||
|
||||
public void Kick(ChatUser user, ChatUser moderator, bool wasBanned)
|
||||
{
|
||||
if (!ValidateModerator(moderator) || !ValidateAccess(moderator, user))
|
||||
return;
|
||||
|
||||
if (Contains(user))
|
||||
{
|
||||
if (moderator != null)
|
||||
{
|
||||
if (wasBanned)
|
||||
user.SendMessage(63,
|
||||
moderator.Username); // %1, a conference moderator, has banned you from the conference.
|
||||
else
|
||||
user.SendMessage(45,
|
||||
moderator.Username); // %1, a conference moderator, has kicked you out of the conference.
|
||||
}
|
||||
|
||||
RemoveUser(user);
|
||||
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.AddUserToChannel,
|
||||
user.GetColorCharacter() + user.Username);
|
||||
|
||||
SendMessage(44, user.Username); // %1 has been kicked out of the conference.
|
||||
}
|
||||
|
||||
if (wasBanned)
|
||||
moderator?.SendMessage(62, user.Username); // You are banning %1 from this conference.
|
||||
}
|
||||
|
||||
public void AddVoiced(ChatUser user, ChatUser moderator = null)
|
||||
{
|
||||
if (!ValidateModerator(moderator))
|
||||
return;
|
||||
|
||||
if (!IsBanned(user) && !IsModerator(user) && !IsVoiced(user))
|
||||
{
|
||||
m_Voices.Add(user);
|
||||
|
||||
if (moderator != null)
|
||||
user.SendMessage(54,
|
||||
moderator
|
||||
.Username); // %1, a conference moderator, has granted you speaking privileges in this conference.
|
||||
|
||||
SendMessage(52, user, user.Username); // %1 now has speaking privileges in this conference.
|
||||
SendCommand(ChatCommand.AddUserToChannel, user, user.GetColorCharacter() + user.Username);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveVoiced(ChatUser user, ChatUser moderator)
|
||||
{
|
||||
if (!ValidateModerator(moderator) || !ValidateAccess(moderator, user))
|
||||
return;
|
||||
|
||||
if (!IsModerator(user) && IsVoiced(user))
|
||||
{
|
||||
m_Voices.Remove(user);
|
||||
|
||||
if (moderator != null)
|
||||
user.SendMessage(53,
|
||||
moderator
|
||||
.Username); // %1, a conference moderator, has removed your speaking privileges for this conference.
|
||||
|
||||
SendMessage(51, user, user.Username); // %1 no longer has speaking privileges in this conference.
|
||||
SendCommand(ChatCommand.AddUserToChannel, user, user.GetColorCharacter() + user.Username);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddModerator(ChatUser user, ChatUser moderator = null)
|
||||
{
|
||||
if (!ValidateModerator(moderator))
|
||||
return;
|
||||
|
||||
if (IsBanned(user) || IsModerator(user))
|
||||
return;
|
||||
|
||||
if (IsVoiced(user))
|
||||
m_Voices.Remove(user);
|
||||
|
||||
m_Moderators.Add(user);
|
||||
|
||||
if (moderator != null)
|
||||
user.SendMessage(50, moderator.Username); // %1 has made you a conference moderator.
|
||||
|
||||
SendMessage(48, user, user.Username); // %1 is now a conference moderator.
|
||||
SendCommand(ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username);
|
||||
}
|
||||
|
||||
public void RemoveModerator(ChatUser user, ChatUser moderator = null)
|
||||
{
|
||||
if (!ValidateModerator(moderator) || !ValidateAccess(moderator, user))
|
||||
return;
|
||||
|
||||
if (IsModerator(user))
|
||||
{
|
||||
m_Moderators.Remove(user);
|
||||
|
||||
if (moderator != null)
|
||||
user.SendMessage(49, moderator.Username); // %1 has removed you from the list of conference moderators.
|
||||
|
||||
SendMessage(47, user, user.Username); // %1 is no longer a conference moderator.
|
||||
SendCommand(ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendMessage(int number, string param1 = null)
|
||||
{
|
||||
SendMessage(number, null, param1);
|
||||
}
|
||||
|
||||
public void SendMessage(int number, ChatUser initiator, string param1 = null, string param2 = null)
|
||||
{
|
||||
for (int i = 0; i < m_Users.Count; ++i)
|
||||
{
|
||||
ChatUser user = m_Users[i];
|
||||
|
||||
if (user == initiator)
|
||||
continue;
|
||||
|
||||
if (user.CheckOnline())
|
||||
user.SendMessage(number, param1, param2);
|
||||
else if (!Contains(user))
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendIgnorableMessage(int number, ChatUser from, string param1, string param2)
|
||||
{
|
||||
for (int i = 0; i < m_Users.Count; ++i)
|
||||
{
|
||||
ChatUser user = m_Users[i];
|
||||
|
||||
if (user.IsIgnored(from))
|
||||
continue;
|
||||
|
||||
if (user.CheckOnline())
|
||||
user.SendMessage(number, from.Mobile, param1, param2);
|
||||
else if (!Contains(user))
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendCommand(ChatCommand command, string param1 = null, string param2 = null)
|
||||
{
|
||||
SendCommand(command, null, param1, param2);
|
||||
}
|
||||
|
||||
public void SendCommand(ChatCommand command, ChatUser initiator, string param1 = null, string param2 = null)
|
||||
{
|
||||
for (int i = 0; i < m_Users.Count; ++i)
|
||||
{
|
||||
ChatUser user = m_Users[i];
|
||||
|
||||
if (user == initiator)
|
||||
continue;
|
||||
|
||||
if (user.CheckOnline())
|
||||
ChatSystem.SendCommandTo(user.Mobile, command, param1, param2);
|
||||
else if (!Contains(user))
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendUsersTo(ChatUser to)
|
||||
{
|
||||
for (int i = 0; i < m_Users.Count; ++i)
|
||||
{
|
||||
ChatUser user = m_Users[i];
|
||||
|
||||
ChatSystem.SendCommandTo(to.Mobile, ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendChannelsTo(ChatUser user)
|
||||
{
|
||||
for (int i = 0; i < Channels.Count; ++i)
|
||||
{
|
||||
Channel channel = Channels[i];
|
||||
|
||||
if (!channel.IsBanned(user))
|
||||
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.AddChannel, channel.Name, "0");
|
||||
}
|
||||
}
|
||||
|
||||
public static Channel AddChannel(string name, string password = null)
|
||||
{
|
||||
Channel channel = FindChannelByName(name);
|
||||
|
||||
if (channel == null)
|
||||
{
|
||||
channel = new Channel(name, password);
|
||||
Channels.Add(channel);
|
||||
}
|
||||
|
||||
ChatUser.GlobalSendCommand(ChatCommand.AddChannel, name, "0");
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
public static void RemoveChannel(string name)
|
||||
{
|
||||
RemoveChannel(FindChannelByName(name));
|
||||
}
|
||||
|
||||
public static void RemoveChannel(Channel channel)
|
||||
{
|
||||
if (channel == null)
|
||||
return;
|
||||
|
||||
if (Channels.Contains(channel) && channel.m_Users.Count == 0)
|
||||
{
|
||||
ChatUser.GlobalSendCommand(ChatCommand.RemoveChannel, channel.Name);
|
||||
|
||||
channel.m_Moderators.Clear();
|
||||
channel.m_Voices.Clear();
|
||||
|
||||
Channels.Remove(channel);
|
||||
}
|
||||
}
|
||||
|
||||
public static Channel FindChannelByName(string name)
|
||||
{
|
||||
for (int i = 0; i < Channels.Count; ++i)
|
||||
{
|
||||
Channel channel = Channels[i];
|
||||
|
||||
if (channel.m_Name == name)
|
||||
return channel;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
AddStaticChannel("Newbie Help");
|
||||
}
|
||||
|
||||
public static void AddStaticChannel(string name)
|
||||
{
|
||||
AddChannel(name).AlwaysAvailable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
150
Projects/Scripts/Engines/Chat/Chat.cs
Normal file
150
Projects/Scripts/Engines/Chat/Chat.cs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Server.Accounting;
|
||||
using Server.Misc;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.Chat
|
||||
{
|
||||
public class ChatSystem
|
||||
{
|
||||
public static bool Enabled{ get; set; } = true;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
PacketHandlers.Register(0xB5, 0x40, true, OpenChatWindowRequest);
|
||||
PacketHandlers.Register(0xB3, 0, true, ChatAction);
|
||||
}
|
||||
|
||||
public static void SendCommandTo(Mobile to, ChatCommand type, string param1 = null, string param2 = null)
|
||||
{
|
||||
to?.Send(new ChatMessagePacket(null, (int)type + 20, param1, param2));
|
||||
}
|
||||
|
||||
public static void OpenChatWindowRequest(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
Mobile from = state.Mobile;
|
||||
|
||||
if (!Enabled)
|
||||
{
|
||||
from.SendMessage("The chat system has been disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
pvSrc.Seek(2, SeekOrigin.Begin);
|
||||
string chatName = pvSrc.ReadUnicodeStringSafe((0x40 - 2) >> 1).Trim();
|
||||
|
||||
Account acct = state.Account as Account;
|
||||
|
||||
string accountChatName = null;
|
||||
|
||||
if (acct != null)
|
||||
accountChatName = acct.GetTag("ChatName");
|
||||
|
||||
accountChatName = accountChatName?.Trim();
|
||||
|
||||
if (!string.IsNullOrEmpty(accountChatName))
|
||||
{
|
||||
if (chatName.Length > 0 && chatName != accountChatName)
|
||||
from.SendMessage("You cannot change chat nickname once it has been set.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chatName.Length == 0)
|
||||
{
|
||||
SendCommandTo(from, ChatCommand.AskNewNickname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NameVerification.Validate(chatName, 2, 31, true, true, true, 0, NameVerification.SpaceDashPeriodQuote) &&
|
||||
chatName.ToLower().IndexOf("system") == -1)
|
||||
{
|
||||
// TODO: Optimize this search
|
||||
|
||||
foreach (Account checkAccount in Accounts.GetAccounts())
|
||||
{
|
||||
string existingName = checkAccount.GetTag("ChatName");
|
||||
|
||||
if (existingName != null)
|
||||
{
|
||||
existingName = existingName.Trim();
|
||||
|
||||
if (Insensitive.Equals(existingName, chatName))
|
||||
{
|
||||
from.SendMessage("Nickname already in use.");
|
||||
SendCommandTo(from, ChatCommand.AskNewNickname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accountChatName = chatName;
|
||||
|
||||
acct?.AddTag("ChatName", chatName);
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(501173); // That name is disallowed.
|
||||
SendCommandTo(from, ChatCommand.AskNewNickname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SendCommandTo(from, ChatCommand.OpenChatWindow, accountChatName);
|
||||
ChatUser.AddChatUser(from);
|
||||
}
|
||||
|
||||
public static ChatUser SearchForUser(ChatUser from, string name)
|
||||
{
|
||||
ChatUser user = ChatUser.GetChatUser(name);
|
||||
|
||||
if (user == null)
|
||||
from.SendMessage(32, name); // There is no player named '%1'.
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static void ChatAction(NetState state, PacketReader pvSrc)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Mobile from = state.Mobile;
|
||||
ChatUser user = ChatUser.GetChatUser(from);
|
||||
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
string lang = pvSrc.ReadStringSafe(4);
|
||||
int actionID = pvSrc.ReadInt16();
|
||||
string param = pvSrc.ReadUnicodeString();
|
||||
|
||||
ChatActionHandler handler = ChatActionHandlers.GetHandler(actionID);
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
Channel channel = user.CurrentChannel;
|
||||
|
||||
if (handler.RequireConference && channel == null)
|
||||
user.SendMessage(31); /* You must be in a conference to do this.
|
||||
* To join a conference, select one from the Conference menu.
|
||||
*/
|
||||
else if (handler.RequireModerator && !user.IsModerator)
|
||||
user.SendMessage(29); // You must have operator status to do this.
|
||||
else
|
||||
handler.Callback(user, channel, param);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Client: {0}: Unknown chat action 0x{1:X}: {2}", state, actionID, param);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Projects/Scripts/Engines/Chat/ChatActionHandler.cs
Normal file
20
Projects/Scripts/Engines/Chat/ChatActionHandler.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
namespace Server.Engines.Chat
|
||||
{
|
||||
public delegate void OnChatAction(ChatUser from, Channel channel, string param);
|
||||
|
||||
public class ChatActionHandler
|
||||
{
|
||||
public ChatActionHandler(bool requireModerator, bool requireConference, OnChatAction callback)
|
||||
{
|
||||
RequireModerator = requireModerator;
|
||||
RequireConference = requireConference;
|
||||
Callback = callback;
|
||||
}
|
||||
|
||||
public bool RequireModerator{ get; }
|
||||
|
||||
public bool RequireConference{ get; }
|
||||
|
||||
public OnChatAction Callback{ get; }
|
||||
}
|
||||
}
|
||||
358
Projects/Scripts/Engines/Chat/ChatActionHandlers.cs
Normal file
358
Projects/Scripts/Engines/Chat/ChatActionHandlers.cs
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
namespace Server.Engines.Chat
|
||||
{
|
||||
public class ChatActionHandlers
|
||||
{
|
||||
private static ChatActionHandler[] m_Handlers;
|
||||
|
||||
static ChatActionHandlers()
|
||||
{
|
||||
m_Handlers = new ChatActionHandler[0x100];
|
||||
|
||||
Register(0x41, true, true, ChangeChannelPassword);
|
||||
|
||||
Register(0x58, false, false, LeaveChat);
|
||||
|
||||
Register(0x61, false, true, ChannelMessage);
|
||||
Register(0x62, false, false, JoinChannel);
|
||||
Register(0x63, false, false, JoinNewChannel);
|
||||
Register(0x64, true, true, RenameChannel);
|
||||
Register(0x65, false, false, PrivateMessage);
|
||||
Register(0x66, false, false, AddIgnore);
|
||||
Register(0x67, false, false, RemoveIgnore);
|
||||
Register(0x68, false, false, ToggleIgnore);
|
||||
Register(0x69, true, true, AddVoice);
|
||||
Register(0x6A, true, true, RemoveVoice);
|
||||
Register(0x6B, true, true, ToggleVoice);
|
||||
Register(0x6C, true, true, AddModerator);
|
||||
Register(0x6D, true, true, RemoveModerator);
|
||||
Register(0x6E, true, true, ToggleModerator);
|
||||
Register(0x6F, false, false, AllowPrivateMessages);
|
||||
Register(0x70, false, false, DisallowPrivateMessages);
|
||||
Register(0x71, false, false, TogglePrivateMessages);
|
||||
Register(0x72, false, false, ShowCharacterName);
|
||||
Register(0x73, false, false, HideCharacterName);
|
||||
Register(0x74, false, false, ToggleCharacterName);
|
||||
Register(0x75, false, false, QueryWhoIs);
|
||||
Register(0x76, true, true, Kick);
|
||||
Register(0x77, true, true, EnableDefaultVoice);
|
||||
Register(0x78, true, true, DisableDefaultVoice);
|
||||
Register(0x79, true, true, ToggleDefaultVoice);
|
||||
Register(0x7A, false, true, EmoteMessage);
|
||||
}
|
||||
|
||||
public static void Register(int actionID, bool requireModerator, bool requireConference, OnChatAction callback)
|
||||
{
|
||||
if (actionID >= 0 && actionID < m_Handlers.Length)
|
||||
m_Handlers[actionID] = new ChatActionHandler(requireModerator, requireConference, callback);
|
||||
}
|
||||
|
||||
public static ChatActionHandler GetHandler(int actionID)
|
||||
{
|
||||
if (actionID >= 0 && actionID < m_Handlers.Length)
|
||||
return m_Handlers[actionID];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void ChannelMessage(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
if (channel.CanTalk(from))
|
||||
channel.SendIgnorableMessage(57, from, from.GetColorCharacter() + from.Username, param); // %1: %2
|
||||
else
|
||||
from.SendMessage(36); // The moderator of this conference has not given you speaking privileges.
|
||||
}
|
||||
|
||||
public static void EmoteMessage(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
if (channel.CanTalk(from))
|
||||
channel.SendIgnorableMessage(58, from, from.GetColorCharacter() + from.Username, param); // %1 %2
|
||||
else
|
||||
from.SendMessage(36); // The moderator of this conference has not given you speaking privileges.
|
||||
}
|
||||
|
||||
public static void PrivateMessage(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
int indexOf = param.IndexOf(' ');
|
||||
|
||||
string name = param.Substring(0, indexOf);
|
||||
string text = param.Substring(indexOf + 1);
|
||||
|
||||
ChatUser target = ChatSystem.SearchForUser(from, name);
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (target.IsIgnored(from))
|
||||
from.SendMessage(35,
|
||||
target.Username); // %1 has chosen to ignore you. None of your messages to them will get through.
|
||||
else if (target.IgnorePrivateMessage)
|
||||
from.SendMessage(42, target.Username); // %1 has chosen to not receive private messages at the moment.
|
||||
else
|
||||
target.SendMessage(59, from.Mobile, from.GetColorCharacter() + from.Username, text); // [%1]: %2
|
||||
}
|
||||
|
||||
public static void LeaveChat(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser.RemoveChatUser(from);
|
||||
}
|
||||
|
||||
public static void ChangeChannelPassword(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
channel.Password = param;
|
||||
from.SendMessage(60); // The password to the conference has been changed.
|
||||
}
|
||||
|
||||
public static void AllowPrivateMessages(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
from.IgnorePrivateMessage = false;
|
||||
from.SendMessage(37); // You can now receive private messages.
|
||||
}
|
||||
|
||||
public static void DisallowPrivateMessages(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
from.IgnorePrivateMessage = true;
|
||||
from.SendMessage(38); /* You will no longer receive private messages.
|
||||
* Those who send you a message will be notified that you are blocking incoming messages.
|
||||
*/
|
||||
}
|
||||
|
||||
public static void TogglePrivateMessages(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
from.IgnorePrivateMessage = !from.IgnorePrivateMessage;
|
||||
from.SendMessage(from.IgnorePrivateMessage ? 38 : 37); // See above for messages
|
||||
}
|
||||
|
||||
public static void ShowCharacterName(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
from.Anonymous = false;
|
||||
from.SendMessage(
|
||||
39); // You are now showing your character name to any players who inquire with the whois command.
|
||||
}
|
||||
|
||||
public static void HideCharacterName(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
from.Anonymous = true;
|
||||
from.SendMessage(
|
||||
40); // You are no longer showing your character name to any players who inquire with the whois command.
|
||||
}
|
||||
|
||||
public static void ToggleCharacterName(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
from.Anonymous = !from.Anonymous;
|
||||
from.SendMessage(from.Anonymous ? 40 : 39); // See above for messages
|
||||
}
|
||||
|
||||
public static void JoinChannel(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
string name;
|
||||
string password = null;
|
||||
|
||||
int start = param.IndexOf('\"');
|
||||
|
||||
if (start >= 0)
|
||||
{
|
||||
int end = param.IndexOf('\"', ++start);
|
||||
|
||||
if (end >= 0)
|
||||
{
|
||||
name = param.Substring(start, end - start);
|
||||
password = param.Substring(++end);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = param.Substring(start);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int indexOf = param.IndexOf(' ');
|
||||
|
||||
if (indexOf >= 0)
|
||||
{
|
||||
name = param.Substring(0, indexOf++);
|
||||
password = param.Substring(indexOf);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = param;
|
||||
}
|
||||
}
|
||||
|
||||
password = password?.Trim();
|
||||
|
||||
if (password?.Length == 0)
|
||||
password = null;
|
||||
|
||||
Channel joined = Channel.FindChannelByName(name);
|
||||
|
||||
if (joined == null)
|
||||
from.SendMessage(33, name); // There is no conference named '%1'.
|
||||
else
|
||||
joined.AddUser(from, password);
|
||||
}
|
||||
|
||||
public static void JoinNewChannel(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
if ((param = param.Trim()).Length == 0)
|
||||
return;
|
||||
|
||||
string name;
|
||||
string password = null;
|
||||
|
||||
int start = param.IndexOf('{');
|
||||
|
||||
if (start >= 0)
|
||||
{
|
||||
name = param.Substring(0, start++);
|
||||
|
||||
int end = param.IndexOf('}', start);
|
||||
|
||||
if (end >= start)
|
||||
password = param.Substring(start, end - start);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = param;
|
||||
}
|
||||
|
||||
password = password?.Trim();
|
||||
|
||||
if (password?.Length == 0)
|
||||
password = null;
|
||||
|
||||
Channel.AddChannel(name, password).AddUser(from, password);
|
||||
}
|
||||
|
||||
public static void AddIgnore(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
from.AddIgnored(target);
|
||||
}
|
||||
|
||||
public static void RemoveIgnore(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
from.RemoveIgnored(target);
|
||||
}
|
||||
|
||||
public static void ToggleIgnore(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (from.IsIgnored(target))
|
||||
from.RemoveIgnored(target);
|
||||
else
|
||||
from.AddIgnored(target);
|
||||
}
|
||||
|
||||
public static void AddVoice(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target != null)
|
||||
channel.AddVoiced(target, from);
|
||||
}
|
||||
|
||||
public static void RemoveVoice(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target != null)
|
||||
channel.RemoveVoiced(target, from);
|
||||
}
|
||||
|
||||
public static void ToggleVoice(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (channel.IsVoiced(target))
|
||||
channel.RemoveVoiced(target, from);
|
||||
else
|
||||
channel.AddVoiced(target, from);
|
||||
}
|
||||
|
||||
public static void AddModerator(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target != null)
|
||||
channel.AddModerator(target, from);
|
||||
}
|
||||
|
||||
public static void RemoveModerator(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target != null)
|
||||
channel.RemoveModerator(target, from);
|
||||
}
|
||||
|
||||
public static void ToggleModerator(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (channel.IsModerator(target))
|
||||
channel.RemoveModerator(target, from);
|
||||
else
|
||||
channel.AddModerator(target, from);
|
||||
}
|
||||
|
||||
public static void RenameChannel(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
channel.Name = param;
|
||||
}
|
||||
|
||||
public static void QueryWhoIs(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (target.Anonymous)
|
||||
from.SendMessage(41, target.Username); // %1 is remaining anonymous.
|
||||
else
|
||||
from.SendMessage(43, target.Username, target.Mobile.Name); // %2 is known in the lands of Britannia as %2.
|
||||
}
|
||||
|
||||
public static void Kick(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
ChatUser target = ChatSystem.SearchForUser(from, param);
|
||||
|
||||
if (target != null)
|
||||
channel.Kick(target, from);
|
||||
}
|
||||
|
||||
public static void EnableDefaultVoice(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
channel.VoiceRestricted = false;
|
||||
}
|
||||
|
||||
public static void DisableDefaultVoice(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
channel.VoiceRestricted = true;
|
||||
}
|
||||
|
||||
public static void ToggleDefaultVoice(ChatUser from, Channel channel, string param)
|
||||
{
|
||||
channel.VoiceRestricted = !channel.VoiceRestricted;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Projects/Scripts/Engines/Chat/ChatCommand.cs
Normal file
50
Projects/Scripts/Engines/Chat/ChatCommand.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
namespace Server.Engines.Chat
|
||||
{
|
||||
public enum ChatCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Add a channel to top list.
|
||||
/// </summary>
|
||||
AddChannel = 0x3E8,
|
||||
|
||||
/// <summary>
|
||||
/// Remove channel from top list.
|
||||
/// </summary>
|
||||
RemoveChannel = 0x3E9,
|
||||
|
||||
/// <summary>
|
||||
/// Queries for a new chat nickname.
|
||||
/// </summary>
|
||||
AskNewNickname = 0x3EB,
|
||||
|
||||
/// <summary>
|
||||
/// Closes the chat window.
|
||||
/// </summary>
|
||||
CloseChatWindow = 0x3EC,
|
||||
|
||||
/// <summary>
|
||||
/// Opens the chat window.
|
||||
/// </summary>
|
||||
OpenChatWindow = 0x3ED,
|
||||
|
||||
/// <summary>
|
||||
/// Add a user to current channel.
|
||||
/// </summary>
|
||||
AddUserToChannel = 0x3EE,
|
||||
|
||||
/// <summary>
|
||||
/// Remove a user from current channel.
|
||||
/// </summary>
|
||||
RemoveUserFromChannel = 0x3EF,
|
||||
|
||||
/// <summary>
|
||||
/// Send a message putting generic conference name at top when player leaves a channel.
|
||||
/// </summary>
|
||||
LeaveChannel = 0x3F0,
|
||||
|
||||
/// <summary>
|
||||
/// Send a message putting Channel name at top and telling player he joined the channel.
|
||||
/// </summary>
|
||||
JoinedChannel = 0x3F1
|
||||
}
|
||||
}
|
||||
212
Projects/Scripts/Engines/Chat/ChatUser.cs
Normal file
212
Projects/Scripts/Engines/Chat/ChatUser.cs
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Accounting;
|
||||
|
||||
namespace Server.Engines.Chat
|
||||
{
|
||||
public class ChatUser
|
||||
{
|
||||
public const char NormalColorCharacter = '0';
|
||||
public const char ModeratorColorCharacter = '1';
|
||||
public const char VoicedColorCharacter = '2';
|
||||
|
||||
private static List<ChatUser> m_Users = new List<ChatUser>();
|
||||
private static Dictionary<Mobile, ChatUser> m_Table = new Dictionary<Mobile, ChatUser>();
|
||||
|
||||
public ChatUser(Mobile m)
|
||||
{
|
||||
Mobile = m;
|
||||
Ignored = new List<ChatUser>();
|
||||
Ignoring = new List<ChatUser>();
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public List<ChatUser> Ignored{ get; }
|
||||
|
||||
public List<ChatUser> Ignoring{ get; }
|
||||
|
||||
public string Username
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mobile.Account is Account acct)
|
||||
return acct.GetTag("ChatName");
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (Mobile.Account is Account acct)
|
||||
acct.SetTag("ChatName", value);
|
||||
}
|
||||
}
|
||||
|
||||
public Channel CurrentChannel{ get; set; }
|
||||
|
||||
public bool IsOnline => Mobile.NetState != null;
|
||||
|
||||
public bool Anonymous{ get; set; }
|
||||
|
||||
public bool IgnorePrivateMessage{ get; set; }
|
||||
|
||||
public bool IsModerator => CurrentChannel?.IsModerator(this) == true;
|
||||
|
||||
public char GetColorCharacter()
|
||||
{
|
||||
return IsModerator ? ModeratorColorCharacter :
|
||||
CurrentChannel?.IsVoiced(this) == true ? VoicedColorCharacter : NormalColorCharacter;
|
||||
}
|
||||
|
||||
public bool CheckOnline()
|
||||
{
|
||||
if (IsOnline)
|
||||
return true;
|
||||
|
||||
RemoveChatUser(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SendMessage(int number, string param1 = null, string param2 = null)
|
||||
{
|
||||
if (Mobile.NetState != null)
|
||||
Mobile.Send(new ChatMessagePacket(Mobile, number, param1, param2));
|
||||
}
|
||||
|
||||
public void SendMessage(int number, Mobile from, string param1, string param2)
|
||||
{
|
||||
if (Mobile.NetState != null)
|
||||
Mobile.Send(new ChatMessagePacket(from, number, param1, param2));
|
||||
}
|
||||
|
||||
public bool IsIgnored(ChatUser check)
|
||||
{
|
||||
return Ignored.Contains(check);
|
||||
}
|
||||
|
||||
public void AddIgnored(ChatUser user)
|
||||
{
|
||||
if (IsIgnored(user))
|
||||
{
|
||||
SendMessage(22, user.Username); // You are already ignoring %1.
|
||||
}
|
||||
else
|
||||
{
|
||||
Ignored.Add(user);
|
||||
user.Ignoring.Add(this);
|
||||
|
||||
SendMessage(23, user.Username); // You are now ignoring %1.
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveIgnored(ChatUser user)
|
||||
{
|
||||
if (IsIgnored(user))
|
||||
{
|
||||
Ignored.Remove(user);
|
||||
user.Ignoring.Remove(this);
|
||||
|
||||
SendMessage(24, user.Username); // You are no longer ignoring %1.
|
||||
|
||||
if (Ignored.Count == 0)
|
||||
SendMessage(26); // You are no longer ignoring anyone.
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(25, user.Username); // You are not ignoring %1.
|
||||
}
|
||||
}
|
||||
|
||||
public static ChatUser AddChatUser(Mobile from)
|
||||
{
|
||||
ChatUser user = GetChatUser(from);
|
||||
|
||||
if (user != null)
|
||||
return user;
|
||||
|
||||
user = new ChatUser(from);
|
||||
|
||||
m_Users.Add(user);
|
||||
m_Table[from] = user;
|
||||
|
||||
Channel.SendChannelsTo(user);
|
||||
|
||||
List<Channel> list = Channel.Channels;
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
Channel c = list[i];
|
||||
|
||||
if (c.AddUser(user))
|
||||
break;
|
||||
}
|
||||
|
||||
//ChatSystem.SendCommandTo( user.m_Mobile, ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username );
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static void RemoveChatUser(ChatUser user)
|
||||
{
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < user.Ignoring.Count; ++i)
|
||||
user.Ignoring[i].RemoveIgnored(user);
|
||||
|
||||
if (m_Users.Contains(user))
|
||||
{
|
||||
ChatSystem.SendCommandTo(user.Mobile, ChatCommand.CloseChatWindow);
|
||||
|
||||
user.CurrentChannel?.RemoveUser(user);
|
||||
|
||||
m_Users.Remove(user);
|
||||
m_Table.Remove(user.Mobile);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveChatUser(Mobile from)
|
||||
{
|
||||
ChatUser user = GetChatUser(from);
|
||||
|
||||
RemoveChatUser(user);
|
||||
}
|
||||
|
||||
public static ChatUser GetChatUser(Mobile from)
|
||||
{
|
||||
m_Table.TryGetValue(from, out ChatUser c);
|
||||
return c;
|
||||
}
|
||||
|
||||
public static ChatUser GetChatUser(string username)
|
||||
{
|
||||
for (int i = 0; i < m_Users.Count; ++i)
|
||||
{
|
||||
ChatUser user = m_Users[i];
|
||||
|
||||
if (user.Username == username)
|
||||
return user;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void GlobalSendCommand(ChatCommand command, string param1, string param2 = null)
|
||||
{
|
||||
GlobalSendCommand(command, null, param1, param2);
|
||||
}
|
||||
|
||||
public static void GlobalSendCommand(ChatCommand command, ChatUser initiator = null, string param1 = null, string param2 = null)
|
||||
{
|
||||
for (int i = 0; i < m_Users.Count; ++i)
|
||||
{
|
||||
ChatUser user = m_Users[i];
|
||||
|
||||
if (user == initiator)
|
||||
continue;
|
||||
|
||||
if (user.CheckOnline())
|
||||
ChatSystem.SendCommandTo(user.Mobile, command, param1, param2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Projects/Scripts/Engines/Chat/Chatold.cs
Normal file
15
Projects/Scripts/Engines/Chat/Chatold.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
namespace Server.Chat
|
||||
{
|
||||
public class ChatSystem
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.ChatRequest += EventSink_ChatRequest;
|
||||
}
|
||||
|
||||
private static void EventSink_ChatRequest(ChatRequestEventArgs e)
|
||||
{
|
||||
e.Mobile.SendMessage("Chat is not currently supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Projects/Scripts/Engines/Chat/Packets.cs
Normal file
28
Projects/Scripts/Engines/Chat/Packets.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.Chat
|
||||
{
|
||||
public sealed class ChatMessagePacket : Packet
|
||||
{
|
||||
public ChatMessagePacket(Mobile who, int number, string param1, string param2) : base(0xB2)
|
||||
{
|
||||
if (param1 == null)
|
||||
param1 = string.Empty;
|
||||
|
||||
if (param2 == null)
|
||||
param2 = string.Empty;
|
||||
|
||||
EnsureCapacity(13 + (param1.Length + param2.Length) * 2);
|
||||
|
||||
m_Stream.Write((ushort)(number - 20));
|
||||
|
||||
if (who != null)
|
||||
m_Stream.WriteAsciiFixed(who.Language, 4);
|
||||
else
|
||||
m_Stream.Write(0);
|
||||
|
||||
m_Stream.WriteBigUniNull(param1);
|
||||
m_Stream.WriteBigUniNull(param2);
|
||||
}
|
||||
}
|
||||
}
|
||||
279
Projects/Scripts/Engines/ConPVP/AcceptDuelGump.cs
Normal file
279
Projects/Scripts/Engines/ConPVP/AcceptDuelGump.cs
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class AcceptDuelGump : Gump
|
||||
{
|
||||
private const int LabelColor32 = 0xFFFFFF;
|
||||
private const int BlackColor32 = 0x000008;
|
||||
|
||||
private static Dictionary<Mobile, List<IgnoreEntry>> m_IgnoreLists = new Dictionary<Mobile, List<IgnoreEntry>>();
|
||||
|
||||
private bool m_Active = true;
|
||||
private Mobile m_Challenger, m_Challenged;
|
||||
private DuelContext m_Context;
|
||||
private Participant m_Participant;
|
||||
private int m_Slot;
|
||||
|
||||
public AcceptDuelGump(Mobile challenger, Mobile challenged, DuelContext context, Participant p, int slot) : base(50,
|
||||
50)
|
||||
{
|
||||
m_Challenger = challenger;
|
||||
m_Challenged = challenged;
|
||||
m_Context = context;
|
||||
m_Participant = p;
|
||||
m_Slot = slot;
|
||||
|
||||
challenged.CloseGump<AcceptDuelGump>();
|
||||
|
||||
Closable = false;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
//AddBackground( 0, 0, 400, 220, 9150 );
|
||||
AddBackground(1, 1, 398, 218, 3600);
|
||||
//AddBackground( 16, 15, 369, 189, 9100 );
|
||||
|
||||
AddImageTiled(16, 15, 369, 189, 3604);
|
||||
AddAlphaRegion(16, 15, 369, 189);
|
||||
|
||||
AddImage(215, -43, 0xEE40);
|
||||
//AddImage( 330, 141, 0x8BA );
|
||||
|
||||
AddHtml(22 - 1, 22, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22 + 1, 22, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22, 22 - 1, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22, 22 + 1, 294, 20, Color(Center("Duel Challenge"), BlackColor32));
|
||||
AddHtml(22, 22, 294, 20, Color(Center("Duel Challenge"), LabelColor32));
|
||||
|
||||
string fmt;
|
||||
|
||||
if (p.Contains(challenger))
|
||||
fmt = "You have been asked to join sides with {0} in a duel. Do you accept?";
|
||||
else
|
||||
fmt = "You have been challenged to a duel from {0}. Do you accept?";
|
||||
|
||||
AddHtml(22 - 1, 50, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22 + 1, 50, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22, 50 - 1, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22, 50 + 1, 294, 40, Color(string.Format(fmt, challenger.Name), BlackColor32));
|
||||
AddHtml(22, 50, 294, 40, Color(string.Format(fmt, challenger.Name), 0xB0C868));
|
||||
|
||||
AddImageTiled(32, 88, 264, 1, 9107);
|
||||
AddImageTiled(42, 90, 264, 1, 9157);
|
||||
|
||||
AddRadio(24, 100, 9727, 9730, true, 1);
|
||||
AddHtml(60 - 1, 105, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60 + 1, 105, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60, 105 - 1, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60, 105 + 1, 250, 20, Color("Yes, I will fight this duel.", BlackColor32));
|
||||
AddHtml(60, 105, 250, 20, Color("Yes, I will fight this duel.", LabelColor32));
|
||||
|
||||
AddRadio(24, 135, 9727, 9730, false, 2);
|
||||
AddHtml(60 - 1, 140, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60 + 1, 140, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60, 140 - 1, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60, 140 + 1, 250, 20, Color("No, I do not wish to fight.", BlackColor32));
|
||||
AddHtml(60, 140, 250, 20, Color("No, I do not wish to fight.", LabelColor32));
|
||||
|
||||
AddRadio(24, 170, 9727, 9730, false, 3);
|
||||
AddHtml(60 - 1, 175, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60 + 1, 175, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60, 175 - 1, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60, 175 + 1, 250, 20, Color("No, knave. Do not ask again.", BlackColor32));
|
||||
AddHtml(60, 175, 250, 20, Color("No, knave. Do not ask again.", LabelColor32));
|
||||
|
||||
AddButton(314, 173, 247, 248, 1);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(15.0), AutoReject);
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
public void AutoReject()
|
||||
{
|
||||
if (!m_Active)
|
||||
return;
|
||||
|
||||
m_Active = false;
|
||||
|
||||
m_Challenged.CloseGump<AcceptDuelGump>();
|
||||
|
||||
m_Challenger.SendMessage("{0} seems unresponsive.", m_Challenged.Name);
|
||||
m_Challenged.SendMessage("You decline the challenge.");
|
||||
}
|
||||
|
||||
public static void BeginIgnore(Mobile source, Mobile toIgnore)
|
||||
{
|
||||
if (!m_IgnoreLists.TryGetValue(source, out List<IgnoreEntry> list))
|
||||
m_IgnoreLists[source] = list = new List<IgnoreEntry>();
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
IgnoreEntry ie = list[i];
|
||||
|
||||
if (ie.Ignored == toIgnore)
|
||||
{
|
||||
ie.Refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ie.Expired)
|
||||
list.RemoveAt(i--);
|
||||
}
|
||||
|
||||
list.Add(new IgnoreEntry(toIgnore));
|
||||
}
|
||||
|
||||
public static bool IsIgnored(Mobile source, Mobile check)
|
||||
{
|
||||
if (!m_IgnoreLists.TryGetValue(source, out List<IgnoreEntry> list))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
IgnoreEntry ie = list[i];
|
||||
|
||||
if (ie.Expired)
|
||||
list.RemoveAt(i--);
|
||||
else if (ie.Ignored == check)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID != 1 || !m_Active || !m_Context.Registered)
|
||||
return;
|
||||
|
||||
m_Active = false;
|
||||
|
||||
if (!m_Context.Participants.Contains(m_Participant))
|
||||
return;
|
||||
|
||||
if (info.IsSwitched(1))
|
||||
{
|
||||
if (!(m_Challenged is PlayerMobile pm))
|
||||
return;
|
||||
|
||||
if (pm.DuelContext != null)
|
||||
{
|
||||
if (pm.DuelContext.Initiator == pm)
|
||||
pm.SendMessage(0x22, "You have already started a duel.");
|
||||
else
|
||||
pm.SendMessage(0x22, "You have already been challenged in a duel.");
|
||||
|
||||
m_Challenger.SendMessage("{0} cannot fight because they are already assigned to another duel.", pm.Name);
|
||||
}
|
||||
else if (DuelContext.CheckCombat(pm))
|
||||
{
|
||||
pm.SendMessage(0x22,
|
||||
"You have recently been in combat with another player and must wait before starting a duel.");
|
||||
m_Challenger.SendMessage(
|
||||
"{0} cannot fight because they have recently been in combat with another player.", pm.Name);
|
||||
}
|
||||
else if (TournamentController.IsActive)
|
||||
{
|
||||
pm.SendMessage(0x22, "A tournament is currently active and you may not duel.");
|
||||
m_Challenger.SendMessage(0x22, "A tournament is currently active and you may not duel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
bool added = false;
|
||||
|
||||
if (m_Slot >= 0 && m_Slot < m_Participant.Players.Length && m_Participant.Players[m_Slot] == null)
|
||||
{
|
||||
added = true;
|
||||
m_Participant.Players[m_Slot] = new DuelPlayer(m_Challenged, m_Participant);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < m_Participant.Players.Length; ++i)
|
||||
if (m_Participant.Players[i] == null)
|
||||
{
|
||||
added = true;
|
||||
m_Participant.Players[i] = new DuelPlayer(m_Challenged, m_Participant);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (added)
|
||||
{
|
||||
m_Challenger.SendMessage("{0} has accepted the request.", m_Challenged.Name);
|
||||
m_Challenged.SendMessage("You have accepted the request from {0}.", m_Challenger.Name);
|
||||
|
||||
NetState ns = m_Challenger.NetState;
|
||||
|
||||
if (ns != null)
|
||||
foreach (Gump g in ns.Gumps)
|
||||
{
|
||||
if (g is ParticipantGump pg && pg.Participant == m_Participant)
|
||||
{
|
||||
m_Challenger.SendGump(new ParticipantGump(m_Challenger, m_Context, m_Participant));
|
||||
break;
|
||||
}
|
||||
|
||||
if (g is DuelContextGump dcg && dcg.Context == m_Context)
|
||||
{
|
||||
m_Challenger.SendGump(new DuelContextGump(m_Challenger, m_Context));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Challenger.SendMessage("The participant list was full and so {0} could not join.",
|
||||
m_Challenged.Name);
|
||||
m_Challenged.SendMessage(
|
||||
"The participant list was full and so you could not join the fight {1} {0}.", m_Challenger.Name,
|
||||
m_Participant.Contains(m_Challenger) ? "with" : "against");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.IsSwitched(3))
|
||||
BeginIgnore(m_Challenged, m_Challenger);
|
||||
|
||||
m_Challenger.SendMessage("{0} does not wish to fight.", m_Challenged.Name);
|
||||
m_Challenged.SendMessage("You chose not to fight {1} {0}.", m_Challenger.Name,
|
||||
m_Participant.Contains(m_Challenger) ? "with" : "against");
|
||||
}
|
||||
}
|
||||
|
||||
private class IgnoreEntry
|
||||
{
|
||||
private static TimeSpan ExpireDelay = TimeSpan.FromMinutes(15.0);
|
||||
public DateTime m_Expire;
|
||||
public Mobile m_Ignored;
|
||||
|
||||
public IgnoreEntry(Mobile ignored)
|
||||
{
|
||||
m_Ignored = ignored;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public Mobile Ignored => m_Ignored;
|
||||
public bool Expired => DateTime.UtcNow >= m_Expire;
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
m_Expire = DateTime.UtcNow + ExpireDelay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
825
Projects/Scripts/Engines/ConPVP/Arena.cs
Normal file
825
Projects/Scripts/Engines/ConPVP/Arena.cs
Normal file
|
|
@ -0,0 +1,825 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Multis;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class ArenaController : Item
|
||||
{
|
||||
[Constructible]
|
||||
public ArenaController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Arena = new Arena();
|
||||
|
||||
Instances.Add(this);
|
||||
}
|
||||
|
||||
public ArenaController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Arena Arena{ get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IsPrivate{ get; set; }
|
||||
|
||||
public override string DefaultName => "arena controller";
|
||||
|
||||
public static List<ArenaController> Instances{ get; set; } = new List<ArenaController>();
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
base.OnDelete();
|
||||
|
||||
Instances.Remove(this);
|
||||
Arena.Delete();
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster)
|
||||
from.SendGump(new PropertiesGump(from, Arena));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1);
|
||||
|
||||
writer.Write(IsPrivate);
|
||||
|
||||
Arena.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
IsPrivate = reader.ReadBool();
|
||||
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
Arena = new Arena(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Instances.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class ArenaStartPoints
|
||||
{
|
||||
public ArenaStartPoints(Point3D[] points = null)
|
||||
{
|
||||
Points = points ?? new Point3D[8];
|
||||
}
|
||||
|
||||
public ArenaStartPoints(GenericReader reader)
|
||||
{
|
||||
Points = new Point3D[reader.ReadEncodedInt()];
|
||||
|
||||
for (int i = 0; i < Points.Length; ++i)
|
||||
Points[i] = reader.ReadPoint3D();
|
||||
}
|
||||
|
||||
public Point3D[] Points{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeWest
|
||||
{
|
||||
get => Points[0];
|
||||
set => Points[0] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeEast
|
||||
{
|
||||
get => Points[1];
|
||||
set => Points[1] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeNorth
|
||||
{
|
||||
get => Points[2];
|
||||
set => Points[2] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D EdgeSouth
|
||||
{
|
||||
get => Points[3];
|
||||
set => Points[3] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerNW
|
||||
{
|
||||
get => Points[4];
|
||||
set => Points[4] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerSE
|
||||
{
|
||||
get => Points[5];
|
||||
set => Points[5] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerSW
|
||||
{
|
||||
get => Points[6];
|
||||
set => Points[6] = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D CornerNE
|
||||
{
|
||||
get => Points[7];
|
||||
set => Points[7] = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "...";
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(Points.Length);
|
||||
|
||||
for (int i = 0; i < Points.Length; ++i)
|
||||
writer.Write(Points[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class Arena : IComparable<Arena>
|
||||
{
|
||||
private bool m_Active;
|
||||
private Rectangle2D m_Bounds;
|
||||
private Map m_Facet;
|
||||
private Point3D m_GateOut;
|
||||
|
||||
private bool m_IsGuarded;
|
||||
private string m_Name;
|
||||
|
||||
private SafeZone m_Region;
|
||||
|
||||
private TournamentController m_Tournament;
|
||||
private Rectangle2D m_Zone;
|
||||
|
||||
public Arena()
|
||||
{
|
||||
Points = new ArenaStartPoints();
|
||||
Players = new List<Mobile>();
|
||||
}
|
||||
|
||||
public Arena(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 7:
|
||||
{
|
||||
m_IsGuarded = reader.ReadBool();
|
||||
|
||||
goto case 6;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
Ladder = reader.ReadItem() as LadderController;
|
||||
|
||||
goto case 5;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
m_Tournament = reader.ReadItem() as TournamentController;
|
||||
Announcer = reader.ReadMobile();
|
||||
|
||||
goto case 4;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
m_Name = reader.ReadString();
|
||||
|
||||
goto case 3;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
m_Zone = reader.ReadRect2D();
|
||||
|
||||
goto case 2;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
GateIn = reader.ReadPoint3D();
|
||||
m_GateOut = reader.ReadPoint3D();
|
||||
Teleporter = reader.ReadItem();
|
||||
|
||||
goto case 1;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
Players = reader.ReadStrongMobileList();
|
||||
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
m_Facet = reader.ReadMap();
|
||||
m_Bounds = reader.ReadRect2D();
|
||||
Outside = reader.ReadPoint3D();
|
||||
Wall = reader.ReadPoint3D();
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
reader.ReadBool();
|
||||
Players = new List<Mobile>();
|
||||
}
|
||||
|
||||
m_Active = reader.ReadBool();
|
||||
Points = new ArenaStartPoints(reader);
|
||||
|
||||
if (m_Active)
|
||||
{
|
||||
Arenas.Add(this);
|
||||
Arenas.Sort();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null)
|
||||
m_Region = new SafeZone(m_Zone, Outside, m_Facet, m_IsGuarded);
|
||||
|
||||
if (IsOccupied)
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(2.0), Evict);
|
||||
|
||||
if (m_Tournament != null)
|
||||
Timer.DelayCall(TimeSpan.Zero, AttachToTournament_Sandbox);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public LadderController Ladder{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IsGuarded
|
||||
{
|
||||
get => m_IsGuarded;
|
||||
set
|
||||
{
|
||||
m_IsGuarded = value;
|
||||
|
||||
if (m_Region != null)
|
||||
m_Region.Disabled = !m_IsGuarded;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament
|
||||
{
|
||||
get => m_Tournament;
|
||||
set
|
||||
{
|
||||
m_Tournament?.Tournament.Arenas.Remove(this);
|
||||
|
||||
m_Tournament = value;
|
||||
|
||||
m_Tournament?.Tournament.Arenas.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Announcer{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public string Name
|
||||
{
|
||||
get => m_Name;
|
||||
set
|
||||
{
|
||||
m_Name = value;
|
||||
if (m_Active) Arenas.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Map Facet
|
||||
{
|
||||
get => m_Facet;
|
||||
set
|
||||
{
|
||||
m_Facet = value;
|
||||
|
||||
if (Teleporter != null)
|
||||
Teleporter.Map = value;
|
||||
|
||||
m_Region?.Unregister();
|
||||
|
||||
if (m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null)
|
||||
m_Region = new SafeZone(m_Zone, Outside, m_Facet, m_IsGuarded);
|
||||
else
|
||||
m_Region = null;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Rectangle2D Bounds
|
||||
{
|
||||
get => m_Bounds;
|
||||
set => m_Bounds = value;
|
||||
}
|
||||
|
||||
public int Spectators
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Region == null)
|
||||
return 0;
|
||||
|
||||
int specs = m_Region.GetPlayerCount() - Players.Count;
|
||||
|
||||
if (specs < 0)
|
||||
specs = 0;
|
||||
|
||||
return specs;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Rectangle2D Zone
|
||||
{
|
||||
get => m_Zone;
|
||||
set
|
||||
{
|
||||
m_Zone = value;
|
||||
|
||||
if (m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null)
|
||||
{
|
||||
m_Region?.Unregister();
|
||||
|
||||
m_Region = new SafeZone(m_Zone, Outside, m_Facet, m_IsGuarded);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Region?.Unregister();
|
||||
|
||||
m_Region = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D Outside{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D GateIn{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D GateOut
|
||||
{
|
||||
get => m_GateOut;
|
||||
set
|
||||
{
|
||||
m_GateOut = value;
|
||||
if (Teleporter != null)
|
||||
Teleporter.Location = m_GateOut;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Point3D Wall{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IsOccupied => Players.Count > 0;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public ArenaStartPoints Points{ get; private set; }
|
||||
|
||||
public Item Teleporter{ get; set; }
|
||||
|
||||
public List<Mobile> Players{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool Active
|
||||
{
|
||||
get => m_Active;
|
||||
set
|
||||
{
|
||||
if (m_Active == value)
|
||||
return;
|
||||
|
||||
m_Active = value;
|
||||
|
||||
if (m_Active)
|
||||
{
|
||||
Arenas.Add(this);
|
||||
Arenas.Sort();
|
||||
}
|
||||
else
|
||||
{
|
||||
Arenas.Remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator, AccessLevel.Administrator)]
|
||||
public bool ForceEvict
|
||||
{
|
||||
get => false;
|
||||
set
|
||||
{
|
||||
if (value) Evict();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Arena> Arenas{ get; } = new List<Arena>();
|
||||
|
||||
public int CompareTo(Arena c)
|
||||
{
|
||||
string a = m_Name;
|
||||
string b = c.m_Name;
|
||||
|
||||
if (a == null && b == null)
|
||||
return 0;
|
||||
if (a == null)
|
||||
return -1;
|
||||
if (b == null)
|
||||
return +1;
|
||||
|
||||
return a.CompareTo(b);
|
||||
}
|
||||
|
||||
public Ladder AcquireLadder()
|
||||
{
|
||||
return Ladder?.Ladder ?? ConPVP.Ladder.Instance;
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
Active = false;
|
||||
m_Region?.Unregister();
|
||||
m_Region = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "...";
|
||||
}
|
||||
|
||||
public Point3D GetBaseStartPoint(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
return Points.Points[index % Points.Points.Length];
|
||||
}
|
||||
|
||||
public void MoveInside(DuelPlayer[] players, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
else
|
||||
index %= Points.Points.Length;
|
||||
|
||||
Point3D start = GetBaseStartPoint(index);
|
||||
|
||||
int offset = 0;
|
||||
|
||||
Point2D[] offsets = index < 4 ? m_EdgeOffsets : m_CornerOffsets;
|
||||
int[,] matrix = m_Rotate[index];
|
||||
|
||||
for (int i = 0; i < players.Length; ++i)
|
||||
{
|
||||
DuelPlayer pl = players[i];
|
||||
|
||||
if (pl == null)
|
||||
continue;
|
||||
|
||||
Mobile mob = pl.Mobile;
|
||||
|
||||
Point2D p;
|
||||
|
||||
if (offset < offsets.Length)
|
||||
p = offsets[offset++];
|
||||
else
|
||||
p = offsets[offsets.Length - 1];
|
||||
|
||||
p.X = p.X * matrix[0, 0] + p.Y * matrix[0, 1];
|
||||
p.Y = p.X * matrix[1, 0] + p.Y * matrix[1, 1];
|
||||
|
||||
mob.MoveToWorld(new Point3D(start.X + p.X, start.Y + p.Y, start.Z), m_Facet);
|
||||
mob.Direction = mob.GetDirectionTo(Wall);
|
||||
|
||||
Players.Add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachToTournament_Sandbox()
|
||||
{
|
||||
m_Tournament?.Tournament.Arenas.Add(this);
|
||||
}
|
||||
|
||||
public void Evict()
|
||||
{
|
||||
Point3D loc;
|
||||
Map facet;
|
||||
|
||||
if (m_Facet == null)
|
||||
{
|
||||
loc = new Point3D(2715, 2165, 0);
|
||||
facet = Map.Felucca;
|
||||
}
|
||||
else
|
||||
{
|
||||
loc = Outside;
|
||||
facet = m_Facet;
|
||||
}
|
||||
|
||||
bool hasBounds = m_Bounds.Start != Point2D.Zero && m_Bounds.End != Point2D.Zero;
|
||||
|
||||
for (int i = 0; i < Players.Count; ++i)
|
||||
{
|
||||
Mobile mob = Players[i];
|
||||
|
||||
if (mob == null)
|
||||
continue;
|
||||
|
||||
if (mob.Map == Map.Internal)
|
||||
{
|
||||
if ((m_Facet == null || mob.LogoutMap == m_Facet) &&
|
||||
(!hasBounds || m_Bounds.Contains(mob.LogoutLocation)))
|
||||
mob.LogoutLocation = loc;
|
||||
}
|
||||
else if ((m_Facet == null || mob.Map == m_Facet) && (!hasBounds || m_Bounds.Contains(mob.Location)))
|
||||
{
|
||||
mob.MoveToWorld(loc, facet);
|
||||
}
|
||||
|
||||
mob.Combatant = null;
|
||||
mob.Frozen = false;
|
||||
DuelContext.Debuff(mob);
|
||||
DuelContext.CancelSpell(mob);
|
||||
}
|
||||
|
||||
if (hasBounds)
|
||||
{
|
||||
List<Mobile> pets = new List<Mobile>();
|
||||
|
||||
foreach (Mobile mob in facet.GetMobilesInBounds(m_Bounds))
|
||||
if (mob is BaseCreature pet && pet.Controlled && pet.ControlMaster != null &&
|
||||
Players.Contains(pet.ControlMaster))
|
||||
pets.Add(pet);
|
||||
|
||||
foreach (Mobile pet in pets)
|
||||
{
|
||||
pet.Combatant = null;
|
||||
pet.Frozen = false;
|
||||
|
||||
pet.MoveToWorld(loc, facet);
|
||||
}
|
||||
}
|
||||
|
||||
Players.Clear();
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(7);
|
||||
|
||||
writer.Write(m_IsGuarded);
|
||||
|
||||
writer.Write(Ladder);
|
||||
|
||||
writer.Write(m_Tournament);
|
||||
writer.Write(Announcer);
|
||||
|
||||
writer.Write(m_Name);
|
||||
|
||||
writer.Write(m_Zone);
|
||||
|
||||
writer.Write(GateIn);
|
||||
writer.Write(m_GateOut);
|
||||
writer.Write(Teleporter);
|
||||
|
||||
writer.Write(Players);
|
||||
|
||||
writer.Write(m_Facet);
|
||||
writer.Write(m_Bounds);
|
||||
writer.Write(Outside);
|
||||
writer.Write(Wall);
|
||||
writer.Write(m_Active);
|
||||
|
||||
Points.Serialize(writer);
|
||||
}
|
||||
|
||||
public static Arena FindArena(List<Mobile> players)
|
||||
{
|
||||
Preferences prefs = Preferences.Instance;
|
||||
|
||||
if (prefs == null)
|
||||
return FindArena();
|
||||
|
||||
if (Arenas.Count == 0)
|
||||
return null;
|
||||
|
||||
if (players.Count > 0)
|
||||
{
|
||||
Mobile first = players[0];
|
||||
|
||||
List<ArenaController> allControllers = ArenaController.Instances;
|
||||
|
||||
for (int i = 0; i < allControllers.Count; ++i)
|
||||
{
|
||||
ArenaController controller = allControllers[i];
|
||||
|
||||
if (controller?.Deleted == false && controller.Arena != null && controller.IsPrivate &&
|
||||
controller.Map == first.Map && first.InRange(controller, 24))
|
||||
{
|
||||
BaseHouse house = BaseHouse.FindHouseAt(controller);
|
||||
bool allNear = true;
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
Mobile check = players[j];
|
||||
bool isNear;
|
||||
|
||||
if (house == null)
|
||||
isNear = controller.Map == check.Map && check.InRange(controller, 24);
|
||||
else
|
||||
isNear = BaseHouse.FindHouseAt(check) == house;
|
||||
|
||||
if (!isNear)
|
||||
{
|
||||
allNear = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allNear)
|
||||
return controller.Arena;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ArenaEntry> arenas = new List<ArenaEntry>();
|
||||
|
||||
for (int i = 0; i < Arenas.Count; ++i)
|
||||
{
|
||||
Arena arena = Arenas[i];
|
||||
|
||||
if (!arena.IsOccupied)
|
||||
arenas.Add(new ArenaEntry(arena));
|
||||
}
|
||||
|
||||
if (arenas.Count == 0)
|
||||
return Arenas[0];
|
||||
|
||||
int tc = 0;
|
||||
|
||||
for (int i = 0; i < arenas.Count; ++i)
|
||||
{
|
||||
ArenaEntry ae = arenas[i];
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
PreferencesEntry pe = prefs.Find(players[j]);
|
||||
|
||||
if (pe.Disliked.Contains(ae.m_Arena.Name))
|
||||
++ae.m_VotesAgainst;
|
||||
else
|
||||
++ae.m_VotesFor;
|
||||
}
|
||||
|
||||
tc += ae.Value;
|
||||
}
|
||||
|
||||
int rn = Utility.Random(tc);
|
||||
|
||||
for (int i = 0; i < arenas.Count; ++i)
|
||||
{
|
||||
ArenaEntry ae = arenas[i];
|
||||
|
||||
if (rn < ae.Value)
|
||||
return ae.m_Arena;
|
||||
|
||||
rn -= ae.Value;
|
||||
}
|
||||
|
||||
return arenas[Utility.Random(arenas.Count)].m_Arena;
|
||||
}
|
||||
|
||||
public static Arena FindArena()
|
||||
{
|
||||
if (Arenas.Count == 0)
|
||||
return null;
|
||||
|
||||
int offset = Utility.Random(Arenas.Count);
|
||||
|
||||
for (int i = 0; i < Arenas.Count; ++i)
|
||||
{
|
||||
Arena arena = Arenas[(i + offset) % Arenas.Count];
|
||||
|
||||
if (!arena.IsOccupied)
|
||||
return arena;
|
||||
}
|
||||
|
||||
return Arenas[offset];
|
||||
}
|
||||
|
||||
private class ArenaEntry
|
||||
{
|
||||
public Arena m_Arena;
|
||||
public int m_VotesAgainst;
|
||||
public int m_VotesFor;
|
||||
|
||||
public ArenaEntry(Arena arena)
|
||||
{
|
||||
m_Arena = arena;
|
||||
}
|
||||
|
||||
public int Value => m_VotesFor;
|
||||
}
|
||||
|
||||
#region Offsets & Rotation
|
||||
|
||||
private static Point2D[] m_EdgeOffsets =
|
||||
{
|
||||
/*
|
||||
* /\
|
||||
* /\/\
|
||||
* /\/\/\
|
||||
* \/\/\/
|
||||
* \/\/\
|
||||
* \/\/
|
||||
*/
|
||||
new Point2D(0, 0),
|
||||
new Point2D(0, -1),
|
||||
new Point2D(0, +1),
|
||||
new Point2D(1, 0),
|
||||
new Point2D(1, -1),
|
||||
new Point2D(1, +1),
|
||||
new Point2D(2, 0),
|
||||
new Point2D(2, -1),
|
||||
new Point2D(2, +1),
|
||||
new Point2D(3, 0)
|
||||
};
|
||||
|
||||
// nw corner
|
||||
private static Point2D[] m_CornerOffsets =
|
||||
{
|
||||
/*
|
||||
* /\
|
||||
* /\/\
|
||||
* /\/\/\
|
||||
* /\/\/\/\
|
||||
* \/\/\/\/
|
||||
*/
|
||||
new Point2D(0, 0),
|
||||
new Point2D(0, 1),
|
||||
new Point2D(1, 0),
|
||||
new Point2D(1, 1),
|
||||
new Point2D(0, 2),
|
||||
new Point2D(2, 0),
|
||||
new Point2D(2, 1),
|
||||
new Point2D(1, 2),
|
||||
new Point2D(0, 3),
|
||||
new Point2D(3, 0)
|
||||
};
|
||||
|
||||
private static int[][,] m_Rotate =
|
||||
{
|
||||
new[,] { { +1, 0 }, { 0, +1 } }, // west
|
||||
new[,] { { -1, 0 }, { 0, -1 } }, // east
|
||||
new[,] { { 0, +1 }, { +1, 0 } }, // north
|
||||
new[,] { { 0, -1 }, { -1, 0 } }, // south
|
||||
new[,] { { +1, 0 }, { 0, +1 } }, // nw
|
||||
new[,] { { -1, 0 }, { 0, -1 } }, // se
|
||||
new[,] { { 0, +1 }, { +1, 0 } }, // sw
|
||||
new[,] { { 0, -1 }, { -1, 0 } } // ne
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2495
Projects/Scripts/Engines/ConPVP/DuelContext.cs
Normal file
2495
Projects/Scripts/Engines/ConPVP/DuelContext.cs
Normal file
File diff suppressed because it is too large
Load diff
89
Projects/Scripts/Engines/ConPVP/DuelTeleporterAddon.cs
Normal file
89
Projects/Scripts/Engines/ConPVP/DuelTeleporterAddon.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public enum DuelTeleporterType
|
||||
{
|
||||
Squares = 6095,
|
||||
Buds = 6104,
|
||||
Flowers = 6113,
|
||||
Spikes = 6122,
|
||||
Arrows = 6140,
|
||||
Links = 6149
|
||||
}
|
||||
|
||||
public class DuelTeleporterAddon : BaseAddon
|
||||
{
|
||||
[Constructible]
|
||||
public DuelTeleporterAddon(DuelTeleporterType type = DuelTeleporterType.Squares)
|
||||
{
|
||||
int itemID = (int)type;
|
||||
|
||||
AddComponent(new AddonComponent(itemID + 0), -1, -1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 1), -1, 0, 5);
|
||||
AddComponent(new AddonComponent(itemID + 2), 0, -1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 3), -1, +1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 4), 0, 0, 5);
|
||||
AddComponent(new AddonComponent(itemID + 5), +1, -1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 6), 0, +1, 5);
|
||||
AddComponent(new AddonComponent(itemID + 7), +1, 0, 5);
|
||||
AddComponent(new AddonComponent(itemID + 8), +1, +1, 5);
|
||||
|
||||
AddComponent(new AddonComponent(0x759), -2, -2, 0);
|
||||
AddComponent(new AddonComponent(0x75A), +2, +2, 0);
|
||||
AddComponent(new AddonComponent(0x75B), -2, +2, 0);
|
||||
AddComponent(new AddonComponent(0x75C), +2, -2, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x751), -1, +2, 0);
|
||||
AddComponent(new AddonComponent(0x751), 0, +2, 0);
|
||||
AddComponent(new AddonComponent(0x751), +1, +2, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x752), +2, -1, 0);
|
||||
AddComponent(new AddonComponent(0x752), +2, 0, 0);
|
||||
AddComponent(new AddonComponent(0x752), +2, +1, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x753), -1, -2, 0);
|
||||
AddComponent(new AddonComponent(0x753), 0, -2, 0);
|
||||
AddComponent(new AddonComponent(0x753), +1, -2, 0);
|
||||
|
||||
AddComponent(new AddonComponent(0x754), -2, -1, 0);
|
||||
AddComponent(new AddonComponent(0x754), -2, 0, 0);
|
||||
AddComponent(new AddonComponent(0x754), -2, +1, 0);
|
||||
}
|
||||
|
||||
public DuelTeleporterAddon(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DuelTeleporterType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Components.Count > 0)
|
||||
return (DuelTeleporterType)Components[0].ItemID;
|
||||
|
||||
return DuelTeleporterType.Squares;
|
||||
}
|
||||
set
|
||||
{
|
||||
for (int i = 0; i < Components.Count && i < 9; ++i)
|
||||
Components[i].ItemID = i + (int)value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
1797
Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs
Normal file
1797
Projects/Scripts/Engines/ConPVP/Games/BombingRun.cs
Normal file
File diff suppressed because it is too large
Load diff
1205
Projects/Scripts/Engines/ConPVP/Games/CTF.cs
Normal file
1205
Projects/Scripts/Engines/ConPVP/Games/CTF.cs
Normal file
File diff suppressed because it is too large
Load diff
1109
Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs
Normal file
1109
Projects/Scripts/Engines/ConPVP/Games/DoubleDom.cs
Normal file
File diff suppressed because it is too large
Load diff
77
Projects/Scripts/Engines/ConPVP/Games/EventGame.cs
Normal file
77
Projects/Scripts/Engines/ConPVP/Games/EventGame.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public abstract class EventController : Item
|
||||
{
|
||||
public EventController()
|
||||
: base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public EventController(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract string Title{ get; }
|
||||
public abstract EventGame Construct(DuelContext dc);
|
||||
|
||||
public abstract string GetTeamName(int teamID);
|
||||
|
||||
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 override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster)
|
||||
from.SendGump(new PropertiesGump(from, this));
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class EventGame
|
||||
{
|
||||
protected DuelContext m_Context;
|
||||
|
||||
public EventGame(DuelContext context)
|
||||
{
|
||||
m_Context = context;
|
||||
}
|
||||
|
||||
public DuelContext Context => m_Context;
|
||||
|
||||
public virtual bool FreeConsume => true;
|
||||
|
||||
public virtual bool OnDeath(Mobile mob, Container corpse)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool CantDoAnything(Mobile mob)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void OnStart()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnStop()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
1184
Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs
Normal file
1184
Projects/Scripts/Engines/ConPVP/Games/KingOfTheHill.cs
Normal file
File diff suppressed because it is too large
Load diff
123
Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs
Normal file
123
Projects/Scripts/Engines/ConPVP/Games/TourneyMatch.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TourneyMatch
|
||||
{
|
||||
public TourneyMatch(List<TourneyParticipant> participants)
|
||||
{
|
||||
Participants = participants;
|
||||
|
||||
for (int i = 0; i < participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = participants[i];
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("Matched in a duel against ");
|
||||
|
||||
if (participants.Count > 2)
|
||||
sb.AppendFormat("{0} other {1}: ", participants.Count - 1,
|
||||
part.Players.Count == 1 ? "players" : "teams");
|
||||
|
||||
bool hasAppended = false;
|
||||
|
||||
for (int j = 0; j < participants.Count; ++j)
|
||||
{
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
if (hasAppended)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(participants[j].NameList);
|
||||
hasAppended = true;
|
||||
}
|
||||
|
||||
sb.Append(".");
|
||||
|
||||
part.AddLog(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public List<TourneyParticipant> Participants{ get; set; }
|
||||
|
||||
public TourneyParticipant Winner{ get; set; }
|
||||
|
||||
public DuelContext Context{ get; set; }
|
||||
|
||||
public bool InProgress => Context?.Registered == true;
|
||||
|
||||
public void Start(Arena arena, Tournament tourney)
|
||||
{
|
||||
TourneyParticipant first = Participants[0];
|
||||
|
||||
DuelContext dc = new DuelContext(first.Players[0], tourney.Ruleset.Layout, false);
|
||||
dc.Ruleset.Options.SetAll(false);
|
||||
dc.Ruleset.Options.Or(tourney.Ruleset.Options);
|
||||
|
||||
for (int i = 0; i < Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant tourneyPart = Participants[i];
|
||||
Participant duelPart = new Participant(dc, tourneyPart.Players.Count)
|
||||
{
|
||||
TourneyPart = tourneyPart
|
||||
};
|
||||
|
||||
|
||||
for (int j = 0; j < tourneyPart.Players.Count; ++j)
|
||||
duelPart.Add(tourneyPart.Players[j]);
|
||||
|
||||
for (int j = 0; j < duelPart.Players.Length; ++j)
|
||||
if (duelPart.Players[j] != null)
|
||||
duelPart.Players[j].Ready = true;
|
||||
|
||||
dc.Participants.Add(duelPart);
|
||||
}
|
||||
|
||||
if (tourney.EventController != null)
|
||||
dc.m_EventGame = tourney.EventController.Construct(dc);
|
||||
|
||||
dc.m_Tournament = tourney;
|
||||
dc.m_Match = this;
|
||||
|
||||
dc.m_OverrideArena = arena;
|
||||
|
||||
if (tourney.SuddenDeath > TimeSpan.Zero &&
|
||||
(tourney.SuddenDeathRounds == 0 || tourney.Pyramid.Levels.Count <= tourney.SuddenDeathRounds))
|
||||
dc.StartSuddenDeath(tourney.SuddenDeath);
|
||||
|
||||
dc.SendReadyGump(0);
|
||||
|
||||
if (dc.StartedBeginCountdown)
|
||||
{
|
||||
Context = dc;
|
||||
|
||||
for (int i = 0; i < Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant p = Participants[i];
|
||||
|
||||
for (int j = 0; j < p.Players.Count; ++j)
|
||||
{
|
||||
Mobile mob = p.Players[j];
|
||||
|
||||
foreach (Mobile view in mob.GetMobilesInRange(18))
|
||||
if (!mob.CanSee(view))
|
||||
mob.Send(view.RemovePacket);
|
||||
|
||||
mob.LocalOverheadMessage(MessageType.Emote, 0x3B2, false,
|
||||
"* Your mind focuses intently on the fight and all other distractions fade away *");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.Unregister();
|
||||
dc.StopCountdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
382
Projects/Scripts/Engines/ConPVP/Gumps/AcceptTeamGump.cs
Normal file
382
Projects/Scripts/Engines/ConPVP/Gumps/AcceptTeamGump.cs
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class AcceptTeamGump : Gump
|
||||
{
|
||||
private const int BlackColor32 = 0x000008;
|
||||
private const int LabelColor32 = 0xFFFFFF;
|
||||
private bool m_Active;
|
||||
|
||||
private Mobile m_From;
|
||||
private List<Mobile> m_Players;
|
||||
private Mobile m_Registrar;
|
||||
private Mobile m_Requested;
|
||||
private Tournament m_Tournament;
|
||||
|
||||
public AcceptTeamGump(Mobile from, Mobile requested, Tournament tourney, Mobile registrar, List<Mobile> players) :
|
||||
base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Requested = requested;
|
||||
m_Tournament = tourney;
|
||||
m_Registrar = registrar;
|
||||
m_Players = players;
|
||||
|
||||
m_Active = true;
|
||||
|
||||
#region Rules
|
||||
|
||||
Ruleset ruleset = tourney.Ruleset;
|
||||
Ruleset basedef = ruleset.Base;
|
||||
|
||||
int height = 185 + 35 + 60 + 12;
|
||||
|
||||
int changes = 0;
|
||||
|
||||
BitArray defs;
|
||||
|
||||
if (ruleset.Flavors.Count > 0)
|
||||
{
|
||||
defs = new BitArray(basedef.Options);
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i)
|
||||
defs.Or(ruleset.Flavors[i].Options);
|
||||
|
||||
height += ruleset.Flavors.Count * 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
defs = basedef.Options;
|
||||
}
|
||||
|
||||
BitArray opts = ruleset.Options;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
++changes;
|
||||
|
||||
height += changes * 22;
|
||||
|
||||
height += 10 + 22 + 25 + 25;
|
||||
|
||||
#endregion
|
||||
|
||||
Closable = false;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(1, 1, 398, height, 3600);
|
||||
|
||||
AddImageTiled(16, 15, 369, height - 29, 3604);
|
||||
AddAlphaRegion(16, 15, 369, height - 29);
|
||||
|
||||
AddImage(215, -43, 0xEE40);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (tourney.TourneyType == TourneyType.FreeForAll)
|
||||
{
|
||||
sb.Append("FFA");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
sb.Append(tourney.ParticipantsPerMatch);
|
||||
sb.Append("-Team");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.Faction)
|
||||
{
|
||||
sb.Append(tourney.ParticipantsPerMatch);
|
||||
sb.Append("-Team Faction");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
sb.Append("Red v Blue");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tourney.ParticipantsPerMatch; ++i)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append('v');
|
||||
|
||||
sb.Append(tourney.PlayersPerParticipant);
|
||||
}
|
||||
}
|
||||
|
||||
if (tourney.EventController != null)
|
||||
sb.Append(' ').Append(tourney.EventController.Title);
|
||||
|
||||
sb.Append(" Tournament Invitation");
|
||||
|
||||
AddBorderedText(22, 22, 294, 20, Center(sb.ToString()), LabelColor32, BlackColor32);
|
||||
|
||||
AddBorderedText(22, 50, 294, 40,
|
||||
$"You have been asked to partner with {from.Name} in a tournament. Do you accept?",
|
||||
0xB0C868, BlackColor32);
|
||||
|
||||
AddImageTiled(32, 88, 264, 1, 9107);
|
||||
AddImageTiled(42, 90, 264, 1, 9157);
|
||||
|
||||
#region Rules
|
||||
|
||||
int y = 100;
|
||||
|
||||
string groupText = null;
|
||||
|
||||
switch (tourney.GroupType)
|
||||
{
|
||||
case GroupingType.HighVsLow:
|
||||
groupText = "High vs Low";
|
||||
break;
|
||||
case GroupingType.Nearest:
|
||||
groupText = "Closest opponent";
|
||||
break;
|
||||
case GroupingType.Random:
|
||||
groupText = "Random";
|
||||
break;
|
||||
}
|
||||
|
||||
AddBorderedText(35, y, 190, 20, $"Grouping: {groupText}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
string tieText = null;
|
||||
|
||||
switch (tourney.TieType)
|
||||
{
|
||||
case TieType.Random:
|
||||
tieText = "Random";
|
||||
break;
|
||||
case TieType.Highest:
|
||||
tieText = "Highest advances";
|
||||
break;
|
||||
case TieType.Lowest:
|
||||
tieText = "Lowest advances";
|
||||
break;
|
||||
case TieType.FullAdvancement:
|
||||
tieText = tourney.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances";
|
||||
break;
|
||||
case TieType.FullElimination:
|
||||
tieText = tourney.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated";
|
||||
break;
|
||||
}
|
||||
|
||||
AddBorderedText(35, y, 190, 20, $"Tiebreaker: {tieText}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
string sdText = "Off";
|
||||
|
||||
if (tourney.SuddenDeath > TimeSpan.Zero)
|
||||
{
|
||||
sdText = $"{(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2}";
|
||||
|
||||
if (tourney.SuddenDeathRounds > 0)
|
||||
sdText = $"{sdText} (first {tourney.SuddenDeathRounds} rounds)";
|
||||
else
|
||||
sdText = $"{sdText} (all rounds)";
|
||||
}
|
||||
|
||||
AddBorderedText(35, y, 240, 20, $"Sudden Death: {sdText}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
y += 6;
|
||||
AddImageTiled(32, y - 1, 264, 1, 9107);
|
||||
AddImageTiled(42, y + 1, 264, 1, 9157);
|
||||
y += 6;
|
||||
|
||||
AddBorderedText(35, y, 190, 20, $"Ruleset: {basedef.Title}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
|
||||
AddBorderedText(35, y, 190, 20, $" + {ruleset.Flavors[i].Title}", LabelColor32, BlackColor32);
|
||||
|
||||
y += 4;
|
||||
|
||||
if (changes > 0)
|
||||
{
|
||||
AddBorderedText(35, y, 190, 20, "Modifications:", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
{
|
||||
string name = ruleset.Layout.FindByIndex(i);
|
||||
|
||||
if (name != null) // sanity
|
||||
{
|
||||
AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
|
||||
AddBorderedText(60, y, 165, 22, name, LabelColor32, BlackColor32);
|
||||
}
|
||||
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddBorderedText(35, y, 190, 20, "Modifications: None", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
y += 8;
|
||||
AddImageTiled(32, y - 1, 264, 1, 9107);
|
||||
AddImageTiled(42, y + 1, 264, 1, 9157);
|
||||
y += 8;
|
||||
|
||||
AddRadio(24, y, 9727, 9730, true, 1);
|
||||
AddBorderedText(60, y + 5, 250, 20, "Yes, I will join them.", LabelColor32, BlackColor32);
|
||||
y += 35;
|
||||
|
||||
AddRadio(24, y, 9727, 9730, false, 2);
|
||||
AddBorderedText(60, y + 5, 250, 20, "No, I do not wish to fight.", LabelColor32, BlackColor32);
|
||||
y += 35;
|
||||
|
||||
AddRadio(24, y, 9727, 9730, false, 3);
|
||||
AddBorderedText(60, y + 5, 270, 20, "No, most certainly not. Do not ask again.", LabelColor32, BlackColor32);
|
||||
y += 35;
|
||||
|
||||
y -= 3;
|
||||
AddButton(314, y, 247, 248, 1);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(15.0), AutoReject);
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor)
|
||||
{
|
||||
AddColoredText(x - 1, y - 1, width, height, text, borderColor);
|
||||
AddColoredText(x - 1, y + 1, width, height, text, borderColor);
|
||||
AddColoredText(x + 1, y - 1, width, height, text, borderColor);
|
||||
AddColoredText(x + 1, y + 1, width, height, text, borderColor);
|
||||
AddColoredText(x, y, width, height, text, color);
|
||||
}
|
||||
|
||||
private void AddColoredText(int x, int y, int width, int height, string text, int color)
|
||||
{
|
||||
if (color == 0)
|
||||
AddHtml(x, y, width, height, text);
|
||||
else
|
||||
AddHtml(x, y, width, height, Color(text, color));
|
||||
}
|
||||
|
||||
public void AutoReject()
|
||||
{
|
||||
if (!m_Active)
|
||||
return;
|
||||
|
||||
m_Active = false;
|
||||
|
||||
m_Requested.CloseGump<AcceptTeamGump>();
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
if (m_Registrar != null)
|
||||
{
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, $"{m_Requested.Name} seems unresponsive.", m_From.NetState);
|
||||
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, $"You have declined the partnership with {m_From.Name}.", m_Requested.NetState);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
Mobile from = m_From;
|
||||
Mobile mob = m_Requested;
|
||||
|
||||
if (info.ButtonID != 1 || !m_Active)
|
||||
return;
|
||||
|
||||
m_Active = false;
|
||||
|
||||
if (info.IsSwitched(1))
|
||||
{
|
||||
if (!(mob is PlayerMobile pm))
|
||||
return;
|
||||
|
||||
if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They ignore your invitation.", from.NetState);
|
||||
}
|
||||
else if (pm.DuelContext != null)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They are already assigned to another duel.", from.NetState);
|
||||
}
|
||||
else if (m_Players.Contains(mob))
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You have already named them as a team member.", from.NetState);
|
||||
}
|
||||
else if (m_Tournament.HasParticipant(mob))
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They have already entered this tournament.", from.NetState);
|
||||
}
|
||||
else if (m_Players.Count >= m_Tournament.PlayersPerParticipant)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "Your team is full.", from.NetState);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Players.Add(mob);
|
||||
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
if (m_Registrar != null)
|
||||
{
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x59, false, $"{mob.Name} has accepted your offer of partnership.", from.NetState);
|
||||
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x59, false, $"You have accepted the partnership with {from.Name}.", mob.NetState);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.IsSwitched(3))
|
||||
AcceptDuelGump.BeginIgnore(m_Requested, m_From);
|
||||
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
if (m_Registrar != null)
|
||||
{
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, $"{mob.Name} has declined your offer of partnership.", from.NetState);
|
||||
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, $"You have declined the partnership with {from.Name}.", mob.NetState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
285
Projects/Scripts/Engines/ConPVP/Gumps/ArenaGump.cs
Normal file
285
Projects/Scripts/Engines/ConPVP/Gumps/ArenaGump.cs
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class ArenasMoongate : Item
|
||||
{
|
||||
[Constructible]
|
||||
public ArenasMoongate() : base(0x1FD4)
|
||||
{
|
||||
Movable = false;
|
||||
Light = LightType.Circle300;
|
||||
}
|
||||
|
||||
public ArenasMoongate(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override string DefaultName => "arena moongate";
|
||||
|
||||
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();
|
||||
Light = LightType.Circle300;
|
||||
}
|
||||
|
||||
public bool UseGate(Mobile from)
|
||||
{
|
||||
if (DuelContext.CheckCombat(from))
|
||||
{
|
||||
from.SendMessage(0x22, "You have recently been in combat with another player and cannot use this moongate.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from.Spell != null)
|
||||
{
|
||||
from.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
|
||||
return false;
|
||||
}
|
||||
|
||||
from.CloseGump<ArenaGump>();
|
||||
from.SendGump(new ArenaGump(from, this));
|
||||
|
||||
if (!from.Hidden || from.AccessLevel == AccessLevel.Player)
|
||||
Effects.PlaySound(from.Location, from.Map, 0x20E);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.InRange(GetWorldLocation(), 1))
|
||||
UseGate(from);
|
||||
else
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
|
||||
}
|
||||
|
||||
public override bool OnMoveOver(Mobile m)
|
||||
{
|
||||
return !m.Player || UseGate(m);
|
||||
}
|
||||
}
|
||||
|
||||
public class ArenaGump : Gump
|
||||
{
|
||||
private List<Arena> m_Arenas;
|
||||
|
||||
private int m_ColumnX = 12;
|
||||
private Mobile m_From;
|
||||
private ArenasMoongate m_Gate;
|
||||
|
||||
public ArenaGump(Mobile from, ArenasMoongate gate) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Gate = gate;
|
||||
m_Arenas = Arena.Arenas;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
int height = 12 + 20 + m_Arenas.Count * 31 + 24 + 12;
|
||||
|
||||
AddBackground(0, 0, 499 + 40, height, 0x2436);
|
||||
|
||||
List<Arena> list = m_Arenas;
|
||||
|
||||
for (int i = 1; i < list.Count; i += 2)
|
||||
AddImageTiled(12, 32 + i * 31, 475 + 40, 30, 0x2430);
|
||||
|
||||
AddAlphaRegion(10, 10, 479 + 40, height - 20);
|
||||
|
||||
AddColumnHeader(35, null);
|
||||
AddColumnHeader(115, "Arena");
|
||||
AddColumnHeader(325, "Participants");
|
||||
AddColumnHeader(40, "Obs");
|
||||
|
||||
AddButton(499 + 40 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1);
|
||||
AddButton(499 + 40 - 12 - 63, height - 12 - 24, 241, 242, 2);
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
Arena ar = list[i];
|
||||
|
||||
int x = 12;
|
||||
int y = 32 + i * 31;
|
||||
|
||||
int color = ar.Players.Count > 0 ? 0xCCFFCC : 0xCCCCCC;
|
||||
|
||||
AddRadio(x + 3, y + 1, 9727, 9730, false, i);
|
||||
x += 35;
|
||||
|
||||
AddBorderedText(x + 5, y + 5, 115 - 5, ar.Name ?? "(no name)", color, 0);
|
||||
x += 115;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (ar.Players.Count > 0)
|
||||
{
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
if (ladder == null)
|
||||
continue;
|
||||
|
||||
LadderEntry p1 = null, p2 = null, p3 = null, p4 = null;
|
||||
|
||||
for (int j = 0; j < ar.Players.Count; ++j)
|
||||
{
|
||||
Mobile mob = ar.Players[j];
|
||||
LadderEntry c = ladder.Find(mob);
|
||||
|
||||
if (p1 == null || c.Index < p1.Index)
|
||||
{
|
||||
p4 = p3;
|
||||
p3 = p2;
|
||||
p2 = p1;
|
||||
p1 = c;
|
||||
}
|
||||
else if (p2 == null || c.Index < p2.Index)
|
||||
{
|
||||
p4 = p3;
|
||||
p3 = p2;
|
||||
p2 = c;
|
||||
}
|
||||
else if (p3 == null || c.Index < p3.Index)
|
||||
{
|
||||
p4 = p3;
|
||||
p3 = c;
|
||||
}
|
||||
else if (p4 == null || c.Index < p4.Index)
|
||||
{
|
||||
p4 = c;
|
||||
}
|
||||
}
|
||||
|
||||
Append(sb, p1);
|
||||
Append(sb, p2);
|
||||
Append(sb, p3);
|
||||
Append(sb, p4);
|
||||
|
||||
if (ar.Players.Count > 4)
|
||||
sb.Append(", ...");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append("Empty");
|
||||
}
|
||||
|
||||
AddBorderedText(x + 5, y + 5, 325 - 5, sb.ToString(), color, 0);
|
||||
x += 325;
|
||||
|
||||
AddBorderedText(x, y + 5, 40, Center(ar.Spectators.ToString()), color, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void Append(StringBuilder sb, LadderEntry le)
|
||||
{
|
||||
if (le == null)
|
||||
return;
|
||||
|
||||
if (sb.Length > 0)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(le.Mobile.Name);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID != 1)
|
||||
return;
|
||||
|
||||
int[] switches = info.Switches;
|
||||
|
||||
if (switches.Length == 0)
|
||||
return;
|
||||
|
||||
int opt = switches[0];
|
||||
|
||||
if (opt < 0 || opt >= m_Arenas.Count)
|
||||
return;
|
||||
|
||||
Arena arena = m_Arenas[opt];
|
||||
|
||||
if (!m_From.InRange(m_Gate.GetWorldLocation(), 1) || m_From.Map != m_Gate.Map)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1019002); // You are too far away to use the gate.
|
||||
}
|
||||
else if (DuelContext.CheckCombat(m_From))
|
||||
{
|
||||
m_From.SendMessage(0x22,
|
||||
"You have recently been in combat with another player and cannot use this moongate.");
|
||||
}
|
||||
else if (m_From.Spell != null)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1049616); // You are too busy to do that at the moment.
|
||||
}
|
||||
else if (m_From.Map == arena.Facet && arena.Zone.Contains(m_From))
|
||||
{
|
||||
m_From.SendLocalizedMessage(1019003); // You are already there.
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseCreature.TeleportPets(m_From, arena.GateIn, arena.Facet);
|
||||
|
||||
m_From.Combatant = null;
|
||||
m_From.Warmode = false;
|
||||
m_From.Hidden = true;
|
||||
|
||||
m_From.MoveToWorld(arena.GateIn, arena.Facet);
|
||||
|
||||
Effects.PlaySound(arena.GateIn, arena.Facet, 0x1FE);
|
||||
}
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
private void AddBorderedText(int x, int y, int width, string text, int color, int borderColor)
|
||||
{
|
||||
/*AddColoredText( x - 1, y, width, text, borderColor );
|
||||
AddColoredText( x + 1, y, width, text, borderColor );
|
||||
AddColoredText( x, y - 1, width, text, borderColor );
|
||||
AddColoredText( x, y + 1, width, text, borderColor );*/
|
||||
/*AddColoredText( x - 1, y - 1, width, text, borderColor );
|
||||
AddColoredText( x + 1, y + 1, width, text, borderColor );*/
|
||||
AddColoredText(x, y, width, text, color);
|
||||
}
|
||||
|
||||
private void AddColoredText(int x, int y, int width, string text, int color)
|
||||
{
|
||||
if (color == 0)
|
||||
AddHtml(x, y, width, 20, text);
|
||||
else
|
||||
AddHtml(x, y, width, 20, Color(text, color));
|
||||
}
|
||||
|
||||
private void AddColumnHeader(int width, string name)
|
||||
{
|
||||
AddBackground(m_ColumnX, 12, width, 20, 0x242C);
|
||||
AddImageTiled(m_ColumnX + 2, 14, width - 4, 16, 0x2430);
|
||||
|
||||
if (name != null)
|
||||
AddBorderedText(m_ColumnX, 13, width, Center(name), 0xFFFFFF, 0);
|
||||
|
||||
m_ColumnX += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Projects/Scripts/Engines/ConPVP/Gumps/BeginGump.cs
Normal file
72
Projects/Scripts/Engines/ConPVP/Gumps/BeginGump.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
using Server.Gumps;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class BeginGump : Gump
|
||||
{
|
||||
private const int LabelColor32 = 0xFFFFFF;
|
||||
private const int BlackColor32 = 0x000008;
|
||||
|
||||
public BeginGump(int count) : base(50, 50)
|
||||
{
|
||||
AddPage(0);
|
||||
|
||||
const int offset = 50;
|
||||
|
||||
AddBackground(1, 1, 398, 202 - offset, 3600);
|
||||
|
||||
AddImageTiled(16, 15, 369, 173 - offset, 3604);
|
||||
AddAlphaRegion(16, 15, 369, 173 - offset);
|
||||
|
||||
AddImage(215, -43, 0xEE40);
|
||||
|
||||
AddHtml(22 - 1, 22, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
|
||||
AddHtml(22 + 1, 22, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
|
||||
AddHtml(22, 22 - 1, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
|
||||
AddHtml(22, 22 + 1, 294, 20, Color(Center("Duel Countdown"), BlackColor32));
|
||||
AddHtml(22, 22, 294, 20, Color(Center("Duel Countdown"), LabelColor32));
|
||||
|
||||
AddHtml(22 - 1, 50, 294, 80,
|
||||
Color(
|
||||
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.",
|
||||
BlackColor32));
|
||||
AddHtml(22 + 1, 50, 294, 80,
|
||||
Color(
|
||||
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.",
|
||||
BlackColor32));
|
||||
AddHtml(22, 50 - 1, 294, 80,
|
||||
Color(
|
||||
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.",
|
||||
BlackColor32));
|
||||
AddHtml(22, 50 + 1, 294, 80,
|
||||
Color(
|
||||
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.",
|
||||
BlackColor32));
|
||||
AddHtml(22, 50, 294, 80,
|
||||
Color(
|
||||
"The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.",
|
||||
0xFFCC66));
|
||||
|
||||
/*AddImageTiled( 32, 128, 264, 1, 9107 );
|
||||
AddImageTiled( 42, 130, 264, 1, 9157 );
|
||||
|
||||
AddHtml( 60-1, 140, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
|
||||
AddHtml( 60+1, 140, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
|
||||
AddHtml( 60, 140-1, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
|
||||
AddHtml( 60, 140+1, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#{2:X6}>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false );
|
||||
AddHtml( 60, 140, 250, 20, Color( String.Format( "Duel will begin in <BASEFONT COLOR=#FF6666>{0} <BASEFONT COLOR=#{2:X6}>second{1}.", count, count==1?"":"s", 0x66AACC ), 0x66AACC ), false, false );*/
|
||||
|
||||
AddButton(314 - 50, 157 - offset, 247, 248, 1);
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
}
|
||||
}
|
||||
566
Projects/Scripts/Engines/ConPVP/Gumps/ConfirmSignupGump.cs
Normal file
566
Projects/Scripts/Engines/ConPVP/Gumps/ConfirmSignupGump.cs
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Factions;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class ConfirmSignupGump : Gump
|
||||
{
|
||||
private const int BlackColor32 = 0x000008;
|
||||
private const int LabelColor32 = 0xFFFFFF;
|
||||
private Mobile m_From;
|
||||
private List<Mobile> m_Players;
|
||||
private Mobile m_Registrar;
|
||||
private Tournament m_Tournament;
|
||||
|
||||
public ConfirmSignupGump(Mobile from, Mobile registrar, Tournament tourney, List<Mobile> players) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Registrar = registrar;
|
||||
m_Tournament = tourney;
|
||||
m_Players = players;
|
||||
|
||||
m_From.CloseGump<AcceptTeamGump>();
|
||||
m_From.CloseGump<AcceptDuelGump>();
|
||||
m_From.CloseGump<DuelContextGump>();
|
||||
m_From.CloseGump<ConfirmSignupGump>();
|
||||
|
||||
#region Rules
|
||||
|
||||
Ruleset ruleset = tourney.Ruleset;
|
||||
Ruleset basedef = ruleset.Base;
|
||||
|
||||
int height = 185 + 60 + 12;
|
||||
|
||||
int changes = 0;
|
||||
|
||||
BitArray defs;
|
||||
|
||||
if (ruleset.Flavors.Count > 0)
|
||||
{
|
||||
defs = new BitArray(basedef.Options);
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i)
|
||||
defs.Or(ruleset.Flavors[i].Options);
|
||||
|
||||
height += ruleset.Flavors.Count * 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
defs = basedef.Options;
|
||||
}
|
||||
|
||||
BitArray opts = ruleset.Options;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
++changes;
|
||||
|
||||
height += changes * 22;
|
||||
|
||||
height += 10 + 22 + 25 + 25;
|
||||
|
||||
if (tourney.PlayersPerParticipant > 1)
|
||||
height += 36 + tourney.PlayersPerParticipant * 20;
|
||||
|
||||
#endregion
|
||||
|
||||
Closable = false;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
//AddBackground( 0, 0, 400, 220, 9150 );
|
||||
AddBackground(1, 1, 398, height, 3600);
|
||||
//AddBackground( 16, 15, 369, 189, 9100 );
|
||||
|
||||
AddImageTiled(16, 15, 369, height - 29, 3604);
|
||||
AddAlphaRegion(16, 15, 369, height - 29);
|
||||
|
||||
AddImage(215, -43, 0xEE40);
|
||||
//AddImage( 330, 141, 0x8BA );
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (tourney.TourneyType == TourneyType.FreeForAll)
|
||||
{
|
||||
sb.Append("FFA");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
sb.Append(tourney.ParticipantsPerMatch);
|
||||
sb.Append("-Team");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.Faction)
|
||||
{
|
||||
sb.Append(tourney.ParticipantsPerMatch);
|
||||
sb.Append("-Team Faction");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
sb.Append("Red v Blue");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tourney.ParticipantsPerMatch; ++i)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append('v');
|
||||
|
||||
sb.Append(tourney.PlayersPerParticipant);
|
||||
}
|
||||
}
|
||||
|
||||
if (tourney.EventController != null)
|
||||
sb.Append(' ').Append(tourney.EventController.Title);
|
||||
|
||||
sb.Append(" Tournament Signup");
|
||||
|
||||
AddBorderedText(22, 22, 294, 20, Center(sb.ToString()), LabelColor32, BlackColor32);
|
||||
AddBorderedText(22, 50, 294, 40, "You have requested to join the tournament. Do you accept the rules?", 0xB0C868,
|
||||
BlackColor32);
|
||||
|
||||
AddImageTiled(32, 88, 264, 1, 9107);
|
||||
AddImageTiled(42, 90, 264, 1, 9157);
|
||||
|
||||
#region Rules
|
||||
|
||||
int y = 100;
|
||||
|
||||
string groupText = null;
|
||||
|
||||
switch (tourney.GroupType)
|
||||
{
|
||||
case GroupingType.HighVsLow:
|
||||
groupText = "High vs Low";
|
||||
break;
|
||||
case GroupingType.Nearest:
|
||||
groupText = "Closest opponent";
|
||||
break;
|
||||
case GroupingType.Random:
|
||||
groupText = "Random";
|
||||
break;
|
||||
}
|
||||
|
||||
AddBorderedText(35, y, 190, 20, $"Grouping: {groupText}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
string tieText = null;
|
||||
|
||||
switch (tourney.TieType)
|
||||
{
|
||||
case TieType.Random:
|
||||
tieText = "Random";
|
||||
break;
|
||||
case TieType.Highest:
|
||||
tieText = "Highest advances";
|
||||
break;
|
||||
case TieType.Lowest:
|
||||
tieText = "Lowest advances";
|
||||
break;
|
||||
case TieType.FullAdvancement:
|
||||
tieText = tourney.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances";
|
||||
break;
|
||||
case TieType.FullElimination:
|
||||
tieText = tourney.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated";
|
||||
break;
|
||||
}
|
||||
|
||||
AddBorderedText(35, y, 190, 20, $"Tiebreaker: {tieText}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
string sdText = "Off";
|
||||
|
||||
if (tourney.SuddenDeath > TimeSpan.Zero)
|
||||
{
|
||||
sdText = $"{(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2}";
|
||||
|
||||
if (tourney.SuddenDeathRounds > 0)
|
||||
sdText = $"{sdText} (first {tourney.SuddenDeathRounds} rounds)";
|
||||
else
|
||||
sdText = $"{sdText} (all rounds)";
|
||||
}
|
||||
|
||||
AddBorderedText(35, y, 240, 20, $"Sudden Death: {sdText}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
y += 6;
|
||||
AddImageTiled(32, y - 1, 264, 1, 9107);
|
||||
AddImageTiled(42, y + 1, 264, 1, 9157);
|
||||
y += 6;
|
||||
|
||||
AddBorderedText(35, y, 190, 20, $"Ruleset: {basedef.Title}", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
|
||||
AddBorderedText(35, y, 190, 20, $" + {ruleset.Flavors[i].Title}", LabelColor32, BlackColor32);
|
||||
|
||||
y += 4;
|
||||
|
||||
if (changes > 0)
|
||||
{
|
||||
AddBorderedText(35, y, 190, 20, "Modifications:", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
{
|
||||
string name = ruleset.Layout.FindByIndex(i);
|
||||
|
||||
if (name != null) // sanity
|
||||
{
|
||||
AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
|
||||
AddBorderedText(60, y, 165, 22, name, LabelColor32, BlackColor32);
|
||||
}
|
||||
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddBorderedText(35, y, 190, 20, "Modifications: None", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Team
|
||||
|
||||
if (tourney.PlayersPerParticipant > 1)
|
||||
{
|
||||
y += 8;
|
||||
AddImageTiled(32, y - 1, 264, 1, 9107);
|
||||
AddImageTiled(42, y + 1, 264, 1, 9157);
|
||||
y += 8;
|
||||
|
||||
AddBorderedText(35, y, 190, 20, "Your Team", LabelColor32, BlackColor32);
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < players.Count; ++i, y += 20)
|
||||
{
|
||||
if (i == 0)
|
||||
AddImage(35, y, 0xD2);
|
||||
else
|
||||
AddGoldenButton(35, y, 1 + i);
|
||||
|
||||
AddBorderedText(60, y, 200, 20, players[i].Name, LabelColor32, BlackColor32);
|
||||
}
|
||||
|
||||
for (int i = players.Count; i < tourney.PlayersPerParticipant; ++i, y += 20)
|
||||
{
|
||||
if (i == 0)
|
||||
AddImage(35, y, 0xD2);
|
||||
else
|
||||
AddGoldenButton(35, y, 1 + i);
|
||||
|
||||
AddBorderedText(60, y, 200, 20, "(Empty)", LabelColor32, BlackColor32);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
y += 8;
|
||||
AddImageTiled(32, y - 1, 264, 1, 9107);
|
||||
AddImageTiled(42, y + 1, 264, 1, 9157);
|
||||
y += 8;
|
||||
|
||||
AddRadio(24, y, 9727, 9730, true, 1);
|
||||
AddBorderedText(60, y + 5, 250, 20, "Yes, I wish to join the tournament.", LabelColor32, BlackColor32);
|
||||
y += 35;
|
||||
|
||||
AddRadio(24, y, 9727, 9730, false, 2);
|
||||
AddBorderedText(60, y + 5, 250, 20, "No, I do not wish to join.", LabelColor32, BlackColor32);
|
||||
y += 35;
|
||||
|
||||
y -= 3;
|
||||
AddButton(314, y, 247, 248, 1);
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor)
|
||||
{
|
||||
AddColoredText(x - 1, y - 1, width, height, text, borderColor);
|
||||
AddColoredText(x - 1, y + 1, width, height, text, borderColor);
|
||||
AddColoredText(x + 1, y - 1, width, height, text, borderColor);
|
||||
AddColoredText(x + 1, y + 1, width, height, text, borderColor);
|
||||
AddColoredText(x, y, width, height, text, color);
|
||||
}
|
||||
|
||||
private void AddColoredText(int x, int y, int width, int height, string text, int color)
|
||||
{
|
||||
if (color == 0)
|
||||
AddHtml(x, y, width, height, text);
|
||||
else
|
||||
AddHtml(x, y, width, height, Color(text, color));
|
||||
}
|
||||
|
||||
public void AddGoldenButton(int x, int y, int bid)
|
||||
{
|
||||
AddButton(x, y, 0xD2, 0xD2, bid);
|
||||
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 1 && info.IsSwitched(1))
|
||||
{
|
||||
Tournament tourney = m_Tournament;
|
||||
Mobile from = m_From;
|
||||
|
||||
switch (tourney.Stage)
|
||||
{
|
||||
case TournamentStage.Fighting:
|
||||
{
|
||||
if (m_Registrar != null)
|
||||
{
|
||||
if (m_Tournament.HasParticipant(from))
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "Excuse me? You are already signed up.", from.NetState);
|
||||
else
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "The tournament has already begun. You are too late to signup now.",
|
||||
from.NetState);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TournamentStage.Inactive:
|
||||
{
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "The tournament is closed.", from.NetState);
|
||||
|
||||
break;
|
||||
}
|
||||
case TournamentStage.Signup:
|
||||
{
|
||||
if (m_Players.Count != tourney.PlayersPerParticipant)
|
||||
{
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "You have not yet chosen your team.", from.NetState);
|
||||
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
break;
|
||||
}
|
||||
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
for (int i = 0; i < m_Players.Count; ++i)
|
||||
{
|
||||
Mobile mob = m_Players[i];
|
||||
|
||||
LadderEntry entry = ladder?.Find(mob);
|
||||
|
||||
if (entry != null && Ladder.GetLevel(entry.Experience) < tourney.LevelRequirement)
|
||||
{
|
||||
if (m_Registrar != null)
|
||||
{
|
||||
if (mob == from)
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "You have not yet proven yourself a worthy dueler.", from.NetState);
|
||||
else
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, $"{mob.Name} has not yet proven themselves a worthy dueler.",
|
||||
from.NetState);
|
||||
}
|
||||
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tourney.IsFactionRestricted && Faction.Find(mob) == null)
|
||||
{
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "Only those who have declared their faction allegiance may participate.",
|
||||
from.NetState);
|
||||
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tourney.HasParticipant(mob))
|
||||
{
|
||||
if (m_Registrar != null)
|
||||
{
|
||||
if (mob == from)
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "You have already entered this tournament.", from.NetState);
|
||||
else
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, $"{mob.Name} has already entered this tournament.", from.NetState);
|
||||
}
|
||||
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mob is PlayerMobile mobile && mobile.DuelContext != null)
|
||||
{
|
||||
if (mob == from)
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false,
|
||||
"You are already assigned to a duel. You must yield it before joining this tournament.",
|
||||
from.NetState);
|
||||
else
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false,
|
||||
$"{mobile.Name} is already assigned to a duel. They must yield it before joining this tournament.",
|
||||
from.NetState);
|
||||
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Registrar != null)
|
||||
{
|
||||
string fmt;
|
||||
|
||||
if (tourney.PlayersPerParticipant == 1)
|
||||
fmt =
|
||||
"As you say m'{0}. I've written your name to the bracket. The tournament will begin {1}.";
|
||||
else if (tourney.PlayersPerParticipant == 2)
|
||||
fmt =
|
||||
"As you wish m'{0}. The tournament will begin {1}, but first you must name your partner.";
|
||||
else
|
||||
fmt = "As you wish m'{0}. The tournament will begin {1}, but first you must name your team.";
|
||||
|
||||
string timeUntil;
|
||||
int minutesUntil = (int)Math.Round((tourney.SignupStart + tourney.SignupPeriod - DateTime.UtcNow)
|
||||
.TotalMinutes);
|
||||
|
||||
if (minutesUntil == 0)
|
||||
timeUntil = "momentarily";
|
||||
else
|
||||
timeUntil = $"in {minutesUntil} minute{(minutesUntil == 1 ? "" : "s")}";
|
||||
|
||||
m_Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, string.Format(fmt, from.Female ? "Lady" : "Lord", timeUntil), from.NetState);
|
||||
}
|
||||
|
||||
TourneyParticipant part = new TourneyParticipant(from);
|
||||
part.Players.Clear();
|
||||
part.Players.AddRange(m_Players);
|
||||
|
||||
tourney.Participants.Add(part);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (info.ButtonID > 1)
|
||||
{
|
||||
int index = info.ButtonID - 1;
|
||||
|
||||
if (index > 0 && index < m_Players.Count)
|
||||
{
|
||||
m_Players.RemoveAt(index);
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
}
|
||||
else if (m_Players.Count < m_Tournament.PlayersPerParticipant)
|
||||
{
|
||||
m_From.BeginTarget(12, false, TargetFlags.None, AddPlayer_OnTarget);
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddPlayer_OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (!(obj is Mobile mob) || mob == from)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "Excuse me?", from.NetState);
|
||||
}
|
||||
else if (!mob.Player)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
if (mob.Body.IsHuman)
|
||||
mob.SayTo(from, 1005443); // Nay, I would rather stay here and watch a nail rust.
|
||||
else
|
||||
mob.SayTo(from, 1005444); // The creature ignores your offer.
|
||||
}
|
||||
else if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They ignore your invitation.", from.NetState);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(mob is PlayerMobile pm))
|
||||
return;
|
||||
|
||||
if (pm.DuelContext != null)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They are already assigned to another duel.", from.NetState);
|
||||
}
|
||||
else if (mob.HasGump<AcceptTeamGump>())
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They have already been offered a partnership.", from.NetState);
|
||||
}
|
||||
else if (mob.HasGump<ConfirmSignupGump>())
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They are already trying to join this tournament.", from.NetState);
|
||||
}
|
||||
else if (m_Players.Contains(mob))
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You have already named them as a team member.", from.NetState);
|
||||
}
|
||||
else if (m_Tournament.HasParticipant(mob))
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "They have already entered this tournament.", from.NetState);
|
||||
}
|
||||
else if (m_Players.Count >= m_Tournament.PlayersPerParticipant)
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "Your team is full.", from.NetState);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendGump(new ConfirmSignupGump(m_From, m_Registrar, m_Tournament, m_Players));
|
||||
mob.SendGump(new AcceptTeamGump(from, mob, m_Tournament, m_Registrar, m_Players));
|
||||
|
||||
m_Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x59, false,
|
||||
$"As you command m'{(from.Female ? "Lady" : "Lord")}. I've given your offer to {mob.Name}.",
|
||||
from.NetState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
Projects/Scripts/Engines/ConPVP/Gumps/DuelContextGump.cs
Normal file
139
Projects/Scripts/Engines/ConPVP/Gumps/DuelContextGump.cs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class DuelContextGump : Gump
|
||||
{
|
||||
public DuelContextGump(Mobile from, DuelContext context) : base(50, 50)
|
||||
{
|
||||
From = from;
|
||||
Context = context;
|
||||
|
||||
from.CloseGump<RulesetGump>();
|
||||
from.CloseGump<DuelContextGump>();
|
||||
from.CloseGump<ParticipantGump>();
|
||||
|
||||
int count = context.Participants.Count;
|
||||
|
||||
if (count < 3)
|
||||
count = 3;
|
||||
|
||||
int height = 35 + 10 + 22 + 30 + 22 + 22 + 2 + count * 22 + 2 + 30;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 300, height, 9250);
|
||||
AddBackground(10, 10, 280, height - 20, 0xDAC);
|
||||
|
||||
AddHtml(35, 25, 230, 20, Center("Duel Setup"));
|
||||
|
||||
int x = 35;
|
||||
int y = 47;
|
||||
|
||||
AddGoldenButtonLabeled(x, y, 1, "Rules");
|
||||
y += 22;
|
||||
AddGoldenButtonLabeled(x, y, 2, "Start");
|
||||
y += 22;
|
||||
AddGoldenButtonLabeled(x, y, 3, "Add Participant");
|
||||
y += 30;
|
||||
|
||||
AddHtml(35, y, 230, 20, Center("Participants"));
|
||||
y += 22;
|
||||
|
||||
for (int i = 0; i < context.Participants.Count; ++i)
|
||||
{
|
||||
Participant p = context.Participants[i];
|
||||
|
||||
AddGoldenButtonLabeled(x, y, 4 + i,
|
||||
string.Format(p.Count == 1 ? "Player {0}: {3}" : "Team {0}: {1}/{2}: {3}", 1 + i, p.FilledSlots, p.Count,
|
||||
p.NameList));
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile From{ get; }
|
||||
|
||||
public DuelContext Context{ get; }
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public void AddGoldenButton(int x, int y, int bid)
|
||||
{
|
||||
AddButton(x, y, 0xD2, 0xD2, bid);
|
||||
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
|
||||
}
|
||||
|
||||
public void AddGoldenButtonLabeled(int x, int y, int bid, string text)
|
||||
{
|
||||
AddGoldenButton(x, y, bid);
|
||||
AddHtml(x + 25, y, 200, 20, text);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (!Context.Registered)
|
||||
return;
|
||||
|
||||
int index = info.ButtonID;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case -1: // CloseGump
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 0: // closed
|
||||
{
|
||||
Context.Unregister();
|
||||
break;
|
||||
}
|
||||
case 1: // Rules
|
||||
{
|
||||
//m_From.SendGump( new RulesetGump( m_From, m_Context.Ruleset, m_Context.Ruleset.Layout, m_Context ) );
|
||||
From.SendGump(new PickRulesetGump(From, Context, Context.Ruleset));
|
||||
break;
|
||||
}
|
||||
case 2: // Start
|
||||
{
|
||||
if (Context.CheckFull())
|
||||
{
|
||||
Context.CloseAllGumps();
|
||||
Context.SendReadyUpGump();
|
||||
//m_Context.SendReadyGump();
|
||||
}
|
||||
else
|
||||
{
|
||||
From.SendMessage("You cannot start the duel before all participating players have been assigned.");
|
||||
From.SendGump(new DuelContextGump(From, Context));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // New Participant
|
||||
{
|
||||
if (Context.Participants.Count < 10)
|
||||
Context.Participants.Add(new Participant(Context, 1));
|
||||
else
|
||||
From.SendMessage("The number of participating parties may not be increased further.");
|
||||
|
||||
From.SendGump(new DuelContextGump(From, Context));
|
||||
|
||||
break;
|
||||
}
|
||||
default: // Participant
|
||||
{
|
||||
index -= 4;
|
||||
|
||||
if (index >= 0 && index < Context.Participants.Count)
|
||||
From.SendGump(new ParticipantGump(From, Context, Context.Participants[index]));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
248
Projects/Scripts/Engines/ConPVP/Gumps/LadderGump.cs
Normal file
248
Projects/Scripts/Engines/ConPVP/Gumps/LadderGump.cs
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class LadderItem : Item
|
||||
{
|
||||
[Constructible]
|
||||
public LadderItem() : base(0x117F)
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public LadderItem(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public LadderController Ladder{ get; set; }
|
||||
|
||||
public override string DefaultName => "1v1 leaderboard";
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1);
|
||||
|
||||
writer.Write(Ladder);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Ladder = reader.ReadItem<LadderController>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
Ladder ladder = ConPVP.Ladder.Instance ?? Ladder.Ladder;
|
||||
|
||||
if (ladder != null)
|
||||
{
|
||||
from.CloseGump<LadderGump>();
|
||||
from.SendGump(new LadderGump(ladder));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LadderGump : Gump
|
||||
{
|
||||
private int m_ColumnX = 12;
|
||||
private Ladder m_Ladder;
|
||||
|
||||
private List<LadderEntry> m_List;
|
||||
private int m_Page;
|
||||
|
||||
public LadderGump(Ladder ladder, int page = 0) : base(50, 50)
|
||||
{
|
||||
m_Ladder = ladder;
|
||||
m_Page = page;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
m_List = new List<LadderEntry>(ladder.Entries);
|
||||
|
||||
int lc = Math.Min(m_List.Count, 150);
|
||||
|
||||
int start = page * 15;
|
||||
int end = start + 15;
|
||||
|
||||
if (end > lc)
|
||||
end = lc;
|
||||
|
||||
int ct = end - start;
|
||||
|
||||
int height = 12 + 20 + ct * 20 + 23 + 12;
|
||||
|
||||
AddBackground(0, 0, 499, height, 0x2436);
|
||||
|
||||
for (int i = start + 1; i < end; i += 2)
|
||||
AddImageTiled(12, 32 + (i - start) * 20, 475, 20, 0x2430);
|
||||
|
||||
AddAlphaRegion(10, 10, 479, height - 20);
|
||||
|
||||
if (page > 0)
|
||||
AddButton(446, height - 12 - 2 - 16, 0x15E3, 0x15E7, 1);
|
||||
else
|
||||
AddImage(446, height - 12 - 2 - 16, 0x2626);
|
||||
|
||||
if ((page + 1) * 15 < lc)
|
||||
AddButton(466, height - 12 - 2 - 16, 0x15E1, 0x15E5, 2);
|
||||
else
|
||||
AddImage(466, height - 12 - 2 - 16, 0x2622);
|
||||
|
||||
AddHtml(16, height - 12 - 2 - 18, 400, 20,
|
||||
Color(string.Format("Top {3} of {0:N0} duelists, page {1} of {2}", m_List.Count, page + 1, (lc + 14) / 15, lc),
|
||||
0xFFC000));
|
||||
|
||||
AddColumnHeader(75, "Rank");
|
||||
AddColumnHeader(115, "Level");
|
||||
AddColumnHeader(50, "Guild");
|
||||
AddColumnHeader(115, "Name");
|
||||
AddColumnHeader(60, "Wins");
|
||||
AddColumnHeader(60, "Losses");
|
||||
|
||||
for (int i = start; i < end && i < lc; ++i)
|
||||
{
|
||||
LadderEntry entry = m_List[i];
|
||||
|
||||
int y = 32 + (i - start) * 20;
|
||||
int x = 12;
|
||||
|
||||
AddBorderedText(x, y, 75, Center(Rank(i + 1)), 0xFFFFFF, 0);
|
||||
x += 75;
|
||||
|
||||
/*AddImage( 20, y + 5, 0x2616, 0x96C );
|
||||
AddImage( 22, y + 5, 0x2616, 0x96C );
|
||||
AddImage( 20, y + 7, 0x2616, 0x96C );
|
||||
AddImage( 22, y + 7, 0x2616, 0x96C );
|
||||
|
||||
AddImage( 21, y + 6, 0x2616, 0x454 );*/
|
||||
|
||||
AddImage(x + 3, y + 4, 0x805);
|
||||
|
||||
int xp = entry.Experience;
|
||||
int level = Ladder.GetLevel(xp);
|
||||
|
||||
Ladder.GetLevelInfo(level, out int xpBase, out int xpAdvance);
|
||||
|
||||
int width;
|
||||
|
||||
int xpOffset = xp - xpBase;
|
||||
|
||||
if (xpOffset >= xpAdvance)
|
||||
width = 109; // level 50
|
||||
else
|
||||
width = (109 * xpOffset + xpAdvance / 2) / (xpAdvance - 1);
|
||||
|
||||
//AddImageTiled( 21, y + 6, width, 8, 0x2617 );
|
||||
AddImageTiled(x + 3, y + 4, width, 11, 0x806);
|
||||
AddBorderedText(x, y, 115, Center(level.ToString()), 0xFFFFFF, 0);
|
||||
x += 115;
|
||||
|
||||
Mobile mob = entry.Mobile;
|
||||
|
||||
if (mob.Guild != null)
|
||||
AddBorderedText(x, y, 50, Center(mob.Guild.Abbreviation), 0xFFFFFF, 0);
|
||||
|
||||
x += 50;
|
||||
|
||||
AddBorderedText(x + 5, y, 115 - 5, mob.Name, 0xFFFFFF, 0);
|
||||
x += 115;
|
||||
|
||||
AddBorderedText(x, y, 60, Center(entry.Wins.ToString()), 0xFFFFFF, 0);
|
||||
x += 60;
|
||||
|
||||
AddBorderedText(x, y, 60, Center(entry.Losses.ToString()), 0xFFFFFF, 0);
|
||||
x += 60;
|
||||
|
||||
//AddBorderedText( 292 + 15, y, 115 - 30, String.Format( "{0} <DIV ALIGN=CENTER>/</DIV> <DIV ALIGN=RIGHT>{1}</DIV>", entry.Wins, entry.Losses ), 0xFFC000, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
public static string Rank(int num)
|
||||
{
|
||||
string numStr = num.ToString("N0");
|
||||
|
||||
if (num % 100 > 10 && num % 100 < 20)
|
||||
return numStr + "th";
|
||||
|
||||
switch (num % 10)
|
||||
{
|
||||
case 1: return numStr + "st";
|
||||
case 2: return numStr + "nd";
|
||||
case 3: return numStr + "rd";
|
||||
default: return numStr + "th";
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
Mobile from = sender.Mobile;
|
||||
|
||||
if (info.ButtonID == 1 && m_Page > 0)
|
||||
from.SendGump(new LadderGump(m_Ladder, m_Page - 1));
|
||||
else if (info.ButtonID == 2 && (m_Page + 1) * 15 < Math.Min(m_List.Count, 150))
|
||||
from.SendGump(new LadderGump(m_Ladder, m_Page + 1));
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
private void AddBorderedText(int x, int y, int width, string text, int color, int borderColor)
|
||||
{
|
||||
/*AddColoredText( x - 1, y, width, text, borderColor );
|
||||
AddColoredText( x + 1, y, width, text, borderColor );
|
||||
AddColoredText( x, y - 1, width, text, borderColor );
|
||||
AddColoredText( x, y + 1, width, text, borderColor );*/
|
||||
/*AddColoredText( x - 1, y - 1, width, text, borderColor );
|
||||
AddColoredText( x + 1, y + 1, width, text, borderColor );*/
|
||||
AddColoredText(x, y, width, text, color);
|
||||
}
|
||||
|
||||
private void AddColoredText(int x, int y, int width, string text, int color)
|
||||
{
|
||||
if (color == 0)
|
||||
AddHtml(x, y, width, 20, text);
|
||||
else
|
||||
AddHtml(x, y, width, 20, Color(text, color));
|
||||
}
|
||||
|
||||
private void AddColumnHeader(int width, string name)
|
||||
{
|
||||
AddBackground(m_ColumnX, 12, width, 20, 0x242C);
|
||||
AddImageTiled(m_ColumnX + 2, 14, width - 4, 16, 0x2430);
|
||||
AddBorderedText(m_ColumnX, 13, width, Center(name), 0xFFFFFF, 0);
|
||||
|
||||
m_ColumnX += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
253
Projects/Scripts/Engines/ConPVP/Gumps/ParticipantGump.cs
Normal file
253
Projects/Scripts/Engines/ConPVP/Gumps/ParticipantGump.cs
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class ParticipantGump : Gump
|
||||
{
|
||||
public ParticipantGump(Mobile from, DuelContext context, Participant p) : base(50, 50)
|
||||
{
|
||||
From = from;
|
||||
Context = context;
|
||||
Participant = p;
|
||||
|
||||
from.CloseGump<RulesetGump>();
|
||||
from.CloseGump<DuelContextGump>();
|
||||
from.CloseGump<ParticipantGump>();
|
||||
|
||||
int count = p.Players.Length;
|
||||
|
||||
if (count < 4)
|
||||
count = 4;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
int height = 35 + 10 + 22 + 22 + 30 + 22 + 2 + count * 22 + 2 + 30;
|
||||
|
||||
AddBackground(0, 0, 300, height, 9250);
|
||||
AddBackground(10, 10, 280, height - 20, 0xDAC);
|
||||
|
||||
AddButton(240, 25, 0xFB1, 0xFB3, 3);
|
||||
|
||||
//AddButton( 223, 54, 0x265A, 0x265A, 4, );
|
||||
|
||||
AddHtml(35, 25, 230, 20, Center("Participant Setup"));
|
||||
|
||||
int x = 35;
|
||||
int y = 47;
|
||||
|
||||
AddHtml(x, y, 200, 20, $"Team Size: {p.Players.Length}");
|
||||
y += 22;
|
||||
|
||||
AddGoldenButtonLabeled(x + 20, y, 1, "Increase");
|
||||
y += 22;
|
||||
AddGoldenButtonLabeled(x + 20, y, 2, "Decrease");
|
||||
y += 30;
|
||||
|
||||
AddHtml(35, y, 230, 20, Center("Players"));
|
||||
y += 22;
|
||||
|
||||
for (int i = 0; i < p.Players.Length; ++i)
|
||||
{
|
||||
DuelPlayer pl = p.Players[i];
|
||||
|
||||
AddGoldenButtonLabeled(x, y, 5 + i, $"{1 + i}: {(pl == null ? "Empty" : pl.Mobile.Name)}");
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile From{ get; }
|
||||
|
||||
public DuelContext Context{ get; }
|
||||
|
||||
public Participant Participant{ get; }
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public void AddGoldenButton(int x, int y, int bid)
|
||||
{
|
||||
AddButton(x, y, 0xD2, 0xD2, bid);
|
||||
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
|
||||
}
|
||||
|
||||
public void AddGoldenButtonLabeled(int x, int y, int bid, string text)
|
||||
{
|
||||
AddGoldenButton(x, y, bid);
|
||||
AddHtml(x + 25, y, 200, 20, text);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (!Context.Registered)
|
||||
return;
|
||||
|
||||
int bid = info.ButtonID;
|
||||
|
||||
if (bid == 0)
|
||||
{
|
||||
From.SendGump(new DuelContextGump(From, Context));
|
||||
}
|
||||
else if (bid == 1)
|
||||
{
|
||||
if (Participant.Count < 8)
|
||||
Participant.Resize(Participant.Count + 1);
|
||||
else
|
||||
From.SendMessage("You may not raise the team size any further.");
|
||||
|
||||
From.SendGump(new ParticipantGump(From, Context, Participant));
|
||||
}
|
||||
else if (bid == 2)
|
||||
{
|
||||
if (Participant.Count > 1 && Participant.Count > Participant.FilledSlots)
|
||||
Participant.Resize(Participant.Count - 1);
|
||||
else
|
||||
From.SendMessage("You may not lower the team size any further.");
|
||||
|
||||
From.SendGump(new ParticipantGump(From, Context, Participant));
|
||||
}
|
||||
else if (bid == 3)
|
||||
{
|
||||
if (Participant.FilledSlots > 0)
|
||||
{
|
||||
From.SendMessage("There is at least one currently active player. You must remove them first.");
|
||||
From.SendGump(new ParticipantGump(From, Context, Participant));
|
||||
}
|
||||
else if (Context.Participants.Count > 2)
|
||||
{
|
||||
/*Container cont = m_Participant.Stakes;
|
||||
|
||||
if ( cont != null )
|
||||
cont.Delete();*/
|
||||
|
||||
Context.Participants.Remove(Participant);
|
||||
From.SendGump(new DuelContextGump(From, Context));
|
||||
}
|
||||
else
|
||||
{
|
||||
From.SendMessage("Duels must have at least two participating parties.");
|
||||
From.SendGump(new ParticipantGump(From, Context, Participant));
|
||||
}
|
||||
}
|
||||
/*else if ( bid == 4 )
|
||||
{
|
||||
m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) );
|
||||
|
||||
Container cont = m_Participant.Stakes;
|
||||
|
||||
if ( cont != null && !cont.Deleted )
|
||||
{
|
||||
cont.DisplayTo( m_From );
|
||||
|
||||
Item[] checks = cont.FindItemsByType( typeof( BankCheck ) );
|
||||
|
||||
int gold = cont.TotalGold;
|
||||
|
||||
for ( int i = 0; i < checks.Length; ++i )
|
||||
gold += ((BankCheck)checks[i]).Worth;
|
||||
|
||||
m_From.SendMessage( "This container has {0} item{1} and {2} stone{3}. In gold or check form there is a total of {4:D}gp.", cont.TotalItems, cont.TotalItems==1?"":"s", cont.TotalWeight, cont.TotalWeight==1?"":"s", gold );
|
||||
}
|
||||
}*/
|
||||
else
|
||||
{
|
||||
bid -= 5;
|
||||
|
||||
if (bid >= 0 && bid < Participant.Players.Length)
|
||||
{
|
||||
if (Participant.Players[bid] == null)
|
||||
{
|
||||
From.Target = new ParticipantTarget(Context, Participant, bid);
|
||||
From.SendMessage("Target a player.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Participant.Players[bid].Mobile.SendMessage("You have been removed from the duel.");
|
||||
|
||||
if (Participant.Players[bid].Mobile is PlayerMobile)
|
||||
((PlayerMobile)Participant.Players[bid].Mobile).DuelPlayer = null;
|
||||
|
||||
Participant.Players[bid] = null;
|
||||
From.SendMessage("They have been removed from the duel.");
|
||||
From.SendGump(new ParticipantGump(From, Context, Participant));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ParticipantTarget : Target
|
||||
{
|
||||
private DuelContext m_Context;
|
||||
private int m_Index;
|
||||
private Participant m_Participant;
|
||||
|
||||
public ParticipantTarget(DuelContext context, Participant p, int index) : base(12, false, TargetFlags.None)
|
||||
{
|
||||
m_Context = context;
|
||||
m_Participant = p;
|
||||
m_Index = index;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (!m_Context.Registered)
|
||||
return;
|
||||
|
||||
int index = m_Index;
|
||||
|
||||
if (index < 0 || index >= m_Participant.Players.Length)
|
||||
return;
|
||||
|
||||
if (!(targeted is Mobile mob))
|
||||
{
|
||||
from.SendMessage("That is not a player.");
|
||||
}
|
||||
else if (!mob.Player)
|
||||
{
|
||||
if (mob.Body.IsHuman)
|
||||
mob.SayTo(from, 1005443); // Nay, I would rather stay here and watch a nail rust.
|
||||
else
|
||||
mob.SayTo(from, 1005444); // The creature ignores your offer.
|
||||
}
|
||||
else if (AcceptDuelGump.IsIgnored(mob, from) || mob.Blessed)
|
||||
{
|
||||
from.SendMessage("They ignore your offer.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(mob is PlayerMobile pm))
|
||||
return;
|
||||
|
||||
if (pm.DuelContext != null)
|
||||
{
|
||||
from.SendMessage("{0} cannot fight because they are already assigned to another duel.", pm.Name);
|
||||
}
|
||||
else if (DuelContext.CheckCombat(pm))
|
||||
{
|
||||
from.SendMessage("{0} cannot fight because they have recently been in combat with another player.",
|
||||
pm.Name);
|
||||
}
|
||||
else if (mob.HasGump<AcceptDuelGump>())
|
||||
{
|
||||
from.SendMessage("{0} has already been offered a duel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendMessage("You send {0} to {1}.",
|
||||
m_Participant.Find(from) == null ? "a challenge" : "an invitation", mob.Name);
|
||||
mob.SendGump(new AcceptDuelGump(from, mob, m_Context, m_Participant, m_Index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTargetFinish(Mobile from)
|
||||
{
|
||||
from.SendGump(new ParticipantGump(from, m_Context, m_Participant));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Projects/Scripts/Engines/ConPVP/Gumps/PickRulesetGump.cs
Normal file
126
Projects/Scripts/Engines/ConPVP/Gumps/PickRulesetGump.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class PickRulesetGump : Gump
|
||||
{
|
||||
private DuelContext m_Context;
|
||||
private Ruleset[] m_Defaults;
|
||||
private Ruleset[] m_Flavors;
|
||||
private Mobile m_From;
|
||||
private Ruleset m_Ruleset;
|
||||
|
||||
public PickRulesetGump(Mobile from, DuelContext context, Ruleset ruleset) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Context = context;
|
||||
m_Ruleset = ruleset;
|
||||
m_Defaults = ruleset.Layout.Defaults;
|
||||
m_Flavors = ruleset.Layout.Flavors;
|
||||
|
||||
int height = 25 + 20 + (m_Defaults.Length + 1) * 22 + 6 + 20 + m_Flavors.Length * 22 + 25;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 260, height, 9250);
|
||||
AddBackground(10, 10, 240, height - 20, 0xDAC);
|
||||
|
||||
AddHtml(35, 25, 190, 20, Center("Rules"));
|
||||
|
||||
int y = 25 + 20;
|
||||
|
||||
for (int i = 0; i < m_Defaults.Length; ++i)
|
||||
{
|
||||
Ruleset cur = m_Defaults[i];
|
||||
|
||||
AddHtml(35 + 14, y, 176, 20, cur.Title);
|
||||
|
||||
if (ruleset.Base == cur && !ruleset.Changed)
|
||||
AddImage(35, y + 4, 0x939);
|
||||
else if (ruleset.Base == cur)
|
||||
AddButton(35, y + 4, 0x93A, 0x939, 2 + i);
|
||||
else
|
||||
AddButton(35, y + 4, 0x938, 0x939, 2 + i);
|
||||
|
||||
y += 22;
|
||||
}
|
||||
|
||||
AddHtml(35 + 14, y, 176, 20, "Custom");
|
||||
AddButton(35, y + 4, ruleset.Changed ? 0x939 : 0x938, 0x939, 1);
|
||||
|
||||
y += 22;
|
||||
y += 6;
|
||||
|
||||
AddHtml(35, y, 190, 20, Center("Flavors"));
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < m_Flavors.Length; ++i)
|
||||
{
|
||||
Ruleset cur = m_Flavors[i];
|
||||
|
||||
AddHtml(35 + 14, y, 176, 20, cur.Title);
|
||||
|
||||
if (ruleset.Flavors.Contains(cur))
|
||||
AddButton(35, y + 4, 0x939, 0x938, 2 + m_Defaults.Length + i);
|
||||
else
|
||||
AddButton(35, y + 4, 0x938, 0x939, 2 + m_Defaults.Length + i);
|
||||
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (m_Context?.Registered == false)
|
||||
return;
|
||||
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 0: // closed
|
||||
{
|
||||
if (m_Context != null)
|
||||
m_From.SendGump(new DuelContextGump(m_From, m_Context));
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // customize
|
||||
{
|
||||
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Ruleset.Layout, m_Context));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
int idx = info.ButtonID - 2;
|
||||
|
||||
if (idx >= 0 && idx < m_Defaults.Length)
|
||||
{
|
||||
m_Ruleset.ApplyDefault(m_Defaults[idx]);
|
||||
m_From.SendGump(new PickRulesetGump(m_From, m_Context, m_Ruleset));
|
||||
}
|
||||
else
|
||||
{
|
||||
idx -= m_Defaults.Length;
|
||||
|
||||
if (idx >= 0 && idx < m_Flavors.Length)
|
||||
{
|
||||
if (m_Ruleset.Flavors.Contains(m_Flavors[idx]))
|
||||
m_Ruleset.RemoveFlavor(m_Flavors[idx]);
|
||||
else
|
||||
m_Ruleset.AddFlavor(m_Flavors[idx]);
|
||||
|
||||
m_From.SendGump(new PickRulesetGump(m_From, m_Context, m_Ruleset));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Projects/Scripts/Engines/ConPVP/Gumps/ReadyGump.cs
Normal file
109
Projects/Scripts/Engines/ConPVP/Gumps/ReadyGump.cs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class ReadyGump : Gump
|
||||
{
|
||||
private DuelContext m_Context;
|
||||
private int m_Count;
|
||||
private Mobile m_From;
|
||||
|
||||
public ReadyGump(Mobile from, DuelContext context, int count) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Context = context;
|
||||
m_Count = count;
|
||||
|
||||
List<Participant> parts = context.Participants;
|
||||
|
||||
int height = 25 + 20;
|
||||
|
||||
for (int i = 0; i < parts.Count; ++i)
|
||||
{
|
||||
Participant p = parts[i];
|
||||
|
||||
height += 4;
|
||||
|
||||
if (p.Players.Length > 1)
|
||||
height += 22;
|
||||
|
||||
height += p.Players.Length * 22;
|
||||
}
|
||||
|
||||
height += 25;
|
||||
|
||||
Closable = false;
|
||||
Draggable = false;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 260, height, 9250);
|
||||
AddBackground(10, 10, 240, height - 20, 0xDAC);
|
||||
|
||||
if (count == -1)
|
||||
{
|
||||
AddHtml(35, 25, 190, 20, Center("Ready"));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtml(35, 25, 190, 20, Center("Starting"));
|
||||
AddHtml(35, 25, 190, 20, "<DIV ALIGN=RIGHT>" + count);
|
||||
}
|
||||
|
||||
int y = 25 + 20;
|
||||
|
||||
for (int i = 0; i < parts.Count; ++i)
|
||||
{
|
||||
Participant p = parts[i];
|
||||
|
||||
y += 4;
|
||||
|
||||
bool isAllReady = true;
|
||||
int yStore = y;
|
||||
int offset = 0;
|
||||
|
||||
if (p.Players.Length > 1)
|
||||
{
|
||||
AddHtml(35 + 14, y, 176, 20, $"Participant #{i + 1}");
|
||||
y += 22;
|
||||
offset = 10;
|
||||
}
|
||||
|
||||
for (int j = 0; j < p.Players.Length; ++j)
|
||||
{
|
||||
DuelPlayer pl = p.Players[j];
|
||||
|
||||
if (pl?.Ready == true)
|
||||
{
|
||||
AddImage(35 + offset, y + 4, 0x939);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddImage(35 + offset, y + 4, 0x938);
|
||||
isAllReady = false;
|
||||
}
|
||||
|
||||
string name = pl == null ? "(Empty)" : pl.Mobile.Name;
|
||||
|
||||
AddHtml(35 + offset + 14, y, 166, 20, name);
|
||||
|
||||
y += 22;
|
||||
}
|
||||
|
||||
if (p.Players.Length > 1)
|
||||
AddImage(35, yStore + 4, isAllReady ? 0x939 : 0x938);
|
||||
}
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
233
Projects/Scripts/Engines/ConPVP/Gumps/ReadyUpGump.cs
Normal file
233
Projects/Scripts/Engines/ConPVP/Gumps/ReadyUpGump.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class ReadyUpGump : Gump
|
||||
{
|
||||
private DuelContext m_Context;
|
||||
private Mobile m_From;
|
||||
|
||||
public ReadyUpGump(Mobile from, DuelContext context) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Context = context;
|
||||
|
||||
Closable = false;
|
||||
AddPage(0);
|
||||
|
||||
if (context.Rematch)
|
||||
{
|
||||
int height = 25 + 20 + 10 + 22 + 25;
|
||||
|
||||
AddBackground(0, 0, 210, height, 9250);
|
||||
AddBackground(10, 10, 190, height - 20, 0xDAC);
|
||||
|
||||
AddHtml(35, 25, 140, 20, Center("Rematch?"));
|
||||
|
||||
AddButton(35, 55, 247, 248, 1);
|
||||
AddButton(115, 55, 242, 241, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Participants
|
||||
|
||||
AddPage(1);
|
||||
|
||||
List<Participant> parts = context.Participants;
|
||||
|
||||
int height = 25 + 20;
|
||||
|
||||
for (int i = 0; i < parts.Count; ++i)
|
||||
{
|
||||
Participant p = parts[i];
|
||||
|
||||
height += 4;
|
||||
|
||||
if (p.Players.Length > 1)
|
||||
height += 22;
|
||||
|
||||
height += p.Players.Length * 22;
|
||||
}
|
||||
|
||||
height += 10 + 22 + 25;
|
||||
|
||||
AddBackground(0, 0, 260, height, 9250);
|
||||
AddBackground(10, 10, 240, height - 20, 0xDAC);
|
||||
|
||||
AddHtml(35, 25, 190, 20, Center("Participants"));
|
||||
|
||||
int y = 20 + 25;
|
||||
|
||||
for (int i = 0; i < parts.Count; ++i)
|
||||
{
|
||||
Participant p = parts[i];
|
||||
|
||||
y += 4;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
if (p.Players.Length > 1)
|
||||
{
|
||||
AddHtml(35, y, 176, 20, $"Team #{i + 1}");
|
||||
y += 22;
|
||||
offset = 10;
|
||||
}
|
||||
|
||||
for (int j = 0; j < p.Players.Length; ++j)
|
||||
{
|
||||
DuelPlayer pl = p.Players[j];
|
||||
|
||||
string name = pl == null ? "(Empty)" : pl.Mobile.Name;
|
||||
|
||||
AddHtml(35 + offset, y, 166, 20, name);
|
||||
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
|
||||
y += 8;
|
||||
|
||||
AddHtml(35, y, 176, 20, "Continue?");
|
||||
|
||||
y -= 2;
|
||||
|
||||
AddButton(102, y, 247, 248, 0, GumpButtonType.Page, 2);
|
||||
AddButton(169, y, 242, 241, 2);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rules
|
||||
|
||||
AddPage(2);
|
||||
|
||||
Ruleset ruleset = context.Ruleset;
|
||||
Ruleset basedef = ruleset.Base;
|
||||
|
||||
height = 25 + 20 + 5 + 20 + 20 + 4;
|
||||
|
||||
int changes = 0;
|
||||
|
||||
BitArray defs;
|
||||
|
||||
if (ruleset.Flavors.Count > 0)
|
||||
{
|
||||
defs = new BitArray(basedef.Options);
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i)
|
||||
defs.Or(ruleset.Flavors[i].Options);
|
||||
|
||||
height += ruleset.Flavors.Count * 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
defs = basedef.Options;
|
||||
}
|
||||
|
||||
BitArray opts = ruleset.Options;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
++changes;
|
||||
|
||||
height += changes * 22;
|
||||
|
||||
height += 10 + 22 + 25;
|
||||
|
||||
AddBackground(0, 0, 260, height, 9250);
|
||||
AddBackground(10, 10, 240, height - 20, 0xDAC);
|
||||
|
||||
AddHtml(35, 25, 190, 20, Center("Rules"));
|
||||
|
||||
AddHtml(35, 50, 190, 20, $"Set: {basedef.Title}");
|
||||
|
||||
y = 70;
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
|
||||
AddHtml(35, y, 190, 20, $" + {ruleset.Flavors[i].Title}");
|
||||
|
||||
y += 4;
|
||||
|
||||
if (changes > 0)
|
||||
{
|
||||
AddHtml(35, y, 190, 20, "Modifications:");
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
{
|
||||
string name = ruleset.Layout.FindByIndex(i);
|
||||
|
||||
if (name != null) // sanity
|
||||
{
|
||||
AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
|
||||
AddHtml(60, y, 165, 22, name);
|
||||
}
|
||||
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtml(35, y, 190, 20, "Modifications: None");
|
||||
y += 20;
|
||||
}
|
||||
|
||||
y += 8;
|
||||
|
||||
AddHtml(35, y, 176, 20, "Continue?");
|
||||
|
||||
y -= 2;
|
||||
|
||||
AddButton(102, y, 247, 248, 1);
|
||||
AddButton(169, y, 242, 241, 3);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public void AddGoldenButton(int x, int y, int bid)
|
||||
{
|
||||
AddButton(x, y, 0xD2, 0xD2, bid);
|
||||
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (!m_Context.Registered || !m_Context.ReadyWait)
|
||||
return;
|
||||
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 1: // okay
|
||||
{
|
||||
if (!(m_From is PlayerMobile pm))
|
||||
break;
|
||||
|
||||
pm.DuelPlayer.Ready = true;
|
||||
m_Context.SendReadyGump();
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // reject participants
|
||||
{
|
||||
m_Context.RejectReady(m_From, "participants");
|
||||
break;
|
||||
}
|
||||
case 3: // reject rules
|
||||
{
|
||||
m_Context.RejectReady(m_From, "rules");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs
Normal file
130
Projects/Scripts/Engines/ConPVP/Gumps/RulesetGump.cs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
using System.Collections;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class RulesetGump : Gump
|
||||
{
|
||||
private DuelContext m_DuelContext;
|
||||
private Mobile m_From;
|
||||
private RulesetLayout m_Page;
|
||||
private bool m_ReadOnly;
|
||||
private Ruleset m_Ruleset;
|
||||
|
||||
public RulesetGump(Mobile from, Ruleset ruleset, RulesetLayout page, DuelContext duelContext, bool readOnly = false)
|
||||
: base(readOnly ? 310 : 50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Ruleset = ruleset;
|
||||
m_Page = page;
|
||||
m_DuelContext = duelContext;
|
||||
m_ReadOnly = readOnly;
|
||||
|
||||
Draggable = !readOnly;
|
||||
|
||||
from.CloseGump<RulesetGump>();
|
||||
from.CloseGump<DuelContextGump>();
|
||||
from.CloseGump<ParticipantGump>();
|
||||
|
||||
RulesetLayout depthCounter = page;
|
||||
int depth = 0;
|
||||
|
||||
while (depthCounter != null)
|
||||
{
|
||||
++depth;
|
||||
depthCounter = depthCounter.Parent;
|
||||
}
|
||||
|
||||
int count = page.Children.Length + page.Options.Length;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
int height = 35 + 10 + 2 + count * 22 + 2 + 30;
|
||||
|
||||
AddBackground(0, 0, 260, height, 9250);
|
||||
AddBackground(10, 10, 240, height - 20, 0xDAC);
|
||||
|
||||
AddHtml(35, 25, 190, 20, Center(page.Title));
|
||||
|
||||
int x = 35;
|
||||
int y = 47;
|
||||
|
||||
for (int i = 0; i < page.Children.Length; ++i)
|
||||
{
|
||||
AddGoldenButton(x, y, 1 + i);
|
||||
AddHtml(x + 25, y, 250, 22, page.Children[i].Title);
|
||||
|
||||
y += 22;
|
||||
}
|
||||
|
||||
for (int i = 0; i < page.Options.Length; ++i)
|
||||
{
|
||||
bool enabled = ruleset.Options[page.Offset + i];
|
||||
|
||||
if (readOnly)
|
||||
AddImage(x, y, enabled ? 0xD3 : 0xD2);
|
||||
else
|
||||
AddCheck(x, y, 0xD2, 0xD3, enabled, i);
|
||||
|
||||
AddHtml(x + 25, y, 250, 22, page.Options[i]);
|
||||
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public void AddGoldenButton(int x, int y, int bid)
|
||||
{
|
||||
AddButton(x, y, 0xD2, 0xD2, bid);
|
||||
AddButton(x + 3, y + 3, 0xD8, 0xD8, bid);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (m_DuelContext?.Registered == false)
|
||||
return;
|
||||
|
||||
if (!m_ReadOnly)
|
||||
{
|
||||
BitArray opts = new BitArray(m_Page.Options.Length);
|
||||
|
||||
for (int i = 0; i < info.Switches.Length; ++i)
|
||||
{
|
||||
int sid = info.Switches[i];
|
||||
|
||||
if (sid >= 0 && sid < m_Page.Options.Length)
|
||||
opts[sid] = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (m_Ruleset.Options[m_Page.Offset + i] != opts[i])
|
||||
{
|
||||
m_Ruleset.Options[m_Page.Offset + i] = opts[i];
|
||||
m_Ruleset.Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
int bid = info.ButtonID;
|
||||
|
||||
if (bid == 0)
|
||||
{
|
||||
if (m_Page.Parent != null)
|
||||
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Page.Parent, m_DuelContext, m_ReadOnly));
|
||||
else if (!m_ReadOnly)
|
||||
m_From.SendGump(new PickRulesetGump(m_From, m_DuelContext, m_Ruleset));
|
||||
}
|
||||
else
|
||||
{
|
||||
bid -= 1;
|
||||
|
||||
if (bid >= 0 && bid < m_Page.Children.Length)
|
||||
m_From.SendGump(new RulesetGump(m_From, m_Ruleset, m_Page.Children[bid], m_DuelContext, m_ReadOnly));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
856
Projects/Scripts/Engines/ConPVP/Gumps/TournamentBracketGump.cs
Normal file
856
Projects/Scripts/Engines/ConPVP/Gumps/TournamentBracketGump.cs
Normal file
|
|
@ -0,0 +1,856 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public enum TourneyBracketGumpType
|
||||
{
|
||||
Index,
|
||||
Rules_Info,
|
||||
Participant_List,
|
||||
Participant_Info,
|
||||
Round_List,
|
||||
Round_Info,
|
||||
Match_Info,
|
||||
Player_Info
|
||||
}
|
||||
|
||||
public class TournamentBracketGump : Gump
|
||||
{
|
||||
private const int BlackColor32 = 0x000008;
|
||||
private const int LabelColor32 = 0xFFFFFF;
|
||||
private Mobile m_From;
|
||||
private List<object> m_List;
|
||||
private object m_Object;
|
||||
private int m_Page;
|
||||
private int m_PerPage;
|
||||
private Tournament m_Tournament;
|
||||
private TourneyBracketGumpType m_Type;
|
||||
|
||||
public TournamentBracketGump(Mobile from, Tournament tourney, TourneyBracketGumpType type,
|
||||
List<object> list = null, int page = 0, object obj = null) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Tournament = tourney;
|
||||
m_Type = type;
|
||||
m_List = list;
|
||||
m_Page = page;
|
||||
m_Object = obj;
|
||||
m_PerPage = 12;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TourneyBracketGumpType.Index:
|
||||
{
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300, 300, 9380);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (tourney.TourneyType == TourneyType.FreeForAll)
|
||||
{
|
||||
sb.Append("FFA");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
sb.Append(tourney.ParticipantsPerMatch);
|
||||
sb.Append("-Team");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
sb.Append("Red v Blue");
|
||||
}
|
||||
else if (tourney.TourneyType == TourneyType.Faction)
|
||||
{
|
||||
sb.Append(tourney.ParticipantsPerMatch);
|
||||
sb.Append("-Team Faction");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tourney.ParticipantsPerMatch; ++i)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append('v');
|
||||
|
||||
sb.Append(tourney.PlayersPerParticipant);
|
||||
}
|
||||
}
|
||||
|
||||
if (tourney.EventController != null)
|
||||
sb.Append(' ').Append(tourney.EventController.Title);
|
||||
|
||||
sb.Append(" Tournament Bracket");
|
||||
|
||||
AddHtml(25, 35, 250, 20, Center(sb.ToString()));
|
||||
|
||||
AddRightArrow(25, 53, ToButtonID(0, 4), "Rules");
|
||||
AddRightArrow(25, 71, ToButtonID(0, 1), "Participants");
|
||||
|
||||
if (m_Tournament.Stage == TournamentStage.Signup)
|
||||
{
|
||||
TimeSpan until = m_Tournament.SignupStart + m_Tournament.SignupPeriod - DateTime.UtcNow;
|
||||
string text;
|
||||
int secs = (int)until.TotalSeconds;
|
||||
|
||||
if (secs > 0)
|
||||
{
|
||||
int mins = secs / 60;
|
||||
secs %= 60;
|
||||
|
||||
if (mins > 0 && secs > 0)
|
||||
text =
|
||||
$"The tournament will begin in {mins} minute{(mins == 1 ? "" : "s")} and {secs} second{(secs == 1 ? "" : "s")}.";
|
||||
else if (mins > 0)
|
||||
text = $"The tournament will begin in {mins} minute{(mins == 1 ? "" : "s")}.";
|
||||
else if (secs > 0)
|
||||
text = $"The tournament will begin in {secs} second{(secs == 1 ? "" : "s")}.";
|
||||
else
|
||||
text = "The tournament will begin shortly.";
|
||||
}
|
||||
else
|
||||
{
|
||||
text = "The tournament will begin shortly.";
|
||||
}
|
||||
|
||||
AddHtml(25, 92, 250, 40, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRightArrow(25, 89, ToButtonID(0, 2), "Rounds");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyBracketGumpType.Rules_Info:
|
||||
{
|
||||
Ruleset ruleset = tourney.Ruleset;
|
||||
Ruleset basedef = ruleset.Base;
|
||||
|
||||
BitArray defs;
|
||||
|
||||
if (ruleset.Flavors.Count > 0)
|
||||
{
|
||||
defs = new BitArray(basedef.Options);
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i)
|
||||
defs.Or(ruleset.Flavors[i].Options);
|
||||
}
|
||||
else
|
||||
{
|
||||
defs = basedef.Options;
|
||||
}
|
||||
|
||||
int changes = 0;
|
||||
|
||||
BitArray opts = ruleset.Options;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
++changes;
|
||||
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300,
|
||||
60 + 18 + 20 + 20 + 20 + 8 + 20 + ruleset.Flavors.Count * 18 + 4 + 20 + changes * 22 + 6, 9380);
|
||||
|
||||
AddLeftArrow(25, 11, ToButtonID(0, 0));
|
||||
AddHtml(25, 35, 250, 20, Center("Rules"));
|
||||
|
||||
int y = 53;
|
||||
|
||||
string groupText = null;
|
||||
|
||||
switch (tourney.GroupType)
|
||||
{
|
||||
case GroupingType.HighVsLow:
|
||||
groupText = "High vs Low";
|
||||
break;
|
||||
case GroupingType.Nearest:
|
||||
groupText = "Closest opponent";
|
||||
break;
|
||||
case GroupingType.Random:
|
||||
groupText = "Random";
|
||||
break;
|
||||
}
|
||||
|
||||
AddHtml(35, y, 190, 20, $"Grouping: {groupText}");
|
||||
y += 20;
|
||||
|
||||
string tieText = null;
|
||||
|
||||
switch (tourney.TieType)
|
||||
{
|
||||
case TieType.Random:
|
||||
tieText = "Random";
|
||||
break;
|
||||
case TieType.Highest:
|
||||
tieText = "Highest advances";
|
||||
break;
|
||||
case TieType.Lowest:
|
||||
tieText = "Lowest advances";
|
||||
break;
|
||||
case TieType.FullAdvancement:
|
||||
tieText = tourney.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances";
|
||||
break;
|
||||
case TieType.FullElimination:
|
||||
tieText = tourney.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated";
|
||||
break;
|
||||
}
|
||||
|
||||
AddHtml(35, y, 190, 20, $"Tiebreaker: {tieText}");
|
||||
y += 20;
|
||||
|
||||
string sdText = "Off";
|
||||
|
||||
if (tourney.SuddenDeath > TimeSpan.Zero)
|
||||
{
|
||||
sdText = $"{(int)tourney.SuddenDeath.TotalMinutes}:{tourney.SuddenDeath.Seconds:D2}";
|
||||
|
||||
if (tourney.SuddenDeathRounds > 0)
|
||||
sdText = $"{sdText} (first {tourney.SuddenDeathRounds} rounds)";
|
||||
else
|
||||
sdText = $"{sdText} (all rounds)";
|
||||
}
|
||||
|
||||
AddHtml(35, y, 240, 20, $"Sudden Death: {sdText}");
|
||||
y += 20;
|
||||
|
||||
y += 8;
|
||||
|
||||
AddHtml(35, y, 190, 20, $"Ruleset: {basedef.Title}");
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < ruleset.Flavors.Count; ++i, y += 18)
|
||||
AddHtml(35, y, 190, 20, $" + {ruleset.Flavors[i].Title}");
|
||||
|
||||
y += 4;
|
||||
|
||||
if (changes > 0)
|
||||
{
|
||||
AddHtml(35, y, 190, 20, "Modifications:");
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < opts.Length; ++i)
|
||||
if (defs[i] != opts[i])
|
||||
{
|
||||
string name = ruleset.Layout.FindByIndex(i);
|
||||
|
||||
if (name != null) // sanity
|
||||
{
|
||||
AddImage(35, y, opts[i] ? 0xD3 : 0xD2);
|
||||
AddHtml(60, y, 165, 22, name);
|
||||
}
|
||||
|
||||
y += 22;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtml(35, y, 190, 20, "Modifications: None");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyBracketGumpType.Participant_List:
|
||||
{
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300, 300, 9380);
|
||||
|
||||
List<TourneyParticipant> pList = m_List != null
|
||||
? Utility.CastListCovariant<object, TourneyParticipant>(m_List)
|
||||
: new List<TourneyParticipant>(tourney.Participants);
|
||||
|
||||
AddLeftArrow(25, 11, ToButtonID(0, 0));
|
||||
AddHtml(25, 35, 250, 20, Center($"{pList.Count} Participant{(pList.Count == 1 ? "" : "s")}"));
|
||||
|
||||
StartPage(out int index, out int count, out int y, 12);
|
||||
|
||||
for (int i = 0; i < count; ++i, y += 18)
|
||||
{
|
||||
TourneyParticipant part = pList[index + i];
|
||||
string name = part.NameList;
|
||||
|
||||
if (m_Tournament.TourneyType != TourneyType.Standard && part.Players.Count == 1)
|
||||
if (part.Players[0] is PlayerMobile pm && pm.DuelPlayer != null)
|
||||
name = Color(name, pm.DuelPlayer.Eliminated ? 0x6633333 : 0x336666);
|
||||
|
||||
AddRightArrow(25, y, ToButtonID(2, index + i), name);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyBracketGumpType.Participant_Info:
|
||||
{
|
||||
if (!(obj is TourneyParticipant part))
|
||||
break;
|
||||
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300, 60 + 18 + 20 + part.Players.Count * 18 + 20 + 20 + 160, 9380);
|
||||
|
||||
AddLeftArrow(25, 11, ToButtonID(0, 1));
|
||||
AddHtml(25, 35, 250, 20, Center("Participants"));
|
||||
|
||||
int y = 53;
|
||||
|
||||
AddHtml(25, y, 200, 20, part.Players.Count == 1 ? "Players" : "Team");
|
||||
y += 20;
|
||||
|
||||
for (int i = 0; i < part.Players.Count; ++i)
|
||||
{
|
||||
Mobile mob = part.Players[i];
|
||||
string name = mob.Name;
|
||||
|
||||
if (m_Tournament.TourneyType != TourneyType.Standard)
|
||||
if (mob is PlayerMobile pm && pm.DuelPlayer != null)
|
||||
name = Color(name, pm.DuelPlayer.Eliminated ? 0x6633333 : 0x336666);
|
||||
|
||||
AddRightArrow(35, y, ToButtonID(4, i), name);
|
||||
y += 18;
|
||||
}
|
||||
|
||||
AddHtml(25, y, 200, 20,
|
||||
$"Free Advances: {(part.FreeAdvances == 0 ? "None" : part.FreeAdvances.ToString())}");
|
||||
y += 20;
|
||||
|
||||
AddHtml(25, y, 200, 20, "Log:");
|
||||
y += 20;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < part.Log.Count; ++i)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append("<br>");
|
||||
|
||||
sb.Append(part.Log[i]);
|
||||
}
|
||||
|
||||
if (sb.Length == 0)
|
||||
sb.Append("Nothing logged yet.");
|
||||
|
||||
AddHtml(25, y, 250, 150, Color(sb.ToString(), BlackColor32), false, true);
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyBracketGumpType.Player_Info:
|
||||
{
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300, 300, 9380);
|
||||
|
||||
AddLeftArrow(25, 11, ToButtonID(0, 3));
|
||||
AddHtml(25, 35, 250, 20, Center("Participants"));
|
||||
|
||||
if (!(obj is Mobile mob))
|
||||
break;
|
||||
|
||||
Ladder ladder = Ladder.Instance;
|
||||
LadderEntry entry = ladder?.Find(mob);
|
||||
|
||||
AddHtml(25, 53, 250, 20, $"Name: {mob.Name}");
|
||||
AddHtml(25, 73, 250, 20,
|
||||
$"Guild: {(mob.Guild == null ? "None" : mob.Guild.Name + " [" + mob.Guild.Abbreviation + "]")}");
|
||||
AddHtml(25, 93, 250, 20, $"Rank: {(entry == null ? "N/A" : LadderGump.Rank(entry.Index + 1))}");
|
||||
AddHtml(25, 113, 250, 20, $"Level: {(entry == null ? 0 : Ladder.GetLevel(entry.Experience))}");
|
||||
AddHtml(25, 133, 250, 20, $"Wins: {entry?.Wins ?? 0:N0}");
|
||||
AddHtml(25, 153, 250, 20, $"Losses: {entry?.Losses ?? 0:N0}");
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyBracketGumpType.Round_List:
|
||||
{
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300, 300, 9380);
|
||||
|
||||
AddLeftArrow(25, 11, ToButtonID(0, 0));
|
||||
AddHtml(25, 35, 250, 20, Center("Rounds"));
|
||||
|
||||
// List<PyramidLevel> levelsList = m_List != null
|
||||
// ? Utility.CastListCovariant<object, PyramidLevel>(m_List)
|
||||
// : new List<PyramidLevel>(tourney.Pyramid.Levels);
|
||||
|
||||
StartPage(out int index, out int count, out int y, 12);
|
||||
|
||||
for (int i = 0; i < count; ++i, y += 18)
|
||||
AddRightArrow(25, y, ToButtonID(3, index + i), "Round #" + (index + i + 1));
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyBracketGumpType.Round_Info:
|
||||
{
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300, 300, 9380);
|
||||
|
||||
AddLeftArrow(25, 11, ToButtonID(0, 2));
|
||||
AddHtml(25, 35, 250, 20, Center("Rounds"));
|
||||
|
||||
if (!(m_Object is PyramidLevel level))
|
||||
break;
|
||||
|
||||
List<TourneyMatch> matchesList = m_List != null
|
||||
? Utility.CastListCovariant<object, TourneyMatch>(m_List)
|
||||
: new List<TourneyMatch>(level.Matches);
|
||||
|
||||
AddRightArrow(25, 53, ToButtonID(5, 0),
|
||||
$"Free Advance: {(level.FreeAdvance == null ? "None" : level.FreeAdvance.NameList)}");
|
||||
|
||||
AddHtml(25, 73, 200, 20, $"{matchesList.Count} Match{(matchesList.Count == 1 ? "" : "es")}");
|
||||
|
||||
StartPage(out int index, out int count, out int y, 10);
|
||||
|
||||
for (int i = 0; i < count; ++i, y += 18)
|
||||
{
|
||||
TourneyMatch match = matchesList[index + i];
|
||||
|
||||
int color = -1;
|
||||
|
||||
if (match.InProgress)
|
||||
color = 0x336666;
|
||||
else if (match.Context != null && match.Winner == null)
|
||||
color = 0x666666;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (m_Tournament.TourneyType == TourneyType.Standard)
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append(" vs ");
|
||||
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
string txt = part.NameList;
|
||||
|
||||
if (color == -1 && match.Context != null && match.Winner == part)
|
||||
txt = Color(txt, 0x336633);
|
||||
else if (color == -1 && match.Context != null)
|
||||
txt = Color(txt, 0x663333);
|
||||
|
||||
sb.Append(txt);
|
||||
}
|
||||
else if (m_Tournament.EventController != null || m_Tournament.TourneyType == TourneyType.RandomTeam ||
|
||||
m_Tournament.TourneyType == TourneyType.RedVsBlue ||
|
||||
m_Tournament.TourneyType == TourneyType.Faction)
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append(" vs ");
|
||||
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
string txt;
|
||||
|
||||
if (m_Tournament.EventController != null)
|
||||
{
|
||||
txt = $"Team {m_Tournament.EventController.GetTeamName(j)} ({part.Players.Count})";
|
||||
}
|
||||
else if (m_Tournament.TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
txt = $"Team {j + 1} ({part.Players.Count})";
|
||||
}
|
||||
else if (m_Tournament.TourneyType == TourneyType.Faction)
|
||||
{
|
||||
if (m_Tournament.ParticipantsPerMatch == 4)
|
||||
{
|
||||
string name = "(null)";
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
name = "Minax";
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
name = "Council of Mages";
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
name = "True Britannians";
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
name = "Shadowlords";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
txt = $"{name} ({part.Players.Count})";
|
||||
}
|
||||
else if (m_Tournament.ParticipantsPerMatch == 2)
|
||||
{
|
||||
txt = $"{(j == 0 ? "Evil" : "Hero")} Team ({part.Players.Count})";
|
||||
}
|
||||
else
|
||||
{
|
||||
txt = $"Team {j + 1} ({part.Players.Count})";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
txt = $"Team {(j == 0 ? "Red" : "Blue")} ({part.Players.Count})";
|
||||
}
|
||||
|
||||
if (color == -1 && match.Context != null && match.Winner == part)
|
||||
txt = Color(txt, 0x336633);
|
||||
else if (color == -1 && match.Context != null)
|
||||
txt = Color(txt, 0x663333);
|
||||
|
||||
sb.Append(txt);
|
||||
}
|
||||
else if (m_Tournament.TourneyType == TourneyType.FreeForAll) sb.Append("Free For All");
|
||||
|
||||
string str = sb.ToString();
|
||||
|
||||
if (color >= 0)
|
||||
str = Color(str, color);
|
||||
|
||||
AddRightArrow(25, y, ToButtonID(5, index + i + 1), str);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyBracketGumpType.Match_Info:
|
||||
{
|
||||
if (!(obj is TourneyMatch match))
|
||||
break;
|
||||
|
||||
int ct = m_Tournament.TourneyType == TourneyType.FreeForAll ? 2 : match.Participants.Count;
|
||||
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 300, 60 + 18 + 20 + 20 + 20 + ct * 18 + 6, 9380);
|
||||
|
||||
AddLeftArrow(25, 11, ToButtonID(0, 5));
|
||||
AddHtml(25, 35, 250, 20, Center("Rounds"));
|
||||
|
||||
AddHtml(25, 53, 250, 20, $"Winner: {(match.Winner == null ? "N/A" : match.Winner.NameList)}");
|
||||
AddHtml(25, 73, 250, 20,
|
||||
$"State: {(match.InProgress ? "In progress" : match.Context != null ? "Complete" : "Waiting")}");
|
||||
AddHtml(25, 93, 250, 20, "Participants:");
|
||||
|
||||
if (m_Tournament.TourneyType == TourneyType.Standard)
|
||||
for (int i = 0; i < match.Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[i];
|
||||
|
||||
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i), part.NameList);
|
||||
}
|
||||
else if (m_Tournament.EventController != null || m_Tournament.TourneyType == TourneyType.RandomTeam ||
|
||||
m_Tournament.TourneyType == TourneyType.RedVsBlue ||
|
||||
m_Tournament.TourneyType == TourneyType.Faction)
|
||||
for (int i = 0; i < match.Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[i];
|
||||
|
||||
if (m_Tournament.EventController != null)
|
||||
{
|
||||
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
|
||||
$"Team {m_Tournament.EventController.GetTeamName(i)} ({part.Players.Count})");
|
||||
}
|
||||
else if (m_Tournament.TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
|
||||
$"Team {i + 1} ({part.Players.Count})");
|
||||
}
|
||||
else if (m_Tournament.TourneyType == TourneyType.Faction)
|
||||
{
|
||||
if (m_Tournament.ParticipantsPerMatch == 4)
|
||||
{
|
||||
string name = "(null)";
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
name = "Minax";
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
name = "Council of Mages";
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
name = "True Britannians";
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
name = "Shadowlords";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
|
||||
$"{name} ({part.Players.Count})");
|
||||
}
|
||||
else if (m_Tournament.ParticipantsPerMatch == 2)
|
||||
{
|
||||
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
|
||||
$"{(i == 0 ? "Evil" : "Hero")} Team ({part.Players.Count})");
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
|
||||
$"Team {i + 1} ({part.Players.Count})");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRightArrow(25, 113 + i * 18, ToButtonID(6, i),
|
||||
$"Team {(i == 0 ? "Red" : "Blue")} ({part.Players.Count})");
|
||||
}
|
||||
}
|
||||
else if (m_Tournament.TourneyType == TourneyType.FreeForAll)
|
||||
AddHtml(25, 113, 250, 20, "Free For All");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor)
|
||||
{
|
||||
AddColoredText(x - 1, y - 1, width, height, text, borderColor);
|
||||
AddColoredText(x - 1, y + 1, width, height, text, borderColor);
|
||||
AddColoredText(x + 1, y - 1, width, height, text, borderColor);
|
||||
AddColoredText(x + 1, y + 1, width, height, text, borderColor);
|
||||
AddColoredText(x, y, width, height, text, color);
|
||||
}
|
||||
|
||||
private void AddColoredText(int x, int y, int width, int height, string text, int color)
|
||||
{
|
||||
if (color == 0)
|
||||
AddHtml(x, y, width, height, text);
|
||||
else
|
||||
AddHtml(x, y, width, height, Color(text, color));
|
||||
}
|
||||
|
||||
public void AddRightArrow(int x, int y, int bid, string text)
|
||||
{
|
||||
AddButton(x, y, 0x15E1, 0x15E5, bid);
|
||||
|
||||
if (text != null)
|
||||
AddHtml(x + 20, y - 1, 230, 20, text);
|
||||
}
|
||||
|
||||
public void AddRightArrow(int x, int y, int bid)
|
||||
{
|
||||
AddRightArrow(x, y, bid, null);
|
||||
}
|
||||
|
||||
public void AddLeftArrow(int x, int y, int bid, string text)
|
||||
{
|
||||
AddButton(x, y, 0x15E3, 0x15E7, bid);
|
||||
|
||||
if (text != null)
|
||||
AddHtml(x + 20, y - 1, 230, 20, text);
|
||||
}
|
||||
|
||||
public void AddLeftArrow(int x, int y, int bid)
|
||||
{
|
||||
AddLeftArrow(x, y, bid, null);
|
||||
}
|
||||
|
||||
public int ToButtonID(int type, int index)
|
||||
{
|
||||
return 1 + index * 7 + type;
|
||||
}
|
||||
|
||||
public bool FromButtonID(int bid, out int type, out int index)
|
||||
{
|
||||
type = (bid - 1) % 7;
|
||||
index = (bid - 1) / 7;
|
||||
return bid >= 1;
|
||||
}
|
||||
|
||||
public void StartPage(out int index, out int count, out int y, int perPage)
|
||||
{
|
||||
m_PerPage = perPage;
|
||||
|
||||
index = Math.Max(m_Page * perPage, 0);
|
||||
count = Math.Max(Math.Min(m_List.Count - index, perPage), 0);
|
||||
|
||||
y = 53 + (12 - perPage) * 18;
|
||||
|
||||
if (m_Page > 0)
|
||||
AddLeftArrow(242, 35, ToButtonID(1, 0));
|
||||
|
||||
if ((m_Page + 1) * perPage < m_List.Count)
|
||||
AddRightArrow(260, 35, ToButtonID(1, 1));
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (!FromButtonID(info.ButtonID, out int type, out int index))
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Index));
|
||||
break;
|
||||
case 1:
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
|
||||
TourneyBracketGumpType.Participant_List));
|
||||
break;
|
||||
case 2:
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Round_List));
|
||||
break;
|
||||
case 4:
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Rules_Info));
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
Mobile mob = m_Object as Mobile;
|
||||
|
||||
for (int i = 0; i < m_Tournament.Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = m_Tournament.Participants[i];
|
||||
|
||||
if (part.Players.Contains(mob))
|
||||
{
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
|
||||
TourneyBracketGumpType.Participant_Info, null, 0, part));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
if (!(m_Object is TourneyMatch match))
|
||||
break;
|
||||
|
||||
for (int i = 0; i < m_Tournament.Pyramid.Levels.Count; ++i)
|
||||
{
|
||||
PyramidLevel level = m_Tournament.Pyramid.Levels[i];
|
||||
|
||||
if (level.Matches.Contains(match))
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
|
||||
TourneyBracketGumpType.Round_Info, null, 0, level));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (m_List != null && m_Page > 0)
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, m_Type, m_List, m_Page - 1,
|
||||
m_Object));
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (m_List != null && (m_Page + 1) * m_PerPage < m_List.Count)
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, m_Type, m_List, m_Page + 1,
|
||||
m_Object));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (m_Type != TourneyBracketGumpType.Participant_List)
|
||||
break;
|
||||
|
||||
if (index >= 0 && index < m_List.Count)
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
|
||||
TourneyBracketGumpType.Participant_Info, null, 0, m_List[index]));
|
||||
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
if (m_Type != TourneyBracketGumpType.Round_List)
|
||||
break;
|
||||
|
||||
if (index >= 0 && index < m_List.Count)
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Round_Info,
|
||||
null, 0, m_List[index]));
|
||||
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if (m_Type != TourneyBracketGumpType.Participant_Info)
|
||||
break;
|
||||
|
||||
if (m_Object is TourneyParticipant part && index >= 0 && index < part.Players.Count)
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Player_Info,
|
||||
null, 0, part.Players[index]));
|
||||
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
if (m_Type != TourneyBracketGumpType.Round_Info)
|
||||
break;
|
||||
|
||||
if (!(m_Object is PyramidLevel level))
|
||||
break;
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
if (level.FreeAdvance != null)
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
|
||||
TourneyBracketGumpType.Participant_Info, null, 0, level.FreeAdvance));
|
||||
else
|
||||
m_From.SendGump(
|
||||
new TournamentBracketGump(m_From, m_Tournament, m_Type, m_List, m_Page, m_Object));
|
||||
}
|
||||
else if (index >= 1 && index <= level.Matches.Count)
|
||||
{
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament, TourneyBracketGumpType.Match_Info,
|
||||
null, 0, level.Matches[index - 1]));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
if (m_Type != TourneyBracketGumpType.Match_Info)
|
||||
break;
|
||||
|
||||
if (m_Object is TourneyMatch match && index >= 0 && index < match.Participants.Count)
|
||||
m_From.SendGump(new TournamentBracketGump(m_From, m_Tournament,
|
||||
TourneyBracketGumpType.Participant_Info, null, 0, match.Participants[index]));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
366
Projects/Scripts/Engines/ConPVP/Ladder.cs
Normal file
366
Projects/Scripts/Engines/ConPVP/Ladder.cs
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class LadderController : Item
|
||||
{
|
||||
[Constructible]
|
||||
public LadderController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Ladder = new Ladder();
|
||||
|
||||
if (Ladder.Instance == null)
|
||||
Ladder.Instance = Ladder;
|
||||
}
|
||||
|
||||
public LadderController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public Ladder Ladder{ get; private set; }
|
||||
|
||||
public override string DefaultName => "ladder controller";
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
if (Ladder.Instance == Ladder)
|
||||
Ladder.Instance = null;
|
||||
|
||||
base.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1);
|
||||
|
||||
Ladder.Serialize(writer);
|
||||
|
||||
writer.Write(Ladder.Instance == Ladder);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
Ladder = new Ladder(reader);
|
||||
|
||||
if (version < 1 || reader.ReadBool())
|
||||
Ladder.Instance = Ladder;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Ladder
|
||||
{
|
||||
private static int[] m_ShortLevels =
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3, 3,
|
||||
4, 4,
|
||||
5, 5, 5,
|
||||
6, 6, 6,
|
||||
7, 7, 7, 7,
|
||||
8, 8, 8, 8,
|
||||
9, 9, 9, 9, 9
|
||||
};
|
||||
|
||||
private static int[] m_BaseXP =
|
||||
{
|
||||
0, 100, 200, 400, 600, 900, 1200, 1600, 2000, 2500
|
||||
};
|
||||
|
||||
private static int[] m_LossFactors =
|
||||
{
|
||||
10,
|
||||
11, 11,
|
||||
25, 25,
|
||||
43, 43,
|
||||
67, 67
|
||||
};
|
||||
|
||||
private static int[,] m_OffsetScalar =
|
||||
{
|
||||
/* { win, los } */
|
||||
/* -6 */ { 175, 25 },
|
||||
/* -5 */ { 165, 35 },
|
||||
/* -4 */ { 155, 45 },
|
||||
/* -3 */ { 145, 55 },
|
||||
/* -2 */ { 130, 70 },
|
||||
/* -1 */ { 115, 85 },
|
||||
/* 0 */ { 100, 100 },
|
||||
/* +1 */ { 90, 110 },
|
||||
/* +2 */ { 80, 120 },
|
||||
/* +3 */ { 70, 130 },
|
||||
/* +4 */ { 60, 140 },
|
||||
/* +5 */ { 50, 150 },
|
||||
/* +6 */ { 40, 160 }
|
||||
};
|
||||
|
||||
public List<LadderEntry> Entries{ get; } = new List<LadderEntry>();
|
||||
|
||||
private Dictionary<Mobile, LadderEntry> m_Table;
|
||||
|
||||
public Ladder()
|
||||
{
|
||||
m_Table = new Dictionary<Mobile, LadderEntry>();
|
||||
}
|
||||
|
||||
public Ladder(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
int count = reader.ReadEncodedInt();
|
||||
|
||||
m_Table = new Dictionary<Mobile, LadderEntry>(count);
|
||||
Entries = new List<LadderEntry>(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
LadderEntry entry = new LadderEntry(reader, this, version);
|
||||
|
||||
if (entry.Mobile != null)
|
||||
{
|
||||
m_Table[entry.Mobile] = entry;
|
||||
entry.Index = Entries.Count;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
Entries.Sort();
|
||||
|
||||
for (int i = 0; i < Entries.Count; ++i)
|
||||
{
|
||||
LadderEntry entry = Entries[i];
|
||||
|
||||
entry.Index = i;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Ladder Instance{ get; set; }
|
||||
|
||||
public static int GetLevel(int xp)
|
||||
{
|
||||
if (xp >= 22500)
|
||||
return 50;
|
||||
if (xp >= 2500)
|
||||
return 10 + (xp - 2500) / 500;
|
||||
if (xp < 0)
|
||||
xp = 0;
|
||||
|
||||
return m_ShortLevels[xp / 100];
|
||||
}
|
||||
|
||||
public static void GetLevelInfo(int level, out int xpBase, out int xpAdvance)
|
||||
{
|
||||
if (level >= 10)
|
||||
{
|
||||
xpBase = 2500 + (level - 10) * 500;
|
||||
xpAdvance = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
xpBase = m_BaseXP[level - 1];
|
||||
xpAdvance = m_BaseXP[level] - xpBase;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetLossFactor(int level)
|
||||
{
|
||||
if (level >= 10)
|
||||
return 100;
|
||||
|
||||
return m_LossFactors[level - 1];
|
||||
}
|
||||
|
||||
public static int GetOffsetScalar(int ourLevel, int theirLevel, bool win)
|
||||
{
|
||||
int x = ourLevel - theirLevel;
|
||||
|
||||
if (x < -6 || x > +6)
|
||||
return 0;
|
||||
|
||||
int y = win ? 0 : 1;
|
||||
|
||||
return m_OffsetScalar[x + 6, y];
|
||||
}
|
||||
|
||||
public static int GetExperienceGain(LadderEntry us, LadderEntry them, bool weWon)
|
||||
{
|
||||
if (us == null || them == null)
|
||||
return 0;
|
||||
|
||||
int ourLevel = GetLevel(us.Experience);
|
||||
int theirLevel = GetLevel(them.Experience);
|
||||
|
||||
int scalar = GetOffsetScalar(ourLevel, theirLevel, weWon);
|
||||
|
||||
if (scalar == 0)
|
||||
return 0;
|
||||
|
||||
int xp = 25 * scalar;
|
||||
|
||||
if (!weWon)
|
||||
xp = xp * GetLossFactor(ourLevel) / 100;
|
||||
|
||||
xp /= 100;
|
||||
|
||||
if (xp <= 0)
|
||||
xp = 1;
|
||||
|
||||
return xp * (weWon ? 1 : -1);
|
||||
}
|
||||
|
||||
private int Swap(int idx, int newIdx)
|
||||
{
|
||||
LadderEntry hold = Entries[idx];
|
||||
|
||||
Entries[idx] = Entries[newIdx];
|
||||
Entries[newIdx] = hold;
|
||||
|
||||
Entries[idx].Index = idx;
|
||||
Entries[newIdx].Index = newIdx;
|
||||
|
||||
return newIdx;
|
||||
}
|
||||
|
||||
public void UpdateEntry(LadderEntry entry)
|
||||
{
|
||||
int index = entry.Index;
|
||||
|
||||
if (index >= 0 && index < Entries.Count)
|
||||
{
|
||||
while (index - 1 >= 0 && (entry.CompareTo(Entries[index - 1])) < 0)
|
||||
index = Swap(index, index - 1);
|
||||
|
||||
while (index + 1 < Entries.Count && (entry.CompareTo(Entries[index + 1])) > 0)
|
||||
index = Swap(index, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public LadderEntry Find(Mobile mob)
|
||||
{
|
||||
if (m_Table.TryGetValue(mob, out LadderEntry entry))
|
||||
{
|
||||
m_Table[mob] = entry = new LadderEntry(mob, this);
|
||||
entry.Index = Entries.Count;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public LadderEntry FindNoCreate(Mobile mob)
|
||||
{
|
||||
m_Table.TryGetValue(mob, out LadderEntry entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(1); // version;
|
||||
|
||||
writer.WriteEncodedInt(Entries.Count);
|
||||
|
||||
for (int i = 0; i < Entries.Count; ++i)
|
||||
Entries[i].Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public class LadderEntry : IComparable<LadderEntry>
|
||||
{
|
||||
private int m_Experience;
|
||||
private Ladder m_Ladder;
|
||||
|
||||
public LadderEntry(Mobile mob, Ladder ladder)
|
||||
{
|
||||
m_Ladder = ladder;
|
||||
Mobile = mob;
|
||||
}
|
||||
|
||||
public LadderEntry(GenericReader reader, Ladder ladder, int version)
|
||||
{
|
||||
m_Ladder = ladder;
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
case 0:
|
||||
{
|
||||
Mobile = reader.ReadMobile();
|
||||
m_Experience = reader.ReadEncodedInt();
|
||||
Wins = reader.ReadEncodedInt();
|
||||
Losses = reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public int Experience
|
||||
{
|
||||
get => m_Experience;
|
||||
set
|
||||
{
|
||||
m_Experience = value;
|
||||
m_Ladder.UpdateEntry(this);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public int Wins{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public int Losses{ get; set; }
|
||||
|
||||
public int Index{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Rank => Index;
|
||||
|
||||
public int CompareTo(LadderEntry l)
|
||||
{
|
||||
return (l?.m_Experience ?? 0) - m_Experience;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(Mobile);
|
||||
writer.WriteEncodedInt(m_Experience);
|
||||
writer.WriteEncodedInt(Wins);
|
||||
writer.WriteEncodedInt(Losses);
|
||||
}
|
||||
}
|
||||
}
|
||||
231
Projects/Scripts/Engines/ConPVP/Participant.cs
Normal file
231
Projects/Scripts/Engines/ConPVP/Participant.cs
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class Participant
|
||||
{
|
||||
public Participant(DuelContext context, int count)
|
||||
{
|
||||
Context = context;
|
||||
//m_Stakes = new StakesContainer( context, this );
|
||||
Resize(count);
|
||||
}
|
||||
|
||||
public int Count => Players.Length;
|
||||
public DuelPlayer[] Players{ get; private set; }
|
||||
|
||||
public DuelContext Context{ get; }
|
||||
|
||||
public TourneyParticipant TourneyPart{ get; set; }
|
||||
|
||||
public int FilledSlots
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] != null)
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasOpenSlot
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] == null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Eliminated
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i]?.Eliminated == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public string NameList
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
{
|
||||
if (Players[i] == null)
|
||||
continue;
|
||||
|
||||
Mobile mob = Players[i].Mobile;
|
||||
|
||||
if (sb.Length > 0)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(mob.Name);
|
||||
}
|
||||
|
||||
if (sb.Length == 0)
|
||||
return "Empty";
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public DuelPlayer Find(Mobile mob)
|
||||
{
|
||||
if (mob is PlayerMobile pm)
|
||||
{
|
||||
if (pm.DuelContext == Context && pm.DuelPlayer.Participant == this)
|
||||
return pm.DuelPlayer;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i]?.Mobile == mob)
|
||||
return Players[i];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Contains(Mobile mob)
|
||||
{
|
||||
return Find(mob) != null;
|
||||
}
|
||||
|
||||
public void Broadcast(int hue, string message, string nonLocalOverhead, string localOverhead)
|
||||
{
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] != null)
|
||||
{
|
||||
if (message != null)
|
||||
Players[i].Mobile.SendMessage(hue, message);
|
||||
|
||||
if (nonLocalOverhead != null)
|
||||
Players[i].Mobile.NonlocalOverheadMessage(MessageType.Regular, hue, false,
|
||||
string.Format(nonLocalOverhead, Players[i].Mobile.Name,
|
||||
Players[i].Mobile.Female ? "her" : "his"));
|
||||
|
||||
if (localOverhead != null)
|
||||
Players[i].Mobile.LocalOverheadMessage(MessageType.Regular, hue, false, localOverhead);
|
||||
}
|
||||
}
|
||||
|
||||
public void Nullify(DuelPlayer player)
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
int index = Array.IndexOf(Players, player);
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
Players[index] = null;
|
||||
}
|
||||
|
||||
public void Remove(DuelPlayer player)
|
||||
{
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
int index = Array.IndexOf(Players, player);
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
DuelPlayer[] old = Players;
|
||||
Players = new DuelPlayer[old.Length - 1];
|
||||
|
||||
for (int i = 0; i < index; ++i)
|
||||
Players[i] = old[i];
|
||||
|
||||
for (int i = index + 1; i < old.Length; ++i)
|
||||
Players[i - 1] = old[i];
|
||||
}
|
||||
|
||||
public void Remove(Mobile player)
|
||||
{
|
||||
Remove(Find(player));
|
||||
}
|
||||
|
||||
public void Add(Mobile player)
|
||||
{
|
||||
if (Contains(player))
|
||||
return;
|
||||
|
||||
for (int i = 0; i < Players.Length; ++i)
|
||||
if (Players[i] == null)
|
||||
{
|
||||
Players[i] = new DuelPlayer(player, this);
|
||||
return;
|
||||
}
|
||||
|
||||
Resize(Players.Length + 1);
|
||||
Players[Players.Length - 1] = new DuelPlayer(player, this);
|
||||
}
|
||||
|
||||
public void Resize(int count)
|
||||
{
|
||||
DuelPlayer[] old = Players;
|
||||
Players = new DuelPlayer[count];
|
||||
|
||||
if (old != null)
|
||||
{
|
||||
int ct = 0;
|
||||
|
||||
for (int i = 0; i < old.Length; ++i)
|
||||
if (old[i] != null && ct < count)
|
||||
Players[ct++] = old[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DuelPlayer
|
||||
{
|
||||
private bool m_Eliminated;
|
||||
|
||||
public DuelPlayer(Mobile mob, Participant p)
|
||||
{
|
||||
Mobile = mob;
|
||||
Participant = p;
|
||||
|
||||
if (mob is PlayerMobile mobile)
|
||||
mobile.DuelPlayer = this;
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public bool Ready{ get; set; }
|
||||
|
||||
public bool Eliminated
|
||||
{
|
||||
get => m_Eliminated;
|
||||
set
|
||||
{
|
||||
m_Eliminated = value;
|
||||
if (Participant.Context.m_Tournament != null && m_Eliminated)
|
||||
{
|
||||
Participant.Context.m_Tournament.OnEliminated(this);
|
||||
Mobile.SendEverything();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Participant Participant{ get; set; }
|
||||
}
|
||||
}
|
||||
277
Projects/Scripts/Engines/ConPVP/Preferences.cs
Normal file
277
Projects/Scripts/Engines/ConPVP/Preferences.cs
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class PreferencesController : Item
|
||||
{
|
||||
[Constructible]
|
||||
public PreferencesController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Preferences = new Preferences();
|
||||
|
||||
if (Preferences.Instance == null)
|
||||
Preferences.Instance = Preferences;
|
||||
else
|
||||
Delete();
|
||||
}
|
||||
|
||||
public PreferencesController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Administrator )]
|
||||
public Preferences Preferences{ get; private set; }
|
||||
|
||||
public override string DefaultName => "preferences controller";
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
if (Preferences.Instance != Preferences)
|
||||
base.Delete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
Preferences.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Preferences = new Preferences(reader);
|
||||
Preferences.Instance = Preferences;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Preferences
|
||||
{
|
||||
private Dictionary<Mobile, PreferencesEntry> m_Table;
|
||||
|
||||
public Preferences()
|
||||
{
|
||||
m_Table = new Dictionary<Mobile, PreferencesEntry>();
|
||||
Entries = new List<PreferencesEntry>();
|
||||
}
|
||||
|
||||
public Preferences(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int count = reader.ReadEncodedInt();
|
||||
|
||||
m_Table = new Dictionary<Mobile, PreferencesEntry>(count);
|
||||
Entries = new List<PreferencesEntry>(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
PreferencesEntry entry = new PreferencesEntry(reader, version);
|
||||
|
||||
if (entry.Mobile != null)
|
||||
{
|
||||
m_Table[entry.Mobile] = entry;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<PreferencesEntry> Entries{ get; }
|
||||
|
||||
public static Preferences Instance{ get; set; }
|
||||
|
||||
public PreferencesEntry Find(Mobile mob)
|
||||
{
|
||||
if (m_Table.TryGetValue(mob, out PreferencesEntry entry))
|
||||
{
|
||||
m_Table[mob] = entry = new PreferencesEntry(mob);
|
||||
Entries.Add(entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version;
|
||||
|
||||
writer.WriteEncodedInt(Entries.Count);
|
||||
|
||||
for (int i = 0; i < Entries.Count; ++i)
|
||||
Entries[i].Serialize(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public class PreferencesEntry
|
||||
{
|
||||
public PreferencesEntry(Mobile mob)
|
||||
{
|
||||
Mobile = mob;
|
||||
Disliked = new List<string>();
|
||||
}
|
||||
|
||||
public PreferencesEntry(GenericReader reader, int version)
|
||||
{
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Mobile = reader.ReadMobile();
|
||||
|
||||
int count = reader.ReadEncodedInt();
|
||||
|
||||
Disliked = new List<string>(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
Disliked.Add(reader.ReadString());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public List<string> Disliked{ get; }
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(Mobile);
|
||||
|
||||
writer.WriteEncodedInt(Disliked.Count);
|
||||
|
||||
for (int i = 0; i < Disliked.Count; ++i)
|
||||
writer.Write(Disliked[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public class PreferencesGump : Gump
|
||||
{
|
||||
private int m_ColumnX = 12;
|
||||
private PreferencesEntry m_Entry;
|
||||
|
||||
public PreferencesGump(Mobile from, Preferences prefs) : base(50, 50)
|
||||
{
|
||||
m_Entry = prefs.Find(from);
|
||||
|
||||
if (m_Entry == null)
|
||||
return;
|
||||
|
||||
List<Arena> arenas = Arena.Arenas;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
int height = 12 + 20 + arenas.Count * 31 + 24 + 12;
|
||||
|
||||
AddBackground(0, 0, 499 + 40 - 365, height, 0x2436);
|
||||
|
||||
for (int i = 1; i < arenas.Count; i += 2)
|
||||
AddImageTiled(12, 32 + i * 31, 475 + 40 - 365, 30, 0x2430);
|
||||
|
||||
AddAlphaRegion(10, 10, 479 + 40 - 365, height - 20);
|
||||
|
||||
AddColumnHeader(35, null);
|
||||
AddColumnHeader(115, "Arena");
|
||||
|
||||
AddButton(499 + 40 - 365 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1);
|
||||
AddButton(499 + 40 - 365 - 12 - 63, height - 12 - 24, 241, 242, 2);
|
||||
|
||||
for (int i = 0; i < arenas.Count; ++i)
|
||||
{
|
||||
Arena ar = arenas[i];
|
||||
|
||||
string name = ar.Name ?? "(no name)";
|
||||
|
||||
int x = 12;
|
||||
int y = 32 + i * 31;
|
||||
|
||||
int color = 0xCCFFCC;
|
||||
|
||||
AddCheck(x + 3, y + 1, 9730, 9727, m_Entry.Disliked.Contains(name), i);
|
||||
x += 35;
|
||||
|
||||
AddBorderedText(x + 5, y + 5, 115 - 5, name, color, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (m_Entry == null)
|
||||
return;
|
||||
|
||||
if (info.ButtonID != 1)
|
||||
return;
|
||||
|
||||
m_Entry.Disliked.Clear();
|
||||
|
||||
List<Arena> arenas = Arena.Arenas;
|
||||
|
||||
for (int i = 0; i < info.Switches.Length; ++i)
|
||||
{
|
||||
int idx = info.Switches[i];
|
||||
|
||||
if (idx >= 0 && idx < arenas.Count)
|
||||
m_Entry.Disliked.Add(arenas[idx].Name);
|
||||
}
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
private void AddBorderedText(int x, int y, int width, string text, int color, int borderColor)
|
||||
{
|
||||
AddColoredText(x, y, width, text, color);
|
||||
}
|
||||
|
||||
private void AddColoredText(int x, int y, int width, string text, int color)
|
||||
{
|
||||
if (color == 0)
|
||||
AddHtml(x, y, width, 20, text);
|
||||
else
|
||||
AddHtml(x, y, width, 20, Color(text, color));
|
||||
}
|
||||
|
||||
private void AddColumnHeader(int width, string name)
|
||||
{
|
||||
AddBackground(m_ColumnX, 12, width, 20, 0x242C);
|
||||
AddImageTiled(m_ColumnX + 2, 14, width - 4, 16, 0x2430);
|
||||
|
||||
if (name != null)
|
||||
AddBorderedText(m_ColumnX, 13, width, Center(name), 0xFFFFFF, 0);
|
||||
|
||||
m_ColumnX += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
Projects/Scripts/Engines/ConPVP/Ruleset.cs
Normal file
102
Projects/Scripts/Engines/ConPVP/Ruleset.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class Ruleset
|
||||
{
|
||||
public Ruleset(RulesetLayout layout)
|
||||
{
|
||||
Layout = layout;
|
||||
Options = new BitArray(layout.TotalLength);
|
||||
}
|
||||
|
||||
public RulesetLayout Layout{ get; }
|
||||
|
||||
public BitArray Options{ get; private set; }
|
||||
|
||||
public string Title{ get; set; }
|
||||
|
||||
public Ruleset Base{ get; private set; }
|
||||
|
||||
public List<Ruleset> Flavors{ get; } = new List<Ruleset>();
|
||||
|
||||
public bool Changed{ get; set; }
|
||||
|
||||
public void ApplyDefault(Ruleset newDefault)
|
||||
{
|
||||
Base = newDefault;
|
||||
Changed = false;
|
||||
|
||||
Options = new BitArray(newDefault.Options);
|
||||
|
||||
ApplyFlavorsTo(this);
|
||||
}
|
||||
|
||||
public void ApplyFlavorsTo(Ruleset ruleset)
|
||||
{
|
||||
for (int i = 0; i < Flavors.Count; ++i)
|
||||
{
|
||||
Ruleset flavor = Flavors[i];
|
||||
|
||||
Options.Or(flavor.Options);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFlavor(Ruleset flavor)
|
||||
{
|
||||
if (Flavors.Contains(flavor))
|
||||
return;
|
||||
|
||||
Flavors.Add(flavor);
|
||||
Options.Or(flavor.Options);
|
||||
}
|
||||
|
||||
public void RemoveFlavor(Ruleset flavor)
|
||||
{
|
||||
if (!Flavors.Contains(flavor))
|
||||
return;
|
||||
|
||||
Flavors.Remove(flavor);
|
||||
Options.And(flavor.Options.Not());
|
||||
flavor.Options.Not();
|
||||
}
|
||||
|
||||
public void SetOptionRange(string title, bool value)
|
||||
{
|
||||
RulesetLayout layout = Layout.FindByTitle(title);
|
||||
|
||||
if (layout == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < layout.TotalLength; ++i)
|
||||
Options[i + layout.Offset] = value;
|
||||
|
||||
Changed = true;
|
||||
}
|
||||
|
||||
public bool GetOption(string title, string option)
|
||||
{
|
||||
int index = 0;
|
||||
RulesetLayout layout = Layout.FindByOption(title, option, ref index);
|
||||
|
||||
if (layout == null)
|
||||
return true;
|
||||
|
||||
return Options[layout.Offset + index];
|
||||
}
|
||||
|
||||
public void SetOption(string title, string option, bool value)
|
||||
{
|
||||
int index = 0;
|
||||
RulesetLayout layout = Layout.FindByOption(title, option, ref index);
|
||||
|
||||
if (layout == null)
|
||||
return;
|
||||
|
||||
Options[layout.Offset + index] = value;
|
||||
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
764
Projects/Scripts/Engines/ConPVP/RulesetLayout.cs
Normal file
764
Projects/Scripts/Engines/ConPVP/RulesetLayout.cs
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class RulesetLayout
|
||||
{
|
||||
private static RulesetLayout m_Root;
|
||||
|
||||
public RulesetLayout(string title, string[] options) : this(title, title, new RulesetLayout[0], options)
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, string description, string[] options) : this(title, description,
|
||||
new RulesetLayout[0], options)
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, RulesetLayout[] children) : this(title, title, children, new string[0])
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, string description, RulesetLayout[] children) : this(title, description, children,
|
||||
new string[0])
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, RulesetLayout[] children, string[] options) : this(title, title, children,
|
||||
options)
|
||||
{
|
||||
}
|
||||
|
||||
public RulesetLayout(string title, string description, RulesetLayout[] children, string[] options)
|
||||
{
|
||||
Title = title;
|
||||
Description = description;
|
||||
Children = children;
|
||||
Options = options;
|
||||
|
||||
for (int i = 0; i < children.Length; ++i)
|
||||
children[i].Parent = this;
|
||||
}
|
||||
|
||||
public static RulesetLayout Root
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Root != null)
|
||||
return m_Root;
|
||||
|
||||
List<RulesetLayout> entries = new List<RulesetLayout>
|
||||
{
|
||||
new RulesetLayout("Spells",
|
||||
new[]
|
||||
{
|
||||
new RulesetLayout("1st Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Reactive Armor", "Clumsy", "Create Food", "Feeblemind", "Heal", "Magic Arrow", "Night Sight",
|
||||
"Weaken"
|
||||
}),
|
||||
new RulesetLayout("2nd Circle", "Spells",
|
||||
new[] { "Agility", "Cunning", "Cure", "Harm", "Magic Trap", "Untrap", "Protection", "Strength" }),
|
||||
new RulesetLayout("3rd Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Bless", "Fireball", "Magic Lock", "Poison", "Telekinesis", "Teleport", "Unlock Spell",
|
||||
"Wall of Stone"
|
||||
}),
|
||||
new RulesetLayout("4th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Arch Cure", "Arch Protection", "Curse", "Fire Field", "Greater Heal", "Lightning", "Mana Drain",
|
||||
"Recall"
|
||||
}),
|
||||
new RulesetLayout("5th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Blade Spirits", "Dispel Field", "Incognito", "Magic Reflection", "Mind Blast", "Paralyze",
|
||||
"Poison Field", "Summon Creature"
|
||||
}),
|
||||
new RulesetLayout("6th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Dispel", "Energy Bolt", "Explosion", "Invisibility", "Mark", "Mass Curse", "Paralyze Field",
|
||||
"Reveal"
|
||||
}),
|
||||
new RulesetLayout("7th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Chain Lightning", "Energy Field", "Flame Strike", "Gate Travel", "Mana Vampire", "Mass Dispel",
|
||||
"Meteor Swarm", "Polymorph"
|
||||
}),
|
||||
new RulesetLayout("8th Circle", "Spells",
|
||||
new[]
|
||||
{
|
||||
"Earthquake", "Energy Vortex", "Resurrection", "Air Elemental", "Summon Daemon", "Earth Elemental",
|
||||
"Fire Elemental", "Water Elemental"
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
entries.Add(new RulesetLayout("Chivalry", new[]
|
||||
{
|
||||
"Cleanse by Fire",
|
||||
"Close Wounds",
|
||||
"Consecrate Weapon",
|
||||
"Dispel Evil",
|
||||
"Divine Fury",
|
||||
"Enemy of One",
|
||||
"Holy Light",
|
||||
"Noble Sacrifice",
|
||||
"Remove Curse",
|
||||
"Sacred Journey"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Necromancy", new[]
|
||||
{
|
||||
"Animate Dead",
|
||||
"Blood Oath",
|
||||
"Corpse Skin",
|
||||
"Curse Weapon",
|
||||
"Evil Omen",
|
||||
"Horrific Beast",
|
||||
"Lich Form",
|
||||
"Mind Rot",
|
||||
"Pain Spike",
|
||||
"Poison Strike",
|
||||
"Strangle",
|
||||
"Summon Familiar",
|
||||
"Vampiric Embrace",
|
||||
"Vengeful Spirit",
|
||||
"Wither",
|
||||
"Wraith Form"
|
||||
}));
|
||||
|
||||
if (Core.SE)
|
||||
{
|
||||
entries.Add(new RulesetLayout("Bushido", new[]
|
||||
{
|
||||
"Confidence",
|
||||
"Counter Attack",
|
||||
"Evasion",
|
||||
"Honorable Execution",
|
||||
"Lightning Strike",
|
||||
"Momentum Strike"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Ninjitsu", new[]
|
||||
{
|
||||
"Animal Form",
|
||||
"Backstab",
|
||||
"Death Strike",
|
||||
"Focus Attack",
|
||||
"Ki Attack",
|
||||
"Mirror Image",
|
||||
"Shadow Jump",
|
||||
"Suprise Attack"
|
||||
}));
|
||||
|
||||
if (Core.ML)
|
||||
entries.Add(new RulesetLayout("Spellweaving", new[]
|
||||
{
|
||||
"Arcane Circle",
|
||||
"Arcane Empowerment",
|
||||
"Attune Weapon",
|
||||
"Dryad Allure",
|
||||
"Essence of Wind",
|
||||
"Ethereal Voyage",
|
||||
"Gift of Life",
|
||||
"Gift of Renewal",
|
||||
"Immolating Weapon",
|
||||
"Nature's Fury",
|
||||
"Reaper Form",
|
||||
"Summon Fey",
|
||||
"Summon Fiend",
|
||||
"Thunderstorm",
|
||||
"Wildfire",
|
||||
"Word of Death"
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
if (Core.SE)
|
||||
entries.Add(new RulesetLayout("Combat Abilities", new[]
|
||||
{
|
||||
"Stun",
|
||||
"Disarm",
|
||||
"Armor Ignore",
|
||||
"Bleed Attack",
|
||||
"Concussion Blow",
|
||||
"Crushing Blow",
|
||||
"Disarm",
|
||||
"Dismount",
|
||||
"Double Strike",
|
||||
"Infectious Strike",
|
||||
"Mortal Strike",
|
||||
"Moving Shot",
|
||||
"Paralyzing Blow",
|
||||
"Shadow Strike",
|
||||
"Whirlwind Attack",
|
||||
"Riding Swipe",
|
||||
"Frenzied Whirlwind",
|
||||
"Block",
|
||||
"Defense Mastery",
|
||||
"Nerve Strike",
|
||||
"Talon Strike",
|
||||
"Feint",
|
||||
"Dual Wield",
|
||||
"Double Shot",
|
||||
"Armor Pierce"
|
||||
}));
|
||||
else
|
||||
entries.Add(new RulesetLayout("Combat Abilities", new[]
|
||||
{
|
||||
"Stun",
|
||||
"Disarm",
|
||||
"Armor Ignore",
|
||||
"Bleed Attack",
|
||||
"Concussion Blow",
|
||||
"Crushing Blow",
|
||||
"Disarm",
|
||||
"Dismount",
|
||||
"Double Strike",
|
||||
"Infectious Strike",
|
||||
"Mortal Strike",
|
||||
"Moving Shot",
|
||||
"Paralyzing Blow",
|
||||
"Shadow Strike",
|
||||
"Whirlwind Attack"
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(new RulesetLayout("Combat Abilities", new[]
|
||||
{
|
||||
"Stun",
|
||||
"Disarm",
|
||||
"Concussion Blow",
|
||||
"Crushing Blow",
|
||||
"Paralyzing Blow"
|
||||
}));
|
||||
}
|
||||
|
||||
entries.Add(new RulesetLayout("Skills", new[]
|
||||
{
|
||||
"Anatomy",
|
||||
"Detect Hidden",
|
||||
"Evaluating Intelligence",
|
||||
"Hiding",
|
||||
"Poisoning",
|
||||
"Snooping",
|
||||
"Stealing",
|
||||
"Spirit Speak",
|
||||
"Stealth"
|
||||
}));
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
entries.Add(new RulesetLayout("Weapons", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Melee",
|
||||
"Ranged",
|
||||
"Poisoned",
|
||||
"Wrestling"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Armor", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Shields"
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(new RulesetLayout("Weapons", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Melee",
|
||||
"Ranged",
|
||||
"Poisoned",
|
||||
"Wrestling",
|
||||
"Runics"
|
||||
}));
|
||||
|
||||
entries.Add(new RulesetLayout("Armor", new[]
|
||||
{
|
||||
"Magical",
|
||||
"Shields",
|
||||
"Colored"
|
||||
}));
|
||||
}
|
||||
|
||||
if (Core.SE)
|
||||
entries.Add(new RulesetLayout("Items", new[]
|
||||
{
|
||||
new RulesetLayout("Potions", new[]
|
||||
{
|
||||
"Agility",
|
||||
"Cure",
|
||||
"Explosion",
|
||||
"Heal",
|
||||
"Nightsight",
|
||||
"Poison",
|
||||
"Refresh",
|
||||
"Strength"
|
||||
})
|
||||
},
|
||||
new[]
|
||||
{
|
||||
"Bandages",
|
||||
"Wands",
|
||||
"Trapped Containers",
|
||||
"Bolas",
|
||||
"Mounts",
|
||||
"Orange Petals",
|
||||
"Shurikens",
|
||||
"Fukiya Darts",
|
||||
"Fire Horns"
|
||||
}));
|
||||
else
|
||||
entries.Add(new RulesetLayout("Items", new[]
|
||||
{
|
||||
new RulesetLayout("Potions", new[]
|
||||
{
|
||||
"Agility",
|
||||
"Cure",
|
||||
"Explosion",
|
||||
"Heal",
|
||||
"Nightsight",
|
||||
"Poison",
|
||||
"Refresh",
|
||||
"Strength"
|
||||
})
|
||||
},
|
||||
new[]
|
||||
{
|
||||
"Bandages",
|
||||
"Wands",
|
||||
"Trapped Containers",
|
||||
"Bolas",
|
||||
"Mounts",
|
||||
"Orange Petals",
|
||||
"Fire Horns"
|
||||
}));
|
||||
|
||||
m_Root = new RulesetLayout("Rules", entries.ToArray());
|
||||
m_Root.ComputeOffsets();
|
||||
|
||||
// Set up default rulesets
|
||||
|
||||
if (!Core.AOS)
|
||||
{
|
||||
#region Mage 5x
|
||||
|
||||
Ruleset m5x = new Ruleset(m_Root);
|
||||
|
||||
m5x.Title = "Mage 5x";
|
||||
|
||||
m5x.SetOptionRange("Spells", true);
|
||||
|
||||
m5x.SetOption("Spells", "Wall of Stone", false);
|
||||
m5x.SetOption("Spells", "Fire Field", false);
|
||||
m5x.SetOption("Spells", "Poison Field", false);
|
||||
m5x.SetOption("Spells", "Energy Field", false);
|
||||
m5x.SetOption("Spells", "Reactive Armor", false);
|
||||
m5x.SetOption("Spells", "Protection", false);
|
||||
m5x.SetOption("Spells", "Teleport", false);
|
||||
m5x.SetOption("Spells", "Wall of Stone", false);
|
||||
m5x.SetOption("Spells", "Arch Protection", false);
|
||||
m5x.SetOption("Spells", "Recall", false);
|
||||
m5x.SetOption("Spells", "Blade Spirits", false);
|
||||
m5x.SetOption("Spells", "Incognito", false);
|
||||
m5x.SetOption("Spells", "Magic Reflection", false);
|
||||
m5x.SetOption("Spells", "Paralyze", false);
|
||||
m5x.SetOption("Spells", "Summon Creature", false);
|
||||
m5x.SetOption("Spells", "Invisibility", false);
|
||||
m5x.SetOption("Spells", "Mark", false);
|
||||
m5x.SetOption("Spells", "Paralyze Field", false);
|
||||
m5x.SetOption("Spells", "Energy Field", false);
|
||||
m5x.SetOption("Spells", "Gate Travel", false);
|
||||
m5x.SetOption("Spells", "Polymorph", false);
|
||||
m5x.SetOption("Spells", "Energy Vortex", false);
|
||||
m5x.SetOption("Spells", "Air Elemental", false);
|
||||
m5x.SetOption("Spells", "Summon Daemon", false);
|
||||
m5x.SetOption("Spells", "Earth Elemental", false);
|
||||
m5x.SetOption("Spells", "Fire Elemental", false);
|
||||
m5x.SetOption("Spells", "Water Elemental", false);
|
||||
m5x.SetOption("Spells", "Earthquake", false);
|
||||
m5x.SetOption("Spells", "Meteor Swarm", false);
|
||||
m5x.SetOption("Spells", "Chain Lightning", false);
|
||||
m5x.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
m5x.SetOption("Weapons", "Wrestling", true);
|
||||
|
||||
m5x.SetOption("Skills", "Anatomy", true);
|
||||
m5x.SetOption("Skills", "Detect Hidden", true);
|
||||
m5x.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
m5x.SetOption("Items", "Trapped Containers", true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mage 7x
|
||||
|
||||
Ruleset m7x = new Ruleset(m_Root);
|
||||
|
||||
m7x.Title = "Mage 7x";
|
||||
|
||||
m7x.SetOptionRange("Spells", true);
|
||||
|
||||
m7x.SetOption("Spells", "Wall of Stone", false);
|
||||
m7x.SetOption("Spells", "Fire Field", false);
|
||||
m7x.SetOption("Spells", "Poison Field", false);
|
||||
m7x.SetOption("Spells", "Energy Field", false);
|
||||
m7x.SetOption("Spells", "Reactive Armor", false);
|
||||
m7x.SetOption("Spells", "Protection", false);
|
||||
m7x.SetOption("Spells", "Teleport", false);
|
||||
m7x.SetOption("Spells", "Wall of Stone", false);
|
||||
m7x.SetOption("Spells", "Arch Protection", false);
|
||||
m7x.SetOption("Spells", "Recall", false);
|
||||
m7x.SetOption("Spells", "Blade Spirits", false);
|
||||
m7x.SetOption("Spells", "Incognito", false);
|
||||
m7x.SetOption("Spells", "Magic Reflection", false);
|
||||
m7x.SetOption("Spells", "Paralyze", false);
|
||||
m7x.SetOption("Spells", "Summon Creature", false);
|
||||
m7x.SetOption("Spells", "Invisibility", false);
|
||||
m7x.SetOption("Spells", "Mark", false);
|
||||
m7x.SetOption("Spells", "Paralyze Field", false);
|
||||
m7x.SetOption("Spells", "Energy Field", false);
|
||||
m7x.SetOption("Spells", "Gate Travel", false);
|
||||
m7x.SetOption("Spells", "Polymorph", false);
|
||||
m7x.SetOption("Spells", "Energy Vortex", false);
|
||||
m7x.SetOption("Spells", "Air Elemental", false);
|
||||
m7x.SetOption("Spells", "Summon Daemon", false);
|
||||
m7x.SetOption("Spells", "Earth Elemental", false);
|
||||
m7x.SetOption("Spells", "Fire Elemental", false);
|
||||
m7x.SetOption("Spells", "Water Elemental", false);
|
||||
m7x.SetOption("Spells", "Earthquake", false);
|
||||
m7x.SetOption("Spells", "Meteor Swarm", false);
|
||||
m7x.SetOption("Spells", "Chain Lightning", false);
|
||||
m7x.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
m7x.SetOption("Combat Abilities", "Stun", true);
|
||||
|
||||
m7x.SetOption("Skills", "Anatomy", true);
|
||||
m7x.SetOption("Skills", "Detect Hidden", true);
|
||||
m7x.SetOption("Skills", "Poisoning", true);
|
||||
m7x.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
m7x.SetOption("Weapons", "Wrestling", true);
|
||||
|
||||
m7x.SetOption("Potions", "Refresh", true);
|
||||
m7x.SetOption("Items", "Trapped Containers", true);
|
||||
m7x.SetOption("Items", "Bandages", true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Standard 7x
|
||||
|
||||
Ruleset s7x = new Ruleset(m_Root);
|
||||
|
||||
s7x.Title = "Standard 7x";
|
||||
|
||||
s7x.SetOptionRange("Spells", true);
|
||||
|
||||
s7x.SetOption("Spells", "Wall of Stone", false);
|
||||
s7x.SetOption("Spells", "Fire Field", false);
|
||||
s7x.SetOption("Spells", "Poison Field", false);
|
||||
s7x.SetOption("Spells", "Energy Field", false);
|
||||
s7x.SetOption("Spells", "Teleport", false);
|
||||
s7x.SetOption("Spells", "Wall of Stone", false);
|
||||
s7x.SetOption("Spells", "Arch Protection", false);
|
||||
s7x.SetOption("Spells", "Recall", false);
|
||||
s7x.SetOption("Spells", "Blade Spirits", false);
|
||||
s7x.SetOption("Spells", "Incognito", false);
|
||||
s7x.SetOption("Spells", "Magic Reflection", false);
|
||||
s7x.SetOption("Spells", "Paralyze", false);
|
||||
s7x.SetOption("Spells", "Summon Creature", false);
|
||||
s7x.SetOption("Spells", "Invisibility", false);
|
||||
s7x.SetOption("Spells", "Mark", false);
|
||||
s7x.SetOption("Spells", "Paralyze Field", false);
|
||||
s7x.SetOption("Spells", "Energy Field", false);
|
||||
s7x.SetOption("Spells", "Gate Travel", false);
|
||||
s7x.SetOption("Spells", "Polymorph", false);
|
||||
s7x.SetOption("Spells", "Energy Vortex", false);
|
||||
s7x.SetOption("Spells", "Air Elemental", false);
|
||||
s7x.SetOption("Spells", "Summon Daemon", false);
|
||||
s7x.SetOption("Spells", "Earth Elemental", false);
|
||||
s7x.SetOption("Spells", "Fire Elemental", false);
|
||||
s7x.SetOption("Spells", "Water Elemental", false);
|
||||
s7x.SetOption("Spells", "Earthquake", false);
|
||||
s7x.SetOption("Spells", "Meteor Swarm", false);
|
||||
s7x.SetOption("Spells", "Chain Lightning", false);
|
||||
s7x.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
s7x.SetOptionRange("Combat Abilities", true);
|
||||
|
||||
s7x.SetOption("Skills", "Anatomy", true);
|
||||
s7x.SetOption("Skills", "Detect Hidden", true);
|
||||
s7x.SetOption("Skills", "Poisoning", true);
|
||||
s7x.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
s7x.SetOptionRange("Weapons", true);
|
||||
s7x.SetOption("Weapons", "Runics", false);
|
||||
s7x.SetOptionRange("Armor", true);
|
||||
|
||||
s7x.SetOption("Potions", "Refresh", true);
|
||||
s7x.SetOption("Items", "Bandages", true);
|
||||
s7x.SetOption("Items", "Trapped Containers", true);
|
||||
|
||||
#endregion
|
||||
|
||||
m_Root.Defaults = new[] { m5x, m7x, s7x };
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Standard All Skills
|
||||
|
||||
Ruleset all = new Ruleset(m_Root);
|
||||
|
||||
all.Title = "Standard All Skills";
|
||||
|
||||
|
||||
all.SetOptionRange("Spells", true);
|
||||
|
||||
all.SetOption("Spells", "Wall of Stone", false);
|
||||
all.SetOption("Spells", "Fire Field", false);
|
||||
all.SetOption("Spells", "Poison Field", false);
|
||||
all.SetOption("Spells", "Energy Field", false);
|
||||
all.SetOption("Spells", "Teleport", false);
|
||||
all.SetOption("Spells", "Wall of Stone", false);
|
||||
all.SetOption("Spells", "Arch Protection", false);
|
||||
all.SetOption("Spells", "Recall", false);
|
||||
all.SetOption("Spells", "Blade Spirits", false);
|
||||
all.SetOption("Spells", "Incognito", false);
|
||||
all.SetOption("Spells", "Magic Reflection", false);
|
||||
all.SetOption("Spells", "Paralyze", false);
|
||||
all.SetOption("Spells", "Summon Creature", false);
|
||||
all.SetOption("Spells", "Invisibility", false);
|
||||
all.SetOption("Spells", "Mark", false);
|
||||
all.SetOption("Spells", "Paralyze Field", false);
|
||||
all.SetOption("Spells", "Energy Field", false);
|
||||
all.SetOption("Spells", "Gate Travel", false);
|
||||
all.SetOption("Spells", "Polymorph", false);
|
||||
all.SetOption("Spells", "Energy Vortex", false);
|
||||
all.SetOption("Spells", "Air Elemental", false);
|
||||
all.SetOption("Spells", "Summon Daemon", false);
|
||||
all.SetOption("Spells", "Earth Elemental", false);
|
||||
all.SetOption("Spells", "Fire Elemental", false);
|
||||
all.SetOption("Spells", "Water Elemental", false);
|
||||
all.SetOption("Spells", "Earthquake", false);
|
||||
all.SetOption("Spells", "Meteor Swarm", false);
|
||||
all.SetOption("Spells", "Chain Lightning", false);
|
||||
all.SetOption("Spells", "Resurrection", false);
|
||||
|
||||
all.SetOptionRange("Necromancy", true);
|
||||
all.SetOption("Necromancy", "Summon Familiar", false);
|
||||
all.SetOption("Necromancy", "Vengeful Spirit", false);
|
||||
all.SetOption("Necromancy", "Animate Dead", false);
|
||||
all.SetOption("Necromancy", "Wither", false);
|
||||
all.SetOption("Necromancy", "Poison Strike", false);
|
||||
|
||||
all.SetOptionRange("Chivalry", true);
|
||||
all.SetOption("Chivalry", "Sacred Journey", false);
|
||||
all.SetOption("Chivalry", "Enemy of One", false);
|
||||
all.SetOption("Chivalry", "Noble Sacrifice", false);
|
||||
|
||||
all.SetOptionRange("Combat Abilities", true);
|
||||
all.SetOption("Combat Abilities", "Paralyzing Blow", false);
|
||||
all.SetOption("Combat Abilities", "Shadow Strike", false);
|
||||
|
||||
all.SetOption("Skills", "Anatomy", true);
|
||||
all.SetOption("Skills", "Detect Hidden", true);
|
||||
all.SetOption("Skills", "Poisoning", true);
|
||||
all.SetOption("Skills", "Spirit Speak", true);
|
||||
all.SetOption("Skills", "Evaluating Intelligence", true);
|
||||
|
||||
all.SetOptionRange("Weapons", true);
|
||||
all.SetOption("Weapons", "Poisoned", false);
|
||||
|
||||
all.SetOptionRange("Armor", true);
|
||||
|
||||
all.SetOptionRange("Ninjitsu", true);
|
||||
all.SetOption("Ninjitsu", "Animal Form", false);
|
||||
all.SetOption("Ninjitsu", "Mirror Image", false);
|
||||
all.SetOption("Ninjitsu", "Backstab", false);
|
||||
all.SetOption("Ninjitsu", "Suprise Attack", false);
|
||||
all.SetOption("Ninjitsu", "Shadow Jump", false);
|
||||
|
||||
all.SetOptionRange("Bushido", true);
|
||||
|
||||
all.SetOptionRange("Spellweaving", true);
|
||||
all.SetOption("Spellweaving", "Gift of Life", false);
|
||||
all.SetOption("Spellweaving", "Summon Fey", false);
|
||||
all.SetOption("Spellweaving", "Summon Fiend", false);
|
||||
all.SetOption("Spellweaving", "Nature's Fury", false);
|
||||
|
||||
all.SetOption("Potions", "Refresh", true);
|
||||
all.SetOption("Items", "Bandages", true);
|
||||
all.SetOption("Items", "Trapped Containers", true);
|
||||
|
||||
m_Root.Defaults = new[] { all };
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
// Set up flavors
|
||||
|
||||
Ruleset pots = new Ruleset(m_Root) { Title = "Potions" };
|
||||
|
||||
|
||||
pots.SetOptionRange("Potions", true);
|
||||
pots.SetOption("Potions", "Explosion", false);
|
||||
|
||||
Ruleset para = new Ruleset(m_Root) { Title = "Paralyze" };
|
||||
|
||||
para.SetOption("Spells", "Paralyze", true);
|
||||
para.SetOption("Spells", "Paralyze Field", true);
|
||||
para.SetOption("Combat Abilities", "Paralyzing Blow", true);
|
||||
|
||||
Ruleset fields = new Ruleset(m_Root) { Title = "Fields" };
|
||||
|
||||
fields.SetOption("Spells", "Wall of Stone", true);
|
||||
fields.SetOption("Spells", "Fire Field", true);
|
||||
fields.SetOption("Spells", "Poison Field", true);
|
||||
fields.SetOption("Spells", "Energy Field", true);
|
||||
fields.SetOption("Spells", "Wildfire", true);
|
||||
|
||||
Ruleset area = new Ruleset(m_Root) { Title = "Area Effect" };
|
||||
|
||||
area.SetOption("Spells", "Earthquake", true);
|
||||
area.SetOption("Spells", "Meteor Swarm", true);
|
||||
area.SetOption("Spells", "Chain Lightning", true);
|
||||
area.SetOption("Necromancy", "Wither", true);
|
||||
area.SetOption("Necromancy", "Poison Strike", true);
|
||||
|
||||
Ruleset summons = new Ruleset(m_Root) { Title = "Summons" };
|
||||
|
||||
summons.SetOption("Spells", "Blade Spirits", true);
|
||||
summons.SetOption("Spells", "Energy Vortex", true);
|
||||
summons.SetOption("Spells", "Air Elemental", true);
|
||||
summons.SetOption("Spells", "Summon Daemon", true);
|
||||
summons.SetOption("Spells", "Earth Elemental", true);
|
||||
summons.SetOption("Spells", "Fire Elemental", true);
|
||||
summons.SetOption("Spells", "Water Elemental", true);
|
||||
summons.SetOption("Necromancy", "Summon Familiar", true);
|
||||
summons.SetOption("Necromancy", "Vengeful Spirit", true);
|
||||
summons.SetOption("Necromancy", "Animate Dead", true);
|
||||
summons.SetOption("Ninjitsu", "Mirror Image", true);
|
||||
summons.SetOption("Spellweaving", "Summon Fey", true);
|
||||
summons.SetOption("Spellweaving", "Summon Fiend", true);
|
||||
summons.SetOption("Spellweaving", "Nature's Fury", true);
|
||||
|
||||
m_Root.Flavors = new[] { pots, para, fields, area, summons };
|
||||
|
||||
return m_Root;
|
||||
}
|
||||
}
|
||||
|
||||
public string Title{ get; }
|
||||
|
||||
public string Description{ get; }
|
||||
|
||||
public string[] Options{ get; }
|
||||
|
||||
public int Offset{ get; private set; }
|
||||
|
||||
public int TotalLength{ get; private set; }
|
||||
|
||||
public RulesetLayout Parent{ get; private set; }
|
||||
|
||||
public RulesetLayout[] Children{ get; }
|
||||
|
||||
public Ruleset[] Defaults{ get; set; }
|
||||
|
||||
public Ruleset[] Flavors{ get; set; }
|
||||
|
||||
public RulesetLayout FindByTitle(string title)
|
||||
{
|
||||
if (Title == title)
|
||||
return this;
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
{
|
||||
RulesetLayout layout = Children[i].FindByTitle(title);
|
||||
|
||||
if (layout != null)
|
||||
return layout;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string FindByIndex(int index)
|
||||
{
|
||||
if (index >= Offset && index < Offset + Options.Length)
|
||||
return Description + ": " + Options[index - Offset];
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
{
|
||||
string opt = Children[i].FindByIndex(index);
|
||||
|
||||
if (opt != null)
|
||||
return opt;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public RulesetLayout FindByOption(string title, string option, ref int index)
|
||||
{
|
||||
if (title == null || Title == title)
|
||||
{
|
||||
index = GetOptionIndex(option);
|
||||
|
||||
if (index >= 0)
|
||||
return this;
|
||||
|
||||
title = null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
{
|
||||
RulesetLayout layout = Children[i].FindByOption(title, option, ref index);
|
||||
|
||||
if (layout != null)
|
||||
return layout;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int GetOptionIndex(string option)
|
||||
{
|
||||
return Array.IndexOf(Options, option);
|
||||
}
|
||||
|
||||
public void ComputeOffsets()
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
RecurseComputeOffsets(ref offset);
|
||||
}
|
||||
|
||||
private int RecurseComputeOffsets(ref int offset)
|
||||
{
|
||||
Offset = offset;
|
||||
|
||||
offset += Options.Length;
|
||||
TotalLength += Options.Length;
|
||||
|
||||
for (int i = 0; i < Children.Length; ++i)
|
||||
TotalLength += Children[i].RecurseComputeOffsets(ref offset);
|
||||
|
||||
return TotalLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Projects/Scripts/Engines/ConPVP/SafeZone.cs
Normal file
66
Projects/Scripts/Engines/ConPVP/SafeZone.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Regions;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class SafeZone : GuardedRegion
|
||||
{
|
||||
public static readonly int SafeZonePriority = HouseRegion.HousePriority + 1;
|
||||
|
||||
/*public override bool AllowReds => true;*/
|
||||
|
||||
public SafeZone(Rectangle2D area, Point3D goloc, Map map, bool isGuarded) : base(null, map, SafeZonePriority, area)
|
||||
{
|
||||
GoLocation = goloc;
|
||||
|
||||
Disabled = !isGuarded;
|
||||
|
||||
Register();
|
||||
}
|
||||
|
||||
public override bool AllowHousing(Mobile from, Point3D p)
|
||||
{
|
||||
return from.AccessLevel >= AccessLevel.GameMaster && base.AllowHousing(from, p);
|
||||
}
|
||||
|
||||
public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
|
||||
{
|
||||
if (m.Player && Sigil.ExistsOn(m))
|
||||
{
|
||||
m.SendMessage(0x22, "You are holding a sigil and cannot enter this zone.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerMobile pm = m as PlayerMobile ??
|
||||
(m is BaseCreature bc && bc.Summoned ?
|
||||
bc.SummonMaster as PlayerMobile : null);
|
||||
|
||||
if (pm?.DuelContext?.StartedBeginCountdown == true)
|
||||
return true;
|
||||
|
||||
if (DuelContext.CheckCombat(m))
|
||||
{
|
||||
m.SendMessage(0x22, "You have recently been in combat and cannot enter this zone.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.OnMoveInto(m, d, newLocation, oldLocation);
|
||||
}
|
||||
|
||||
public override void OnEnter(Mobile m)
|
||||
{
|
||||
m.SendMessage("You have entered a dueling safezone. No combat other than duels are allowed in this zone.");
|
||||
}
|
||||
|
||||
public override void OnExit(Mobile m)
|
||||
{
|
||||
m.SendMessage("You have left a dueling safezone. Combat is now unrestricted.");
|
||||
}
|
||||
|
||||
public override bool CanUseStuckMenu(Mobile m)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
910
Projects/Scripts/Engines/ConPVP/Tournament.cs
Normal file
910
Projects/Scripts/Engines/ConPVP/Tournament.cs
Normal file
|
|
@ -0,0 +1,910 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Factions;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
using Server.Regions;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public enum TournamentStage
|
||||
{
|
||||
Inactive,
|
||||
Signup,
|
||||
Fighting
|
||||
}
|
||||
|
||||
public enum GroupingType
|
||||
{
|
||||
HighVsLow,
|
||||
Nearest,
|
||||
Random
|
||||
}
|
||||
|
||||
public enum TieType
|
||||
{
|
||||
Random,
|
||||
Highest,
|
||||
Lowest,
|
||||
FullElimination,
|
||||
FullAdvancement
|
||||
}
|
||||
|
||||
public enum TourneyType
|
||||
{
|
||||
Standard,
|
||||
FreeForAll,
|
||||
RandomTeam,
|
||||
RedVsBlue,
|
||||
Faction
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class Tournament
|
||||
{
|
||||
private static readonly TimeSpan SliceInterval = TimeSpan.FromSeconds(12.0);
|
||||
private int m_ParticipantsPerMatch;
|
||||
private int m_PlayersPerParticipant;
|
||||
|
||||
public Tournament(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 5:
|
||||
{
|
||||
FactionRestricted = reader.ReadBool();
|
||||
|
||||
goto case 4;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
EventController = reader.ReadItem() as EventController;
|
||||
|
||||
goto case 3;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
SuddenDeathRounds = reader.ReadEncodedInt();
|
||||
|
||||
goto case 2;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
TourneyType = (TourneyType)reader.ReadEncodedInt();
|
||||
|
||||
goto case 1;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
GroupType = (GroupingType)reader.ReadEncodedInt();
|
||||
TieType = (TieType)reader.ReadEncodedInt();
|
||||
SignupPeriod = reader.ReadTimeSpan();
|
||||
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
if (version < 3)
|
||||
SuddenDeathRounds = 3;
|
||||
|
||||
m_ParticipantsPerMatch = reader.ReadEncodedInt();
|
||||
m_PlayersPerParticipant = reader.ReadEncodedInt();
|
||||
SignupPeriod = reader.ReadTimeSpan();
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
Pyramid = new TourneyPyramid();
|
||||
Ruleset = new Ruleset(RulesetLayout.Root);
|
||||
Ruleset.ApplyDefault(Ruleset.Layout.Defaults[0]);
|
||||
Participants = new List<TourneyParticipant>();
|
||||
Undefeated = new List<TourneyParticipant>();
|
||||
Arenas = new List<Arena>();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Timer.DelayCall(SliceInterval, SliceInterval, Slice);
|
||||
}
|
||||
|
||||
public Tournament()
|
||||
{
|
||||
m_ParticipantsPerMatch = 2;
|
||||
m_PlayersPerParticipant = 1;
|
||||
Pyramid = new TourneyPyramid();
|
||||
Ruleset = new Ruleset(RulesetLayout.Root);
|
||||
Ruleset.ApplyDefault(Ruleset.Layout.Defaults[0]);
|
||||
Participants = new List<TourneyParticipant>();
|
||||
Undefeated = new List<TourneyParticipant>();
|
||||
Arenas = new List<Arena>();
|
||||
SignupPeriod = TimeSpan.FromMinutes(10.0);
|
||||
|
||||
Timer.DelayCall(SliceInterval, SliceInterval, Slice);
|
||||
}
|
||||
|
||||
public bool IsNotoRestricted => TourneyType != TourneyType.Standard;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public EventController EventController{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int SuddenDeathRounds{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TourneyType TourneyType{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public GroupingType GroupType{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TieType TieType{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan SuddenDeath{ get; set; }
|
||||
|
||||
public Ruleset Ruleset{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ParticipantsPerMatch
|
||||
{
|
||||
get => m_ParticipantsPerMatch;
|
||||
set
|
||||
{
|
||||
if (value < 2) value = 2;
|
||||
else if (value > 10) value = 10;
|
||||
m_ParticipantsPerMatch = value;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int PlayersPerParticipant
|
||||
{
|
||||
get => m_PlayersPerParticipant;
|
||||
set
|
||||
{
|
||||
if (value < 1) value = 1;
|
||||
else if (value > 10) value = 10;
|
||||
m_PlayersPerParticipant = value;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int LevelRequirement{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool FactionRestricted{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan SignupPeriod{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime SignupStart{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentStage CurrentStage{ get; private set; }
|
||||
|
||||
public TournamentStage Stage
|
||||
{
|
||||
get => CurrentStage;
|
||||
set => CurrentStage = value;
|
||||
}
|
||||
|
||||
public TourneyPyramid Pyramid{ get; set; }
|
||||
|
||||
public List<Arena> Arenas{ get; set; }
|
||||
|
||||
public List<TourneyParticipant> Participants{ get; set; }
|
||||
|
||||
public List<TourneyParticipant> Undefeated{ get; set; }
|
||||
|
||||
public bool IsFactionRestricted => FactionRestricted || TourneyType == TourneyType.Faction;
|
||||
|
||||
public bool HasParticipant(Mobile mob)
|
||||
{
|
||||
for (int i = 0; i < Participants.Count; ++i)
|
||||
{
|
||||
if (Participants[i].Players.Contains(mob))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(5); // version
|
||||
|
||||
writer.Write(FactionRestricted);
|
||||
|
||||
writer.Write(EventController);
|
||||
|
||||
writer.WriteEncodedInt(SuddenDeathRounds);
|
||||
|
||||
writer.WriteEncodedInt((int)TourneyType);
|
||||
|
||||
writer.WriteEncodedInt((int)GroupType);
|
||||
writer.WriteEncodedInt((int)TieType);
|
||||
writer.Write(SuddenDeath);
|
||||
|
||||
writer.WriteEncodedInt(m_ParticipantsPerMatch);
|
||||
writer.WriteEncodedInt(m_PlayersPerParticipant);
|
||||
writer.Write(SignupPeriod);
|
||||
}
|
||||
|
||||
public void HandleTie(Arena arena, TourneyMatch match, List<TourneyParticipant> remaining)
|
||||
{
|
||||
if (remaining.Count == 1)
|
||||
HandleWon(arena, match, remaining[0]);
|
||||
|
||||
if (remaining.Count < 2)
|
||||
return;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("The match has ended in a tie ");
|
||||
|
||||
sb.Append(remaining.Count == 2 ? "between " : "among ");
|
||||
|
||||
sb.Append(remaining.Count);
|
||||
|
||||
sb.Append(remaining[0].Players.Count == 1 ? " players: " : " teams: ");
|
||||
|
||||
bool hasAppended = false;
|
||||
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
|
||||
if (remaining.Contains(part))
|
||||
{
|
||||
if (hasAppended)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(part.NameList);
|
||||
hasAppended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Undefeated.Remove(part);
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append(". ");
|
||||
|
||||
string whole = remaining.Count == 2 ? "both" : "all";
|
||||
|
||||
TieType tieType = TieType;
|
||||
|
||||
if (tieType == TieType.FullElimination && remaining.Count >= Undefeated.Count)
|
||||
tieType = TieType.FullAdvancement;
|
||||
|
||||
switch (tieType)
|
||||
{
|
||||
case TieType.FullAdvancement:
|
||||
{
|
||||
sb.AppendFormat("In accordance with the rules, {0} parties are advanced.", whole);
|
||||
break;
|
||||
}
|
||||
case TieType.FullElimination:
|
||||
{
|
||||
for (int j = 0; j < remaining.Count; ++j)
|
||||
Undefeated.Remove(remaining[j]);
|
||||
|
||||
sb.AppendFormat("In accordance with the rules, {0} parties are eliminated.", whole);
|
||||
break;
|
||||
}
|
||||
case TieType.Random:
|
||||
{
|
||||
TourneyParticipant advanced = remaining[Utility.Random(remaining.Count)];
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
if (remaining[i] != advanced)
|
||||
Undefeated.Remove(remaining[i]);
|
||||
|
||||
if (advanced != null)
|
||||
sb.AppendFormat("In accordance with the rules, {0} {1} advanced.", advanced.NameList,
|
||||
advanced.Players.Count == 1 ? "is" : "are");
|
||||
|
||||
break;
|
||||
}
|
||||
case TieType.Highest:
|
||||
{
|
||||
TourneyParticipant advanced = null;
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = remaining[i];
|
||||
|
||||
if (advanced == null || part.TotalLadderXP > advanced.TotalLadderXP)
|
||||
advanced = part;
|
||||
}
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
if (remaining[i] != advanced)
|
||||
Undefeated.Remove(remaining[i]);
|
||||
|
||||
if (advanced != null)
|
||||
sb.AppendFormat("In accordance with the rules, {0} {1} advanced.", advanced.NameList,
|
||||
advanced.Players.Count == 1 ? "is" : "are");
|
||||
|
||||
break;
|
||||
}
|
||||
case TieType.Lowest:
|
||||
{
|
||||
TourneyParticipant advanced = null;
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = remaining[i];
|
||||
|
||||
if (advanced == null || part.TotalLadderXP < advanced.TotalLadderXP)
|
||||
advanced = part;
|
||||
}
|
||||
|
||||
for (int i = 0; i < remaining.Count; ++i)
|
||||
if (remaining[i] != advanced)
|
||||
Undefeated.Remove(remaining[i]);
|
||||
|
||||
if (advanced != null)
|
||||
sb.AppendFormat("In accordance with the rules, {0} {1} advanced.", advanced.NameList,
|
||||
advanced.Players.Count == 1 ? "is" : "are");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Alert(arena, sb.ToString());
|
||||
}
|
||||
|
||||
public void OnEliminated(DuelPlayer player)
|
||||
{
|
||||
Participant part = player.Participant;
|
||||
|
||||
if (!part.Eliminated)
|
||||
return;
|
||||
|
||||
if (TourneyType == TourneyType.FreeForAll)
|
||||
{
|
||||
int rem = 0;
|
||||
|
||||
for (int i = 0; i < part.Context.Participants.Count; ++i)
|
||||
{
|
||||
if (part.Context.Participants[i]?.Eliminated == false)
|
||||
++rem;
|
||||
}
|
||||
|
||||
TourneyParticipant tp = part.TourneyPart;
|
||||
|
||||
if (tp == null)
|
||||
return;
|
||||
|
||||
if (rem == 1)
|
||||
GiveAwards(tp.Players, TrophyRank.Silver, ComputeCashAward() / 2);
|
||||
else if (rem == 2)
|
||||
GiveAwards(tp.Players, TrophyRank.Bronze, ComputeCashAward() / 4);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleWon(Arena arena, TourneyMatch match, TourneyParticipant winner)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("The match is complete. ");
|
||||
sb.Append(winner.NameList);
|
||||
|
||||
if (winner.Players.Count > 1)
|
||||
sb.Append(" have bested ");
|
||||
else
|
||||
sb.Append(" has bested ");
|
||||
|
||||
if (match.Participants.Count > 2)
|
||||
sb.AppendFormat("{0} other {1}: ", match.Participants.Count - 1,
|
||||
winner.Players.Count == 1 ? "players" : "teams");
|
||||
|
||||
bool hasAppended = false;
|
||||
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
|
||||
if (part == winner)
|
||||
continue;
|
||||
|
||||
Undefeated.Remove(part);
|
||||
|
||||
if (hasAppended)
|
||||
sb.Append(", ");
|
||||
|
||||
sb.Append(part.NameList);
|
||||
hasAppended = true;
|
||||
}
|
||||
|
||||
sb.Append(".");
|
||||
|
||||
if (TourneyType == TourneyType.Standard)
|
||||
Alert(arena, sb.ToString());
|
||||
}
|
||||
|
||||
private int ComputeCashAward()
|
||||
{
|
||||
return Participants.Count * m_PlayersPerParticipant * 2500;
|
||||
}
|
||||
|
||||
private void GiveAwards()
|
||||
{
|
||||
switch (TourneyType)
|
||||
{
|
||||
case TourneyType.FreeForAll:
|
||||
{
|
||||
if (Pyramid.Levels.Count < 1)
|
||||
break;
|
||||
|
||||
PyramidLevel top = Pyramid.Levels[Pyramid.Levels.Count - 1];
|
||||
|
||||
if (top.FreeAdvance != null || top.Matches.Count != 1)
|
||||
break;
|
||||
|
||||
TourneyMatch match = top.Matches[0];
|
||||
TourneyParticipant winner = match.Winner;
|
||||
|
||||
if (winner != null)
|
||||
GiveAwards(winner.Players, TrophyRank.Gold, ComputeCashAward());
|
||||
|
||||
break;
|
||||
}
|
||||
case TourneyType.Standard:
|
||||
{
|
||||
if (Pyramid.Levels.Count < 2)
|
||||
break;
|
||||
|
||||
PyramidLevel top = Pyramid.Levels[Pyramid.Levels.Count - 1];
|
||||
|
||||
if (top.FreeAdvance != null || top.Matches.Count != 1)
|
||||
break;
|
||||
|
||||
int cash = ComputeCashAward();
|
||||
|
||||
TourneyMatch match = top.Matches[0];
|
||||
TourneyParticipant winner = match.Winner;
|
||||
|
||||
for (int i = 0; i < match.Participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[i];
|
||||
|
||||
if (part == winner)
|
||||
GiveAwards(part.Players, TrophyRank.Gold, cash);
|
||||
else
|
||||
GiveAwards(part.Players, TrophyRank.Silver, cash / 2);
|
||||
}
|
||||
|
||||
PyramidLevel next = Pyramid.Levels[Pyramid.Levels.Count - 2];
|
||||
|
||||
if (next.Matches.Count > 2)
|
||||
break;
|
||||
|
||||
for (int i = 0; i < next.Matches.Count; ++i)
|
||||
{
|
||||
match = next.Matches[i];
|
||||
winner = match.Winner;
|
||||
|
||||
for (int j = 0; j < match.Participants.Count; ++j)
|
||||
{
|
||||
TourneyParticipant part = match.Participants[j];
|
||||
|
||||
if (part != winner)
|
||||
GiveAwards(part.Players, TrophyRank.Bronze, cash / 4);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GiveAwards(List<Mobile> players, TrophyRank rank, int cash)
|
||||
{
|
||||
if (players.Count == 0)
|
||||
return;
|
||||
|
||||
if (players.Count > 1)
|
||||
cash /= players.Count - 1;
|
||||
|
||||
cash += 500;
|
||||
cash /= 1000;
|
||||
cash *= 1000;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (TourneyType == TourneyType.FreeForAll)
|
||||
{
|
||||
sb.Append(Participants.Count * m_PlayersPerParticipant);
|
||||
sb.Append("-man FFA");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
sb.Append(m_ParticipantsPerMatch);
|
||||
sb.Append("-Team");
|
||||
}
|
||||
else if (TourneyType == TourneyType.Faction)
|
||||
{
|
||||
sb.Append(m_ParticipantsPerMatch);
|
||||
sb.Append("-Team Faction");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
sb.Append("Red v Blue");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < m_ParticipantsPerMatch; ++i)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append('v');
|
||||
|
||||
sb.Append(m_PlayersPerParticipant);
|
||||
}
|
||||
}
|
||||
|
||||
if (EventController != null)
|
||||
sb.Append(' ').Append(EventController.Title);
|
||||
|
||||
sb.Append(" Champion");
|
||||
|
||||
string title = sb.ToString();
|
||||
|
||||
for (int i = 0; i < players.Count; ++i)
|
||||
{
|
||||
Mobile mob = players[i];
|
||||
|
||||
if (mob?.Deleted != false)
|
||||
continue;
|
||||
|
||||
Item item = new Trophy(title, rank);
|
||||
|
||||
if (!mob.PlaceInBackpack(item))
|
||||
mob.BankBox.DropItem(item);
|
||||
|
||||
if (cash > 0)
|
||||
{
|
||||
item = new BankCheck(cash);
|
||||
|
||||
if (!mob.PlaceInBackpack(item))
|
||||
mob.BankBox.DropItem(item);
|
||||
|
||||
mob.SendMessage(
|
||||
"You have been awarded a {0} trophy and {1:N0}gp for your participation in this tournament.",
|
||||
rank.ToString().ToLower(), cash);
|
||||
}
|
||||
else
|
||||
{
|
||||
mob.SendMessage("You have been awarded a {0} trophy for your participation in this tournament.",
|
||||
rank.ToString().ToLower());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Slice()
|
||||
{
|
||||
if (CurrentStage == TournamentStage.Signup)
|
||||
{
|
||||
TimeSpan until = SignupStart + SignupPeriod - DateTime.UtcNow;
|
||||
|
||||
if (until <= TimeSpan.Zero)
|
||||
{
|
||||
for (int i = Participants.Count - 1; i >= 0; --i)
|
||||
{
|
||||
TourneyParticipant part = Participants[i];
|
||||
bool bad = false;
|
||||
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
{
|
||||
Mobile check = part.Players[j];
|
||||
|
||||
if (check.Deleted || check.Map == null || check.Map == Map.Internal || !check.Alive ||
|
||||
Sigil.ExistsOn(check) || check.Region.IsPartOf<Jail>())
|
||||
{
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bad)
|
||||
{
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
part.Players[j].SendMessage("You have been disqualified from the tournament.");
|
||||
|
||||
Participants.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (Participants.Count >= 2)
|
||||
{
|
||||
CurrentStage = TournamentStage.Fighting;
|
||||
|
||||
Undefeated.Clear();
|
||||
|
||||
Pyramid.Levels.Clear();
|
||||
Pyramid.AddLevel(m_ParticipantsPerMatch, Participants, GroupType, TourneyType);
|
||||
|
||||
PyramidLevel level = Pyramid.Levels[0];
|
||||
|
||||
if (level.FreeAdvance != null)
|
||||
Undefeated.Add(level.FreeAdvance);
|
||||
|
||||
for (int i = 0; i < level.Matches.Count; ++i)
|
||||
{
|
||||
TourneyMatch match = level.Matches[i];
|
||||
|
||||
Undefeated.AddRange(match.Participants);
|
||||
}
|
||||
|
||||
Alert("Hear ye! Hear ye!", "The tournament will begin shortly.");
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Alert( "Is this all?", "Pitiful. Signup extended." );
|
||||
m_SignupStart = DateTime.UtcNow;*/
|
||||
|
||||
Alert("Is this all?", "Pitiful. Tournament cancelled.");
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
}
|
||||
}
|
||||
else if (Math.Abs(until.TotalSeconds - TimeSpan.FromMinutes(1.0).TotalSeconds) <
|
||||
SliceInterval.TotalSeconds / 2)
|
||||
{
|
||||
Alert("Last call!", "If you wish to enter the tournament, sign up with the registrar now.");
|
||||
}
|
||||
else if (Math.Abs(until.TotalSeconds - TimeSpan.FromMinutes(5.0).TotalSeconds) <
|
||||
SliceInterval.TotalSeconds / 2)
|
||||
{
|
||||
Alert("The tournament will begin in 5 minutes.", "Sign up now before it's too late.");
|
||||
}
|
||||
}
|
||||
else if (CurrentStage == TournamentStage.Fighting)
|
||||
{
|
||||
if (Undefeated.Count == 1)
|
||||
{
|
||||
TourneyParticipant winner = Undefeated[0];
|
||||
|
||||
try
|
||||
{
|
||||
if (EventController != null)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {EventController.GetTeamName(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner))} has won!");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
else if (TourneyType == TourneyType.Faction)
|
||||
{
|
||||
if (m_ParticipantsPerMatch == 4)
|
||||
{
|
||||
string name = "(null)";
|
||||
|
||||
switch (Pyramid.Levels[0].Matches[0].Participants.IndexOf(
|
||||
winner))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
name = "Minax";
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
name = "Council of Mages";
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
name = "True Britannians";
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
name = "Shadowlords";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Alert("The tournament has completed!", $"The {name} team has won!");
|
||||
}
|
||||
else if (m_ParticipantsPerMatch == 2)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"The {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Evil" : "Hero")} team has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
}
|
||||
else if (TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Red" : "Blue")} has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"{winner.NameList} {(winner.Players.Count > 1 ? "are" : "is")} the champion{(winner.Players.Count == 1 ? "" : "s")}.");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
GiveAwards();
|
||||
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
Undefeated.Clear();
|
||||
}
|
||||
else if (Pyramid.Levels.Count > 0)
|
||||
{
|
||||
PyramidLevel activeLevel = Pyramid.Levels[Pyramid.Levels.Count - 1];
|
||||
bool stillGoing = false;
|
||||
|
||||
for (int i = 0; i < activeLevel.Matches.Count; ++i)
|
||||
{
|
||||
TourneyMatch match = activeLevel.Matches[i];
|
||||
|
||||
if (match.Winner == null)
|
||||
{
|
||||
stillGoing = true;
|
||||
|
||||
if (!match.InProgress)
|
||||
for (int j = 0; j < Arenas.Count; ++j)
|
||||
{
|
||||
Arena arena = Arenas[j];
|
||||
|
||||
if (!arena.IsOccupied)
|
||||
{
|
||||
match.Start(arena, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!stillGoing)
|
||||
{
|
||||
for (int i = Undefeated.Count - 1; i >= 0; --i)
|
||||
{
|
||||
TourneyParticipant part = Undefeated[i];
|
||||
bool bad = false;
|
||||
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
{
|
||||
Mobile check = part.Players[j];
|
||||
|
||||
if (check.Deleted || check.Map == null || check.Map == Map.Internal || !check.Alive ||
|
||||
Sigil.ExistsOn(check) || check.Region.IsPartOf<Jail>())
|
||||
{
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bad)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < part.Players.Count; ++j)
|
||||
part.Players[j].SendMessage("You have been disqualified from the tournament.");
|
||||
|
||||
Undefeated.RemoveAt(i);
|
||||
|
||||
if (Undefeated.Count == 1)
|
||||
{
|
||||
TourneyParticipant winner = Undefeated[0];
|
||||
|
||||
try
|
||||
{
|
||||
if (EventController != null)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {EventController.GetTeamName(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner))} has won");
|
||||
}
|
||||
else if (TourneyType == TourneyType.RandomTeam)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
else if (TourneyType == TourneyType.Faction)
|
||||
{
|
||||
if (m_ParticipantsPerMatch == 4)
|
||||
{
|
||||
string name = "(null)";
|
||||
|
||||
switch (Pyramid.Levels[0].Matches[0]
|
||||
.Participants.IndexOf(winner))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
name = "Minax";
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
name = "Council of Mages";
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
name = "True Britannians";
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
name = "Shadowlords";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Alert("The tournament has completed!", $"The {name} team has won!");
|
||||
}
|
||||
else if (m_ParticipantsPerMatch == 2)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"The {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Evil" : "Hero")} team has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) + 1} has won!");
|
||||
}
|
||||
}
|
||||
else if (TourneyType == TourneyType.RedVsBlue)
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"Team {(Pyramid.Levels[0].Matches[0].Participants.IndexOf(winner) == 0 ? "Red" : "Blue")} has won!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert("The tournament has completed!",
|
||||
$"{winner.NameList} {(winner.Players.Count > 1 ? "are" : "is")} the champion{(winner.Players.Count == 1 ? "" : "s")}.");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
GiveAwards();
|
||||
|
||||
CurrentStage = TournamentStage.Inactive;
|
||||
Undefeated.Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Undefeated.Count > 1)
|
||||
Pyramid.AddLevel(m_ParticipantsPerMatch, Undefeated, GroupType, TourneyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Alert(params string[] alerts)
|
||||
{
|
||||
for (int i = 0; i < Arenas.Count; ++i)
|
||||
Alert(Arenas[i], alerts);
|
||||
}
|
||||
|
||||
public void Alert(Arena arena, params string[] alerts)
|
||||
{
|
||||
if (arena?.Announcer != null)
|
||||
for (int j = 0; j < alerts.Length; ++j)
|
||||
{
|
||||
string alert = alerts[j];
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(Math.Max(j - 0.5, 0.0)),
|
||||
() => arena.Announcer.PublicOverheadMessage(MessageType.Regular, 0x35, false, alert));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
Projects/Scripts/Engines/ConPVP/TournamentBracketItem.cs
Normal file
65
Projects/Scripts/Engines/ConPVP/TournamentBracketItem.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentBracketItem : Item
|
||||
{
|
||||
[Constructible]
|
||||
public TournamentBracketItem() : base(3774)
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public TournamentBracketItem(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament{ get; set; }
|
||||
|
||||
public override string DefaultName => "tournament bracket";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
|
||||
}
|
||||
else
|
||||
{
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (tourney != null)
|
||||
{
|
||||
from.CloseGump<TournamentBracketGump>();
|
||||
from.SendGump(new TournamentBracketGump(from, tourney, TourneyBracketGumpType.Index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
writer.Write(Tournament);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = reader.ReadItem() as TournamentController;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
Projects/Scripts/Engines/ConPVP/TournamentController.cs
Normal file
143
Projects/Scripts/Engines/ConPVP/TournamentController.cs
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.ContextMenus;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentController : Item
|
||||
{
|
||||
private static List<TournamentController> m_Instances = new List<TournamentController>();
|
||||
|
||||
[Constructible]
|
||||
public TournamentController() : base(0x1B7A)
|
||||
{
|
||||
Visible = false;
|
||||
Movable = false;
|
||||
|
||||
Tournament = new Tournament();
|
||||
m_Instances.Add(this);
|
||||
}
|
||||
|
||||
public TournamentController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Tournament Tournament{ get; private set; }
|
||||
|
||||
public static bool IsActive
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < m_Instances.Count; ++i)
|
||||
{
|
||||
TournamentController controller = m_Instances[i];
|
||||
|
||||
if (controller?.Deleted == false && controller.Tournament != null &&
|
||||
controller.Tournament.Stage != TournamentStage.Inactive)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultName => "tournament controller";
|
||||
|
||||
public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
{
|
||||
base.GetContextMenuEntries(from, list);
|
||||
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster && Tournament != null)
|
||||
{
|
||||
list.Add(new EditEntry(Tournament));
|
||||
|
||||
if (Tournament.CurrentStage == TournamentStage.Inactive)
|
||||
list.Add(new StartEntry(Tournament));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.GameMaster && Tournament != null)
|
||||
{
|
||||
from.CloseGump<PickRulesetGump>();
|
||||
from.CloseGump<RulesetGump>();
|
||||
from.SendGump(new PickRulesetGump(from, null, Tournament.Ruleset));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
Tournament.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = new Tournament(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_Instances.Add(this);
|
||||
}
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
base.OnDelete();
|
||||
|
||||
m_Instances.Remove(this);
|
||||
}
|
||||
|
||||
private class EditEntry : ContextMenuEntry
|
||||
{
|
||||
private Tournament m_Tournament;
|
||||
|
||||
public EditEntry(Tournament tourney) : base(5101)
|
||||
{
|
||||
m_Tournament = tourney;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
Owner.From.SendGump(new PropertiesGump(Owner.From, m_Tournament));
|
||||
}
|
||||
}
|
||||
|
||||
private class StartEntry : ContextMenuEntry
|
||||
{
|
||||
private Tournament m_Tournament;
|
||||
|
||||
public StartEntry(Tournament tourney) : base(5113)
|
||||
{
|
||||
m_Tournament = tourney;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
if (m_Tournament.Stage == TournamentStage.Inactive)
|
||||
{
|
||||
m_Tournament.SignupStart = DateTime.UtcNow;
|
||||
m_Tournament.Stage = TournamentStage.Signup;
|
||||
m_Tournament.Participants.Clear();
|
||||
m_Tournament.Pyramid.Levels.Clear();
|
||||
m_Tournament.Alert("Hear ye! Hear ye!",
|
||||
"Tournament signup has opened. You can enter by signing up with the registrar.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
190
Projects/Scripts/Engines/ConPVP/TournamentPyramid.cs
Normal file
190
Projects/Scripts/Engines/ConPVP/TournamentPyramid.cs
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Ethics;
|
||||
using Server.Factions;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TourneyPyramid
|
||||
{
|
||||
public TourneyPyramid()
|
||||
{
|
||||
Levels = new List<PyramidLevel>();
|
||||
}
|
||||
|
||||
public List<PyramidLevel> Levels{ get; set; }
|
||||
|
||||
public void AddLevel(int partsPerMatch, List<TourneyParticipant> participants, GroupingType groupType, TourneyType tourneyType)
|
||||
{
|
||||
List<TourneyParticipant> copy = new List<TourneyParticipant>(participants);
|
||||
|
||||
if (groupType == GroupingType.Nearest || groupType == GroupingType.HighVsLow)
|
||||
copy.Sort();
|
||||
|
||||
PyramidLevel level = new PyramidLevel();
|
||||
|
||||
switch (tourneyType)
|
||||
{
|
||||
case TourneyType.RedVsBlue:
|
||||
{
|
||||
TourneyParticipant[] parts = new TourneyParticipant[2];
|
||||
|
||||
for (int i = 0; i < parts.Length; ++i)
|
||||
parts[i] = new TourneyParticipant(new List<Mobile>());
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
{
|
||||
List<Mobile> players = copy[i].Players;
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
Mobile mob = players[j];
|
||||
|
||||
if (mob.Kills >= 5)
|
||||
parts[0].Players.Add(mob);
|
||||
else
|
||||
parts[1].Players.Add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
level.Matches.Add(new TourneyMatch(new List<TourneyParticipant>(parts)));
|
||||
break;
|
||||
}
|
||||
case TourneyType.Faction:
|
||||
{
|
||||
TourneyParticipant[] parts = new TourneyParticipant[partsPerMatch];
|
||||
|
||||
for (int i = 0; i < parts.Length; ++i)
|
||||
parts[i] = new TourneyParticipant(new List<Mobile>());
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
{
|
||||
List<Mobile> players = copy[i].Players;
|
||||
|
||||
for (int j = 0; j < players.Count; ++j)
|
||||
{
|
||||
Mobile mob = players[j];
|
||||
|
||||
int index = -1;
|
||||
|
||||
if (partsPerMatch == 4)
|
||||
{
|
||||
Faction fac = Faction.Find(mob);
|
||||
|
||||
if (fac != null)
|
||||
index = fac.Definition.Sort;
|
||||
}
|
||||
else if (partsPerMatch == 2)
|
||||
{
|
||||
if (Ethic.Evil.IsEligible(mob))
|
||||
index = 0;
|
||||
else if (Ethic.Hero.IsEligible(mob)) index = 1;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= partsPerMatch) index = i % partsPerMatch;
|
||||
|
||||
parts[index].Players.Add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
level.Matches.Add(new TourneyMatch(new List<TourneyParticipant>(parts)));
|
||||
break;
|
||||
}
|
||||
case TourneyType.RandomTeam:
|
||||
{
|
||||
TourneyParticipant[] parts = new TourneyParticipant[partsPerMatch];
|
||||
|
||||
for (int i = 0; i < partsPerMatch; ++i)
|
||||
parts[i] = new TourneyParticipant(new List<Mobile>());
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
parts[i % parts.Length].Players.AddRange(copy[i].Players);
|
||||
|
||||
level.Matches.Add(new TourneyMatch(new List<TourneyParticipant>(parts)));
|
||||
break;
|
||||
}
|
||||
case TourneyType.FreeForAll:
|
||||
{
|
||||
level.Matches.Add(new TourneyMatch(copy));
|
||||
break;
|
||||
}
|
||||
case TourneyType.Standard:
|
||||
{
|
||||
if (partsPerMatch >= 2 && participants.Count % partsPerMatch == 1)
|
||||
{
|
||||
int lowAdvances = int.MaxValue;
|
||||
|
||||
for (int i = 0; i < participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant p = participants[i];
|
||||
|
||||
if (p.FreeAdvances < lowAdvances)
|
||||
lowAdvances = p.FreeAdvances;
|
||||
}
|
||||
|
||||
List<TourneyParticipant> toAdvance = new List<TourneyParticipant>();
|
||||
|
||||
for (int i = 0; i < participants.Count; ++i)
|
||||
{
|
||||
TourneyParticipant p = participants[i];
|
||||
|
||||
if (p.FreeAdvances == lowAdvances)
|
||||
toAdvance.Add(p);
|
||||
}
|
||||
|
||||
if (toAdvance.Count == 0)
|
||||
toAdvance = copy; // sanity
|
||||
|
||||
int idx = Utility.Random(toAdvance.Count);
|
||||
|
||||
toAdvance[idx].AddLog(
|
||||
"Advanced automatically due to an odd number of challengers.");
|
||||
level.FreeAdvance = toAdvance[idx];
|
||||
++level.FreeAdvance.FreeAdvances;
|
||||
copy.Remove(toAdvance[idx]);
|
||||
}
|
||||
|
||||
while (copy.Count >= partsPerMatch)
|
||||
{
|
||||
List<TourneyParticipant> thisMatch = new List<TourneyParticipant>();
|
||||
|
||||
for (int i = 0; i < partsPerMatch; ++i)
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
switch (groupType)
|
||||
{
|
||||
case GroupingType.HighVsLow:
|
||||
idx = i * (copy.Count - 1) / (partsPerMatch - 1);
|
||||
break;
|
||||
case GroupingType.Nearest:
|
||||
idx = 0;
|
||||
break;
|
||||
case GroupingType.Random:
|
||||
idx = Utility.Random(copy.Count);
|
||||
break;
|
||||
}
|
||||
|
||||
thisMatch.Add(copy[idx]);
|
||||
copy.RemoveAt(idx);
|
||||
}
|
||||
|
||||
level.Matches.Add(new TourneyMatch(thisMatch));
|
||||
}
|
||||
|
||||
if (copy.Count > 1)
|
||||
level.Matches.Add(new TourneyMatch(copy));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Levels.Add(level);
|
||||
}
|
||||
}
|
||||
|
||||
public class PyramidLevel
|
||||
{
|
||||
public List<TourneyMatch> Matches{ get; set; } = new List<TourneyMatch>();
|
||||
public TourneyParticipant FreeAdvance{ get; set; }
|
||||
}
|
||||
}
|
||||
93
Projects/Scripts/Engines/ConPVP/TournamentRegistrar.cs
Normal file
93
Projects/Scripts/Engines/ConPVP/TournamentRegistrar.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentRegistrar : Banker
|
||||
{
|
||||
[Constructible]
|
||||
public TournamentRegistrar()
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(30.0), TimeSpan.FromSeconds(30.0), Announce_Callback);
|
||||
}
|
||||
|
||||
public TournamentRegistrar(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament{ get; set; }
|
||||
|
||||
private void Announce_Callback()
|
||||
{
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (tourney?.Stage == TournamentStage.Signup)
|
||||
PublicOverheadMessage(MessageType.Regular, 0x35, false,
|
||||
"Come one, come all! Do you aspire to be a fighter of great renown? Join this tournament and show the world your abilities.");
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
base.OnMovement(m, oldLocation);
|
||||
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (InRange(m, 4) && !InRange(oldLocation, 4) && tourney != null && tourney.Stage == TournamentStage.Signup &&
|
||||
m.CanBeginAction(this))
|
||||
{
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
LadderEntry entry = ladder?.Find(m);
|
||||
|
||||
if (entry != null && Ladder.GetLevel(entry.Experience) < tourney.LevelRequirement)
|
||||
return;
|
||||
|
||||
if (tourney.IsFactionRestricted && Faction.Find(m) == null) return;
|
||||
|
||||
if (tourney.HasParticipant(m))
|
||||
return;
|
||||
|
||||
PrivateOverheadMessage(MessageType.Regular, 0x35, false,
|
||||
$"Hello m'{(m.Female ? "Lady" : "Lord")}. Dost thou wish to enter this tournament? You need only to write your name in this book.",
|
||||
m.NetState);
|
||||
m.BeginAction(this);
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(10.0), ReleaseLock_Callback, m);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseLock_Callback(Mobile m)
|
||||
{
|
||||
m.EndAction(this);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
writer.Write(Tournament);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = reader.ReadItem() as TournamentController;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(30.0), TimeSpan.FromSeconds(30.0), Announce_Callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
149
Projects/Scripts/Engines/ConPVP/TournamentSignupItem.cs
Normal file
149
Projects/Scripts/Engines/ConPVP/TournamentSignupItem.cs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TournamentSignupItem : Item
|
||||
{
|
||||
[Constructible]
|
||||
public TournamentSignupItem() : base(4029)
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public TournamentSignupItem(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TournamentController Tournament{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Registrar{ get; set; }
|
||||
|
||||
public override string DefaultName => "tournament signup book";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that
|
||||
}
|
||||
else
|
||||
{
|
||||
Tournament tourney = Tournament?.Tournament;
|
||||
|
||||
if (tourney == null)
|
||||
return;
|
||||
|
||||
if (Registrar != null)
|
||||
Registrar.Direction = Registrar.GetDirectionTo(this);
|
||||
|
||||
switch (tourney.Stage)
|
||||
{
|
||||
case TournamentStage.Fighting:
|
||||
{
|
||||
if (Registrar != null)
|
||||
{
|
||||
if (tourney.HasParticipant(from))
|
||||
Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "Excuse me? You are already signed up.", from.NetState);
|
||||
else
|
||||
Registrar.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "The tournament has already begun. You are too late to signup now.",
|
||||
from.NetState);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TournamentStage.Inactive:
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "The tournament is closed.", from.NetState);
|
||||
|
||||
break;
|
||||
}
|
||||
case TournamentStage.Signup:
|
||||
{
|
||||
Ladder ladder = Ladder.Instance;
|
||||
LadderEntry entry = ladder?.Find(from);
|
||||
|
||||
if (entry != null && Ladder.GetLevel(entry.Experience) < tourney.LevelRequirement)
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "You have not yet proven yourself a worthy dueler.", from.NetState);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (tourney.IsFactionRestricted && Faction.Find(from) == null)
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "Only those who have declared their faction allegiance may participate.",
|
||||
from.NetState);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (from.HasGump<AcceptTeamGump>())
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You must first respond to the offer I've given you.", from.NetState);
|
||||
}
|
||||
else if (from.HasGump<AcceptDuelGump>())
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You must first cancel your duel offer.", from.NetState);
|
||||
}
|
||||
else if (from is PlayerMobile mobile && mobile.DuelContext != null)
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x22, false, "You are already participating in a duel.", mobile.NetState);
|
||||
}
|
||||
else if (!tourney.HasParticipant(from))
|
||||
{
|
||||
from.CloseGump<ConfirmSignupGump>();
|
||||
from.SendGump(new ConfirmSignupGump(from, Registrar, tourney, new List<Mobile> { from }));
|
||||
}
|
||||
else
|
||||
{
|
||||
Registrar?.PrivateOverheadMessage(MessageType.Regular,
|
||||
0x35, false, "You have already entered this tournament.", from.NetState);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
|
||||
writer.Write(Tournament);
|
||||
writer.Write(Registrar);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Tournament = reader.ReadItem() as TournamentController;
|
||||
Registrar = reader.ReadMobile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Projects/Scripts/Engines/ConPVP/TourneyParticipant.cs
Normal file
109
Projects/Scripts/Engines/ConPVP/TourneyParticipant.cs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Engines.ConPVP
|
||||
{
|
||||
public class TourneyParticipant : IComparable<TourneyParticipant>
|
||||
{
|
||||
public TourneyParticipant(Mobile owner)
|
||||
{
|
||||
Log = new List<string>();
|
||||
Players = new List<Mobile> { owner };
|
||||
}
|
||||
|
||||
public TourneyParticipant(List<Mobile> players)
|
||||
{
|
||||
Log = new List<string>();
|
||||
Players = players;
|
||||
}
|
||||
|
||||
public List<Mobile> Players{ get; set; }
|
||||
|
||||
public List<string> Log{ get; set; }
|
||||
|
||||
public int FreeAdvances{ get; set; }
|
||||
|
||||
public int TotalLadderXP
|
||||
{
|
||||
get
|
||||
{
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
if (ladder == null)
|
||||
return 0;
|
||||
|
||||
int total = 0;
|
||||
|
||||
for (int i = 0; i < Players.Count; ++i)
|
||||
{
|
||||
Mobile mob = Players[i];
|
||||
LadderEntry entry = ladder.Find(mob);
|
||||
|
||||
if (entry != null)
|
||||
total += entry.Experience;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
public string NameList
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < Players.Count; ++i)
|
||||
{
|
||||
if (Players[i] == null)
|
||||
continue;
|
||||
|
||||
Mobile mob = Players[i];
|
||||
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
if (Players.Count == 2)
|
||||
sb.Append(" and ");
|
||||
else if (i + 1 < Players.Count)
|
||||
sb.Append(", ");
|
||||
else
|
||||
sb.Append(", and ");
|
||||
}
|
||||
|
||||
sb.Append(mob.Name);
|
||||
}
|
||||
|
||||
if (sb.Length == 0)
|
||||
return "Empty";
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(TourneyParticipant p)
|
||||
{
|
||||
return p.TotalLadderXP - TotalLadderXP;
|
||||
}
|
||||
|
||||
public void AddLog(string text)
|
||||
{
|
||||
Log.Add(text);
|
||||
}
|
||||
|
||||
public void AddLog(string format, params object[] args)
|
||||
{
|
||||
AddLog(string.Format(format, args));
|
||||
}
|
||||
|
||||
public void WonMatch(TourneyMatch match)
|
||||
{
|
||||
AddLog("Match won.");
|
||||
}
|
||||
|
||||
public void LostMatch(TourneyMatch match)
|
||||
{
|
||||
AddLog("Match lost.");
|
||||
}
|
||||
}
|
||||
}
|
||||
119
Projects/Scripts/Engines/ConPVP/Trophy.cs
Normal file
119
Projects/Scripts/Engines/ConPVP/Trophy.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public enum TrophyRank
|
||||
{
|
||||
Bronze,
|
||||
Silver,
|
||||
Gold
|
||||
}
|
||||
|
||||
[Flippable(5020, 4647)]
|
||||
public class Trophy : Item
|
||||
{
|
||||
private TrophyRank m_Rank;
|
||||
|
||||
[Constructible]
|
||||
public Trophy(string title, TrophyRank rank) : base(5020)
|
||||
{
|
||||
Title = title;
|
||||
m_Rank = rank;
|
||||
Date = DateTime.UtcNow;
|
||||
|
||||
LootType = LootType.Blessed;
|
||||
|
||||
UpdateStyle();
|
||||
}
|
||||
|
||||
public Trophy(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public string Title{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TrophyRank Rank
|
||||
{
|
||||
get => m_Rank;
|
||||
set
|
||||
{
|
||||
m_Rank = value;
|
||||
UpdateStyle();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Owner{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime Date{ get; private set; }
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1); // version
|
||||
|
||||
writer.Write(Title);
|
||||
writer.Write((int)m_Rank);
|
||||
writer.Write(Owner);
|
||||
writer.Write(Date);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Title = reader.ReadString();
|
||||
m_Rank = (TrophyRank)reader.ReadInt();
|
||||
Owner = reader.ReadMobile();
|
||||
Date = reader.ReadDateTime();
|
||||
|
||||
if (version == 0)
|
||||
LootType = LootType.Blessed;
|
||||
}
|
||||
|
||||
public override void OnAdded(IEntity parent)
|
||||
{
|
||||
base.OnAdded(parent);
|
||||
|
||||
if (Owner == null)
|
||||
Owner = RootParent as Mobile;
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
base.OnSingleClick(from);
|
||||
|
||||
if (Owner != null)
|
||||
LabelTo(from, "{0} -- {1}", Title, Owner.RawName);
|
||||
else if (Title != null)
|
||||
LabelTo(from, Title);
|
||||
|
||||
if (Date != DateTime.MinValue)
|
||||
LabelTo(from, Date.ToString("d"));
|
||||
}
|
||||
|
||||
public void UpdateStyle()
|
||||
{
|
||||
Name = $"{m_Rank.ToString().ToLower()} trophy";
|
||||
|
||||
switch (m_Rank)
|
||||
{
|
||||
case TrophyRank.Gold:
|
||||
Hue = 2213;
|
||||
break;
|
||||
case TrophyRank.Silver:
|
||||
Hue = 0;
|
||||
break;
|
||||
case TrophyRank.Bronze:
|
||||
Hue = 2206;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Projects/Scripts/Engines/Craft/Core/CraftContext.cs
Normal file
55
Projects/Scripts/Engines/Craft/Core/CraftContext.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public enum CraftMarkOption
|
||||
{
|
||||
MarkItem,
|
||||
DoNotMark,
|
||||
PromptForMark
|
||||
}
|
||||
|
||||
public class CraftContext
|
||||
{
|
||||
public CraftContext()
|
||||
{
|
||||
Items = new List<CraftItem>();
|
||||
LastResourceIndex = -1;
|
||||
LastResourceIndex2 = -1;
|
||||
LastGroupIndex = -1;
|
||||
}
|
||||
|
||||
public List<CraftItem> Items{ get; }
|
||||
|
||||
public int LastResourceIndex{ get; set; }
|
||||
|
||||
public int LastResourceIndex2{ get; set; }
|
||||
|
||||
public int LastGroupIndex{ get; set; }
|
||||
|
||||
public bool DoNotColor{ get; set; }
|
||||
|
||||
public CraftMarkOption MarkOption{ get; set; }
|
||||
|
||||
public CraftItem LastMade
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Items.Count > 0)
|
||||
return Items[0];
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMade(CraftItem item)
|
||||
{
|
||||
Items.Remove(item);
|
||||
|
||||
if (Items.Count == 10)
|
||||
Items.RemoveAt(9);
|
||||
|
||||
Items.Insert(0, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Projects/Scripts/Engines/Craft/Core/CraftGroup.cs
Normal file
23
Projects/Scripts/Engines/Craft/Core/CraftGroup.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftGroup
|
||||
{
|
||||
public CraftGroup(TextDefinition groupName)
|
||||
{
|
||||
NameNumber = groupName;
|
||||
NameString = groupName;
|
||||
CraftItems = new CraftItemCol();
|
||||
}
|
||||
|
||||
public CraftItemCol CraftItems{ get; }
|
||||
|
||||
public string NameString{ get; }
|
||||
|
||||
public int NameNumber{ get; }
|
||||
|
||||
public void AddCraftItem(CraftItem craftItem)
|
||||
{
|
||||
CraftItems.Add(craftItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Projects/Scripts/Engines/Craft/Core/CraftGroupCol.cs
Normal file
45
Projects/Scripts/Engines/Craft/Core/CraftGroupCol.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftGroupCol : CollectionBase
|
||||
{
|
||||
public int Add(CraftGroup craftGroup)
|
||||
{
|
||||
return List.Add(craftGroup);
|
||||
}
|
||||
|
||||
public void Remove(int index)
|
||||
{
|
||||
if (index > Count - 1 || index < 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
List.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public CraftGroup GetAt(int index)
|
||||
{
|
||||
return (CraftGroup)List[index];
|
||||
}
|
||||
|
||||
public int SearchFor(TextDefinition groupName)
|
||||
{
|
||||
for (int i = 0; i < List.Count; i++)
|
||||
{
|
||||
CraftGroup craftGroup = (CraftGroup)List[i];
|
||||
|
||||
int nameNumber = craftGroup.NameNumber;
|
||||
string nameString = craftGroup.NameString;
|
||||
|
||||
if (nameNumber != 0 && nameNumber == groupName.Number ||
|
||||
nameString != null && nameString == groupName.String)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
608
Projects/Scripts/Engines/Craft/Core/CraftGump.cs
Normal file
608
Projects/Scripts/Engines/Craft/Core/CraftGump.cs
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftGump : Gump
|
||||
{
|
||||
private const int LabelHue = 0x480;
|
||||
private const int LabelColor = 0x7FFF;
|
||||
private const int FontColor = 0xFFFFFF;
|
||||
private CraftSystem m_CraftSystem;
|
||||
private Mobile m_From;
|
||||
|
||||
private CraftPage m_Page;
|
||||
private BaseTool m_Tool;
|
||||
|
||||
public CraftGump(Mobile from, CraftSystem craftSystem, BaseTool tool, object notice, CraftPage page = CraftPage.None) : base(40, 40)
|
||||
{
|
||||
m_From = from;
|
||||
m_CraftSystem = craftSystem;
|
||||
m_Tool = tool;
|
||||
m_Page = page;
|
||||
|
||||
CraftContext context = craftSystem.GetContext(from);
|
||||
|
||||
from.CloseGump<CraftGump>();
|
||||
from.CloseGump<CraftGumpItem>();
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 530, 437, 5054);
|
||||
AddImageTiled(10, 10, 510, 22, 2624);
|
||||
AddImageTiled(10, 292, 150, 45, 2624);
|
||||
AddImageTiled(165, 292, 355, 45, 2624);
|
||||
AddImageTiled(10, 342, 510, 85, 2624);
|
||||
AddImageTiled(10, 37, 200, 250, 2624);
|
||||
AddImageTiled(215, 37, 305, 250, 2624);
|
||||
AddAlphaRegion(10, 10, 510, 417);
|
||||
|
||||
if (craftSystem.GumpTitleNumber > 0)
|
||||
AddHtmlLocalized(10, 12, 510, 20, craftSystem.GumpTitleNumber, LabelColor);
|
||||
else
|
||||
AddHtml(10, 12, 510, 20, craftSystem.GumpTitleString);
|
||||
|
||||
AddHtmlLocalized(10, 37, 200, 22, 1044010, LabelColor); // <CENTER>CATEGORIES</CENTER>
|
||||
AddHtmlLocalized(215, 37, 305, 22, 1044011, LabelColor); // <CENTER>SELECTIONS</CENTER>
|
||||
AddHtmlLocalized(10, 302, 150, 25, 1044012, LabelColor); // <CENTER>NOTICES</CENTER>
|
||||
|
||||
AddButton(15, 402, 4017, 4019, 0);
|
||||
AddHtmlLocalized(50, 405, 150, 18, 1011441, LabelColor); // EXIT
|
||||
|
||||
AddButton(270, 402, 4005, 4007, GetButtonID(6, 2));
|
||||
AddHtmlLocalized(305, 405, 150, 18, 1044013, LabelColor); // MAKE LAST
|
||||
|
||||
// Mark option
|
||||
if (craftSystem.MarkOption)
|
||||
{
|
||||
AddButton(270, 362, 4005, 4007, GetButtonID(6, 6));
|
||||
AddHtmlLocalized(305, 365, 150, 18, 1044017 + (context == null ? 0 : (int)context.MarkOption), LabelColor); // MARK ITEM
|
||||
}
|
||||
// ****************************************
|
||||
|
||||
// Resmelt option
|
||||
if (craftSystem.Resmelt)
|
||||
{
|
||||
AddButton(15, 342, 4005, 4007, GetButtonID(6, 1));
|
||||
AddHtmlLocalized(50, 345, 150, 18, 1044259, LabelColor); // SMELT ITEM
|
||||
}
|
||||
// ****************************************
|
||||
|
||||
// Repair option
|
||||
if (craftSystem.Repair)
|
||||
{
|
||||
AddButton(270, 342, 4005, 4007, GetButtonID(6, 5));
|
||||
AddHtmlLocalized(305, 345, 150, 18, 1044260, LabelColor); // REPAIR ITEM
|
||||
}
|
||||
// ****************************************
|
||||
|
||||
// Enhance option
|
||||
if (craftSystem.CanEnhance)
|
||||
{
|
||||
AddButton(270, 382, 4005, 4007, GetButtonID(6, 8));
|
||||
AddHtmlLocalized(305, 385, 150, 18, 1061001, LabelColor); // ENHANCE ITEM
|
||||
}
|
||||
// ****************************************
|
||||
|
||||
if (notice is int noticeInt && noticeInt > 0)
|
||||
AddHtmlLocalized(170, 295, 350, 40, noticeInt, LabelColor);
|
||||
else if (notice is string)
|
||||
AddHtml(170, 295, 350, 40, $"<BASEFONT COLOR=#{FontColor:X6}>{notice}</BASEFONT>");
|
||||
|
||||
// If the system has more than one resource
|
||||
if (craftSystem.CraftSubRes.Init)
|
||||
{
|
||||
string nameString = craftSystem.CraftSubRes.NameString;
|
||||
int nameNumber = craftSystem.CraftSubRes.NameNumber;
|
||||
|
||||
int resIndex = context?.LastResourceIndex ?? -1;
|
||||
|
||||
Type resourceType = craftSystem.CraftSubRes.ResType;
|
||||
|
||||
if (resIndex > -1)
|
||||
{
|
||||
CraftSubRes subResource = craftSystem.CraftSubRes.GetAt(resIndex);
|
||||
|
||||
nameString = subResource.NameString;
|
||||
nameNumber = subResource.NameNumber;
|
||||
resourceType = subResource.ItemType;
|
||||
}
|
||||
|
||||
int resourceCount = 0;
|
||||
|
||||
if (from.Backpack != null)
|
||||
{
|
||||
Item[] items = from.Backpack.FindItemsByType(resourceType);
|
||||
|
||||
for (int i = 0; i < items.Length; ++i)
|
||||
resourceCount += items[i].Amount;
|
||||
}
|
||||
|
||||
AddButton(15, 362, 4005, 4007, GetButtonID(6, 0));
|
||||
|
||||
if (nameNumber > 0)
|
||||
AddHtmlLocalized(50, 365, 250, 18, nameNumber, resourceCount.ToString(), LabelColor);
|
||||
else
|
||||
AddLabel(50, 362, LabelHue, $"{nameString} ({resourceCount} Available)");
|
||||
}
|
||||
// ****************************************
|
||||
|
||||
// For dragon scales
|
||||
if (craftSystem.CraftSubRes2.Init)
|
||||
{
|
||||
string nameString = craftSystem.CraftSubRes2.NameString;
|
||||
int nameNumber = craftSystem.CraftSubRes2.NameNumber;
|
||||
|
||||
int resIndex = context?.LastResourceIndex2 ?? -1;
|
||||
|
||||
Type resourceType = craftSystem.CraftSubRes2.ResType;
|
||||
|
||||
if (resIndex > -1)
|
||||
{
|
||||
CraftSubRes subResource = craftSystem.CraftSubRes2.GetAt(resIndex);
|
||||
|
||||
nameString = subResource.NameString;
|
||||
nameNumber = subResource.NameNumber;
|
||||
resourceType = subResource.ItemType;
|
||||
}
|
||||
|
||||
int resourceCount = 0;
|
||||
|
||||
if (from.Backpack != null)
|
||||
{
|
||||
Item[] items = from.Backpack.FindItemsByType(resourceType);
|
||||
|
||||
for (int i = 0; i < items.Length; ++i)
|
||||
resourceCount += items[i].Amount;
|
||||
}
|
||||
|
||||
AddButton(15, 382, 4005, 4007, GetButtonID(6, 7));
|
||||
|
||||
if (nameNumber > 0)
|
||||
AddHtmlLocalized(50, 385, 250, 18, nameNumber, resourceCount.ToString(), LabelColor);
|
||||
else
|
||||
AddLabel(50, 385, LabelHue, $"{nameString} ({resourceCount} Available)");
|
||||
}
|
||||
// ****************************************
|
||||
|
||||
CreateGroupList();
|
||||
|
||||
if (page == CraftPage.PickResource)
|
||||
CreateResList(false, from);
|
||||
else if (page == CraftPage.PickResource2)
|
||||
CreateResList(true, from);
|
||||
else if (context?.LastGroupIndex > -1)
|
||||
CreateItemList(context.LastGroupIndex);
|
||||
}
|
||||
|
||||
public void CreateResList(bool opt, Mobile from)
|
||||
{
|
||||
CraftSubResCol res = opt ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes;
|
||||
|
||||
for (int i = 0; i < res.Count; ++i)
|
||||
{
|
||||
int index = i % 10;
|
||||
|
||||
CraftSubRes subResource = res.GetAt(i);
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
if (i > 0)
|
||||
AddButton(485, 260, 4005, 4007, 0, GumpButtonType.Page, i / 10 + 1);
|
||||
|
||||
AddPage(i / 10 + 1);
|
||||
|
||||
if (i > 0)
|
||||
AddButton(455, 260, 4014, 4015, 0, GumpButtonType.Page, i / 10);
|
||||
|
||||
CraftContext context = m_CraftSystem.GetContext(m_From);
|
||||
|
||||
AddButton(220, 260, 4005, 4007, GetButtonID(6, 4));
|
||||
AddHtmlLocalized(255, 263, 200, 18, context == null || !context.DoNotColor ? 1061591 : 1061590,
|
||||
LabelColor);
|
||||
}
|
||||
|
||||
int resourceCount = 0;
|
||||
|
||||
if (from.Backpack != null)
|
||||
{
|
||||
Item[] items = from.Backpack.FindItemsByType(subResource.ItemType);
|
||||
|
||||
for (int j = 0; j < items.Length; ++j)
|
||||
resourceCount += items[j].Amount;
|
||||
}
|
||||
|
||||
AddButton(220, 60 + index * 20, 4005, 4007, GetButtonID(5, i));
|
||||
|
||||
if (subResource.NameNumber > 0)
|
||||
AddHtmlLocalized(255, 63 + index * 20, 250, 18, subResource.NameNumber, resourceCount.ToString(),
|
||||
LabelColor);
|
||||
else
|
||||
AddLabel(255, 60 + index * 20, LabelHue, $"{subResource.NameString} ({resourceCount})");
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateMakeLastList()
|
||||
{
|
||||
CraftContext context = m_CraftSystem.GetContext(m_From);
|
||||
|
||||
if (context == null)
|
||||
return;
|
||||
|
||||
List<CraftItem> items = context.Items;
|
||||
|
||||
if (items.Count > 0)
|
||||
for (int i = 0; i < items.Count; ++i)
|
||||
{
|
||||
int index = i % 10;
|
||||
|
||||
CraftItem craftItem = items[i];
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
AddButton(370, 260, 4005, 4007, 0, GumpButtonType.Page, i / 10 + 1);
|
||||
AddHtmlLocalized(405, 263, 100, 18, 1044045, LabelColor); // NEXT PAGE
|
||||
}
|
||||
|
||||
AddPage(i / 10 + 1);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
AddButton(220, 260, 4014, 4015, 0, GumpButtonType.Page, i / 10);
|
||||
AddHtmlLocalized(255, 263, 100, 18, 1044044, LabelColor); // PREV PAGE
|
||||
}
|
||||
}
|
||||
|
||||
AddButton(220, 60 + index * 20, 4005, 4007, GetButtonID(3, i));
|
||||
|
||||
if (craftItem.NameNumber > 0)
|
||||
AddHtmlLocalized(255, 63 + index * 20, 220, 18, craftItem.NameNumber, LabelColor);
|
||||
else
|
||||
AddLabel(255, 60 + index * 20, LabelHue, craftItem.NameString);
|
||||
|
||||
AddButton(480, 60 + index * 20, 4011, 4012, GetButtonID(4, i));
|
||||
}
|
||||
else
|
||||
AddHtmlLocalized(230, 62, 200, 22, 1044165, LabelColor); // You haven't made anything yet.
|
||||
}
|
||||
|
||||
public void CreateItemList(int selectedGroup)
|
||||
{
|
||||
if (selectedGroup == 501) // 501 : Last 10
|
||||
{
|
||||
CreateMakeLastList();
|
||||
return;
|
||||
}
|
||||
|
||||
CraftGroupCol craftGroupCol = m_CraftSystem.CraftGroups;
|
||||
CraftGroup craftGroup = craftGroupCol.GetAt(selectedGroup);
|
||||
CraftItemCol craftItemCol = craftGroup.CraftItems;
|
||||
|
||||
for (int i = 0; i < craftItemCol.Count; ++i)
|
||||
{
|
||||
int index = i % 10;
|
||||
|
||||
CraftItem craftItem = craftItemCol.GetAt(i);
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
AddButton(370, 260, 4005, 4007, 0, GumpButtonType.Page, i / 10 + 1);
|
||||
AddHtmlLocalized(405, 263, 100, 18, 1044045, LabelColor); // NEXT PAGE
|
||||
}
|
||||
|
||||
AddPage(i / 10 + 1);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
AddButton(220, 260, 4014, 4015, 0, GumpButtonType.Page, i / 10);
|
||||
AddHtmlLocalized(255, 263, 100, 18, 1044044, LabelColor); // PREV PAGE
|
||||
}
|
||||
}
|
||||
|
||||
AddButton(220, 60 + index * 20, 4005, 4007, GetButtonID(1, i));
|
||||
|
||||
if (craftItem.NameNumber > 0)
|
||||
AddHtmlLocalized(255, 63 + index * 20, 220, 18, craftItem.NameNumber, LabelColor);
|
||||
else
|
||||
AddLabel(255, 60 + index * 20, LabelHue, craftItem.NameString);
|
||||
|
||||
AddButton(480, 60 + index * 20, 4011, 4012, GetButtonID(2, i));
|
||||
}
|
||||
}
|
||||
|
||||
public int CreateGroupList()
|
||||
{
|
||||
CraftGroupCol craftGroupCol = m_CraftSystem.CraftGroups;
|
||||
|
||||
AddButton(15, 60, 4005, 4007, GetButtonID(6, 3));
|
||||
AddHtmlLocalized(50, 63, 150, 18, 1044014, LabelColor); // LAST TEN
|
||||
|
||||
for (int i = 0; i < craftGroupCol.Count; i++)
|
||||
{
|
||||
CraftGroup craftGroup = craftGroupCol.GetAt(i);
|
||||
|
||||
AddButton(15, 80 + i * 20, 4005, 4007, GetButtonID(0, i));
|
||||
|
||||
if (craftGroup.NameNumber > 0)
|
||||
AddHtmlLocalized(50, 83 + i * 20, 150, 18, craftGroup.NameNumber, LabelColor);
|
||||
else
|
||||
AddLabel(50, 80 + i * 20, LabelHue, craftGroup.NameString);
|
||||
}
|
||||
|
||||
return craftGroupCol.Count;
|
||||
}
|
||||
|
||||
public static int GetButtonID(int type, int index)
|
||||
{
|
||||
return 1 + type + index * 7;
|
||||
}
|
||||
|
||||
public void CraftItem(CraftItem item)
|
||||
{
|
||||
int num = m_CraftSystem.CanCraft(m_From, m_Tool, item.ItemType);
|
||||
|
||||
if (num > 0)
|
||||
{
|
||||
m_From.SendGump(new CraftGump(m_From, m_CraftSystem, m_Tool, num));
|
||||
}
|
||||
else
|
||||
{
|
||||
Type type = null;
|
||||
|
||||
CraftContext context = m_CraftSystem.GetContext(m_From);
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
CraftSubResCol res = item.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes;
|
||||
int resIndex = item.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex;
|
||||
|
||||
if (resIndex >= 0 && resIndex < res.Count)
|
||||
type = res.GetAt(resIndex).ItemType;
|
||||
}
|
||||
|
||||
m_CraftSystem.CreateItem(m_From, item.ItemType, type, m_Tool, item);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID <= 0)
|
||||
return; // Canceled
|
||||
|
||||
int buttonID = info.ButtonID - 1;
|
||||
int type = buttonID % 7;
|
||||
int index = buttonID / 7;
|
||||
|
||||
CraftSystem system = m_CraftSystem;
|
||||
CraftGroupCol groups = system.CraftGroups;
|
||||
CraftContext context = system.GetContext(m_From);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0: // Show group
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
if (index >= 0 && index < groups.Count)
|
||||
{
|
||||
context.LastGroupIndex = index;
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, null));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // Create item
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
int groupIndex = context.LastGroupIndex;
|
||||
|
||||
if (groupIndex >= 0 && groupIndex < groups.Count)
|
||||
{
|
||||
CraftGroup group = groups.GetAt(groupIndex);
|
||||
|
||||
if (index >= 0 && index < group.CraftItems.Count)
|
||||
CraftItem(group.CraftItems.GetAt(index));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // Item details
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
int groupIndex = context.LastGroupIndex;
|
||||
|
||||
if (groupIndex >= 0 && groupIndex < groups.Count)
|
||||
{
|
||||
CraftGroup group = groups.GetAt(groupIndex);
|
||||
|
||||
if (index >= 0 && index < group.CraftItems.Count)
|
||||
m_From.SendGump(new CraftGumpItem(m_From, system, group.CraftItems.GetAt(index), m_Tool));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Create item (last 10)
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
List<CraftItem> lastTen = context.Items;
|
||||
|
||||
if (index >= 0 && index < lastTen.Count)
|
||||
CraftItem(lastTen[index]);
|
||||
|
||||
break;
|
||||
}
|
||||
case 4: // Item details (last 10)
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
List<CraftItem> lastTen = context.Items;
|
||||
|
||||
if (index >= 0 && index < lastTen.Count)
|
||||
m_From.SendGump(new CraftGumpItem(m_From, system, lastTen[index], m_Tool));
|
||||
|
||||
break;
|
||||
}
|
||||
case 5: // Resource selected
|
||||
{
|
||||
if (m_Page == CraftPage.PickResource && index >= 0 && index < system.CraftSubRes.Count)
|
||||
{
|
||||
CraftSubRes res = system.CraftSubRes.GetAt(index);
|
||||
|
||||
if (m_From.Skills[system.MainSkill].Base < res.RequiredSkill)
|
||||
{
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, res.Message));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context != null)
|
||||
context.LastResourceIndex = index;
|
||||
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, null));
|
||||
}
|
||||
}
|
||||
else if (m_Page == CraftPage.PickResource2 && index >= 0 && index < system.CraftSubRes2.Count)
|
||||
{
|
||||
CraftSubRes res = system.CraftSubRes2.GetAt(index);
|
||||
|
||||
if (m_From.Skills[system.MainSkill].Base < res.RequiredSkill)
|
||||
{
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, res.Message));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context != null)
|
||||
context.LastResourceIndex2 = index;
|
||||
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, null));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 6: // Misc. buttons
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: // Resource selection
|
||||
{
|
||||
if (system.CraftSubRes.Init)
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, null, CraftPage.PickResource));
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // Smelt item
|
||||
{
|
||||
if (system.Resmelt)
|
||||
Resmelt.Do(m_From, system, m_Tool);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // Make last
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
CraftItem item = context.LastMade;
|
||||
|
||||
if (item != null)
|
||||
CraftItem(item);
|
||||
else
|
||||
m_From.SendGump(new CraftGump(m_From, m_CraftSystem, m_Tool, 1044165,
|
||||
m_Page)); // You haven't made anything yet.
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Last 10
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
context.LastGroupIndex = 501;
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, null));
|
||||
|
||||
break;
|
||||
}
|
||||
case 4: // Toggle use resource hue
|
||||
{
|
||||
if (context == null)
|
||||
break;
|
||||
|
||||
context.DoNotColor = !context.DoNotColor;
|
||||
|
||||
m_From.SendGump(new CraftGump(m_From, m_CraftSystem, m_Tool, null, m_Page));
|
||||
|
||||
break;
|
||||
}
|
||||
case 5: // Repair item
|
||||
{
|
||||
if (system.Repair)
|
||||
Repair.Do(m_From, system, m_Tool);
|
||||
|
||||
break;
|
||||
}
|
||||
case 6: // Toggle mark option
|
||||
{
|
||||
if (context == null || !system.MarkOption)
|
||||
break;
|
||||
|
||||
switch (context.MarkOption)
|
||||
{
|
||||
case CraftMarkOption.MarkItem:
|
||||
context.MarkOption = CraftMarkOption.DoNotMark;
|
||||
break;
|
||||
case CraftMarkOption.DoNotMark:
|
||||
context.MarkOption = CraftMarkOption.PromptForMark;
|
||||
break;
|
||||
case CraftMarkOption.PromptForMark:
|
||||
context.MarkOption = CraftMarkOption.MarkItem;
|
||||
break;
|
||||
}
|
||||
|
||||
m_From.SendGump(new CraftGump(m_From, m_CraftSystem, m_Tool, null, m_Page));
|
||||
|
||||
break;
|
||||
}
|
||||
case 7: // Resource selection 2
|
||||
{
|
||||
if (system.CraftSubRes2.Init)
|
||||
m_From.SendGump(new CraftGump(m_From, system, m_Tool, null, CraftPage.PickResource2));
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: // Enhance item
|
||||
{
|
||||
if (system.CanEnhance)
|
||||
Enhance.BeginTarget(m_From, system, m_Tool);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum CraftPage
|
||||
{
|
||||
None,
|
||||
PickResource,
|
||||
PickResource2
|
||||
}
|
||||
}
|
||||
}
|
||||
289
Projects/Scripts/Engines/Craft/Core/CraftGumpItem.cs
Normal file
289
Projects/Scripts/Engines/Craft/Core/CraftGumpItem.cs
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
using System;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftGumpItem : Gump
|
||||
{
|
||||
private const int LabelHue = 0x480; // 0x384
|
||||
private const int RedLabelHue = 0x20;
|
||||
|
||||
private const int LabelColor = 0x7FFF;
|
||||
private const int RedLabelColor = 0x6400;
|
||||
|
||||
private const int GreyLabelColor = 0x3DEF;
|
||||
|
||||
private static Type typeofBlankScroll = typeof(BlankScroll);
|
||||
private static Type typeofSpellScroll = typeof(SpellScroll);
|
||||
private CraftItem m_CraftItem;
|
||||
private CraftSystem m_CraftSystem;
|
||||
private Mobile m_From;
|
||||
|
||||
private int m_OtherCount;
|
||||
|
||||
private bool m_ShowExceptionalChance;
|
||||
private BaseTool m_Tool;
|
||||
|
||||
public CraftGumpItem(Mobile from, CraftSystem craftSystem, CraftItem craftItem, BaseTool tool) : base(40, 40)
|
||||
{
|
||||
m_From = from;
|
||||
m_CraftSystem = craftSystem;
|
||||
m_CraftItem = craftItem;
|
||||
m_Tool = tool;
|
||||
|
||||
from.CloseGump<CraftGump>();
|
||||
from.CloseGump<CraftGumpItem>();
|
||||
|
||||
AddPage(0);
|
||||
AddBackground(0, 0, 530, 417, 5054);
|
||||
AddImageTiled(10, 10, 510, 22, 2624);
|
||||
AddImageTiled(10, 37, 150, 148, 2624);
|
||||
AddImageTiled(165, 37, 355, 90, 2624);
|
||||
AddImageTiled(10, 190, 155, 22, 2624);
|
||||
AddImageTiled(10, 217, 150, 53, 2624);
|
||||
AddImageTiled(165, 132, 355, 80, 2624);
|
||||
AddImageTiled(10, 275, 155, 22, 2624);
|
||||
AddImageTiled(10, 302, 150, 53, 2624);
|
||||
AddImageTiled(165, 217, 355, 80, 2624);
|
||||
AddImageTiled(10, 360, 155, 22, 2624);
|
||||
AddImageTiled(165, 302, 355, 80, 2624);
|
||||
AddImageTiled(10, 387, 510, 22, 2624);
|
||||
AddAlphaRegion(10, 10, 510, 399);
|
||||
|
||||
AddHtmlLocalized(170, 40, 150, 20, 1044053, LabelColor); // ITEM
|
||||
AddHtmlLocalized(10, 192, 150, 22, 1044054, LabelColor); // <CENTER>SKILLS</CENTER>
|
||||
AddHtmlLocalized(10, 277, 150, 22, 1044055, LabelColor); // <CENTER>MATERIALS</CENTER>
|
||||
AddHtmlLocalized(10, 362, 150, 22, 1044056, LabelColor); // <CENTER>OTHER</CENTER>
|
||||
|
||||
if (craftSystem.GumpTitleNumber > 0)
|
||||
AddHtmlLocalized(10, 12, 510, 20, craftSystem.GumpTitleNumber, LabelColor);
|
||||
else
|
||||
AddHtml(10, 12, 510, 20, craftSystem.GumpTitleString);
|
||||
|
||||
AddButton(15, 387, 4014, 4016, 0);
|
||||
AddHtmlLocalized(50, 390, 150, 18, 1044150, LabelColor); // BACK
|
||||
|
||||
bool needsRecipe = craftItem.Recipe != null && from is PlayerMobile mobile &&
|
||||
!mobile.HasRecipe(craftItem.Recipe);
|
||||
|
||||
if (needsRecipe)
|
||||
{
|
||||
AddButton(270, 387, 4005, 4007, 0, GumpButtonType.Page);
|
||||
AddHtmlLocalized(305, 390, 150, 18, 1044151, GreyLabelColor); // MAKE NOW
|
||||
}
|
||||
else
|
||||
{
|
||||
AddButton(270, 387, 4005, 4007, 1);
|
||||
AddHtmlLocalized(305, 390, 150, 18, 1044151, LabelColor); // MAKE NOW
|
||||
}
|
||||
|
||||
if (craftItem.NameNumber > 0)
|
||||
AddHtmlLocalized(330, 40, 180, 18, craftItem.NameNumber, LabelColor);
|
||||
else
|
||||
AddLabel(330, 40, LabelHue, craftItem.NameString);
|
||||
|
||||
if (craftItem.UseAllRes)
|
||||
AddHtmlLocalized(170, 302 + m_OtherCount++ * 20, 310, 18, 1048176, LabelColor); // Makes as many as possible at once
|
||||
|
||||
DrawItem();
|
||||
DrawSkill();
|
||||
DrawResource();
|
||||
|
||||
/*
|
||||
if ( craftItem.RequiresSE )
|
||||
AddHtmlLocalized( 170, 302 + (m_OtherCount++ * 20), 310, 18, 1063363, LabelColor, false, false ); //* Requires the "Samurai Empire" expansion
|
||||
* */
|
||||
|
||||
if (craftItem.RequiredExpansion != Expansion.None)
|
||||
{
|
||||
bool supportsEx = from.NetState?.SupportsExpansion(craftItem.RequiredExpansion) == true;
|
||||
TextDefinition.AddHtmlText(this, 170, 302 + m_OtherCount++ * 20, 310, 18,
|
||||
RequiredExpansionMessage(craftItem.RequiredExpansion), false, false,
|
||||
supportsEx ? LabelColor : RedLabelColor, supportsEx ? LabelHue : RedLabelHue);
|
||||
}
|
||||
|
||||
if (needsRecipe)
|
||||
AddHtmlLocalized(170, 302 + m_OtherCount++ * 20, 310, 18, 1073620, RedLabelColor); // You have not learned this recipe.
|
||||
}
|
||||
|
||||
private TextDefinition RequiredExpansionMessage(Expansion expansion)
|
||||
{
|
||||
switch (expansion)
|
||||
{
|
||||
case Expansion.SE:
|
||||
return 1063363; // * Requires the "Samurai Empire" expansion
|
||||
case Expansion.ML:
|
||||
return 1072651; // * Requires the "Mondain's Legacy" expansion
|
||||
default:
|
||||
return $"* Requires the \"{ExpansionInfo.GetInfo(expansion).Name}\" expansion";
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawItem()
|
||||
{
|
||||
Type type = m_CraftItem.ItemType;
|
||||
|
||||
AddItem(20, 50, CraftItem.ItemIDOf(type), m_CraftItem.ItemHue);
|
||||
|
||||
if (m_CraftItem.IsMarkable(type))
|
||||
{
|
||||
AddHtmlLocalized(170, 302 + m_OtherCount++ * 20, 310, 18, 1044059, LabelColor); // This item may hold its maker's mark
|
||||
m_ShowExceptionalChance = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSkill()
|
||||
{
|
||||
for (int i = 0; i < m_CraftItem.Skills.Count; i++)
|
||||
{
|
||||
CraftSkill skill = m_CraftItem.Skills.GetAt(i);
|
||||
double minSkill = skill.MinSkill;
|
||||
|
||||
if (minSkill < 0)
|
||||
minSkill = 0;
|
||||
|
||||
AddHtmlLocalized(170, 132 + i * 20, 200, 18, AosSkillBonuses.GetLabel(skill.SkillToMake), LabelColor);
|
||||
AddLabel(430, 132 + i * 20, LabelHue, $"{minSkill:F1}");
|
||||
}
|
||||
|
||||
CraftSubResCol res = m_CraftItem.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes;
|
||||
int resIndex = -1;
|
||||
|
||||
CraftContext context = m_CraftSystem.GetContext(m_From);
|
||||
|
||||
if (context != null)
|
||||
resIndex = m_CraftItem.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex;
|
||||
|
||||
bool allRequiredSkills = true;
|
||||
double chance = m_CraftItem.GetSuccessChance(m_From, resIndex > -1 ? res.GetAt(resIndex).ItemType : null,
|
||||
m_CraftSystem, false, ref allRequiredSkills);
|
||||
double excepChance = m_CraftItem.GetExceptionalChance(m_CraftSystem, chance, m_From);
|
||||
|
||||
if (chance < 0.0)
|
||||
chance = 0.0;
|
||||
else if (chance > 1.0)
|
||||
chance = 1.0;
|
||||
|
||||
AddHtmlLocalized(170, 80, 250, 18, 1044057, LabelColor); // Success Chance:
|
||||
AddLabel(430, 80, LabelHue, $"{chance * 100:F1}%");
|
||||
|
||||
if (m_ShowExceptionalChance)
|
||||
{
|
||||
if (excepChance < 0.0)
|
||||
excepChance = 0.0;
|
||||
else if (excepChance > 1.0)
|
||||
excepChance = 1.0;
|
||||
|
||||
AddHtmlLocalized(170, 100, 250, 18, 1044058, 32767); // Exceptional Chance:
|
||||
AddLabel(430, 100, LabelHue, $"{excepChance * 100:F1}%");
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawResource()
|
||||
{
|
||||
bool retainedColor = false;
|
||||
|
||||
CraftContext context = m_CraftSystem.GetContext(m_From);
|
||||
|
||||
CraftSubResCol res = m_CraftItem.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes;
|
||||
int resIndex = -1;
|
||||
|
||||
if (context != null)
|
||||
resIndex = m_CraftItem.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex;
|
||||
|
||||
bool cropScroll = m_CraftItem.Resources.Count > 1
|
||||
&& m_CraftItem.Resources.GetAt(m_CraftItem.Resources.Count - 1).ItemType == typeofBlankScroll
|
||||
&& typeofSpellScroll.IsAssignableFrom(m_CraftItem.ItemType);
|
||||
|
||||
for (int i = 0; i < m_CraftItem.Resources.Count - (cropScroll ? 1 : 0) && i < 4; i++)
|
||||
{
|
||||
Type type;
|
||||
string nameString;
|
||||
int nameNumber;
|
||||
|
||||
CraftRes craftResource = m_CraftItem.Resources.GetAt(i);
|
||||
|
||||
type = craftResource.ItemType;
|
||||
nameString = craftResource.NameString;
|
||||
nameNumber = craftResource.NameNumber;
|
||||
|
||||
// Resource Mutation
|
||||
if (type == res.ResType && resIndex > -1)
|
||||
{
|
||||
CraftSubRes subResource = res.GetAt(resIndex);
|
||||
|
||||
type = subResource.ItemType;
|
||||
|
||||
nameString = subResource.NameString;
|
||||
nameNumber = subResource.GenericNameNumber;
|
||||
|
||||
if (nameNumber <= 0)
|
||||
nameNumber = subResource.NameNumber;
|
||||
}
|
||||
// ******************
|
||||
|
||||
if (!retainedColor && m_CraftItem.RetainsColorFrom(m_CraftSystem, type))
|
||||
{
|
||||
retainedColor = true;
|
||||
AddHtmlLocalized(170, 302 + m_OtherCount++ * 20, 310, 18, 1044152, LabelColor); // * The item retains the color of this material
|
||||
AddLabel(500, 219 + i * 20, LabelHue, "*");
|
||||
}
|
||||
|
||||
if (nameNumber > 0)
|
||||
AddHtmlLocalized(170, 219 + i * 20, 310, 18, nameNumber, LabelColor);
|
||||
else
|
||||
AddLabel(170, 219 + i * 20, LabelHue, nameString);
|
||||
|
||||
AddLabel(430, 219 + i * 20, LabelHue, craftResource.Amount.ToString());
|
||||
}
|
||||
|
||||
if (m_CraftItem.NameNumber == 1041267) // runebook
|
||||
{
|
||||
AddHtmlLocalized(170, 219 + m_CraftItem.Resources.Count * 20, 310, 18, 1044447, LabelColor);
|
||||
AddLabel(430, 219 + m_CraftItem.Resources.Count * 20, LabelHue, "1");
|
||||
}
|
||||
|
||||
if (cropScroll)
|
||||
AddHtmlLocalized(170, 302 + m_OtherCount++ * 20, 360, 18, 1044379, LabelColor); // Inscribing scrolls also requires a blank scroll and mana.
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
// Back Button
|
||||
if (info.ButtonID == 0)
|
||||
{
|
||||
CraftGump craftGump = new CraftGump(m_From, m_CraftSystem, m_Tool, null);
|
||||
m_From.SendGump(craftGump);
|
||||
}
|
||||
else // Make Button
|
||||
{
|
||||
int num = m_CraftSystem.CanCraft(m_From, m_Tool, m_CraftItem.ItemType);
|
||||
|
||||
if (num > 0)
|
||||
{
|
||||
m_From.SendGump(new CraftGump(m_From, m_CraftSystem, m_Tool, num));
|
||||
}
|
||||
else
|
||||
{
|
||||
Type type = null;
|
||||
|
||||
CraftContext context = m_CraftSystem.GetContext(m_From);
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
CraftSubResCol res = m_CraftItem.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes;
|
||||
int resIndex = m_CraftItem.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex;
|
||||
|
||||
if (resIndex > -1)
|
||||
type = res.GetAt(resIndex).ItemType;
|
||||
}
|
||||
|
||||
m_CraftSystem.CreateItem(m_From, m_CraftItem.ItemType, type, m_Tool, m_CraftItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1248
Projects/Scripts/Engines/Craft/Core/CraftItem.cs
Normal file
1248
Projects/Scripts/Engines/Craft/Core/CraftItem.cs
Normal file
File diff suppressed because it is too large
Load diff
53
Projects/Scripts/Engines/Craft/Core/CraftItemCol.cs
Normal file
53
Projects/Scripts/Engines/Craft/Core/CraftItemCol.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftItemCol : CollectionBase
|
||||
{
|
||||
public int Add(CraftItem craftItem)
|
||||
{
|
||||
return List.Add(craftItem);
|
||||
}
|
||||
|
||||
public void Remove(int index)
|
||||
{
|
||||
if (index > Count - 1 || index < 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
List.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public CraftItem GetAt(int index)
|
||||
{
|
||||
return (CraftItem)List[index];
|
||||
}
|
||||
|
||||
public CraftItem SearchForSubclass(Type type)
|
||||
{
|
||||
for (int i = 0; i < List.Count; i++)
|
||||
{
|
||||
CraftItem craftItem = (CraftItem)List[i];
|
||||
|
||||
if (craftItem.ItemType == type || type.IsSubclassOf(craftItem.ItemType))
|
||||
return craftItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public CraftItem SearchFor(Type type)
|
||||
{
|
||||
for (int i = 0; i < List.Count; i++)
|
||||
{
|
||||
CraftItem craftItem = (CraftItem)List[i];
|
||||
if (craftItem.ItemType == type) return craftItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Projects/Scripts/Engines/Craft/Core/CraftItemIDAttribute.cs
Normal file
15
Projects/Scripts/Engines/Craft/Core/CraftItemIDAttribute.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class CraftItemIDAttribute : Attribute
|
||||
{
|
||||
public CraftItemIDAttribute(int itemID)
|
||||
{
|
||||
ItemID = itemID;
|
||||
}
|
||||
|
||||
public int ItemID{ get; }
|
||||
}
|
||||
}
|
||||
41
Projects/Scripts/Engines/Craft/Core/CraftRes.cs
Normal file
41
Projects/Scripts/Engines/Craft/Core/CraftRes.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftRes
|
||||
{
|
||||
public CraftRes(Type type, TextDefinition name, int amount, TextDefinition message = null)
|
||||
{
|
||||
ItemType = type;
|
||||
Amount = amount;
|
||||
|
||||
NameNumber = name;
|
||||
MessageNumber = message;
|
||||
|
||||
NameString = name;
|
||||
MessageString = message;
|
||||
}
|
||||
|
||||
public Type ItemType{ get; }
|
||||
|
||||
public string MessageString{ get; }
|
||||
|
||||
public int MessageNumber{ get; }
|
||||
|
||||
public string NameString{ get; }
|
||||
|
||||
public int NameNumber{ get; }
|
||||
|
||||
public int Amount{ get; }
|
||||
|
||||
public void SendMessage(Mobile from)
|
||||
{
|
||||
if (MessageNumber > 0)
|
||||
from.SendLocalizedMessage(MessageNumber);
|
||||
else if (!string.IsNullOrEmpty(MessageString))
|
||||
from.SendMessage(MessageString);
|
||||
else
|
||||
from.SendLocalizedMessage(502925); // You don't have the resources required to make that item.
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Projects/Scripts/Engines/Craft/Core/CraftResCol.cs
Normal file
28
Projects/Scripts/Engines/Craft/Core/CraftResCol.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftResCol : CollectionBase
|
||||
{
|
||||
public void Add(CraftRes craftRes)
|
||||
{
|
||||
List.Add(craftRes);
|
||||
}
|
||||
|
||||
public void Remove(int index)
|
||||
{
|
||||
if (index > Count - 1 || index < 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
List.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public CraftRes GetAt(int index)
|
||||
{
|
||||
return (CraftRes)List[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Projects/Scripts/Engines/Craft/Core/CraftSkill.cs
Normal file
18
Projects/Scripts/Engines/Craft/Core/CraftSkill.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftSkill
|
||||
{
|
||||
public CraftSkill(SkillName skillToMake, double minSkill, double maxSkill)
|
||||
{
|
||||
SkillToMake = skillToMake;
|
||||
MinSkill = minSkill;
|
||||
MaxSkill = maxSkill;
|
||||
}
|
||||
|
||||
public SkillName SkillToMake{ get; }
|
||||
|
||||
public double MinSkill{ get; }
|
||||
|
||||
public double MaxSkill{ get; }
|
||||
}
|
||||
}
|
||||
28
Projects/Scripts/Engines/Craft/Core/CraftSkillCol.cs
Normal file
28
Projects/Scripts/Engines/Craft/Core/CraftSkillCol.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftSkillCol : CollectionBase
|
||||
{
|
||||
public void Add(CraftSkill craftSkill)
|
||||
{
|
||||
List.Add(craftSkill);
|
||||
}
|
||||
|
||||
public void Remove(int index)
|
||||
{
|
||||
if (index > Count - 1 || index < 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
List.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public CraftSkill GetAt(int index)
|
||||
{
|
||||
return (CraftSkill)List[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Projects/Scripts/Engines/Craft/Core/CraftSubRes.cs
Normal file
34
Projects/Scripts/Engines/Craft/Core/CraftSubRes.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftSubRes
|
||||
{
|
||||
public CraftSubRes(Type type, TextDefinition name, double reqSkill, object message) : this(type, name, reqSkill, 0,
|
||||
message)
|
||||
{
|
||||
}
|
||||
|
||||
public CraftSubRes(Type type, TextDefinition name, double reqSkill, int genericNameNumber, object message)
|
||||
{
|
||||
ItemType = type;
|
||||
NameNumber = name;
|
||||
NameString = name;
|
||||
RequiredSkill = reqSkill;
|
||||
GenericNameNumber = genericNameNumber;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public Type ItemType{ get; }
|
||||
|
||||
public string NameString{ get; }
|
||||
|
||||
public int NameNumber{ get; }
|
||||
|
||||
public int GenericNameNumber{ get; }
|
||||
|
||||
public object Message{ get; }
|
||||
|
||||
public double RequiredSkill{ get; }
|
||||
}
|
||||
}
|
||||
53
Projects/Scripts/Engines/Craft/Core/CraftSubResCol.cs
Normal file
53
Projects/Scripts/Engines/Craft/Core/CraftSubResCol.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class CraftSubResCol : CollectionBase
|
||||
{
|
||||
public CraftSubResCol()
|
||||
{
|
||||
Init = false;
|
||||
}
|
||||
|
||||
public bool Init{ get; set; }
|
||||
|
||||
public Type ResType{ get; set; }
|
||||
|
||||
public string NameString{ get; set; }
|
||||
|
||||
public int NameNumber{ get; set; }
|
||||
|
||||
public void Add(CraftSubRes craftSubRes)
|
||||
{
|
||||
List.Add(craftSubRes);
|
||||
}
|
||||
|
||||
public void Remove(int index)
|
||||
{
|
||||
if (index > Count - 1 || index < 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
List.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public CraftSubRes GetAt(int index)
|
||||
{
|
||||
return (CraftSubRes)List[index];
|
||||
}
|
||||
|
||||
public CraftSubRes SearchFor(Type type)
|
||||
{
|
||||
for (int i = 0; i < List.Count; i++)
|
||||
{
|
||||
CraftSubRes craftSubRes = (CraftSubRes)List[i];
|
||||
if (craftSubRes.ItemType == type) return craftSubRes;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
358
Projects/Scripts/Engines/Craft/Core/CraftSystem.cs
Normal file
358
Projects/Scripts/Engines/Craft/Core/CraftSystem.cs
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public enum CraftECA
|
||||
{
|
||||
ChanceMinusSixty,
|
||||
FiftyPercentChanceMinusTenPercent,
|
||||
ChanceMinusSixtyToFourtyFive
|
||||
}
|
||||
|
||||
public abstract class CraftSystem
|
||||
{
|
||||
private Dictionary<Mobile, CraftContext> m_ContextTable = new Dictionary<Mobile, CraftContext>();
|
||||
private List<int> m_RareRecipes;
|
||||
private List<int> m_Recipes;
|
||||
|
||||
public CraftSystem(int minCraftEffect, int maxCraftEffect, double delay)
|
||||
{
|
||||
MinCraftEffect = minCraftEffect;
|
||||
MaxCraftEffect = maxCraftEffect;
|
||||
Delay = delay;
|
||||
|
||||
CraftItems = new CraftItemCol();
|
||||
CraftGroups = new CraftGroupCol();
|
||||
CraftSubRes = new CraftSubResCol();
|
||||
CraftSubRes2 = new CraftSubResCol();
|
||||
|
||||
m_Recipes = new List<int>();
|
||||
m_RareRecipes = new List<int>();
|
||||
|
||||
InitCraftList();
|
||||
}
|
||||
|
||||
public int MinCraftEffect{ get; }
|
||||
|
||||
public int MaxCraftEffect{ get; }
|
||||
|
||||
public double Delay{ get; }
|
||||
|
||||
public CraftItemCol CraftItems{ get; }
|
||||
|
||||
public CraftGroupCol CraftGroups{ get; }
|
||||
|
||||
public CraftSubResCol CraftSubRes{ get; }
|
||||
|
||||
public CraftSubResCol CraftSubRes2{ get; }
|
||||
|
||||
public abstract SkillName MainSkill{ get; }
|
||||
|
||||
public virtual int GumpTitleNumber => 0;
|
||||
public virtual string GumpTitleString => "";
|
||||
|
||||
public virtual CraftECA ECA => CraftECA.ChanceMinusSixty;
|
||||
|
||||
public bool Resmelt{ get; set; }
|
||||
|
||||
public bool Repair{ get; set; }
|
||||
|
||||
public bool MarkOption{ get; set; }
|
||||
|
||||
public bool CanEnhance{ get; set; }
|
||||
|
||||
public abstract double GetChanceAtMin(CraftItem item);
|
||||
|
||||
public virtual bool RetainsColorFrom(CraftItem item, Type type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public CraftContext GetContext(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
return null;
|
||||
|
||||
if (m.Deleted)
|
||||
{
|
||||
m_ContextTable.Remove(m);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!m_ContextTable.TryGetValue(m, out CraftContext c))
|
||||
m_ContextTable[m] = c = new CraftContext();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public void OnMade(Mobile m, CraftItem item)
|
||||
{
|
||||
GetContext(m)?.OnMade(item);
|
||||
}
|
||||
|
||||
public virtual bool ConsumeOnFailure(Mobile from, Type resourceType, CraftItem craftItem)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void CreateItem(Mobile from, Type type, Type typeRes, BaseTool tool, CraftItem realCraftItem)
|
||||
{
|
||||
// Verify if the type is in the list of the craftable item
|
||||
if (CraftItems.SearchFor(type) != null)
|
||||
realCraftItem.Craft(from, this, typeRes, tool);
|
||||
}
|
||||
|
||||
public int RandomRecipe()
|
||||
{
|
||||
if (m_Recipes.Count == 0)
|
||||
return -1;
|
||||
|
||||
return m_Recipes[Utility.Random(m_Recipes.Count)];
|
||||
}
|
||||
|
||||
public int RandomRareRecipe()
|
||||
{
|
||||
if (m_RareRecipes.Count == 0)
|
||||
return -1;
|
||||
|
||||
return m_RareRecipes[Utility.Random(m_RareRecipes.Count)];
|
||||
}
|
||||
|
||||
|
||||
public int AddCraft(Type typeItem, TextDefinition group, TextDefinition name, double minSkill, double maxSkill,
|
||||
Type typeRes, TextDefinition nameRes, int amount)
|
||||
{
|
||||
return AddCraft(typeItem, group, name, MainSkill, minSkill, maxSkill, typeRes, nameRes, amount, "");
|
||||
}
|
||||
|
||||
public int AddCraft(Type typeItem, TextDefinition group, TextDefinition name, double minSkill, double maxSkill,
|
||||
Type typeRes, TextDefinition nameRes, int amount, TextDefinition message)
|
||||
{
|
||||
return AddCraft(typeItem, group, name, MainSkill, minSkill, maxSkill, typeRes, nameRes, amount, message);
|
||||
}
|
||||
|
||||
public int AddCraft(Type typeItem, TextDefinition group, TextDefinition name, SkillName skillToMake, double minSkill,
|
||||
double maxSkill, Type typeRes, TextDefinition nameRes, int amount)
|
||||
{
|
||||
return AddCraft(typeItem, group, name, skillToMake, minSkill, maxSkill, typeRes, nameRes, amount, "");
|
||||
}
|
||||
|
||||
public int AddCraft(Type typeItem, TextDefinition group, TextDefinition name, SkillName skillToMake, double minSkill,
|
||||
double maxSkill, Type typeRes, TextDefinition nameRes, int amount, TextDefinition message)
|
||||
{
|
||||
CraftItem craftItem = new CraftItem(typeItem, group, name);
|
||||
craftItem.AddRes(typeRes, nameRes, amount, message);
|
||||
craftItem.AddSkill(skillToMake, minSkill, maxSkill);
|
||||
|
||||
DoGroup(group, craftItem);
|
||||
return CraftItems.Add(craftItem);
|
||||
}
|
||||
|
||||
|
||||
private void DoGroup(TextDefinition groupName, CraftItem craftItem)
|
||||
{
|
||||
int index = CraftGroups.SearchFor(groupName);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
CraftGroup craftGroup = new CraftGroup(groupName);
|
||||
craftGroup.AddCraftItem(craftItem);
|
||||
CraftGroups.Add(craftGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
CraftGroups.GetAt(index).AddCraftItem(craftItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetItemHue(int index, int hue)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.ItemHue = hue;
|
||||
}
|
||||
|
||||
public void SetManaReq(int index, int mana)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.Mana = mana;
|
||||
}
|
||||
|
||||
public void SetStamReq(int index, int stam)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.Stam = stam;
|
||||
}
|
||||
|
||||
public void SetHitsReq(int index, int hits)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.Hits = hits;
|
||||
}
|
||||
|
||||
public void SetUseAllRes(int index, bool useAll)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.UseAllRes = useAll;
|
||||
}
|
||||
|
||||
public void SetNeedHeat(int index, bool needHeat)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.NeedHeat = needHeat;
|
||||
}
|
||||
|
||||
public void SetNeedOven(int index, bool needOven)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.NeedOven = needOven;
|
||||
}
|
||||
|
||||
public void SetBeverageType(int index, BeverageType requiredBeverage)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.RequiredBeverage = requiredBeverage;
|
||||
}
|
||||
|
||||
public void SetNeedMill(int index, bool needMill)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.NeedMill = needMill;
|
||||
}
|
||||
|
||||
public void SetNeededExpansion(int index, Expansion expansion)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.RequiredExpansion = expansion;
|
||||
}
|
||||
|
||||
public void AddRes(int index, Type type, TextDefinition name, int amount)
|
||||
{
|
||||
AddRes(index, type, name, amount, "");
|
||||
}
|
||||
|
||||
public void AddRes(int index, Type type, TextDefinition name, int amount, TextDefinition message)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.AddRes(type, name, amount, message);
|
||||
}
|
||||
|
||||
public void AddSkill(int index, SkillName skillToMake, double minSkill, double maxSkill)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.AddSkill(skillToMake, minSkill, maxSkill);
|
||||
}
|
||||
|
||||
public void SetUseSubRes2(int index, bool val)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.UseSubRes2 = val;
|
||||
}
|
||||
|
||||
private void AddRecipeBase(int index, int id)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.AddRecipe(id, this);
|
||||
}
|
||||
|
||||
public void AddRecipe(int index, int id)
|
||||
{
|
||||
AddRecipeBase(index, id);
|
||||
m_Recipes.Add(id);
|
||||
}
|
||||
|
||||
public void AddRareRecipe(int index, int id)
|
||||
{
|
||||
AddRecipeBase(index, id);
|
||||
m_RareRecipes.Add(id);
|
||||
}
|
||||
|
||||
public void AddQuestRecipe(int index, int id)
|
||||
{
|
||||
AddRecipeBase(index, id);
|
||||
}
|
||||
|
||||
public void ForceNonExceptional(int index)
|
||||
{
|
||||
CraftItem craftItem = CraftItems.GetAt(index);
|
||||
craftItem.ForceNonExceptional = true;
|
||||
}
|
||||
|
||||
|
||||
public void SetSubRes(Type type, string name)
|
||||
{
|
||||
CraftSubRes.ResType = type;
|
||||
CraftSubRes.NameString = name;
|
||||
CraftSubRes.Init = true;
|
||||
}
|
||||
|
||||
public void SetSubRes(Type type, int name)
|
||||
{
|
||||
CraftSubRes.ResType = type;
|
||||
CraftSubRes.NameNumber = name;
|
||||
CraftSubRes.Init = true;
|
||||
}
|
||||
|
||||
public void AddSubRes(Type type, int name, double reqSkill, object message)
|
||||
{
|
||||
CraftSubRes craftSubRes = new CraftSubRes(type, name, reqSkill, message);
|
||||
CraftSubRes.Add(craftSubRes);
|
||||
}
|
||||
|
||||
public void AddSubRes(Type type, int name, double reqSkill, int genericName, object message)
|
||||
{
|
||||
CraftSubRes craftSubRes = new CraftSubRes(type, name, reqSkill, genericName, message);
|
||||
CraftSubRes.Add(craftSubRes);
|
||||
}
|
||||
|
||||
public void AddSubRes(Type type, string name, double reqSkill, object message)
|
||||
{
|
||||
CraftSubRes craftSubRes = new CraftSubRes(type, name, reqSkill, message);
|
||||
CraftSubRes.Add(craftSubRes);
|
||||
}
|
||||
|
||||
|
||||
public void SetSubRes2(Type type, string name)
|
||||
{
|
||||
CraftSubRes2.ResType = type;
|
||||
CraftSubRes2.NameString = name;
|
||||
CraftSubRes2.Init = true;
|
||||
}
|
||||
|
||||
public void SetSubRes2(Type type, int name)
|
||||
{
|
||||
CraftSubRes2.ResType = type;
|
||||
CraftSubRes2.NameNumber = name;
|
||||
CraftSubRes2.Init = true;
|
||||
}
|
||||
|
||||
public void AddSubRes2(Type type, int name, double reqSkill, object message)
|
||||
{
|
||||
CraftSubRes craftSubRes = new CraftSubRes(type, name, reqSkill, message);
|
||||
CraftSubRes2.Add(craftSubRes);
|
||||
}
|
||||
|
||||
public void AddSubRes2(Type type, int name, double reqSkill, int genericName, object message)
|
||||
{
|
||||
CraftSubRes craftSubRes = new CraftSubRes(type, name, reqSkill, genericName, message);
|
||||
CraftSubRes2.Add(craftSubRes);
|
||||
}
|
||||
|
||||
public void AddSubRes2(Type type, string name, double reqSkill, object message)
|
||||
{
|
||||
CraftSubRes craftSubRes = new CraftSubRes(type, name, reqSkill, message);
|
||||
CraftSubRes2.Add(craftSubRes);
|
||||
}
|
||||
|
||||
public abstract void InitCraftList();
|
||||
|
||||
public abstract void PlayCraftEffect(Mobile from);
|
||||
|
||||
public abstract int PlayEndingEffect(Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality,
|
||||
bool makersMark, CraftItem item);
|
||||
|
||||
public abstract int CanCraft(Mobile from, BaseTool tool, Type itemType);
|
||||
}
|
||||
}
|
||||
34
Projects/Scripts/Engines/Craft/Core/CustomCraft.cs
Normal file
34
Projects/Scripts/Engines/Craft/Core/CustomCraft.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public abstract class CustomCraft
|
||||
{
|
||||
public CustomCraft(Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes, BaseTool tool,
|
||||
int quality)
|
||||
{
|
||||
From = from;
|
||||
CraftItem = craftItem;
|
||||
CraftSystem = craftSystem;
|
||||
TypeRes = typeRes;
|
||||
Tool = tool;
|
||||
Quality = quality;
|
||||
}
|
||||
|
||||
public Mobile From{ get; }
|
||||
|
||||
public CraftItem CraftItem{ get; }
|
||||
|
||||
public CraftSystem CraftSystem{ get; }
|
||||
|
||||
public Type TypeRes{ get; }
|
||||
|
||||
public BaseTool Tool{ get; }
|
||||
|
||||
public int Quality{ get; }
|
||||
|
||||
public abstract void EndCraftAction();
|
||||
public abstract Item CompleteCraft(out int message);
|
||||
}
|
||||
}
|
||||
340
Projects/Scripts/Engines/Craft/Core/Enhance.cs
Normal file
340
Projects/Scripts/Engines/Craft/Core/Enhance.cs
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
using System;
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public enum EnhanceResult
|
||||
{
|
||||
None,
|
||||
NotInBackpack,
|
||||
BadItem,
|
||||
BadResource,
|
||||
AlreadyEnhanced,
|
||||
Success,
|
||||
Failure,
|
||||
Broken,
|
||||
NoResources,
|
||||
NoSkill
|
||||
}
|
||||
|
||||
public class Enhance
|
||||
{
|
||||
public static EnhanceResult Invoke(Mobile from, CraftSystem craftSystem, BaseTool tool, Item item,
|
||||
CraftResource resource, Type resType, ref object resMessage)
|
||||
{
|
||||
if (item == null)
|
||||
return EnhanceResult.BadItem;
|
||||
|
||||
if (!item.IsChildOf(from.Backpack))
|
||||
return EnhanceResult.NotInBackpack;
|
||||
|
||||
if (!(item is BaseArmor) && !(item is BaseWeapon))
|
||||
return EnhanceResult.BadItem;
|
||||
|
||||
if (item is IArcaneEquip eq && eq.IsArcane)
|
||||
return EnhanceResult.BadItem;
|
||||
|
||||
if (CraftResources.IsStandard(resource))
|
||||
return EnhanceResult.BadResource;
|
||||
|
||||
int num = craftSystem.CanCraft(from, tool, item.GetType());
|
||||
|
||||
if (num > 0)
|
||||
{
|
||||
resMessage = num;
|
||||
return EnhanceResult.None;
|
||||
}
|
||||
|
||||
CraftItem craftItem = craftSystem.CraftItems.SearchFor(item.GetType());
|
||||
|
||||
if (craftItem == null || craftItem.Resources.Count == 0)
|
||||
return EnhanceResult.BadItem;
|
||||
|
||||
bool allRequiredSkills = false;
|
||||
if (craftItem.GetSuccessChance(from, resType, craftSystem, false, ref allRequiredSkills) <= 0.0)
|
||||
return EnhanceResult.NoSkill;
|
||||
|
||||
CraftResourceInfo info = CraftResources.GetInfo(resource);
|
||||
|
||||
if (info == null || info.ResourceTypes.Length == 0)
|
||||
return EnhanceResult.BadResource;
|
||||
|
||||
CraftAttributeInfo attributes = info.AttributeInfo;
|
||||
|
||||
if (attributes == null)
|
||||
return EnhanceResult.BadResource;
|
||||
|
||||
int resHue = 0, maxAmount = 0;
|
||||
|
||||
if (!craftItem.ConsumeRes(from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.None,
|
||||
ref resMessage))
|
||||
return EnhanceResult.NoResources;
|
||||
|
||||
if (craftSystem is DefBlacksmithy)
|
||||
if (from.FindItemOnLayer(Layer.OneHanded) is AncientSmithyHammer hammer)
|
||||
{
|
||||
hammer.UsesRemaining--;
|
||||
if (hammer.UsesRemaining < 1)
|
||||
hammer.Delete();
|
||||
}
|
||||
|
||||
int phys = 0, fire = 0, cold = 0, pois = 0, nrgy = 0;
|
||||
int dura, luck, lreq, dinc = 0;
|
||||
int baseChance;
|
||||
|
||||
bool physBonus = false;
|
||||
bool fireBonus;
|
||||
bool coldBonus;
|
||||
bool nrgyBonus;
|
||||
bool poisBonus;
|
||||
bool duraBonus;
|
||||
bool luckBonus;
|
||||
bool lreqBonus;
|
||||
bool dincBonus;
|
||||
|
||||
if (item is BaseWeapon weapon)
|
||||
{
|
||||
if (!CraftResources.IsStandard(weapon.Resource))
|
||||
return EnhanceResult.AlreadyEnhanced;
|
||||
|
||||
baseChance = 20;
|
||||
|
||||
dura = weapon.MaxHitPoints;
|
||||
luck = weapon.Attributes.Luck;
|
||||
lreq = weapon.WeaponAttributes.LowerStatReq;
|
||||
dinc = weapon.Attributes.WeaponDamage;
|
||||
|
||||
fireBonus = attributes.WeaponFireDamage > 0;
|
||||
coldBonus = attributes.WeaponColdDamage > 0;
|
||||
nrgyBonus = attributes.WeaponEnergyDamage > 0;
|
||||
poisBonus = attributes.WeaponPoisonDamage > 0;
|
||||
|
||||
duraBonus = attributes.WeaponDurability > 0;
|
||||
luckBonus = attributes.WeaponLuck > 0;
|
||||
lreqBonus = attributes.WeaponLowerRequirements > 0;
|
||||
dincBonus = dinc > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseArmor armor = (BaseArmor)item;
|
||||
|
||||
if (!CraftResources.IsStandard(armor.Resource))
|
||||
return EnhanceResult.AlreadyEnhanced;
|
||||
|
||||
baseChance = 20;
|
||||
|
||||
phys = armor.PhysicalResistance;
|
||||
fire = armor.FireResistance;
|
||||
cold = armor.ColdResistance;
|
||||
pois = armor.PoisonResistance;
|
||||
nrgy = armor.EnergyResistance;
|
||||
|
||||
dura = armor.MaxHitPoints;
|
||||
luck = armor.Attributes.Luck;
|
||||
lreq = armor.ArmorAttributes.LowerStatReq;
|
||||
|
||||
physBonus = attributes.ArmorPhysicalResist > 0;
|
||||
fireBonus = attributes.ArmorFireResist > 0;
|
||||
coldBonus = attributes.ArmorColdResist > 0;
|
||||
nrgyBonus = attributes.ArmorEnergyResist > 0;
|
||||
poisBonus = attributes.ArmorPoisonResist > 0;
|
||||
|
||||
duraBonus = attributes.ArmorDurability > 0;
|
||||
luckBonus = attributes.ArmorLuck > 0;
|
||||
lreqBonus = attributes.ArmorLowerRequirements > 0;
|
||||
dincBonus = false;
|
||||
}
|
||||
|
||||
int skill = from.Skills[craftSystem.MainSkill].Fixed / 10;
|
||||
|
||||
if (skill >= 100)
|
||||
baseChance -= (skill - 90) / 10;
|
||||
|
||||
EnhanceResult res = EnhanceResult.Success;
|
||||
|
||||
if (physBonus)
|
||||
CheckResult(ref res, baseChance + phys);
|
||||
|
||||
if (fireBonus)
|
||||
CheckResult(ref res, baseChance + fire);
|
||||
|
||||
if (coldBonus)
|
||||
CheckResult(ref res, baseChance + cold);
|
||||
|
||||
if (nrgyBonus)
|
||||
CheckResult(ref res, baseChance + nrgy);
|
||||
|
||||
if (poisBonus)
|
||||
CheckResult(ref res, baseChance + pois);
|
||||
|
||||
if (duraBonus)
|
||||
CheckResult(ref res, baseChance + dura / 40);
|
||||
|
||||
if (luckBonus)
|
||||
CheckResult(ref res, baseChance + 10 + luck / 2);
|
||||
|
||||
if (lreqBonus)
|
||||
CheckResult(ref res, baseChance + lreq / 4);
|
||||
|
||||
if (dincBonus)
|
||||
CheckResult(ref res, baseChance + dinc / 4);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case EnhanceResult.Broken:
|
||||
{
|
||||
if (!craftItem.ConsumeRes(from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.Half,
|
||||
ref resMessage))
|
||||
return EnhanceResult.NoResources;
|
||||
|
||||
item.Delete();
|
||||
break;
|
||||
}
|
||||
case EnhanceResult.Success:
|
||||
{
|
||||
if (!craftItem.ConsumeRes(from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.All,
|
||||
ref resMessage))
|
||||
return EnhanceResult.NoResources;
|
||||
|
||||
if (item is BaseWeapon w)
|
||||
{
|
||||
w.Resource = resource;
|
||||
|
||||
int hue = w.GetElementalDamageHue();
|
||||
if (hue > 0)
|
||||
w.Hue = hue;
|
||||
}
|
||||
else
|
||||
{
|
||||
((BaseArmor)item).Resource = resource;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EnhanceResult.Failure:
|
||||
{
|
||||
if (!craftItem.ConsumeRes(from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.Half,
|
||||
ref resMessage))
|
||||
return EnhanceResult.NoResources;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void CheckResult(ref EnhanceResult res, int chance)
|
||||
{
|
||||
if (res != EnhanceResult.Success)
|
||||
return; // we've already failed..
|
||||
|
||||
int random = Utility.Random(100);
|
||||
|
||||
if (10 > random)
|
||||
res = EnhanceResult.Failure;
|
||||
else if (chance > random)
|
||||
res = EnhanceResult.Broken;
|
||||
}
|
||||
|
||||
public static void BeginTarget(Mobile from, CraftSystem craftSystem, BaseTool tool)
|
||||
{
|
||||
CraftContext context = craftSystem.GetContext(from);
|
||||
|
||||
if (context == null)
|
||||
return;
|
||||
|
||||
int lastRes = context.LastResourceIndex;
|
||||
CraftSubResCol subRes = craftSystem.CraftSubRes;
|
||||
|
||||
if (lastRes >= 0 && lastRes < subRes.Count)
|
||||
{
|
||||
CraftSubRes res = subRes.GetAt(lastRes);
|
||||
|
||||
if (from.Skills[craftSystem.MainSkill].Value < res.RequiredSkill)
|
||||
{
|
||||
from.SendGump(new CraftGump(from, craftSystem, tool, res.Message));
|
||||
}
|
||||
else
|
||||
{
|
||||
CraftResource resource = CraftResources.GetFromType(res.ItemType);
|
||||
|
||||
if (resource != CraftResource.None)
|
||||
{
|
||||
from.Target = new InternalTarget(craftSystem, tool, res.ItemType, resource);
|
||||
from.SendLocalizedMessage(
|
||||
1061004); // Target an item to enhance with the properties of your selected material.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendGump(new CraftGump(from, craftSystem, tool,
|
||||
1061010)); // You must select a special material in order to enhance an item with its properties.
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendGump(new CraftGump(from, craftSystem, tool,
|
||||
1061010)); // You must select a special material in order to enhance an item with its properties.
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTarget : Target
|
||||
{
|
||||
private CraftSystem m_CraftSystem;
|
||||
private CraftResource m_Resource;
|
||||
private Type m_ResourceType;
|
||||
private BaseTool m_Tool;
|
||||
|
||||
public InternalTarget(CraftSystem craftSystem, BaseTool tool, Type resourceType, CraftResource resource) : base(
|
||||
2, false, TargetFlags.None)
|
||||
{
|
||||
m_CraftSystem = craftSystem;
|
||||
m_Tool = tool;
|
||||
m_ResourceType = resourceType;
|
||||
m_Resource = resource;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (targeted is Item item)
|
||||
{
|
||||
object message = null;
|
||||
EnhanceResult res = Enhance.Invoke(from, m_CraftSystem, m_Tool, item, m_Resource, m_ResourceType,
|
||||
ref message);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case EnhanceResult.NotInBackpack:
|
||||
message = 1061005;
|
||||
break; // The item must be in your backpack to enhance it.
|
||||
case EnhanceResult.AlreadyEnhanced:
|
||||
message = 1061012;
|
||||
break; // This item is already enhanced with the properties of a special material.
|
||||
case EnhanceResult.BadItem:
|
||||
message = 1061011;
|
||||
break; // You cannot enhance this type of item with the properties of the selected special material.
|
||||
case EnhanceResult.BadResource:
|
||||
message = 1061010;
|
||||
break; // You must select a special material in order to enhance an item with its properties.
|
||||
case EnhanceResult.Broken:
|
||||
message = 1061080;
|
||||
break; // You attempt to enhance the item, but fail catastrophically. The item is lost.
|
||||
case EnhanceResult.Failure:
|
||||
message = 1061082;
|
||||
break; // You attempt to enhance the item, but fail. Some material is lost in the process.
|
||||
case EnhanceResult.Success:
|
||||
message = 1061008;
|
||||
break; // You enhance the item with the properties of the special material.
|
||||
case EnhanceResult.NoSkill:
|
||||
message = 1044153;
|
||||
break; // You don't have the required skills to attempt this item.
|
||||
}
|
||||
|
||||
from.SendGump(new CraftGump(from, m_CraftSystem, m_Tool, message));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Projects/Scripts/Engines/Craft/Core/QueryMakersMarkGump.cs
Normal file
55
Projects/Scripts/Engines/Craft/Core/QueryMakersMarkGump.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.Craft
|
||||
{
|
||||
public class QueryMakersMarkGump : Gump
|
||||
{
|
||||
private CraftItem m_CraftItem;
|
||||
private CraftSystem m_CraftSystem;
|
||||
private Mobile m_From;
|
||||
private int m_Quality;
|
||||
private BaseTool m_Tool;
|
||||
private Type m_TypeRes;
|
||||
|
||||
public QueryMakersMarkGump(int quality, Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes,
|
||||
BaseTool tool) : base(100, 200)
|
||||
{
|
||||
from.CloseGump<QueryMakersMarkGump>();
|
||||
|
||||
m_Quality = quality;
|
||||
m_From = from;
|
||||
m_CraftItem = craftItem;
|
||||
m_CraftSystem = craftSystem;
|
||||
m_TypeRes = typeRes;
|
||||
m_Tool = tool;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 220, 170, 5054);
|
||||
AddBackground(10, 10, 200, 150, 3000);
|
||||
|
||||
AddHtmlLocalized(20, 20, 180, 80, 1018317); // Do you wish to place your maker's mark on this item?
|
||||
|
||||
AddHtmlLocalized(55, 100, 140, 25, 1011011); // CONTINUE
|
||||
AddButton(20, 100, 4005, 4007, 1);
|
||||
|
||||
AddHtmlLocalized(55, 125, 140, 25, 1011012); // CANCEL
|
||||
AddButton(20, 125, 4005, 4007, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
bool makersMark = info.ButtonID == 1;
|
||||
|
||||
if (makersMark)
|
||||
m_From.SendLocalizedMessage(501808); // You mark the item.
|
||||
else
|
||||
m_From.SendLocalizedMessage(501809); // Cancelled mark.
|
||||
|
||||
m_CraftItem.CompleteCraft(m_Quality, makersMark, m_From, m_CraftSystem, m_TypeRes, m_Tool, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue