mirror of
https://github.com/raphaelcheung/zircon-legend-server.git
synced 2026-10-29 14:10:22 +08:00
770 lines
22 KiB
C#
770 lines
22 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using Library;
|
|
using Library.SystemModels;
|
|
using MirDB;
|
|
using Server.Envir;
|
|
|
|
namespace Server.DBModels
|
|
{
|
|
[UserObject]
|
|
public sealed class UserItem : DBObject
|
|
{
|
|
|
|
public ItemInfo Info
|
|
{
|
|
get { return _Info; }
|
|
set
|
|
{
|
|
if (_Info == value) return;
|
|
|
|
var oldValue = _Info;
|
|
_Info = value;
|
|
|
|
OnChanged(oldValue, value, "Info");
|
|
}
|
|
}
|
|
private ItemInfo _Info;
|
|
|
|
public int CurrentDurability
|
|
{
|
|
get { return _CurrentDurability; }
|
|
set
|
|
{
|
|
if (_CurrentDurability == value) return;
|
|
|
|
var oldValue = _CurrentDurability;
|
|
_CurrentDurability = value;
|
|
|
|
OnChanged(oldValue, value, "CurrentDurability");
|
|
}
|
|
}
|
|
private int _CurrentDurability;
|
|
|
|
public int MaxDurability
|
|
{
|
|
get { return _MaxDurability; }
|
|
set
|
|
{
|
|
if (_MaxDurability == value) return;
|
|
|
|
var oldValue = _MaxDurability;
|
|
_MaxDurability = value;
|
|
|
|
OnChanged(oldValue, value, "MaxDurability");
|
|
}
|
|
}
|
|
private int _MaxDurability;
|
|
|
|
public long Count
|
|
{
|
|
get { return _Count; }
|
|
set
|
|
{
|
|
if (_Count == value) return;
|
|
|
|
var oldValue = _Count;
|
|
_Count = value;
|
|
|
|
OnChanged(oldValue, value, "Count");
|
|
}
|
|
}
|
|
private long _Count;
|
|
|
|
public int Slot
|
|
{
|
|
get { return _Slot; }
|
|
set
|
|
{
|
|
if (_Slot == value) return;
|
|
|
|
var oldValue = _Slot;
|
|
_Slot = value;
|
|
|
|
OnChanged(oldValue, value, "Slot");
|
|
}
|
|
}
|
|
private int _Slot;
|
|
|
|
public int Level
|
|
{
|
|
get { return _Level; }
|
|
set
|
|
{
|
|
if (_Level == value) return;
|
|
|
|
var oldValue = _Level;
|
|
_Level = value;
|
|
|
|
OnChanged(oldValue, value, "Level");
|
|
}
|
|
}
|
|
private int _Level;
|
|
|
|
public decimal Experience
|
|
{
|
|
get { return _Experience; }
|
|
set
|
|
{
|
|
if (_Experience == value) return;
|
|
|
|
var oldValue = _Experience;
|
|
_Experience = value;
|
|
|
|
OnChanged(oldValue, value, "Experience");
|
|
}
|
|
}
|
|
private decimal _Experience;
|
|
|
|
public Color Colour
|
|
{
|
|
get { return _Colour; }
|
|
set
|
|
{
|
|
if (_Colour == value) return;
|
|
|
|
var oldValue = _Colour;
|
|
_Colour = value;
|
|
|
|
OnChanged(oldValue, value, "Colour");
|
|
}
|
|
}
|
|
private Color _Colour;
|
|
|
|
public DateTime SpecialRepairCoolDown
|
|
{
|
|
get { return _specialRepairCoolDown; }
|
|
set
|
|
{
|
|
if (_specialRepairCoolDown == value) return;
|
|
|
|
var oldValue = _specialRepairCoolDown;
|
|
_specialRepairCoolDown = value;
|
|
|
|
OnChanged(oldValue, value, "SpecialRepairCoolDown");
|
|
}
|
|
}
|
|
private DateTime _specialRepairCoolDown;
|
|
|
|
public DateTime ResetCoolDown
|
|
{
|
|
get { return _ResetCoolDown; }
|
|
set
|
|
{
|
|
if (_ResetCoolDown == value) return;
|
|
|
|
var oldValue = _ResetCoolDown;
|
|
_ResetCoolDown = value;
|
|
|
|
OnChanged(oldValue, value, "ResetCoolDown");
|
|
}
|
|
}
|
|
private DateTime _ResetCoolDown;
|
|
|
|
|
|
|
|
public UserQuestTask UserTask;
|
|
|
|
|
|
[Association("Items")]
|
|
public CharacterInfo Character
|
|
{
|
|
get { return _Character; }
|
|
set
|
|
{
|
|
if (_Character == value) return;
|
|
|
|
var oldValue = _Character;
|
|
_Character = value;
|
|
|
|
OnChanged(oldValue, value, "Character");
|
|
}
|
|
}
|
|
private CharacterInfo _Character;
|
|
|
|
[Association("Items")]
|
|
public AccountInfo Account
|
|
{
|
|
get { return _Account; }
|
|
set
|
|
{
|
|
if (_Account == value) return;
|
|
|
|
var oldValue = _Account;
|
|
_Account = value;
|
|
|
|
OnChanged(oldValue, value, "Account");
|
|
}
|
|
}
|
|
private AccountInfo _Account;
|
|
|
|
[Association("Items")]
|
|
public GuildInfo Guild
|
|
{
|
|
get { return _Guild; }
|
|
set
|
|
{
|
|
if (_Guild == value) return;
|
|
|
|
var oldValue = _Guild;
|
|
_Guild = value;
|
|
|
|
OnChanged(oldValue, value, "Guild");
|
|
}
|
|
}
|
|
private GuildInfo _Guild;
|
|
|
|
[Association("Items")]
|
|
public UserCompanion Companion
|
|
{
|
|
get { return _Companion; }
|
|
set
|
|
{
|
|
if (_Companion == value) return;
|
|
|
|
var oldValue = _Companion;
|
|
_Companion = value;
|
|
|
|
OnChanged(oldValue, value, "Companion");
|
|
}
|
|
}
|
|
private UserCompanion _Companion;
|
|
|
|
|
|
[Association("Refine")]
|
|
public RefineInfo Refine
|
|
{
|
|
get { return _Refine; }
|
|
set
|
|
{
|
|
if (_Refine == value) return;
|
|
|
|
var oldValue = _Refine;
|
|
_Refine = value;
|
|
|
|
OnChanged(oldValue, value, "Refine");
|
|
}
|
|
}
|
|
private RefineInfo _Refine;
|
|
|
|
[Association("Auction")]
|
|
public AuctionInfo Auction
|
|
{
|
|
get { return _Auction; }
|
|
set
|
|
{
|
|
if (_Auction == value) return;
|
|
|
|
var oldValue = _Auction;
|
|
_Auction = value;
|
|
|
|
OnChanged(oldValue, value, "Auction");
|
|
}
|
|
}
|
|
private AuctionInfo _Auction;
|
|
|
|
[Association("Mail")]
|
|
public MailInfo Mail
|
|
{
|
|
get { return _Mail; }
|
|
set
|
|
{
|
|
if (_Mail == value) return;
|
|
|
|
var oldValue = _Mail;
|
|
_Mail = value;
|
|
|
|
OnChanged(oldValue, value, "Mail");
|
|
}
|
|
}
|
|
private MailInfo _Mail;
|
|
|
|
public UserItemFlags Flags
|
|
{
|
|
get { return _Flags; }
|
|
set
|
|
{
|
|
if (_Flags == value) return;
|
|
|
|
var oldValue = _Flags;
|
|
_Flags = value;
|
|
|
|
OnChanged(oldValue, value, "Flags");
|
|
}
|
|
}
|
|
private UserItemFlags _Flags;
|
|
|
|
public TimeSpan ExpireTime
|
|
{
|
|
get { return _ExpireTime; }
|
|
set
|
|
{
|
|
if (_ExpireTime == value) return;
|
|
|
|
var oldValue = _ExpireTime;
|
|
_ExpireTime = value;
|
|
|
|
OnChanged(oldValue, value, "ExpireTime");
|
|
}
|
|
}
|
|
private TimeSpan _ExpireTime;
|
|
|
|
|
|
|
|
[Association("AddedStats", true)]
|
|
public DBBindingList<UserItemStat> AddedStats { get; set; }
|
|
|
|
[IgnoreProperty]
|
|
public int Weight
|
|
{
|
|
get
|
|
{
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Poison:
|
|
case ItemType.Amulet:
|
|
return Info.Weight;
|
|
default:
|
|
return (int)Math.Min(int.MaxValue, Info.Weight * Count);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Stats Stats = new Stats();
|
|
|
|
protected override void OnChanged(object oldValue, object newValue, string propertyName)
|
|
{
|
|
base.OnChanged(oldValue, newValue, propertyName);
|
|
|
|
switch (propertyName)
|
|
{
|
|
case "Account":
|
|
if (Account != null)
|
|
{
|
|
Character = null;
|
|
Refine = null;
|
|
Auction = null;
|
|
Mail = null;
|
|
Guild = null;
|
|
Companion = null;
|
|
}
|
|
break;
|
|
case "Character":
|
|
if (Character != null)
|
|
{
|
|
Account = null;
|
|
Refine = null;
|
|
Auction = null;
|
|
Mail = null;
|
|
Guild = null;
|
|
Companion = null;
|
|
}
|
|
break;
|
|
case "Refine":
|
|
if (Refine != null)
|
|
{
|
|
Account = null;
|
|
Character = null;
|
|
Auction = null;
|
|
Mail = null;
|
|
Guild = null;
|
|
Companion = null;
|
|
}
|
|
break;
|
|
case "Auction":
|
|
if (Auction != null)
|
|
{
|
|
Account = null;
|
|
Character = null;
|
|
Refine = null;
|
|
Mail = null;
|
|
Guild = null;
|
|
Companion = null;
|
|
}
|
|
break;
|
|
case "Mail":
|
|
if (Mail != null)
|
|
{
|
|
Account = null;
|
|
Character = null;
|
|
Refine = null;
|
|
Auction = null;
|
|
Guild = null;
|
|
Companion = null;
|
|
}
|
|
break;
|
|
case "Guild":
|
|
if (Guild != null)
|
|
{
|
|
Character = null;
|
|
Account = null;
|
|
Refine = null;
|
|
Auction = null;
|
|
Mail = null;
|
|
Companion = null;
|
|
}
|
|
break;
|
|
case "Companion":
|
|
if (Companion != null)
|
|
{
|
|
Character = null;
|
|
Account = null;
|
|
Refine = null;
|
|
Auction = null;
|
|
Mail = null;
|
|
Guild = null;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
protected override void OnDeleted()
|
|
{
|
|
Info = null;
|
|
|
|
Character = null;
|
|
Account = null;
|
|
Guild = null;
|
|
Companion = null;
|
|
Refine = null;
|
|
Auction = null;
|
|
Mail = null;
|
|
UserTask = null;
|
|
|
|
for (int i = AddedStats.Count - 1; i >= 0; i--)
|
|
AddedStats[i].Delete();
|
|
|
|
UserTask = null;
|
|
|
|
base.OnDeleted();
|
|
}
|
|
|
|
|
|
protected override void OnCreated()
|
|
{
|
|
base.OnCreated();
|
|
|
|
Count = 1;
|
|
Slot = -1;
|
|
Level = 1;
|
|
}
|
|
protected override void OnLoaded()
|
|
{
|
|
base.OnLoaded();
|
|
|
|
StatsChanged();
|
|
}
|
|
|
|
public void StatsChanged()
|
|
{
|
|
Stats.Clear();
|
|
|
|
foreach (UserItemStat stat in AddedStats)
|
|
Stats[stat.Stat] += stat.Amount;
|
|
}
|
|
public void AddStat(Stat stat, int amount, StatSource source)
|
|
{
|
|
foreach (UserItemStat addedStat in AddedStats)
|
|
{
|
|
if (addedStat.Stat != stat || addedStat.StatSource != source) continue;
|
|
|
|
|
|
addedStat.Amount += amount;
|
|
|
|
return;
|
|
}
|
|
|
|
if (amount == 0) return;
|
|
|
|
UserItemStat newStat = SEnvir.UserItemStatsList.CreateNewObject();
|
|
|
|
newStat.StatSource = source;
|
|
newStat.Stat = stat;
|
|
newStat.Amount = amount;
|
|
newStat.Item = this;
|
|
}
|
|
|
|
public ClientUserItem ToClientInfo()
|
|
{
|
|
return new ClientUserItem
|
|
{
|
|
Index = Index,
|
|
|
|
InfoIndex = Info.Index,
|
|
|
|
CurrentDurability = CurrentDurability,
|
|
MaxDurability = MaxDurability,
|
|
|
|
Count = Count,
|
|
|
|
Slot = Slot,
|
|
|
|
Level = Level,
|
|
Experience = Experience,
|
|
|
|
Colour = Colour,
|
|
|
|
SpecialRepairCoolDown = SpecialRepairCoolDown > SEnvir.Now ? SpecialRepairCoolDown - SEnvir.Now : TimeSpan.Zero,
|
|
ResetCoolDown = ResetCoolDown > SEnvir.Now ? ResetCoolDown - SEnvir.Now : TimeSpan.Zero,
|
|
|
|
AddedStats = new Stats(Stats),
|
|
|
|
Flags = Flags,
|
|
|
|
ExpireTime = ExpireTime,
|
|
};
|
|
}
|
|
|
|
public long Price(long count)
|
|
{
|
|
if (Info == null) return 0;
|
|
if ((Flags & UserItemFlags.Worthless) == UserItemFlags.Worthless) return 0;
|
|
|
|
decimal p = Info.Price;
|
|
|
|
if (Info.Durability > 0)
|
|
{
|
|
decimal r = Info.Price / 2M / Info.Durability;
|
|
|
|
p = MaxDurability * r;
|
|
|
|
r = MaxDurability > 0 ? CurrentDurability / (decimal)MaxDurability : 0;
|
|
|
|
p = Math.Floor(p / 2M + p / 2M * r + Info.Price / 2M);
|
|
}
|
|
|
|
p = p * (Stats.Count * 0.1M + 1M);
|
|
|
|
if (Info.Stats[Stat.SaleBonus20] > 0 && Info.Stats[Stat.SaleBonus20] <= count)
|
|
p *= 1.2M;
|
|
else if (Info.Stats[Stat.SaleBonus15] > 0 && Info.Stats[Stat.SaleBonus15] <= count)
|
|
p *= 1.15M;
|
|
else if (Info.Stats[Stat.SaleBonus10] > 0 && Info.Stats[Stat.SaleBonus10] <= count)
|
|
p *= 1.1M;
|
|
else if (Info.Stats[Stat.SaleBonus5] > 0 && Info.Stats[Stat.SaleBonus5] <= count)
|
|
p *= 1.05M;
|
|
|
|
return (long)(p * count * Info.SellRate);
|
|
}
|
|
public long RepairCost(bool special)
|
|
{
|
|
if (Info.Durability == 0 || CurrentDurability >= MaxDurability) return 0;
|
|
|
|
int rate = special ? 2 : 1;
|
|
|
|
decimal p = Math.Floor(MaxDurability * (Info.Price / 2M / Info.Durability) + Info.Price / 2M);
|
|
p = p * (Stats.Count * 0.1M + 1M);
|
|
|
|
return (long)(p * Count - Price(Count)) * rate;
|
|
}
|
|
public bool CanFragment()
|
|
{
|
|
if ((Flags & UserItemFlags.Worthless) == UserItemFlags.Worthless || (Flags & UserItemFlags.NonRefinable) == UserItemFlags.NonRefinable) return false;
|
|
|
|
switch (Info.Rarity)
|
|
{
|
|
case Rarity.Common:
|
|
if (Info.RequiredAmount <= 15) return false;
|
|
break;
|
|
case Rarity.Superior:
|
|
break;
|
|
case Rarity.Elite:
|
|
break;
|
|
}
|
|
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Weapon:
|
|
case ItemType.Armour:
|
|
case ItemType.Helmet:
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
case ItemType.Shoes:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
public int FragmentCost()
|
|
{
|
|
switch (Info.Rarity)
|
|
{
|
|
case Rarity.Common:
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Armour:
|
|
case ItemType.Weapon:
|
|
case ItemType.Helmet:
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
case ItemType.Shoes:
|
|
return Info.RequiredAmount * 10000 / 9;
|
|
/* case ItemType.Helmet:
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
case ItemType.Shoes:
|
|
return Info.RequiredAmount * 7000 / 9;*/
|
|
default:
|
|
return 0;
|
|
}
|
|
case Rarity.Superior:
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Armour:
|
|
case ItemType.Weapon:
|
|
case ItemType.Helmet:
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
case ItemType.Shoes:
|
|
return Info.RequiredAmount * 10000 / 2;
|
|
/* case ItemType.Helmet:
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
case ItemType.Shoes:
|
|
return Info.RequiredAmount * 10000 / 10;*/
|
|
default:
|
|
return 0;
|
|
}
|
|
case Rarity.Elite:
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Weapon:
|
|
case ItemType.Armour:
|
|
return 250000;
|
|
case ItemType.Helmet:
|
|
return 50000;
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
return 150000;
|
|
case ItemType.Shoes:
|
|
return 30000;
|
|
default:
|
|
return 0;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
public int FragmentCount()
|
|
{
|
|
switch (Info.Rarity)
|
|
{
|
|
case Rarity.Common:
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Armour:
|
|
case ItemType.Weapon:
|
|
case ItemType.Helmet:
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
case ItemType.Shoes:
|
|
return Math.Max(1, Info.RequiredAmount / 2 + 5);
|
|
/* case ItemType.Helmet:
|
|
return Math.Max(1, (Info.RequiredAmount - 30) / 6);
|
|
case ItemType.Necklace:
|
|
return Math.Max(1, Info.RequiredAmount / 8);
|
|
case ItemType.Bracelet:
|
|
return Math.Max(1, Info.RequiredAmount / 15);
|
|
case ItemType.Ring:
|
|
return Math.Max(1, Info.RequiredAmount / 9);
|
|
case ItemType.Shoes:
|
|
return Math.Max(1, (Info.RequiredAmount - 35) / 6);*/
|
|
default:
|
|
return 0;
|
|
}
|
|
case Rarity.Superior:
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Armour:
|
|
case ItemType.Weapon:
|
|
case ItemType.Helmet:
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
case ItemType.Shoes:
|
|
return Math.Max(1, Info.RequiredAmount / 2 + 5);
|
|
/* case ItemType.Helmet:
|
|
return Math.Max(1, (Info.RequiredAmount - 30) / 6);
|
|
case ItemType.Necklace:
|
|
return Math.Max(1, Info.RequiredAmount / 10);
|
|
case ItemType.Bracelet:
|
|
return Math.Max(1, Info.RequiredAmount / 15);
|
|
case ItemType.Ring:
|
|
return Math.Max(1, Info.RequiredAmount / 10);
|
|
case ItemType.Shoes:
|
|
return Math.Max(1, (Info.RequiredAmount - 35) / 6);*/
|
|
default:
|
|
return 0;
|
|
}
|
|
case Rarity.Elite:
|
|
switch (Info.ItemType)
|
|
{
|
|
case ItemType.Armour:
|
|
case ItemType.Weapon:
|
|
return 50;
|
|
case ItemType.Helmet:
|
|
return 5;
|
|
case ItemType.Necklace:
|
|
case ItemType.Bracelet:
|
|
case ItemType.Ring:
|
|
return 10;
|
|
case ItemType.Shoes:
|
|
return 3;
|
|
default:
|
|
return 0;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public int MergeRefineElements(out Stat element)
|
|
{
|
|
int value = 0;
|
|
element = Stats.GetWeaponElement();
|
|
|
|
for (int i = AddedStats.Count - 1; i >= 0; i--)
|
|
{
|
|
UserItemStat stat = AddedStats[i];
|
|
if (stat.StatSource != StatSource.Refine) continue;
|
|
|
|
switch (stat.Stat)
|
|
{
|
|
case Stat.FireAttack:
|
|
case Stat.IceAttack:
|
|
case Stat.LightningAttack:
|
|
case Stat.WindAttack:
|
|
case Stat.HolyAttack:
|
|
case Stat.DarkAttack:
|
|
case Stat.PhantomAttack:
|
|
value += stat.Amount;
|
|
stat.Delete();
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (value > 0 && element != Stat.None)
|
|
AddStat(element, value, StatSource.Refine);
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
public override string ToString()
|
|
{
|
|
return Info.ToString();
|
|
}
|
|
}
|
|
}
|