July 26, 2017, 08:44:37 PM

Vita-Nex: Core



ServUO
RunUO

JetBrains

User Info

 
 
Welcome, Guest. Please login or register.

Who's Online

  • Dot Guests: 1
  • Dot Hidden: 0
  • Dot Users: 0

There aren't any users online.

Advertisment

Current Board

Support  >  Custom Support

Give and receive help and advice to do with any aspect of customizing the project. This is the best board to post in if you're having issues with a custom module, service or modification.


Author Topic: Customizing the Skill Codex  (Read 12419 times)

0 Members and 1 Guest are viewing this topic.

Offline Greed

  • User
  • *
  • Posts: 21
  • Likes: 2
    • View Profile
Customizing the Skill Codex
« on: February 10, 2015, 08:30:58 AM »
Hi Vorspire,

I'm interested in changing the skill codex, as great as it is, to only offer pre-AOS skills when used. If it isn't too much trouble would you mind pointing me in the direction of how to do that? Thanks so much for any reply. Oh and also I was curious how to make it not delete on use/not require to be in my backpack have an infinite number of uses

Edit - Figured out the strikethrough'd part on my own

Best,

Greed

P.S. Sorry for so many threads as of late. Not trying to spam it's just that you've done such a marvelous job creating and developing your VNC I can't help but enjoy learning more about it.
« Last Edit: February 10, 2015, 10:38:46 AM by Greed »

Offline Vorspire

  • Administrator
  • *****
  • Posts: 142
  • Likes: 34
  • Founder & Developer
    • View Profile
    • Vita-Nex: Core
Re: Customizing the Skill Codex
« Reply #1 on: February 10, 2015, 12:05:28 PM »
Your best option would be to create a child class that inherits the SkillCodex, then override the functions you want to change.

The SkillCodex has a way to filter skills from the list, but here is an example of what I use for some variations to it;

Code: [Select]
#region Header
//   Vorspire    _,-'/-'/  SkillCodexBase.cs
//   .      __,-; ,'( '/
//    \.    `-.__`-._`:_,-._       _ , . ``
//     `:-._,------' ` _,`--` -: `_ , ` ,' :
//        `---..__,,--'  (C) 2015  ` -'. -'
//        #  Vita-Nex [http://core.vita-nex.com]  #
//  {o)xxx|===============-   #   -===============|xxx(o}
//        #        The MIT License (MIT)          #
#endregion

#region References
using Server.Mobiles;

using VitaNex.Items;
using VitaNex.SuperGumps;
#endregion

namespace Server.Items
{
public abstract class SkillCodexBase : SkillCodex
{
private static readonly SkillName[] DefaultIgnoredSkills = {SkillName.Mysticism, SkillName.Imbuing};

public SkillCodexBase(int count, double value, bool deleteWhenEmpty, SkillCodexMode mode, SkillCodexFlags flags)
: base(count, value, deleteWhenEmpty, mode, flags)
{
IgnoredSkills.AddRange(DefaultIgnoredSkills);
}

public SkillCodexBase(Serial serial)
: base(serial)
{ }

public override bool ValidateSkill(Mobile user, Skill skill, bool message)
{
if (user is PlayerMobile)
{
var pm = (PlayerMobile)user;

if (skill.SkillName == SkillName.Spellweaving)
{
if (!pm.Spellweaving)
{
if (message)
{
pm.SendMessage(
SuperGump.DefaultErrorHue,
"You must complete the Patience or Discipline quest chains to unlock {0}.",
skill.Name);
}

return false;
}
}
}

return base.ValidateSkill(user, skill, message);
}

public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);

var version = 0;

writer.Write(version);

switch (version)
{
case 0:
{ }
break;
}
}

public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);

var version = reader.ReadInt();

switch (version)
{
case 0:
{ }
break;
}
}
}

public abstract class SkillCodexFixedBase : SkillCodexBase
{
public SkillCodexFixedBase(int count, double value)
: base(count, value, true, SkillCodexMode.Fixed, SkillCodexFlags.Base)
{ }

public SkillCodexFixedBase(Serial serial)
: base(serial)
{ }

public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);

var version = 0;

writer.Write(version);

switch (version)
{
case 0:
{ }
break;
}
}

public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);

var version = reader.ReadInt();

switch (version)
{
case 0:
{ }
break;
}
}
}
}

I use these new child classes as parents to other child derivatives - the "FixedBase" version will set the selected skills to the given value outright, rather than using an offset (like plus or minus the value).

For example, if I wanted to give them 6 skill at 100.0, this would be appropriate:

Code: [Select]
	public sealed class SkillCodexFixedBase6At100 : SkillCodexFixedBase
{
[Constructable]
public SkillCodexFixedBase6At100()
: base(6, 100.0)
{ }

public SkillCodexFixedBase6At100(Serial serial)
: base(serial)
{ }

public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);

writer.SetVersion(0);
}

public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);

reader.GetVersion();
}
}

To answer your question about ignoring skills, you can do something like this:

Code: [Select]
IgnoredSkills.AddRange( SkillName.Alchemy, SkillName.Macing, SkillName.Imbuing );

IgnoredSkills is a dynamic list available to each SkillCodex instance, any skills listed will not be shown on the gump.
« Last Edit: February 10, 2015, 12:12:03 PM by Vorspire »

Offline Greed

  • User
  • *
  • Posts: 21
  • Likes: 2
    • View Profile
Re: Customizing the Skill Codex
« Reply #2 on: February 10, 2015, 12:11:09 PM »
Awesome thanks so much! I'll check it out later today :D

Offline Vorspire

  • Administrator
  • *****
  • Posts: 142
  • Likes: 34
  • Founder & Developer
    • View Profile
    • Vita-Nex: Core
Re: Customizing the Skill Codex
« Reply #3 on: February 10, 2015, 12:14:01 PM »
No problem :)
It's good that you're asking so many questions because it's a good substitute for others who can't find the docs (until they become available) :P

Offline Greed

  • User
  • *
  • Posts: 21
  • Likes: 2
    • View Profile
Re: Customizing the Skill Codex
« Reply #4 on: February 12, 2015, 12:30:27 AM »
Okay, and by the way thank you again, now I tried those excellent changes and of course they compiled perfectly however when I edited the part about addrange with regard to ignoring I get this message:

http://imgur.com/Pkbnw7D

Here is the code I'm running:

Code: [Select]

#region Header
//   Vorspire    _,-'/-'/  SkillCodex.cs
//   .      __,-; ,'( '/
//    \.    `-.__`-._`:_,-._       _ , . ``
//     `:-._,------' ` _,`--` -: `_ , ` ,' :
//        `---..__,,--'  (C) 2014  ` -'. -'
//        #  Vita-Nex [http://core.vita-nex.com]  #
//  {o)xxx|===============-   #   -===============|xxx(o}
//        #        The MIT License (MIT)          #
#endregion

#region References
using System;
using System.Collections.Generic;
using System.Drawing;

using Server;
using Server.Mobiles;

using VitaNex.Items;
using VitaNex.SuperGumps;
using VitaNex.SuperGumps.UI;
#endregion

namespace Server.Items
{
    public abstract class SkillCodexBase : SkillCodex
    {
        private static readonly SkillName[] DefaultIgnoredSkills = { SkillName.Mysticism, SkillName.Imbuing };

        public SkillCodexBase(int count, double value, bool deleteWhenEmpty, SkillCodexMode mode, SkillCodexFlags flags)
            : base(count, value, deleteWhenEmpty, mode, flags)
        {
            IgnoredSkills.AddRange(SkillName.Alchemy, SkillName.Macing, SkillName.Imbuing);
        }

        public SkillCodexBase(Serial serial)
            : base(serial)
        { }

        public override bool ValidateSkill(Mobile user, Skill skill, bool message)
        {
            if (user is PlayerMobile)
            {
                var pm = (PlayerMobile)user;

                if (skill.SkillName == SkillName.Spellweaving)
                {
                    if (!pm.Spellweaving)
                    {
                        if (message)
                        {
                            pm.SendMessage(
                                SuperGump.DefaultErrorHue,
                                "You must complete the Patience or Discipline quest chains to unlock {0}.",
                                skill.Name);
                        }

                        return false;
                    }
                }
            }

            return base.ValidateSkill(user, skill, message);
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            var version = 0;

            writer.Write(version);

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            var version = reader.ReadInt();

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }
    }

    public abstract class SkillCodexFixedBase : SkillCodexBase
    {
        public SkillCodexFixedBase(int count, double value)
            : base(count, value, true, SkillCodexMode.Fixed, SkillCodexFlags.Base)
        { }

        public SkillCodexFixedBase(Serial serial)
            : base(serial)
        { }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            var version = 0;

            writer.Write(version);

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            var version = reader.ReadInt();

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }
    }
}

namespace VitaNex.Items
{
public enum SkillCodexFlags : byte
{
Base = 0x00,
Cap = 0x01,
Both = 0x02
}

public enum SkillCodexMode : byte
{
Fixed = 0x00,
Increase = 0x01,
Decrease = 0x02
}

public class SkillCodex : Item
{
private SuperGump SelectionGump { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public SkillCodexMode Mode { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public SkillCodexFlags Flags { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public int Count { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public double Value { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public int ValueFixed { get { return (int)(Value * 10); } set { Value = value / 10; } }

[CommandProperty(AccessLevel.GameMaster)]
public bool DeleteWhenEmpty { get; set; }

public List<SkillName> IgnoredSkills { get; protected set; }
public List<SkillName> SelectedSkills { get; protected set; }

[Constructable]
public SkillCodex()
: this(1)
{ }

[Constructable]
public SkillCodex(int count)
: this(count, 100.0)
{ }

[Constructable]
public SkillCodex(int count, double value)
: this(count, value, true)
{ }

[Constructable]
public SkillCodex(int count, double value, bool deleteWhenEmpty)
: this(count, value, deleteWhenEmpty, SkillCodexMode.Fixed)
{ }

[Constructable]
public SkillCodex(int count, double value, bool deleteWhenEmpty, SkillCodexMode mode)
: this(count, value, deleteWhenEmpty, mode, SkillCodexFlags.Base)
{ }

[Constructable]
public SkillCodex(int count, double value, bool deleteWhenEmpty, SkillCodexMode mode, SkillCodexFlags flags)
: base(8793)
{
SelectedSkills = new List<SkillName>();
IgnoredSkills = new List<SkillName>();

Mode = mode;
Flags = flags;
Count = count;
Value = value;
DeleteWhenEmpty = deleteWhenEmpty;

Name = "Codex of Wisdom";
LootType = LootType.Blessed;
Stackable = false;
}

public SkillCodex(Serial serial)
: base(serial)
{ }

public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);

string html = String.Empty, flags = String.Empty;

html += String.Format("<basefont color=#{0:X6}>Use: ", Color.Cyan.ToArgb());

switch (Flags)
{
case SkillCodexFlags.Base:
flags = "value";
break;
case SkillCodexFlags.Cap:
flags = "cap";
break;
case SkillCodexFlags.Both:
flags = "value and cap";
break;
}

switch (Mode)
{
case SkillCodexMode.Increase:
{
html += String.Format(
"Increase {0} skill{1} {2} by {3:F2}%", Count, Count == 1 ? String.Empty : "s", flags, Value);
}
break;
case SkillCodexMode.Decrease:
{
html += String.Format(
"Decrease {0} skill{1} {2} by {3:F2}%", Count, Count == 1 ? String.Empty : "s", flags, Value);
}
break;
case SkillCodexMode.Fixed:
{
html += String.Format("Set {0} skill{1} {2} to {3:F2}%", Count, Count == 1 ? String.Empty : "s", flags, Value);
}
break;
}

list.Add(html);
}

public override void OnDoubleClick(Mobile from)
{
if (from == null || from.Deleted || !Validate(from, true))
{
return;
}

SelectSkills(from);
InvalidateProperties();
}

public virtual bool ValidateSkill(Mobile user, Skill skill, bool message)
{
if (user == null || user.Deleted || skill == null)
{
return false;
}

switch (Mode)
{
case SkillCodexMode.Increase:
{
if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
if (user.SkillsTotal + ValueFixed > user.SkillsCap)
{
if (!CanReduceSkills(user))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already know everything this codex can offer, reduce some skills to make room for more knowledge.");
}

return false;
}
}

if (skill.IsCapped() || skill.WillCap(Value, false))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue, "You already know everything this codex can offer about {0}.", skill.Name);
}

return false;
}

if (!skill.IsLocked(SkillLock.Up))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "The skill {0} is locked.", skill.Name);
}

return false;
}
}
}
break;
case SkillCodexMode.Decrease:
{
if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
if (user.SkillsTotal - ValueFixed < 0)
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "You already forgot everything this codex can offer.");
}

return false;
}

if (skill.IsZero() || skill.WillZero(Value, false))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already forgot everything this codex can offer about {0}, any further and you'll forget how to breath!",
skill.Name);
}

return false;
}

if (!skill.IsLocked(SkillLock.Down))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "The skill {0} is locked.", skill.Name);
}

return false;
}
}
}
break;
case SkillCodexMode.Fixed:
{
if (Flags == SkillCodexFlags.Cap)
{
if (skill.CapFixedPoint == ValueFixed)
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue, "You already know everything this codex can offer about {0}.", skill.Name);
}

return false;
}
}

if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
if (ValueFixed < skill.BaseFixedPoint)
{
if (user.SkillsTotal - (skill.BaseFixedPoint - ValueFixed) < 0)
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already forgot everything this codex can offer, any further and you'll forget how to breath!");
}

return false;
}
}
else if (ValueFixed > skill.BaseFixedPoint)
{
if (user.SkillsTotal + (ValueFixed - skill.BaseFixedPoint) > user.SkillsCap)
{
if (!CanReduceSkills(user))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already know everything this codex can offer, reduce some skills to make room for more knowledge.");
}

return false;
}
}
}
else
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue, "You already know everything this codex can offer about {0}.", skill.Name);
}

return false;
}

if (skill.IsLocked(SkillLock.Locked))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "The skill {0} is locked.", skill.Name);
}

return false;
}
}
}
break;
}

return true;
}

public virtual bool Validate(Mobile user, bool message)
{
if (user == null || user.Deleted || !user.CanSee(this))
{
return false;
}

if (!IsChildOf(user.Backpack))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "This codex must be in your backpack to read it.");
}

return false;
}

if (Count <= 0)
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "This codex does not contain any skills to learn.");
}

return false;
}

return true;
}

public virtual void SelectSkills(Mobile user)
{
if (user == null || user.Deleted || !Validate(user, true) || !(user is PlayerMobile))
{
return;
}

if (SelectionGump != null)
{
SelectionGump.Close(true);
}

SelectionGump = new SkillSelectionGump(
user as PlayerMobile,
null,
Count,
null,
null,
skills =>
{
if (!ApplySkills(user, skills))
{
SelectSkills(user);
}
},
IgnoredSkills.ToArray()).Send();
}

public virtual bool ApplySkills(Mobile user, SkillName[] skills)
{
if (user == null || user.Deleted || skills == null || skills.Length == 0 || !Validate(user, true))
{
return false;
}

foreach (SkillName sn in skills)
{
if (user.Deleted || !Validate(user, true))
{
return false;
}

Skill skill = user.Skills[sn];

if (!ValidateSkill(user, skill, true))
{
continue;
}

bool charge = false;

if (Flags == SkillCodexFlags.Cap || Flags == SkillCodexFlags.Both)
{
switch (Mode)
{
case SkillCodexMode.Increase:
{
skill.IncreaseCap(Value);
}
break;
case SkillCodexMode.Decrease:
{
skill.DecreaseCap(Value);
}
break;
case SkillCodexMode.Fixed:
{
skill.SetCap(Value);
}
break;
}

if (Flags != SkillCodexFlags.Both)
{
EndApply(skill);
return true;
}

charge = true;
}

if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
charge = false;

switch (Mode)
{
case SkillCodexMode.Increase:
{
if (user.SkillsTotal + ValueFixed > user.SkillsCap)
{
if (TryReduceSkills(user) && skill.IncreaseBase(Value))
{
charge = true;
}
}
else if (skill.IncreaseBase(Value))
{
charge = true;
}
}
break;
case SkillCodexMode.Decrease:
{
if (skill.DecreaseBase(Value))
{
charge = true;
}
}
break;
case SkillCodexMode.Fixed:
{
if (ValueFixed > skill.BaseFixedPoint)
{
if (user.SkillsTotal + ValueFixed > user.SkillsCap)
{
if (TryReduceSkills(user) && skill.SetBase(Value))
{
charge = true;
}
}
else if (skill.SetBase(Value))
{
charge = true;
}
}
else if (ValueFixed < skill.BaseFixedPoint && skill.SetBase(Value))
{
charge = true;
}
}
break;
}
}

if (charge)
{
EndApply(skill);
}
}

return true;
}

protected void EndApply(Skill skill)
{
skill.Normalize();
UseCharges();

if (Count <= 0)
{
if (DeleteWhenEmpty)
{
Delete();
}
}
}

protected bool CanReduceSkills(Mobile user)
{
int target = (user.SkillsTotal + ValueFixed) - user.SkillsCap;
int canReduceBy = 0;

foreach (Skill s in user.Skills)
{
if (s.IsLocked(SkillLock.Down))
{
if (canReduceBy + s.BaseFixedPoint > target)
{
canReduceBy += (target - canReduceBy);
}
else
{
canReduceBy += s.BaseFixedPoint;
}
}

if (canReduceBy >= target)
{
return true;
}
}

return false;
}

protected bool TryReduceSkills(Mobile user)
{
if (!CanReduceSkills(user))
{
return false;
}

int target = (user.SkillsTotal + ValueFixed) - user.SkillsCap;
int reducedBy = 0;

foreach (Skill s in user.Skills)
{
if (s.IsLocked(SkillLock.Down))
{
if (reducedBy + s.BaseFixedPoint > target)
{
int diff = (target - reducedBy);

if (s.DecreaseBase(diff / 10))
{
reducedBy += diff;
}
}
else
{
if (s.SetBase(0))
{
reducedBy += s.BaseFixedPoint;
}
}
}

if (reducedBy >= target)
{
return true;
}
}

return false;
}

public virtual void UseCharges(int count = 1)
{
Count = Math.Max(0, Count - count);
InvalidateProperties();
}

public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);

int version = writer.SetVersion(1);

switch (version)
{
case 1:
{
writer.WriteFlag(Mode);
writer.WriteFlag(Flags);
writer.Write(Count);
writer.Write(Value);
writer.Write(DeleteWhenEmpty);
writer.WriteList(IgnoredSkills, skill => writer.WriteFlag(skill));
}
break;
case 0:
{
writer.Write((byte)Mode);
writer.Write((byte)Flags);
writer.Write(Count);
writer.Write(Value);
writer.Write(DeleteWhenEmpty);
writer.WriteList(IgnoredSkills, skill => writer.Write((short)skill));
}
break;
}
}

public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);

int version = reader.GetVersion();

switch (version)
{
case 1:
{
Mode = reader.ReadFlag<SkillCodexMode>();
Flags = reader.ReadFlag<SkillCodexFlags>();
Count = reader.ReadInt();
Value = reader.ReadDouble();
DeleteWhenEmpty = reader.ReadBool();
IgnoredSkills = reader.ReadList(r => r.ReadFlag<SkillName>());
}
break;
case 0:
{
Mode = (SkillCodexMode)reader.ReadByte();
Flags = (SkillCodexFlags)reader.ReadByte();
Count = reader.ReadInt();
Value = reader.ReadDouble();
DeleteWhenEmpty = reader.ReadBool();
IgnoredSkills = reader.ReadList(() => (SkillName)reader.ReadShort());
}
break;
}
}
}
}

« Last Edit: February 12, 2015, 12:35:44 AM by Greed »

Offline Vorspire

  • Administrator
  • *****
  • Posts: 142
  • Likes: 34
  • Founder & Developer
    • View Profile
    • Vita-Nex: Core
Re: Customizing the Skill Codex
« Reply #5 on: February 12, 2015, 03:03:41 PM »
Ah OK, sorry, that AddRange method is from the next VNc update hehe, just change it slightly:

Code: [Select]
IgnoredSkills.AddRange(new[]{SkillName.Alchemy, SkillName.Macing, SkillName.Imbuing});

Offline Greed

  • User
  • *
  • Posts: 21
  • Likes: 2
    • View Profile
Re: Customizing the Skill Codex
« Reply #6 on: February 12, 2015, 04:07:40 PM »
Oh Ok  ;D

Now that does compile but it doesn't seem to get rid of the ignored skills. Hmm.

Code: [Select]
#region Header
//   Vorspire    _,-'/-'/  SkillCodex.cs
//   .      __,-; ,'( '/
//    \.    `-.__`-._`:_,-._       _ , . ``
//     `:-._,------' ` _,`--` -: `_ , ` ,' :
//        `---..__,,--'  (C) 2014  ` -'. -'
//        #  Vita-Nex [http://core.vita-nex.com]  #
//  {o)xxx|===============-   #   -===============|xxx(o}
//        #        The MIT License (MIT)          #
#endregion

#region References
using System;
using System.Collections.Generic;
using System.Drawing;

using Server;
using Server.Mobiles;

using VitaNex.Items;
using VitaNex.SuperGumps;
using VitaNex.SuperGumps.UI;
#endregion

namespace Server.Items
{
    public abstract class SkillCodexBase : SkillCodex
    {
        private static readonly SkillName[] DefaultIgnoredSkills = { SkillName.Mysticism, SkillName.Imbuing };

        public SkillCodexBase(int count, double value, bool deleteWhenEmpty, SkillCodexMode mode, SkillCodexFlags flags)
            : base(count, value, deleteWhenEmpty, mode, flags)
        {
            IgnoredSkills.AddRange(new[] { SkillName.Alchemy, SkillName.Macing, SkillName.Imbuing });
        }

        public SkillCodexBase(Serial serial)
            : base(serial)
        { }

        public override bool ValidateSkill(Mobile user, Skill skill, bool message)
        {
            if (user is PlayerMobile)
            {
                var pm = (PlayerMobile)user;

                if (skill.SkillName == SkillName.Spellweaving)
                {
                    if (!pm.Spellweaving)
                    {
                        if (message)
                        {
                            pm.SendMessage(
                                SuperGump.DefaultErrorHue,
                                "You must complete the Patience or Discipline quest chains to unlock {0}.",
                                skill.Name);
                        }

                        return false;
                    }
                }
            }

            return base.ValidateSkill(user, skill, message);
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            var version = 0;

            writer.Write(version);

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            var version = reader.ReadInt();

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }
    }

    public abstract class SkillCodexFixedBase : SkillCodexBase
    {
        public SkillCodexFixedBase(int count, double value)
            : base(count, value, true, SkillCodexMode.Fixed, SkillCodexFlags.Base)
        { }

        public SkillCodexFixedBase(Serial serial)
            : base(serial)
        { }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            var version = 0;

            writer.Write(version);

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            var version = reader.ReadInt();

            switch (version)
            {
                case 0:
                    { }
                    break;
            }
        }
    }
}

namespace VitaNex.Items
{
public enum SkillCodexFlags : byte
{
Base = 0x00,
Cap = 0x01,
Both = 0x02
}

public enum SkillCodexMode : byte
{
Fixed = 0x00,
Increase = 0x01,
Decrease = 0x02
}

public class SkillCodex : Item
{
private SuperGump SelectionGump { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public SkillCodexMode Mode { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public SkillCodexFlags Flags { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public int Count { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public double Value { get; set; }

[CommandProperty(AccessLevel.GameMaster)]
public int ValueFixed { get { return (int)(Value * 10); } set { Value = value / 10; } }

[CommandProperty(AccessLevel.GameMaster)]
public bool DeleteWhenEmpty { get; set; }

public List<SkillName> IgnoredSkills { get; protected set; }
public List<SkillName> SelectedSkills { get; protected set; }

[Constructable]
public SkillCodex()
: this(1)
{ }

[Constructable]
public SkillCodex(int count)
: this(count, 100.0)
{ }

[Constructable]
public SkillCodex(int count, double value)
: this(count, value, true)
{ }

[Constructable]
public SkillCodex(int count, double value, bool deleteWhenEmpty)
: this(count, value, deleteWhenEmpty, SkillCodexMode.Fixed)
{ }

[Constructable]
public SkillCodex(int count, double value, bool deleteWhenEmpty, SkillCodexMode mode)
: this(count, value, deleteWhenEmpty, mode, SkillCodexFlags.Base)
{ }

[Constructable]
public SkillCodex(int count, double value, bool deleteWhenEmpty, SkillCodexMode mode, SkillCodexFlags flags)
: base(8793)
{
SelectedSkills = new List<SkillName>();
IgnoredSkills = new List<SkillName>();

Mode = mode;
Flags = flags;
Count = count;
Value = value;
DeleteWhenEmpty = deleteWhenEmpty;

Name = "Codex of Wisdom";
LootType = LootType.Blessed;
Stackable = false;
}

public SkillCodex(Serial serial)
: base(serial)
{ }

public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);

string html = String.Empty, flags = String.Empty;

html += String.Format("<basefont color=#{0:X6}>Use: ", Color.Cyan.ToArgb());

switch (Flags)
{
case SkillCodexFlags.Base:
flags = "value";
break;
case SkillCodexFlags.Cap:
flags = "cap";
break;
case SkillCodexFlags.Both:
flags = "value and cap";
break;
}

switch (Mode)
{
case SkillCodexMode.Increase:
{
html += String.Format(
"Increase {0} skill{1} {2} by {3:F2}%", Count, Count == 1 ? String.Empty : "s", flags, Value);
}
break;
case SkillCodexMode.Decrease:
{
html += String.Format(
"Decrease {0} skill{1} {2} by {3:F2}%", Count, Count == 1 ? String.Empty : "s", flags, Value);
}
break;
case SkillCodexMode.Fixed:
{
html += String.Format("Set {0} skill{1} {2} to {3:F2}%", Count, Count == 1 ? String.Empty : "s", flags, Value);
}
break;
}

list.Add(html);
}

public override void OnDoubleClick(Mobile from)
{
if (from == null || from.Deleted || !Validate(from, true))
{
return;
}

SelectSkills(from);
InvalidateProperties();
}

public virtual bool ValidateSkill(Mobile user, Skill skill, bool message)
{
if (user == null || user.Deleted || skill == null)
{
return false;
}

switch (Mode)
{
case SkillCodexMode.Increase:
{
if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
if (user.SkillsTotal + ValueFixed > user.SkillsCap)
{
if (!CanReduceSkills(user))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already know everything this codex can offer, reduce some skills to make room for more knowledge.");
}

return false;
}
}

if (skill.IsCapped() || skill.WillCap(Value, false))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue, "You already know everything this codex can offer about {0}.", skill.Name);
}

return false;
}

if (!skill.IsLocked(SkillLock.Up))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "The skill {0} is locked.", skill.Name);
}

return false;
}
}
}
break;
case SkillCodexMode.Decrease:
{
if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
if (user.SkillsTotal - ValueFixed < 0)
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "You already forgot everything this codex can offer.");
}

return false;
}

if (skill.IsZero() || skill.WillZero(Value, false))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already forgot everything this codex can offer about {0}, any further and you'll forget how to breath!",
skill.Name);
}

return false;
}

if (!skill.IsLocked(SkillLock.Down))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "The skill {0} is locked.", skill.Name);
}

return false;
}
}
}
break;
case SkillCodexMode.Fixed:
{
if (Flags == SkillCodexFlags.Cap)
{
if (skill.CapFixedPoint == ValueFixed)
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue, "You already know everything this codex can offer about {0}.", skill.Name);
}

return false;
}
}

if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
if (ValueFixed < skill.BaseFixedPoint)
{
if (user.SkillsTotal - (skill.BaseFixedPoint - ValueFixed) < 0)
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already forgot everything this codex can offer, any further and you'll forget how to breath!");
}

return false;
}
}
else if (ValueFixed > skill.BaseFixedPoint)
{
if (user.SkillsTotal + (ValueFixed - skill.BaseFixedPoint) > user.SkillsCap)
{
if (!CanReduceSkills(user))
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue,
"You already know everything this codex can offer, reduce some skills to make room for more knowledge.");
}

return false;
}
}
}
else
{
if (message)
{
user.SendMessage(
SuperGump.DefaultErrorHue, "You already know everything this codex can offer about {0}.", skill.Name);
}

return false;
}

if (skill.IsLocked(SkillLock.Locked))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "The skill {0} is locked.", skill.Name);
}

return false;
}
}
}
break;
}

return true;
}

public virtual bool Validate(Mobile user, bool message)
{
if (user == null || user.Deleted || !user.CanSee(this))
{
return false;
}

if (!IsChildOf(user.Backpack))
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "This codex must be in your backpack to read it.");
}

return false;
}

if (Count <= 0)
{
if (message)
{
user.SendMessage(SuperGump.DefaultErrorHue, "This codex does not contain any skills to learn.");
}

return false;
}

return true;
}

public virtual void SelectSkills(Mobile user)
{
if (user == null || user.Deleted || !Validate(user, true) || !(user is PlayerMobile))
{
return;
}

if (SelectionGump != null)
{
SelectionGump.Close(true);
}

SelectionGump = new SkillSelectionGump(
user as PlayerMobile,
null,
Count,
null,
null,
skills =>
{
if (!ApplySkills(user, skills))
{
SelectSkills(user);
}
},
IgnoredSkills.ToArray()).Send();
}

public virtual bool ApplySkills(Mobile user, SkillName[] skills)
{
if (user == null || user.Deleted || skills == null || skills.Length == 0 || !Validate(user, true))
{
return false;
}

foreach (SkillName sn in skills)
{
if (user.Deleted || !Validate(user, true))
{
return false;
}

Skill skill = user.Skills[sn];

if (!ValidateSkill(user, skill, true))
{
continue;
}

bool charge = false;

if (Flags == SkillCodexFlags.Cap || Flags == SkillCodexFlags.Both)
{
switch (Mode)
{
case SkillCodexMode.Increase:
{
skill.IncreaseCap(Value);
}
break;
case SkillCodexMode.Decrease:
{
skill.DecreaseCap(Value);
}
break;
case SkillCodexMode.Fixed:
{
skill.SetCap(Value);
}
break;
}

if (Flags != SkillCodexFlags.Both)
{
EndApply(skill);
return true;
}

charge = true;
}

if (Flags == SkillCodexFlags.Base || Flags == SkillCodexFlags.Both)
{
charge = false;

switch (Mode)
{
case SkillCodexMode.Increase:
{
if (user.SkillsTotal + ValueFixed > user.SkillsCap)
{
if (TryReduceSkills(user) && skill.IncreaseBase(Value))
{
charge = true;
}
}
else if (skill.IncreaseBase(Value))
{
charge = true;
}
}
break;
case SkillCodexMode.Decrease:
{
if (skill.DecreaseBase(Value))
{
charge = true;
}
}
break;
case SkillCodexMode.Fixed:
{
if (ValueFixed > skill.BaseFixedPoint)
{
if (user.SkillsTotal + ValueFixed > user.SkillsCap)
{
if (TryReduceSkills(user) && skill.SetBase(Value))
{
charge = true;
}
}
else if (skill.SetBase(Value))
{
charge = true;
}
}
else if (ValueFixed < skill.BaseFixedPoint && skill.SetBase(Value))
{
charge = true;
}
}
break;
}
}

if (charge)
{
EndApply(skill);
}
}

return true;
}

protected void EndApply(Skill skill)
{
skill.Normalize();
UseCharges();

if (Count <= 0)
{
if (DeleteWhenEmpty)
{
Delete();
}
}
}

protected bool CanReduceSkills(Mobile user)
{
int target = (user.SkillsTotal + ValueFixed) - user.SkillsCap;
int canReduceBy = 0;

foreach (Skill s in user.Skills)
{
if (s.IsLocked(SkillLock.Down))
{
if (canReduceBy + s.BaseFixedPoint > target)
{
canReduceBy += (target - canReduceBy);
}
else
{
canReduceBy += s.BaseFixedPoint;
}
}

if (canReduceBy >= target)
{
return true;
}
}

return false;
}

protected bool TryReduceSkills(Mobile user)
{
if (!CanReduceSkills(user))
{
return false;
}

int target = (user.SkillsTotal + ValueFixed) - user.SkillsCap;
int reducedBy = 0;

foreach (Skill s in user.Skills)
{
if (s.IsLocked(SkillLock.Down))
{
if (reducedBy + s.BaseFixedPoint > target)
{
int diff = (target - reducedBy);

if (s.DecreaseBase(diff / 10))
{
reducedBy += diff;
}
}
else
{
if (s.SetBase(0))
{
reducedBy += s.BaseFixedPoint;
}
}
}

if (reducedBy >= target)
{
return true;
}
}

return false;
}

public virtual void UseCharges(int count = 1)
{
Count = Math.Max(0, Count - count);
InvalidateProperties();
}

public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);

int version = writer.SetVersion(1);

switch (version)
{
case 1:
{
writer.WriteFlag(Mode);
writer.WriteFlag(Flags);
writer.Write(Count);
writer.Write(Value);
writer.Write(DeleteWhenEmpty);
writer.WriteList(IgnoredSkills, skill => writer.WriteFlag(skill));
}
break;
case 0:
{
writer.Write((byte)Mode);
writer.Write((byte)Flags);
writer.Write(Count);
writer.Write(Value);
writer.Write(DeleteWhenEmpty);
writer.WriteList(IgnoredSkills, skill => writer.Write((short)skill));
}
break;
}
}

public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);

int version = reader.GetVersion();

switch (version)
{
case 1:
{
Mode = reader.ReadFlag<SkillCodexMode>();
Flags = reader.ReadFlag<SkillCodexFlags>();
Count = reader.ReadInt();
Value = reader.ReadDouble();
DeleteWhenEmpty = reader.ReadBool();
IgnoredSkills = reader.ReadList(r => r.ReadFlag<SkillName>());
}
break;
case 0:
{
Mode = (SkillCodexMode)reader.ReadByte();
Flags = (SkillCodexFlags)reader.ReadByte();
Count = reader.ReadInt();
Value = reader.ReadDouble();
DeleteWhenEmpty = reader.ReadBool();
IgnoredSkills = reader.ReadList(() => (SkillName)reader.ReadShort());
}
break;
}
}
}
}


Edit - I ended up making my own skill thingies. They aren't as nice as yours but they are still pretty cool and get the job done.  ;)
« Last Edit: February 14, 2015, 09:21:34 AM by Greed »

 

Download VNc

Recent Topics

Vita-Nex: Core 4.0.0.0 Released by Vorspire
[January 15, 2017, 08:56:41 PM]


Effects Help by Vorspire
[January 15, 2017, 06:47:33 PM]


Ultima Online Phoenix is Ready to Begin! by Abracadabra2.0
[December 13, 2016, 01:14:49 AM]


How To: Deceit Braziers Spawn/Despawn by Abracadabra2.0
[November 26, 2016, 07:34:13 PM]


Installing VNC 3.0.0.1 by Johnny
[August 27, 2016, 06:49:40 PM]


JSON Web Stats Stuck Problem by Argalep
[May 27, 2016, 06:16:55 AM]


Modules not Working after being Enabled by ProfessorChaos
[May 19, 2016, 02:44:06 AM]


Issues Installing VitaNex Core 3.0.0.1 on RunUO 2.7 by ProfessorChaos
[May 18, 2016, 09:30:37 PM]


ADM Assistance by Vorspire
[May 18, 2016, 09:23:25 PM]


Suggestion by Vorspire
[April 24, 2016, 06:23:15 PM]

Comments

Refresh History
  • Moderated
  • cmileto: pls delete my comment
    June 08, 2017, 01:03:35 AM
  • cmileto: ServUO - [https://www.servuo.com] Version 0.5, Build 6363.36277 Core: Optimizing for 4 64-bit processors RandomImpl: CSPRandom (Software) Core: Loading config... Scripts: Compiling C# scripts...Failed with: 1 errors, 1 warnings Warnings:  + Clayton/WorldOmniporter/WorldOmniporter.cs:     CS0162: Line 324: Unreachable code detected     CS0168: Line 957: The variable 'e' is declared but never used Errors:  + Clayton/Vita/Mobiles/Vendors/Advanced/AdvancedVendor.cs:     CS1501: Line 530: No overload for method 'GetSellPriceFor' takes 1 arguments     CS1501: Line 634: No overload for method 'GetBuyPriceFor' takes 1 arguments     CS1501: Line 1127: No overload for method 'GetSellPriceFor' takes 1 arguments Scripts: One or more scripts failed to compile or no script files were found.  - Press return to exit, or R to try again.
    June 04, 2017, 05:37:10 AM
  • Terrapin: Hello - and thanks - thought I would check VNC out since using it in JustUO server...
    April 22, 2015, 10:20:17 PM
  • Vorspire: Hello!
    December 16, 2014, 07:11:55 PM
  • Tek: Hello
    December 15, 2014, 08:51:25 AM
  • magnus_mythos: hello
    November 18, 2014, 05:30:22 AM
  • Antares_UO: thanks Vospire
    June 15, 2014, 06:52:17 PM
  • jezika: Thank you is not enough Vorspire! This system is exactly what I was looking for.
    June 04, 2014, 06:01:11 AM
  • Vorspire: VNc 2.1.1.0 Released!
    March 10, 2014, 01:33:06 AM
  • Vorspire: VNc 2.1.0.0 Released!
    January 27, 2014, 12:57:51 PM
  • Kassandra: Many thanks for building my shard for me.  It is awesome, I'm extremely pleased with what you've done and the ongoing support!!!
    November 20, 2013, 01:31:08 AM
  • Regnak: Great news ! Thanks Vorspire :)
    November 16, 2013, 01:55:16 PM
  • Vorspire: VNc: 2.1.0.0 is being developed!
    November 13, 2013, 08:38:35 AM
  • Vorspire: VNc 2.0.0.5 Released!
    September 11, 2013, 12:49:42 AM
  • Vorspire: VNc 2.0.0.4 Released!
    August 23, 2013, 12:47:54 AM
  • Vorspire: VNc 2.0.0.3 Released!
    July 05, 2013, 12:50:13 AM
  • Kaemalux: :-)
    July 01, 2013, 01:51:13 PM
  • Vorspire: VNc 2.0.0.2 Released!
    June 20, 2013, 08:29:19 PM
  • scrlked: I am trying it out on my shard. This is taking UO to the next level.
    June 13, 2013, 11:11:16 AM
  • Vorspire: VNc 2.0.0.0 Released!
    June 03, 2013, 12:53:33 AM

Carbonate design by Bloc
variant: carbon
SMF 2.0.11 | SMF © 2015, Simple Machines
SimplePortal 2.3.6 © 2008-2014, SimplePortal