Skip to content

Commit

Permalink
Fix issues with Specialized Skills (#3040)
Browse files Browse the repository at this point in the history
* Fix issue with Aug Spec Skills

* Fix issue with specialized skill credit limit

* Update PropertyBool.cs

* Update appveyor.yml
  • Loading branch information
LtRipley36706 authored Jun 27, 2020
1 parent ac9cf22 commit 05522ab
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 48 deletions.
8 changes: 8 additions & 0 deletions Source/ACE.Entity/Enum/Properties/PropertyBool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ public enum PropertyBool : ushort
UntrainedSkills = 9004,
[Ephemeral][ServerOnly]
IsEnvoy = 9005,
[ServerOnly]
UnspecializedSkills = 9006,
[ServerOnly]
FreeSkillResetRenewed = 9007,
[ServerOnly]
FreeAttributeResetRenewed = 9008,
[ServerOnly]
SkillTemplesTimerReset = 9009,
}

public static class PropertyBoolExtensions
Expand Down
111 changes: 67 additions & 44 deletions Source/ACE.Server/Command/Handlers/DeveloperFixCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,38 +267,7 @@ public static void HandleVerifySkills(Session session, params string[] parameter
}
else
{
var augProp = 0;
var augType = AugmentationType.None;
switch (skill.Key)
{

case Skill.ArmorTinkering:
augType = AugmentationType.ArmorTinkering;
augProp = player.GetProperty(PropertyInt.AugmentationSpecializeArmorTinkering) ?? 0;
break;

case Skill.ItemTinkering:
augType = AugmentationType.ItemTinkering;
augProp = player.GetProperty(PropertyInt.AugmentationSpecializeItemTinkering) ?? 0;
break;

case Skill.MagicItemTinkering:
augType = AugmentationType.MagicItemTinkering;
augProp = player.GetProperty(PropertyInt.AugmentationSpecializeMagicItemTinkering) ?? 0;
break;

case Skill.WeaponTinkering:
augType = AugmentationType.WeaponTinkering;
augProp = player.GetProperty(PropertyInt.AugmentationSpecializeWeaponTinkering) ?? 0;
break;

case Skill.Salvaging:
augType = AugmentationType.Salvage;
augProp = player.GetProperty(PropertyInt.AugmentationSpecializeSalvaging) ?? 0;
break;
}

if (skill.Value.InitLevel != 10 && augProp == 0)
if (skill.Value.InitLevel != 10)
{
Console.WriteLine($"{player.Name} has {sac} skill {skill.Key} with {skill.Value.InitLevel:N0} InitLevel{fixStr}");
foundIssues = true;
Expand All @@ -307,18 +276,6 @@ public static void HandleVerifySkills(Session session, params string[] parameter
{
skill.Value.InitLevel = 10;

updated = true;
}
}
else if (skill.Value.InitLevel == 10 && augProp == 1)
{
Console.WriteLine($"{player.Name} has {sac} skill {skill.Key} with {skill.Value.InitLevel:N0} InitLevel as a result of {augType} augmentation{fixStr}");
foundIssues = true;

if (fix)
{
skill.Value.InitLevel = 0;

updated = true;
}
}
Expand Down Expand Up @@ -405,6 +362,8 @@ public static void HandleVerifySkillCredits(Session session, params string[] par

var used = 0;

var specCreditsSpent = 0;

foreach (var skill in new Dictionary<Skill, PropertiesSkill>(player.Biota.PropertiesSkill))
{
var sac = skill.Value.SAC;
Expand Down Expand Up @@ -435,6 +394,8 @@ public static void HandleVerifySkillCredits(Session session, params string[] par
}

used += skillInfo.UpgradeCostFromTrainedToSpecialized;

specCreditsSpent += skillInfo.SpecializedCost;
}
}

Expand Down Expand Up @@ -464,6 +425,20 @@ public static void HandleVerifySkillCredits(Session session, params string[] par
continue;
}

if (specCreditsSpent > 70)
{
// if the player has already spent more skill credits than they should have,
// unfortunately this situation requires a partial reset..

Console.WriteLine($"{player.Name} has spent {specCreditsSpent} skill credits on specalization, {specCreditsSpent - 70} over the limit of 70. To fix this situation, specialized skill reset will need to be applied{fixStr}");
foundIssues = true;

if (fix)
UnspecializeSkills(player);

continue;
}

var availableCredits = player.GetProperty(PropertyInt.AvailableSkillCredits) ?? 0;

if (availableCredits != targetCredits)
Expand Down Expand Up @@ -590,6 +565,54 @@ private static void UntrainSkills(OfflinePlayer player, int targetCredits)
player.SaveBiotaToDatabase();
}

/// <summary>
/// This method is only required if the player is found to be over the spec skill limit of 70 credits
/// </summary>
private static void UnspecializeSkills(OfflinePlayer player)
{
long refundXP = 0;

int refundedCredits = 0;

foreach (var skill in new Dictionary<Skill, PropertiesSkill>(player.Biota.PropertiesSkill))
{
if (!DatManager.PortalDat.SkillTable.SkillBaseHash.TryGetValue((uint)skill.Key, out var skillBase))
{
Console.WriteLine($"{player.Name}.UntrainSkills({skill.Key}) - unknown skill");
continue;
}

var sac = skill.Value.SAC;

if (sac != SkillAdvancementClass.Specialized || !Player.IsSkillSpecializedViaAugmentation(skill.Key))
continue;

refundXP += skill.Value.PP;

skill.Value.SAC = SkillAdvancementClass.Trained;
skill.Value.InitLevel = 0;
skill.Value.PP = 0;
skill.Value.LevelFromPP = 0;

refundedCredits += skillBase.UpgradeCostFromTrainedToSpecialized;
}

var availableExperience = player.GetProperty(PropertyInt64.AvailableExperience) ?? 0;

player.SetProperty(PropertyInt64.AvailableExperience, availableExperience + refundXP);

var availableSkillCredits = player.GetProperty(PropertyInt.AvailableSkillCredits) ?? 0;

player.SetProperty(PropertyInt.AvailableSkillCredits, availableSkillCredits + refundedCredits);

player.SetProperty(PropertyBool.UnspecializedSkills, true);

player.SetProperty(PropertyBool.FreeSkillResetRenewed, true);
player.SetProperty(PropertyBool.SkillTemplesTimerReset, true);

player.SaveBiotaToDatabase();
}


[CommandHandler("verify-heritage-augs", AccessLevel.Admin, CommandHandlerFlag.ConsoleInvoke, "Verifies all players have their heritage augs.")]
public static void HandleVerifyHeritageAugs(Session session, params string[] parameters)
Expand Down
2 changes: 1 addition & 1 deletion Source/ACE.Server/WorldObjects/AugmentationDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void DoAugmentation(Player player)
{
var playerSkill = player.GetCreatureSkill(AugTypeHelper.GetSkill(type));
playerSkill.AdvancementClass = SkillAdvancementClass.Specialized;
//playerSkill.InitLevel = 10;
playerSkill.InitLevel = 10;
// adjust rank?
// handle overages?
// if trained skill is maxed, there will be a ~103m xp overage...
Expand Down
4 changes: 4 additions & 0 deletions Source/ACE.Server/WorldObjects/Player_Networking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ public void PlayerEnterWorld()

HandleMissingXp();
HandleSkillCreditRefund();
HandleSkillTemplesReset();
HandleSkillSpecCreditRefund();
HandleFreeSkillResetRenewal();
HandleFreeAttributeResetRenewal();

if (PlayerKillerStatus == PlayerKillerStatus.PKLite && !PropertyManager.GetBool("pkl_server").Item)
{
Expand Down
86 changes: 86 additions & 0 deletions Source/ACE.Server/WorldObjects/Player_Skills.cs
Original file line number Diff line number Diff line change
Expand Up @@ -585,11 +585,24 @@ public void HandleDBUpdates()
Skill.Salvaging
};

public static List<Skill> AugSpecSkills = new List<Skill>()
{
Skill.ArmorTinkering,
Skill.ItemTinkering,
Skill.MagicItemTinkering,
Skill.WeaponTinkering,
Skill.Salvaging
};

public static bool IsSkillUntrainable(Skill skill)
{
return !AlwaysTrained.Contains(skill);
}

public static bool IsSkillSpecializedViaAugmentation(Skill skill)
{
return !AugSpecSkills.Contains(skill);
}

public override bool GetHeritageBonus(WorldObject weapon)
{
Expand Down Expand Up @@ -715,6 +728,79 @@ public void HandleSkillCreditRefund()
actionChain.EnqueueChain();
}

public void HandleSkillSpecCreditRefund()
{
if (!(GetProperty(PropertyBool.UnspecializedSkills) ?? false)) return;

var actionChain = new ActionChain();
actionChain.AddDelaySeconds(5.0f);
actionChain.AddAction(this, () =>
{
Session.Network.EnqueueSend(new GameMessageSystemChat("Your specialized skills have been unspecialized due to an error with skill credits.\nYou have received a refund for these skill credits and experience.", ChatMessageType.Broadcast));

RemoveProperty(PropertyBool.UnspecializedSkills);
});
actionChain.EnqueueChain();
}

public void HandleFreeSkillResetRenewal()
{
if (!(GetProperty(PropertyBool.FreeSkillResetRenewed) ?? false)) return;

var actionChain = new ActionChain();
actionChain.AddDelaySeconds(5.0f);
actionChain.AddAction(this, () =>
{
Session.Network.EnqueueSend(new GameMessageSystemChat("Your opportunity to change your skills is renewed! Visit Fianhe to reset your skills.", ChatMessageType.Magic));

RemoveProperty(PropertyBool.FreeSkillResetRenewed);

QuestManager.Erase("UsedFreeSkillReset");
});
actionChain.EnqueueChain();
}

public void HandleFreeAttributeResetRenewal()
{
if (!(GetProperty(PropertyBool.FreeAttributeResetRenewed) ?? false)) return;

var actionChain = new ActionChain();
actionChain.AddDelaySeconds(5.0f);
actionChain.AddAction(this, () =>
{
// Your opportunity to change your attributes is renewed! Visit Chafulumisa to reset your skills [sic attributes].
Session.Network.EnqueueSend(new GameMessageSystemChat("Your opportunity to change your attributes is renewed! Visit Chafulumisa to reset your attributes.", ChatMessageType.Magic));

RemoveProperty(PropertyBool.FreeAttributeResetRenewed);

QuestManager.Erase("UsedFreeAttributeReset");
});
actionChain.EnqueueChain();
}

public void HandleSkillTemplesReset()
{
if (!(GetProperty(PropertyBool.SkillTemplesTimerReset) ?? false)) return;

var actionChain = new ActionChain();
actionChain.AddDelaySeconds(5.0f);
actionChain.AddAction(this, () =>
{
Session.Network.EnqueueSend(new GameMessageSystemChat("The Temples of Forgetfulness and Enlightenment have had the timer for their use reset due to skill changes.", ChatMessageType.Magic));

RemoveProperty(PropertyBool.SkillTemplesTimerReset);

QuestManager.Erase("ForgetfulnessGems1");
QuestManager.Erase("ForgetfulnessGems2");
QuestManager.Erase("ForgetfulnessGems3");
QuestManager.Erase("ForgetfulnessGems4");
QuestManager.Erase("Forgetfulness6days");
QuestManager.Erase("Forgetfulness13days");
QuestManager.Erase("Forgetfulness20days");
});
actionChain.EnqueueChain();
}

/// <summary>
/// Resets the skill, refunds all experience and skill credits, if allowed.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions Source/ACE.Server/WorldObjects/SkillAlterationDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public bool VerifyRequirements(Player player, CreatureSkill skill, SkillBase ski
}

// ensure player won't exceed limit of 70 specialized credits after operation
if (GetTotalSpecializedCredits(player) + skillBase.UpgradeCostFromTrainedToSpecialized > 70)
if (GetTotalSpecializedCredits(player) + skillBase.SpecializedCost > 70)
{
player.Session.Network.EnqueueSend(new GameEventWeenieErrorWithString(player.Session, WeenieErrorWithString.TooManyCreditsInSpecializedSkills, skill.Skill.ToSentence()));
return false;
Expand Down Expand Up @@ -259,7 +259,7 @@ private int GetTotalSpecializedCredits(Player player)

var skill = DatManager.PortalDat.SkillTable.SkillBaseHash[(uint)kvp.Key];

specializedCreditsTotal += skill.UpgradeCostFromTrainedToSpecialized;
specializedCreditsTotal += skill.SpecializedCost;
}
}

Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 1.5.{build}
version: 1.6.{build}
pull_requests:
do_not_increment_build_number: true
skip_tags: true
Expand Down

0 comments on commit 05522ab

Please sign in to comment.