blizzless-diiis/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs

6175 lines
269 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//Blizzless Project 2022
using System;
//Blizzless Project 2022
using System.Collections.Generic;
//Blizzless Project 2022
using System.Linq;
//Blizzless Project 2022
using DiIiS_NA.Core.Logging;
//Blizzless Project 2022
using DiIiS_NA.LoginServer.Toons;
//Blizzless Project 2022
using DiIiS_NA.GameServer.ClientSystem;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
//Blizzless Project 2022
using GameBalance = DiIiS_NA.Core.MPQ.FileFormats.GameBalance;
//Blizzless Project 2022
using DiIiS_NA.Core.Storage;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.MapSystem;
//Blizzless Project 2022
using System.Threading;
//Blizzless Project 2022
using DiIiS_NA.Core.Storage.AccountDataBase.Entities;
//Blizzless Project 2022
using DiIiS_NA.Core.Extensions;
//Blizzless Project 2022
using DiIiS_NA.GameServer.Core.Types.Math;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Fields;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.ACD;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Text;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Player;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Skill;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.World;
//Blizzless Project 2022
using DiIiS_NA.Core.MPQ;
//Blizzless Project 2022
using DiIiS_NA.GameServer.Core.Types.SNO;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Quest;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Base;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Effect;
//Blizzless Project 2022
using DiIiS_NA.LoginServer.AccountsSystem;
//Blizzless Project 2022
using System.Drawing;
using System.Reflection;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.TickerSystem;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.SkillsSystem;
//Blizzless Project 2022
using DiIiS_NA.GameServer.Core.Types.TagMap;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.PowerSystem;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.AISystem.Brains;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.ItemsSystem;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Hirelings;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Fields.BlizzLess.Net.GS.Message.Fields;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.GameSystem;
//Blizzless Project 2022
using Google.ProtocolBuffers;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Animation;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Waypoint;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Trade;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Inventory;
//Blizzless Project 2022
using DiIiS_NA.Core.Helpers.Math;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Connection;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Artisan;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Portal;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Camera;
//Blizzless Project 2022
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Minions;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Pet;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Game;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Combat;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Hireling;
//Blizzless Project 2022
using DiIiS_NA.Core.Helpers.Hash;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Encounter;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.UI;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans;
using DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem;
using NHibernate.Util;
namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem;
public class Player : Actor, IMessageConsumer, IUpdateable
{
private static readonly Logger Logger = LogManager.CreateLogger();
/// <summary>
/// The ingame-client for player.
/// </summary>
public GameClient InGameClient { get; set; }
/// <summary>
/// The player index.
/// </summary>
public int PlayerIndex { get; private set; }
/// <summary>
/// The player index.
/// </summary>
public int PlayerGroupIndex { get; private set; }
/// <summary>
/// Current crafting NPC type(for learning recipes)
/// </summary>
public ArtisanType? CurrentArtisan { get; set; }
/// <summary>
/// The player's toon.
/// We need a better name /raist.
/// </summary>
public Toon Toon { get; private set; }
public float DecreaseUseResourcePercent = 0;
public int Level { get; private set; }
public int ParagonLevel { get; private set; }
public long ExperienceNext { get; private set; }
public List<Actor> Revived = new() { };
public bool LevelingBoosted { get; set; }
public int PreSceneId = -1;
public List<Actor> NecroSkeletons = new() { };
public bool ActiveSkeletons = false;
public Actor ActiveGolem = null;
public bool EnableGolem = false;
public bool IsInPvPWorld
{
get => World != null && World.IsPvP;
set { }
}
/// <summary>
/// Skillset for the player (or actually for player's toons class).
/// </summary>
public SkillSet SkillSet { get; private set; }
/// <summary>
/// The inventory of player's toon.
/// </summary>
public Inventory Inventory { get; private set; }
public int GearScore
{
get
{
if (Inventory == null)
return 0;
else
return Inventory.GetGearScore();
}
private set { }
}
public Actor PlayerDirectBanner = null;
public uint NewDynamicID(uint globalId, int pIndex = -1)
{
lock (RevealedObjects)
{
if (pIndex > -1)
return (uint)pIndex;
for (uint i = 9; i < 4123; i++)
if (!RevealedObjects.ContainsValue(i))
//Logger.Trace("adding GlobalId {0} -> DynID {1} to player {2}", globalId, i, this.Toon.Name);
return i;
return 0;
}
}
/// <summary>
/// ActorType = Player.
/// </summary>
public override ActorType ActorType => ActorType.Player;
/// <summary>
/// Revealed objects to player.
/// </summary>
public Dictionary<uint, uint> RevealedObjects = new();
public ConversationManager Conversations { get; private set; }
public int SpecialComboIndex = 0;
// Collection of items that only the player can see. This is only used when items drop from killing an actor
// TODO: Might want to just have a field on the item itself to indicate whether it is visible to only one player
/// <summary>
/// Dropped items for the player
/// </summary>
public Dictionary<uint, Item> GroundItems { get; private set; }
/// <summary>
/// Everything connected to ExpBonuses.
/// </summary>
public ExpBonusData ExpBonusData { get; private set; }
public bool EventWeatherEnabled { get; set; }
public bool BlacksmithUnlocked { get; set; }
public bool JewelerUnlocked { get; set; }
public bool MysticUnlocked { get; set; }
public bool KanaiUnlocked { get; set; }
public bool HirelingTemplarUnlocked { get; set; }
public bool HirelingScoundrelUnlocked { get; set; }
public bool HirelingEnchantressUnlocked { get; set; }
public int LastMovementTick = 0;
public int _spiritGenHit = 0;
public int _SpiritGeneratorHit
{
get => _spiritGenHit;
set
{
_spiritGenHit = value;
if (SkillSet.HasPassive(315271) && _spiritGenHit >= 3) //Mythic Rhythm
{
World.BuffManager.AddBuff(this, this, new MythicRhythmBuff());
_spiritGenHit = 0;
}
}
}
/// <summary>
/// NPC currently interaced with
/// </summary>
public InteractiveNPC SelectedNPC { get; set; }
public Dictionary<uint, ActorSno> Followers { get; private set; }
private Hireling _activeHireling = null;
private Hireling _questHireling = null;
public Hireling ActiveHireling
{
get => _activeHireling;
set
{
if (value == null)
{
HirelingId = null;
lock (Toon.DBToon)
{
var dbToon = Toon.DBToon;
dbToon.ActiveHireling = null;
DBSessions.SessionUpdate(dbToon);
}
}
else if (value != _activeHireling)
{
HirelingId = value.Attributes[GameAttribute.Hireling_Class];
lock (Toon.DBToon)
{
var dbToon = Toon.DBToon;
dbToon.ActiveHireling = value.Attributes[GameAttribute.Hireling_Class];
DBSessions.SessionUpdate(dbToon);
}
}
if (value == _activeHireling && value != null)
return;
if (_activeHireling != null) _activeHireling.Dismiss();
_activeHireling = value;
}
}
public Hireling QuestHireling
{
get => _questHireling;
set
{
if (_questHireling != null) _questHireling.Dismiss();
_questHireling = value;
}
}
public int CurrentWingsPowerId = -1;
private int _lastResourceUpdateTick;
private float _CurrentHPValue = -1f;
private float _CurrentResourceValue = -1f;
public int GoldCollectedTempCount = 0;
public int BloodShardsCollectedTempCount = 0;
public int KilledMonstersTempCount = 0;
public int KilledSeasonalTempCount = 0;
public int KilledElitesTempCount = 0;
public int BuffStreakKill = 0;
private ushort[] ParagonBonuses;
public int? HirelingId = null;
public bool IsCasting = false;
private Action CastResult = null;
private Action ConfirmationResult = null;
private const float SkillChangeCooldownLength = 10f;
/// <summary>
/// Creates a new player.
/// </summary>
/// <param name="world">The initial world player joins in.</param>
/// <param name="client">The gameclient for the player.</param>
/// <param name="bnetToon">Toon of the player.</param>
public Player(World world, GameClient client, Toon bnetToon)
: base(world,
bnetToon.Gender == 0
? (ActorSno)bnetToon.HeroTable.SNOMaleActor
: (ActorSno)bnetToon.HeroTable.SNOFemaleActor)
{
InGameClient = client;
PlayerIndex = Interlocked.Increment(ref InGameClient.Game.PlayerIndexCounter);
PlayerGroupIndex = InGameClient.Game.PlayerGroupIndexCounter;
Toon = bnetToon;
LevelingBoosted = Toon.LevelingBoosted;
var dbToon = Toon.DBToon;
HirelingId = dbToon.ActiveHireling;
GBHandle.Type = (int)ActorType.Player;
GBHandle.GBID = Toon.ClassID;
Level = dbToon.Level;
ParagonLevel = Toon.ParagonLevel;
ExperienceNext = Toon.ExperienceNext;
ParagonBonuses = dbToon.ParagonBonuses;
CurrentWingsPowerId = dbToon.WingsActive;
Field2 = 0x00000009;
Scale = ModelScale;
RotationW = 0.05940768f;
RotationAxis = new Vector3D(0f, 0f, 0.9982339f);
Field7 = -1;
NameSNO = ActorSno.__NONE;
Field10 = 0x0;
Dead = false;
EventWeatherEnabled = false;
var achievements =
InGameClient.Game.GameDbSession.SessionQueryWhere<DBAchievements>(dba =>
dba.DBGameAccount.Id == Toon.GameAccount.PersistentID);
BlacksmithUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307766);
JewelerUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307780);
MysticUnlocked = achievements.Any(dba => dba.AchievementId == 74987247205955);
KanaiUnlocked = achievements.Where(dba => dba.AchievementId == 74987254626662)
.SelectMany(x => AchievementSystem.AchievementManager.UnserializeBytes(x.Criteria))
.Any(x => x == unchecked((uint)74987252674266));
if (Level >= 70)
GrantCriteria(74987254853541);
HirelingTemplarUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307073);
HirelingScoundrelUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307147);
HirelingEnchantressUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307145);
SkillSet = new SkillSet(this, Toon.Class, Toon);
GroundItems = new Dictionary<uint, Item>();
Followers = new Dictionary<uint, ActorSno>();
Conversations = new ConversationManager(this);
ExpBonusData = new ExpBonusData(this);
SelectedNPC = null;
_lastResourceUpdateTick = 0;
SavePointData = new SavePointData() { snoWorld = -1, SavepointId = -1 };
// Attributes
if (World.Game.PvP)
Attributes[GameAttribute.TeamID] = PlayerIndex + 2;
else
Attributes[GameAttribute.TeamID] = 2;
//make sure if greater is not active enable banner.
if (!World.Game.NephalemGreater) Attributes[GameAttribute.Banner_Usable] = true;
SetAllStatsInCorrectOrder();
// Enabled stone of recall
if (!World.Game.PvP & Toon.StoneOfPortal)
EnableStoneOfRecall();
else if (InGameClient.Game.CurrentAct == 3000)
EnableStoneOfRecall();
var lores = UnserializeBytes(Toon.DBToon.Lore);
var num = 0;
foreach (var lore in lores)
{
LearnedLore.m_snoLoreLearned[num] = lore;
num++;
}
LearnedLore.Count = lores.Count();
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes.BroadcastChangedIfRevealed();
}
#region Attribute Setters
public void SetAllStatsInCorrectOrder()
{
SetAttributesSkills();
SetAttributesBuffs();
SetAttributesDamage();
SetAttributesRessources();
SetAttributesClassSpecific();
SetAttributesMovement();
SetAttributesMisc();
SetAttributesOther();
if (Inventory == null)
Inventory = new Inventory(this);
SetAttributesByItems(); //needs the Inventory
SetAttributesByItemProcs();
SetAttributesByGems();
SetAttributesByItemSets();
if (SkillSet == null)
SkillSet = new SkillSet(this, Toon.Class, Toon);
SetAttributesByPassives(); //needs the SkillSet
SetAttributesByParagon();
SetNewAttributes();
UpdatePercentageHP(PercHPbeforeChange);
}
public void SetAttributesSkills()
{
//Skills
Attributes[GameAttribute.SkillKit] = Toon.HeroTable.SNOSKillKit0;
Attributes[GameAttribute.Buff_Icon_Start_Tick0, 0x00033C40] = 153;
Attributes[GameAttribute.Buff_Icon_End_Tick0, 0x00033C40] = 3753;
Attributes[GameAttribute.Buff_Icon_Count0, 0x0006B48E] = 1;
Attributes[GameAttribute.Buff_Icon_Count0, 0x0004601B] = 1;
Attributes[GameAttribute.Buff_Icon_Count0, 0x00033C40] = 1;
Attributes[GameAttribute.Currencies_Discovered] = 0x0011FFF8;
Attributes[GameAttribute.Skill, 30592] = 1;
Attributes[GameAttribute.Resource_Degeneration_Prevented] = false;
Attributes[GameAttribute.Resource_Degeneration_Stop_Point] = 0;
//scripted //this.Attributes[GameAttribute.Skill_Total, 0x7545] = 1; //Axe Operate Gizmo
//scripted //this.Attributes[GameAttribute.Skill_Total, 0x76B7] = 1; //Punch!
//scripted //this.Attributes[GameAttribute.Skill_Total, 0x6DF] = 1; //Use Item
//scripted //this.Attributes[GameAttribute.Skill_Total, 0x7780] = 1; //Basic Attack
//scripted //this.Attributes[GameAttribute.Skill_Total, 0xFFFFF] = 1;
//this.Attributes[GameAttribute.Skill, 0xFFFFF] = 1;
}
public void SetAttributesBuffs()
{
//Buffs
Attributes[GameAttribute.Buff_Exclusive_Type_Active, 0x33C40] = true;
Attributes[GameAttribute.Buff_Icon_End_Tick0, 0x00033C40] = 0x000003FB;
Attributes[GameAttribute.Buff_Icon_Start_Tick0, 0x00033C40] = 0x00000077;
Attributes[GameAttribute.Buff_Icon_Count0, 0x00033C40] = 1;
Attributes[GameAttribute.Buff_Exclusive_Type_Active, 0xCE11] = true;
Attributes[GameAttribute.Buff_Icon_Count0, 0x0000CE11] = 1;
Attributes[GameAttribute.Buff_Visual_Effect, 0xFFFFF] = true;
//Wings
if (CurrentWingsPowerId != -1)
{
Attributes[GameAttribute.Buff_Exclusive_Type_Active, CurrentWingsPowerId] = true;
Attributes[GameAttribute.Power_Buff_0_Visual_Effect_None, CurrentWingsPowerId] = true;
Attributes[GameAttribute.Buff_Icon_Start_Tick0, CurrentWingsPowerId] = 0;
Attributes[GameAttribute.Buff_Icon_End_Tick0, CurrentWingsPowerId] = 100;
Attributes[GameAttribute.Buff_Icon_Count0, CurrentWingsPowerId] = 1;
}
}
public void SetAttributesDamage()
{
Attributes[GameAttribute.Primary_Damage_Attribute] = (int)Toon.HeroTable.CoreAttribute + 1;
Attributes[GameAttribute.Attacks_Per_Second_Percent_Cap] = 4f;
}
public void SetAttributesRessources()
{
Attributes[GameAttribute.Resource_Type_Primary] = (int)Toon.HeroTable.PrimaryResource + 1;
Attributes[GameAttribute.Resource_Max, Attributes[GameAttribute.Resource_Type_Primary] - 1] =
Toon.HeroTable.PrimaryResourceBase;
Attributes[GameAttribute.Resource_Max_Bonus, Attributes[GameAttribute.Resource_Type_Primary] - 1] = 0;
Attributes[GameAttribute.Resource_Factor_Level, Attributes[GameAttribute.Resource_Type_Primary] - 1] =
Toon.HeroTable.PrimaryResourceFactorLevel;
Attributes[GameAttribute.Resource_Percent, Attributes[GameAttribute.Resource_Type_Primary] - 1] = 0;
Attributes[GameAttribute.Resource_Cur, (int)Attributes[GameAttribute.Resource_Type_Primary]] =
GetMaxResource((int)Attributes[GameAttribute.Resource_Type_Primary] - 1);
var max = Attributes[GameAttribute.Resource_Max, (int)Attributes[GameAttribute.Resource_Type_Primary] - 1];
var cur = Attributes[GameAttribute.Resource_Cur, (int)Attributes[GameAttribute.Resource_Type_Primary] - 1];
Attributes[GameAttribute.Resource_Regen_Per_Second, (int)Attributes[GameAttribute.Resource_Type_Primary] - 1] =
Toon.HeroTable.PrimaryResourceRegen;
Attributes[GameAttribute.Resource_Regen_Stop_Regen] = false;
if (Toon.Class == ToonClass.Barbarian)
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource + 1] = 0;
else
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource + 1] =
(int)GetMaxResource((int)Toon.HeroTable.PrimaryResource + 1) * 100;
if (Toon.HeroTable.SecondaryResource != GameBalance.HeroTable.Resource.None)
{
Attributes[GameAttribute.Resource_Type_Secondary] = (int)Toon.HeroTable.SecondaryResource + 1;
Attributes[GameAttribute.Resource_Max, (int)Attributes[GameAttribute.Resource_Type_Secondary] - 1] =
Toon.HeroTable.SecondaryResourceBase;
Attributes[GameAttribute.Resource_Max_Bonus, Attributes[GameAttribute.Resource_Type_Secondary] - 1] = 0;
Attributes[GameAttribute.Resource_Percent, Attributes[GameAttribute.Resource_Type_Secondary] - 1] = 0;
Attributes[GameAttribute.Resource_Factor_Level,
(int)Attributes[GameAttribute.Resource_Type_Secondary] - 1] =
Toon.HeroTable.SecondaryResourceFactorLevel;
Attributes[GameAttribute.Resource_Cur, (int)Attributes[GameAttribute.Resource_Type_Secondary] - 1] =
GetMaxResource((int)Toon.HeroTable.SecondaryResource + 1);
Attributes[GameAttribute.Resource_Regen_Per_Second,
(int)Attributes[GameAttribute.Resource_Type_Secondary] - 1] = Toon.HeroTable.SecondaryResourceRegen;
}
Attributes[GameAttribute.Get_Hit_Recovery_Per_Level] = (int)Toon.HeroTable.GetHitRecoveryPerLevel;
Attributes[GameAttribute.Get_Hit_Recovery_Base] = (int)Toon.HeroTable.GetHitRecoveryBase;
Attributes[GameAttribute.Get_Hit_Max_Per_Level] = (int)Toon.HeroTable.GetHitMaxPerLevel;
Attributes[GameAttribute.Get_Hit_Max_Base] = (int)Toon.HeroTable.GetHitMaxBase;
}
public void SetAttributesClassSpecific()
{
// Class specific
switch (Toon.Class)
{
case ToonClass.Barbarian:
//scripted //this.Attributes[GameAttribute.Skill_Total, 30078] = 1; //Fury Trait
Attributes[GameAttribute.Skill, 30078] = 1;
Attributes[GameAttribute.Trait, 30078] = 1;
Attributes[GameAttribute.Buff_Exclusive_Type_Active, 30078] = true;
Attributes[GameAttribute.Buff_Icon_Count0, 30078] = 1;
break;
case ToonClass.DemonHunter:
break;
case ToonClass.Crusader:
Attributes[GameAttribute.Skill, 0x000418F2] = 1;
Attributes[GameAttribute.Skill, 0x00045CCF] = 1;
Attributes[GameAttribute.Skill, 0x000564D4] = 1;
break;
case ToonClass.Monk:
//scripted //this.Attributes[GameAttribute.Skill_Total, 0x0000CE11] = 1; //Spirit Trait
Attributes[GameAttribute.Skill, 0x0000CE11] = 1;
Attributes[GameAttribute.Trait, 0x0000CE11] = 1;
Attributes[GameAttribute.Buff_Exclusive_Type_Active, 0xCE11] = true;
Attributes[GameAttribute.Buff_Icon_Count0, 0x0000CE11] = 1;
break;
case ToonClass.WitchDoctor:
break;
case ToonClass.Wizard:
break;
}
}
public void SetAttributesMovement()
{
Attributes[GameAttribute.Movement_Scalar_Cap] = 3f;
Attributes[GameAttribute.Movement_Scalar] = 1f;
Attributes[GameAttribute.Walking_Rate] = Toon.HeroTable.WalkingRate;
Attributes[GameAttribute.Running_Rate] = Toon.HeroTable.RunningRate;
Attributes[GameAttribute.Experience_Bonus] = 0f;
Attributes[GameAttribute.Sprinting_Rate] = Toon.HeroTable.SprintRate * 2;
Attributes[GameAttribute.Strafing_Rate] = Toon.HeroTable.SprintRate * 2;
}
public void SetAttributesMisc()
{
//Miscellaneous
/*
this.Attributes[GameAttribute.Disabled] = false; // we should be making use of these ones too /raist.
this.Attributes[GameAttribute.Loading] = true;
this.Attributes[GameAttribute.Loading_Player_ACD] = this.PlayerIndex;
this.Attributes[GameAttribute.Invulnerable] = true;
this.Attributes[GameAttribute.Hidden] = false;
this.Attributes[GameAttribute.Immobolize] = true;
this.Attributes[GameAttribute.Untargetable] = true;
this.Attributes[GameAttribute.CantStartDisplayedPowers] = true;
this.Attributes[GameAttribute.IsContentRestrictedActor] = true;
this.Attributes[GameAttribute.Cannot_Dodge] = false;
this.Attributes[GameAttribute.Trait, 0x0000CE11] = 1;
this.Attributes[GameAttribute.Backpack_Slots] = 60;
this.Attributes[GameAttribute.General_Cooldown] = 0;
//*/
Attributes[GameAttribute.Disabled] = true; // we should be making use of these ones too /raist.
Attributes[GameAttribute.Loading] = true;
Attributes[GameAttribute.Loading_Player_ACD] = PlayerIndex;
Attributes[GameAttribute.Invulnerable] = true;
Attributes[GameAttribute.Hidden] = false;
Attributes[GameAttribute.Immobolize] = true;
Attributes[GameAttribute.Untargetable] = true;
Attributes[GameAttribute.CantStartDisplayedPowers] = true;
Attributes[GameAttribute.IsContentRestrictedActor] = true;
Attributes[GameAttribute.Cannot_Dodge] = false;
Attributes[GameAttribute.Trait, 0x0000CE11] = 1;
Attributes[GameAttribute.TeamID] = 2;
Attributes[GameAttribute.Stash_Tabs_Purchased_With_Gold] = 5; // what do these do?
Attributes[GameAttribute.Stash_Tabs_Rewarded_By_Achievements] = 5;
Attributes[GameAttribute.Backpack_Slots] = 60;
Attributes[GameAttribute.General_Cooldown] = 0;
}
public void SetAttributesByParagon()
{
// Until the Paragon 800 should be distributed on the 4 tabs,
// after that only in the first Core tab.
var baseParagonPoints = Math.Min(Toon.ParagonLevel, 800);
var extraParagonPoints = Math.Max(0, Toon.ParagonLevel - 800);
for (var i = 0; i < 4; i++)
{
Attributes[GameAttribute.Paragon_Bonus_Points_Available, i] = baseParagonPoints / 4;
// Process remainder only for base points.
if (i < baseParagonPoints % 4) Attributes[GameAttribute.Paragon_Bonus_Points_Available, i]++;
}
// First tab of Paragon (Core) - pos 0.
Attributes[GameAttribute.Paragon_Bonus_Points_Available, 0] += extraParagonPoints;
var assigned_bonuses = ParagonBonuses;
var bonus_ids = ItemGenerator.GetParagonBonusTable(Toon.Class);
foreach (var bonus in bonus_ids)
{
var slot_index = bonus.Category * 4 + bonus.Index - 1;
Attributes[GameAttribute.Paragon_Bonus_Points_Available, bonus.Category] -= assigned_bonuses[slot_index];
Attributes[GameAttribute.Paragon_Bonus, bonus.Hash] = assigned_bonuses[slot_index];
float result;
if (FormulaScript.Evaluate(bonus.AttributeSpecifiers[0].Formula.ToArray(), new ItemRandomHelper(0),
out result))
{
if (bonus.AttributeSpecifiers[0].AttributeId == 104) //Resistance_All
{
foreach (var damageType in DamageType.AllTypes)
Attributes[GameAttribute.Resistance, damageType.AttributeKey] +=
result * assigned_bonuses[slot_index];
}
else
{
if (bonus.AttributeSpecifiers[0].AttributeId == 133) result = 33f; //Hitpoints_Regen_Per_Second
if (bonus.AttributeSpecifiers[0].AttributeId == 342) result = 16.5f; //Hitpoints_On_Hit
if (GameAttribute.Attributes[bonus.AttributeSpecifiers[0].AttributeId] is GameAttributeF)
{
var attr = GameAttribute.Attributes[bonus.AttributeSpecifiers[0].AttributeId] as GameAttributeF;
if (bonus.AttributeSpecifiers[0].SNOParam != -1)
Attributes[attr, bonus.AttributeSpecifiers[0].SNOParam] +=
result * assigned_bonuses[slot_index];
else
Attributes[attr] += result * assigned_bonuses[slot_index];
}
else if (GameAttribute.Attributes[bonus.AttributeSpecifiers[0].AttributeId] is GameAttributeI)
{
var attr = GameAttribute.Attributes[bonus.AttributeSpecifiers[0].AttributeId] as GameAttributeI;
if (bonus.AttributeSpecifiers[0].SNOParam != -1)
Attributes[attr, bonus.AttributeSpecifiers[0].SNOParam] +=
(int)(result * assigned_bonuses[slot_index]);
else
Attributes[attr] += (int)(result * assigned_bonuses[slot_index]);
}
}
}
//Logger.Debug("Paragon attribute {0} - value {1}", bonus.Attribute[0].AttributeId, (result * assigned_bonuses[slot_index]));
}
}
public float PercHPbeforeChange = 0;
public void SetAttributesByItems()
{
const float nonPhysDefault = 0f; //was 3.051758E-05f
var MaxHPOld = Attributes[GameAttribute.Hitpoints_Max_Total];
var PercentOfOld = Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
PercHPbeforeChange = Attributes[GameAttribute.Hitpoints_Cur] /
(Attributes[GameAttribute.Hitpoints_Max_Total] / 100);
;
var damageAttributeMinValues = new Dictionary<DamageType, float[]>
{
{ DamageType.Physical, new[] { 2f, 2f } },
{ DamageType.Arcane, new[] { nonPhysDefault, nonPhysDefault } },
{ DamageType.Cold, new[] { nonPhysDefault, nonPhysDefault } },
{ DamageType.Fire, new[] { nonPhysDefault, nonPhysDefault } },
{ DamageType.Holy, new[] { nonPhysDefault, nonPhysDefault } },
{ DamageType.Lightning, new[] { nonPhysDefault, nonPhysDefault } },
{ DamageType.Poison, new[] { nonPhysDefault, nonPhysDefault } }
};
foreach (var damageType in DamageType.AllTypes)
{
//var weaponDamageMin = damageType.AttributeKey == 0 ? this.Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Min, 0) : (this.Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Min, 0) + Math.Max(this.Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Min, damageType.AttributeKey), damageAttributeMinValues[damageType][0]));
//var weaponDamageDelta = damageType.AttributeKey == 0 ? this.Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Min, 0) : (this.Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Delta, 0) + Math.Max(this.Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Delta, damageType.AttributeKey), damageAttributeMinValues[damageType][1]));
Attributes[GameAttribute.Damage_Weapon_Min, damageType.AttributeKey] =
Math.Max(Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Min_Total, damageType.AttributeKey),
damageAttributeMinValues[damageType][0]) +
Inventory.GetItemBonus(GameAttribute.Damage_Min, damageType.AttributeKey);
Attributes[GameAttribute.Damage_Weapon_Min, damageType.AttributeKey] -=
Inventory.AdjustDualWieldMin(damageType); //Damage on weapons should not add when dual-wielding
Attributes[GameAttribute.Damage_Weapon_Delta, damageType.AttributeKey] =
Math.Max(Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Delta_Total, damageType.AttributeKey),
damageAttributeMinValues[damageType][1]) +
Inventory.GetItemBonus(GameAttribute.Damage_Delta, damageType.AttributeKey);
Attributes[GameAttribute.Damage_Weapon_Delta, damageType.AttributeKey] -=
Inventory.AdjustDualWieldDelta(damageType); //Damage on weapons should not add when dual-wielding
Attributes[GameAttribute.Damage_Weapon_Bonus_Min, damageType.AttributeKey] = 0f;
Attributes[GameAttribute.Damage_Weapon_Bonus_Min_X1, damageType.AttributeKey] = 0f;
Attributes[GameAttribute.Damage_Weapon_Bonus_Delta, damageType.AttributeKey] = 0f;
Attributes[GameAttribute.Damage_Weapon_Bonus_Delta_X1, damageType.AttributeKey] = 0f;
Attributes[GameAttribute.Damage_Weapon_Bonus_Flat, damageType.AttributeKey] = 0f;
Attributes[GameAttribute.Damage_Type_Percent_Bonus, damageType.AttributeKey] =
Inventory.GetItemBonus(GameAttribute.Damage_Type_Percent_Bonus, damageType.AttributeKey);
Attributes[GameAttribute.Damage_Dealt_Percent_Bonus, damageType.AttributeKey] =
Inventory.GetItemBonus(GameAttribute.Damage_Dealt_Percent_Bonus, damageType.AttributeKey);
Attributes[GameAttribute.Resistance, damageType.AttributeKey] =
Inventory.GetItemBonus(GameAttribute.Resistance, damageType.AttributeKey);
Attributes[GameAttribute.Damage_Percent_Reduction_From_Type, damageType.AttributeKey] =
Inventory.GetItemBonus(GameAttribute.Damage_Percent_Reduction_From_Type, damageType.AttributeKey);
Attributes[GameAttribute.Amplify_Damage_Type_Percent, damageType.AttributeKey] =
Inventory.GetItemBonus(GameAttribute.Amplify_Damage_Type_Percent, damageType.AttributeKey);
}
for (var i = 0; i < 4; i++)
Attributes[GameAttribute.Damage_Percent_Bonus_Vs_Monster_Type, i] =
Inventory.GetItemBonus(GameAttribute.Damage_Percent_Bonus_Vs_Monster_Type, i);
Attributes[GameAttribute.Resistance_All] = Inventory.GetItemBonus(GameAttribute.Resistance_All);
Attributes[GameAttribute.Resistance_Percent_All] = Inventory.GetItemBonus(GameAttribute.Resistance_Percent_All);
Attributes[GameAttribute.Damage_Percent_Reduction_From_Melee] =
Inventory.GetItemBonus(GameAttribute.Damage_Percent_Reduction_From_Melee);
Attributes[GameAttribute.Damage_Percent_Reduction_From_Ranged] =
Inventory.GetItemBonus(GameAttribute.Damage_Percent_Reduction_From_Ranged);
Attributes[GameAttribute.Thorns_Fixed, 0] = Inventory.GetItemBonus(GameAttribute.Thorns_Fixed, 0);
//this.Attributes[GameAttribute.Armor_Item_Percent] = this.Inventory.GetItemBonus(GameAttribute.Armor_Item_Percent);
var allStatsBonus = Inventory.GetItemBonus(GameAttribute.Stats_All_Bonus); // / 1065353216;
/*
this.Attributes[GameAttribute.Armor_Item] = this.Inventory.GetItemBonus(GameAttribute.Armor_Item_Total);
this.Attributes[GameAttribute.Strength_Item] = this.Inventory.GetItemBonus(GameAttribute.Dexterity_Item);// / 1065353216;
this.Attributes[GameAttribute.Strength_Item] += allStatsBonus;
this.Attributes[GameAttribute.Dexterity_Item] = this.Inventory.GetItemBonus(GameAttribute.Intelligence_Item);// / 1065353216;
this.Attributes[GameAttribute.Dexterity_Item] += allStatsBonus;
this.Attributes[GameAttribute.Intelligence_Item] = this.Inventory.GetItemBonus(GameAttribute.Vitality_Item);// / 1065353216; //I know that's wild, but client can't display it properly...
this.Attributes[GameAttribute.Intelligence_Item] += allStatsBonus;
this.Attributes[GameAttribute.Vitality_Item] = this.Inventory.GetItemBonus(GameAttribute.Item_Level_Requirement_Reduction);// / 1065353216;
this.Attributes[GameAttribute.Vitality_Item] += allStatsBonus;
//*/
//*
Attributes[GameAttribute.Strength_Item] = Inventory.GetItemBonus(GameAttribute.Strength_Item); // / 1065353216;
Attributes[GameAttribute.Strength_Item] += allStatsBonus;
Attributes[GameAttribute.Vitality_Item] = Inventory.GetItemBonus(GameAttribute.Vitality_Item); // / 1065353216;
Attributes[GameAttribute.Vitality_Item] += allStatsBonus;
Attributes[GameAttribute.Dexterity_Item] =
Inventory.GetItemBonus(GameAttribute.Dexterity_Item); // / 1065353216;
Attributes[GameAttribute.Dexterity_Item] += allStatsBonus;
Attributes[GameAttribute.Intelligence_Item] =
Inventory.GetItemBonus(GameAttribute
.Intelligence_Item); // / 1065353216; //I know that's wild, but client can't display it properly...
Attributes[GameAttribute.Intelligence_Item] += allStatsBonus;
//*/
//this.Attributes[GameAttribute.Cube_Enchanted_Strength_Item] = 0;
Attributes[GameAttribute.Core_Attributes_From_Item_Bonus_Multiplier] = 1;
Attributes[GameAttribute.Hitpoints_Max_Percent_Bonus] =
Inventory.GetItemBonus(GameAttribute.Hitpoints_Max_Percent_Bonus);
Attributes[GameAttribute.Hitpoints_Max_Percent_Bonus_Item] =
Inventory.GetItemBonus(GameAttribute.Hitpoints_Max_Percent_Bonus_Item);
Attributes[GameAttribute.Hitpoints_Max_Bonus] = Inventory.GetItemBonus(GameAttribute.Hitpoints_Max_Bonus);
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource] =
Inventory.GetItemBonus(GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource);
Attributes[GameAttribute.Attacks_Per_Second] = Inventory.GetAPS();
Attributes[GameAttribute.Attacks_Per_Second_Percent] =
Inventory.GetItemBonus(GameAttribute.Attacks_Per_Second_Item_Percent) +
Inventory.GetItemBonus(GameAttribute.Attacks_Per_Second_Percent);
Attributes[GameAttribute.Attacks_Per_Second_Bonus] =
Inventory.GetItemBonus(GameAttribute.Attacks_Per_Second_Item_Bonus);
Attributes[GameAttribute.Attacks_Per_Second_Item] =
Inventory.GetItemBonus(GameAttribute.Attacks_Per_Second_Item);
var a = Attributes[GameAttribute.Attacks_Per_Second];
var b = Attributes[GameAttribute.Attacks_Per_Second_Percent];
var c = Attributes[GameAttribute.Attacks_Per_Second_Bonus];
var d = Attributes[GameAttribute.Attacks_Per_Second_Item];
var e = Attributes[GameAttribute.Attacks_Per_Second_Item_CurrentHand];
var f = Attributes[GameAttribute.Attacks_Per_Second_Item_Bonus];
var g = Attributes[GameAttribute.Attacks_Per_Second_Percent_Subtotal];
var h = Attributes[GameAttribute.Attacks_Per_Second_Percent_Cap];
var j = Attributes[GameAttribute.Attacks_Per_Second_Percent_Uncapped];
var k = Attributes[GameAttribute.Attacks_Per_Second_Percent_Reduction];
var o = Attributes[GameAttribute.Attacks_Per_Second_Total];
if (Attributes[GameAttribute.Attacks_Per_Second_Total] < 1)
Attributes[GameAttribute.Attacks_Per_Second] = 1.0f;
Attributes[GameAttribute.Crit_Percent_Bonus_Capped] =
Inventory.GetItemBonus(GameAttribute.Crit_Percent_Bonus_Capped);
Attributes[GameAttribute.Weapon_Crit_Chance] = 0.05f + Inventory.GetItemBonus(GameAttribute.Weapon_Crit_Chance);
Attributes[GameAttribute.Crit_Damage_Percent] =
0.5f + Inventory.GetItemBonus(GameAttribute.Crit_Damage_Percent);
Attributes[GameAttribute.Splash_Damage_Effect_Percent] =
Inventory.GetItemBonus(GameAttribute.Splash_Damage_Effect_Percent);
Attributes[GameAttribute.On_Hit_Fear_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Fear_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Fear_Proc_Chance);
Attributes[GameAttribute.On_Hit_Stun_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Stun_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Stun_Proc_Chance);
Attributes[GameAttribute.On_Hit_Blind_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Blind_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Blind_Proc_Chance);
Attributes[GameAttribute.On_Hit_Freeze_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Freeze_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Freeze_Proc_Chance);
Attributes[GameAttribute.On_Hit_Chill_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Chill_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Chill_Proc_Chance);
Attributes[GameAttribute.On_Hit_Slow_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Slow_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Slow_Proc_Chance);
Attributes[GameAttribute.On_Hit_Immobilize_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Immobilize_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Immobilize_Proc_Chance);
Attributes[GameAttribute.On_Hit_Knockback_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Knockback_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Knockback_Proc_Chance);
Attributes[GameAttribute.On_Hit_Bleed_Proc_Chance] =
Inventory.GetItemBonus(GameAttribute.On_Hit_Bleed_Proc_Chance) +
Inventory.GetItemBonus(GameAttribute.Weapon_On_Hit_Bleed_Proc_Chance);
Attributes[GameAttribute.Running_Rate] =
Toon.HeroTable.RunningRate + Inventory.GetItemBonus(GameAttribute.Running_Rate);
Attributes[GameAttribute.Movement_Scalar_Uncapped_Bonus] =
Inventory.GetItemBonus(GameAttribute.Movement_Scalar_Uncapped_Bonus);
Attributes[GameAttribute.Movement_Scalar] = Inventory.GetItemBonus(GameAttribute.Movement_Scalar) + 1.0f;
//this.Attributes[GameAttribute.Magic_Find] = this.Inventory.GetItemBonus(GameAttribute.Magic_Find);
Attributes[GameAttribute.Magic_Find] = Inventory.GetMagicFind();
//this.Attributes[GameAttribute.Gold_Find] = this.Inventory.GetItemBonus(GameAttribute.Gold_Find);
Attributes[GameAttribute.Gold_Find] = Inventory.GetGoldFind();
Attributes[GameAttribute.Gold_PickUp_Radius] = 5f + Inventory.GetItemBonus(GameAttribute.Gold_PickUp_Radius);
Attributes[GameAttribute.Experience_Bonus] = Inventory.GetItemBonus(GameAttribute.Experience_Bonus);
Attributes[GameAttribute.Experience_Bonus_Percent] =
Inventory.GetItemBonus(GameAttribute.Experience_Bonus_Percent);
Attributes[GameAttribute.Resistance_Freeze] = Inventory.GetItemBonus(GameAttribute.Resistance_Freeze);
Attributes[GameAttribute.Resistance_Penetration] = Inventory.GetItemBonus(GameAttribute.Resistance_Penetration);
Attributes[GameAttribute.Resistance_Percent] = Inventory.GetItemBonus(GameAttribute.Resistance_Percent);
Attributes[GameAttribute.Resistance_Root] = Inventory.GetItemBonus(GameAttribute.Resistance_Root);
Attributes[GameAttribute.Resistance_Stun] = Inventory.GetItemBonus(GameAttribute.Resistance_Stun);
Attributes[GameAttribute.Resistance_StunRootFreeze] =
Inventory.GetItemBonus(GameAttribute.Resistance_StunRootFreeze);
Attributes[GameAttribute.Dodge_Chance_Bonus] = Inventory.GetItemBonus(GameAttribute.Dodge_Chance_Bonus);
Attributes[GameAttribute.Block_Amount_Item_Min] = Inventory.GetItemBonus(GameAttribute.Block_Amount_Item_Min);
Attributes[GameAttribute.Block_Amount_Item_Delta] =
Inventory.GetItemBonus(GameAttribute.Block_Amount_Item_Delta);
Attributes[GameAttribute.Block_Amount_Bonus_Percent] =
Inventory.GetItemBonus(GameAttribute.Block_Amount_Bonus_Percent);
Attributes[GameAttribute.Block_Chance] = Inventory.GetItemBonus(GameAttribute.Block_Chance_Item_Total);
Attributes[GameAttribute.Power_Cooldown_Reduction_Percent] = 0;
Attributes[GameAttribute.Health_Globe_Bonus_Health] =
Inventory.GetItemBonus(GameAttribute.Health_Globe_Bonus_Health);
Attributes[GameAttribute.Hitpoints_Regen_Per_Second] =
Inventory.GetItemBonus(GameAttribute.Hitpoints_Regen_Per_Second) + Toon.HeroTable.GetHitRecoveryBase +
Toon.HeroTable.GetHitRecoveryPerLevel * Level;
Attributes[GameAttribute.Resource_Cost_Reduction_Percent_All] =
Inventory.GetItemBonus(GameAttribute.Resource_Cost_Reduction_Percent_All);
Attributes[GameAttribute.Resource_Cost_Reduction_Percent, (int)Toon.HeroTable.PrimaryResource] =
Inventory.GetItemBonus(GameAttribute.Resource_Cost_Reduction_Percent, (int)Toon.HeroTable.PrimaryResource);
Attributes[GameAttribute.Resource_Regen_Per_Second, (int)Toon.HeroTable.PrimaryResource] =
Toon.HeroTable.PrimaryResourceRegen + Inventory.GetItemBonus(GameAttribute.Resource_Regen_Per_Second,
(int)Toon.HeroTable.PrimaryResource);
Attributes[GameAttribute.Resource_Regen_Bonus_Percent, (int)Toon.HeroTable.PrimaryResource] =
Inventory.GetItemBonus(GameAttribute.Resource_Regen_Bonus_Percent, (int)Toon.HeroTable.PrimaryResource);
Attributes[GameAttribute.Resource_Cost_Reduction_Percent, (int)Toon.HeroTable.SecondaryResource] =
Inventory.GetItemBonus(GameAttribute.Resource_Cost_Reduction_Percent,
(int)Toon.HeroTable.SecondaryResource);
Attributes[GameAttribute.Resource_Regen_Per_Second, (int)Toon.HeroTable.SecondaryResource] =
Toon.HeroTable.SecondaryResourceRegen + Inventory.GetItemBonus(GameAttribute.Resource_Regen_Per_Second,
(int)Toon.HeroTable.SecondaryResource);
Attributes[GameAttribute.Resource_Regen_Bonus_Percent, (int)Toon.HeroTable.SecondaryResource] =
Inventory.GetItemBonus(GameAttribute.Resource_Regen_Bonus_Percent, (int)Toon.HeroTable.SecondaryResource);
Attributes[GameAttribute.Resource_On_Hit] = 0;
Attributes[GameAttribute.Resource_On_Hit, 0] = Inventory.GetItemBonus(GameAttribute.Resource_On_Hit, 0);
Attributes[GameAttribute.Resource_On_Crit, 1] = Inventory.GetItemBonus(GameAttribute.Resource_On_Crit, 1);
Attributes[GameAttribute.Steal_Health_Percent] =
Inventory.GetItemBonus(GameAttribute.Steal_Health_Percent) * 0.1f;
Attributes[GameAttribute.Hitpoints_On_Hit] = Inventory.GetItemBonus(GameAttribute.Hitpoints_On_Hit);
Attributes[GameAttribute.Hitpoints_On_Kill] = Inventory.GetItemBonus(GameAttribute.Hitpoints_On_Kill);
Attributes[GameAttribute.Damage_Weapon_Percent_Bonus] =
Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Percent_Bonus);
Attributes[GameAttribute.Damage_Percent_Bonus_Vs_Elites] =
Inventory.GetItemBonus(GameAttribute.Damage_Percent_Bonus_Vs_Elites);
//this.Attributes[GameAttribute.Power_Cooldown_Reduction_Percent_All_Capped] = 0.5f;
//this.Attributes[GameAttribute.Power_Cooldown_Reduction_Percent_Cap] = 0.5f;
Attributes[GameAttribute.Power_Cooldown_Reduction_Percent] = 0.5f;
Attributes[GameAttribute.Power_Cooldown_Reduction_Percent_All] =
Inventory.GetItemBonus(GameAttribute.Power_Cooldown_Reduction_Percent_All);
Attributes[GameAttribute.Crit_Percent_Bonus_Uncapped] =
Inventory.GetItemBonus(GameAttribute.Crit_Percent_Bonus_Uncapped);
//this.Attributes[GameAttribute.Projectile_Speed] = 0.3f;
switch (Toon.Class)
{
case ToonClass.Barbarian:
Attributes[GameAttribute.Power_Resource_Reduction, 80028] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 80028);
Attributes[GameAttribute.Power_Resource_Reduction, 70472] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 70472);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 79242] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 79242);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 80263] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 80263);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 78548] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 78548);
Attributes[GameAttribute.Power_Resource_Reduction, 93885] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 93885);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 86989] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 86989);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 96296] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 96296);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 109342] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 109342);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 159169] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 159169);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 93885] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 93885);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 69979] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 69979);
break;
case ToonClass.DemonHunter:
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.SecondaryResource] =
Inventory.GetItemBonus(GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.SecondaryResource);
Attributes[GameAttribute.Bow] = Inventory.GetItemBonus(GameAttribute.Bow);
Attributes[GameAttribute.Crossbow] = Inventory.GetItemBonus(GameAttribute.Crossbow);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 129215] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 129215);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 134209] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 134209);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 77552] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 77552);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 75873] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 75873);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 86610] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 86610);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 131192] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 131192);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 131325] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 131325);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 77649] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 77649);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 134030] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 134030);
Attributes[GameAttribute.Power_Resource_Reduction, 129214] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 129214);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 75301] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 75301);
Attributes[GameAttribute.Power_Resource_Reduction, 131366] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 131366);
Attributes[GameAttribute.Power_Resource_Reduction, 129213] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 129213);
break;
case ToonClass.Monk:
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 95940] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 95940);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 96019] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 96019);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 96311] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 96311);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 97328] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 97328);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 96090] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 96090);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 97110] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 97110);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 121442] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 121442);
Attributes[GameAttribute.Power_Resource_Reduction, 111676] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 111676);
Attributes[GameAttribute.Power_Resource_Reduction, 223473] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 223473);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 96033] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 96033);
break;
case ToonClass.WitchDoctor:
Attributes[GameAttribute.Power_Resource_Reduction, 105963] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 105963);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 103181] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 103181);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 106465] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 106465);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 83602] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 83602);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 108506] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 108506);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 69866] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 69866);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 69867] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 69867);
Attributes[GameAttribute.Power_Resource_Reduction, 74003] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 74003);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 70455] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 103181);
Attributes[GameAttribute.Power_Resource_Reduction, 67567] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 67567);
Attributes[GameAttribute.Power_Cooldown_Reduction, 134837] =
Inventory.GetItemBonus(GameAttribute.Power_Cooldown_Reduction, 134837);
Attributes[GameAttribute.Power_Cooldown_Reduction, 67600] =
Inventory.GetItemBonus(GameAttribute.Power_Cooldown_Reduction, 67600);
Attributes[GameAttribute.Power_Cooldown_Reduction, 102573] =
Inventory.GetItemBonus(GameAttribute.Power_Cooldown_Reduction, 102573);
Attributes[GameAttribute.Power_Cooldown_Reduction, 30624] =
Inventory.GetItemBonus(GameAttribute.Power_Cooldown_Reduction, 30624);
break;
case ToonClass.Wizard:
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 30744] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 30744);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 30783] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 30783);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 71548] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 71548);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 1765] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 1765);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 30668] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 30668);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 77113] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 77113);
Attributes[GameAttribute.Power_Resource_Reduction, 91549] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 91549);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 87525] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 87525);
Attributes[GameAttribute.Power_Crit_Percent_Bonus, 93395] =
Inventory.GetItemBonus(GameAttribute.Power_Crit_Percent_Bonus, 93395);
Attributes[GameAttribute.Power_Resource_Reduction, 134456] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 134456);
Attributes[GameAttribute.Power_Resource_Reduction, 30725] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 30725);
Attributes[GameAttribute.Power_Duration_Increase, 30680] =
Inventory.GetItemBonus(GameAttribute.Power_Duration_Increase, 30680);
Attributes[GameAttribute.Power_Resource_Reduction, 69190] =
Inventory.GetItemBonus(GameAttribute.Power_Resource_Reduction, 69190);
Attributes[GameAttribute.Power_Cooldown_Reduction, 168344] =
Inventory.GetItemBonus(GameAttribute.Power_Cooldown_Reduction, 168344);
Attributes[GameAttribute.Power_Damage_Percent_Bonus, 71548] =
Inventory.GetItemBonus(GameAttribute.Power_Damage_Percent_Bonus, 71548);
break;
}
}
public void UpdatePercentageHP(float percent)
{
var m = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes[GameAttribute.Hitpoints_Cur] = percent * Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
Attributes.BroadcastChangedIfRevealed();
}
public void UpdatePercentageHP()
{
}
public void SetAttributesByGems()
{
Inventory.SetGemBonuses();
}
public void SetAttributesByItemProcs()
{
Attributes[GameAttribute.Item_Power_Passive, 248776] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 248776); //cluck
Attributes[GameAttribute.Item_Power_Passive, 248629] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 248629); //death laugh
Attributes[GameAttribute.Item_Power_Passive, 247640] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 247640); //gore1
Attributes[GameAttribute.Item_Power_Passive, 249963] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 249963); //gore2
Attributes[GameAttribute.Item_Power_Passive, 249954] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 249954); //gore3
Attributes[GameAttribute.Item_Power_Passive, 246116] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 246116); //butcher
Attributes[GameAttribute.Item_Power_Passive, 247724] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 247724); //plum!
Attributes[GameAttribute.Item_Power_Passive, 245741] =
Inventory.GetItemBonus(GameAttribute.Item_Power_Passive, 245741); //weee!
}
public void SetAttributesByItemSets()
{
Attributes[GameAttribute.Strength] = Strength;
Attributes[GameAttribute.Dexterity] = Dexterity;
Attributes[GameAttribute.Vitality] = Vitality;
Attributes[GameAttribute.Intelligence] = Intelligence;
Attributes.BroadcastChangedIfRevealed();
Inventory.SetItemSetBonuses();
}
public void SetAttributesByPassives() //also reapplies synergy buffs
{
// Class specific
Attributes[GameAttribute.Damage_Percent_All_From_Skills] = 0;
Attributes[GameAttribute.Allow_2H_And_Shield] = false;
Attributes[GameAttribute.Cannot_Dodge] = false;
foreach (var passiveId in SkillSet.PassiveSkills)
switch (Toon.Class)
{
case ToonClass.Barbarian:
switch (passiveId)
{
case 217819: //NervesOfSteel
Attributes[GameAttribute.Armor_Item] += Attributes[GameAttribute.Vitality_Total] * 0.50f;
break;
case 205228: //Animosity
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource] += 20;
Attributes[GameAttribute.Resource_Regen_Per_Second, (int)Toon.HeroTable.PrimaryResource] =
Attributes[GameAttribute.Resource_Regen_Per_Second,
(int)Toon.HeroTable.PrimaryResource] * 1.1f;
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource] =
Toon.HeroTable.PrimaryResourceBase + Attributes[GameAttribute.Resource_Max_Bonus,
(int)Toon.HeroTable.PrimaryResource];
break;
case 205848: //ToughAsNails
Attributes[GameAttribute.Armor_Item] *= 1.25f;
break;
case 205707: //Juggernaut
Attributes[GameAttribute.CrowdControl_Reduction] += 0.3f;
break;
case 206147: //WeaponsMaster
var weapon = Inventory.GetEquippedWeapon();
if (weapon != null)
{
var name = weapon.ItemDefinition.Name.ToLower();
if (name.Contains("sword") || name.Contains("dagger"))
Attributes[GameAttribute.Damage_Weapon_Percent_Bonus] += 0.08f;
else if (name.Contains("axe") || name.Contains("mace"))
Attributes[GameAttribute.Weapon_Crit_Chance] += 0.05f;
else if (name.Contains("spear") || name.Contains("polearm"))
Attributes[GameAttribute.Attacks_Per_Second] *= 1.08f;
else if (name.Contains("mighty"))
Attributes[GameAttribute.Resource_On_Hit] += 1f;
}
break;
}
break;
case ToonClass.DemonHunter:
switch (passiveId)
{
case 155714: //Blood Vengeance
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource] += 25;
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource] =
Toon.HeroTable.PrimaryResourceBase + Attributes[GameAttribute.Resource_Max_Bonus,
(int)Toon.HeroTable.PrimaryResource];
break;
case 210801: //Brooding
Attributes[GameAttribute.Hitpoints_Regen_Per_Second] +=
Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
break;
case 155715: //Sharpshooter
World.BuffManager.RemoveBuffs(this, 155715);
World.BuffManager.AddBuff(this, this, new SharpshooterBuff());
break;
case 324770: //Awareness
World.BuffManager.RemoveBuffs(this, 324770);
World.BuffManager.AddBuff(this, this, new AwarenessBuff());
break;
case 209734: //Archery
var weapon = Inventory.GetEquippedWeapon();
if (weapon != null)
{
var name = weapon.ItemDefinition.Name.ToLower();
if (name.Contains("xbow"))
Attributes[GameAttribute.Crit_Damage_Percent] += 0.5f;
if (name.Contains("handxbow"))
{
Attributes[GameAttribute.Crit_Percent_Bonus_Uncapped] += 0.05f;
}
else if (name.Contains("xbow"))
{
Attributes[GameAttribute.Resource_Regen_Per_Second,
(int)Toon.HeroTable.PrimaryResource] += 1f;
}
else if (name.Contains("bow"))
{
Attributes[GameAttribute.Damage_Weapon_Percent_Bonus] += 0.08f;
Attributes[GameAttribute.Damage_Percent_All_From_Skills] = 0.08f;
}
}
break;
case 155722: //Perfectionist
Attributes[GameAttribute.Armor_Item] *= 1.1f;
Attributes[GameAttribute.Hitpoints_Max_Percent_Bonus] += 0.1f;
Attributes[GameAttribute.Resistance_Percent_All] += 0.1f;
break;
}
break;
case ToonClass.Monk:
switch (passiveId)
{
case 209029: //FleetFooted
Attributes[GameAttribute.Movement_Scalar_Uncapped_Bonus] += 0.1f;
break;
case 209027: //ExaltedSoul
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource] += 100;
//this.Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource] = Toon.HeroTable.PrimaryResourceMax + this.Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource];
Attributes[GameAttribute.Resource_Regen_Per_Second, 3] += 2f;
break;
case 209628: //SeizeTheInitiative
Attributes[GameAttribute.Armor_Item] += Attributes[GameAttribute.Dexterity_Total] * 0.3f;
break;
case 209622: //SixthSense
Attributes[GameAttribute.Dodge_Chance_Bonus] += Math.Min(
(Attributes[GameAttribute.Weapon_Crit_Chance] +
Attributes[GameAttribute.Crit_Percent_Bonus_Capped] +
Attributes[GameAttribute.Crit_Percent_Bonus_Uncapped]) * 0.425f, 0.15f);
break;
case 209104: //BeaconOfYtar
Attributes[GameAttribute.Power_Cooldown_Reduction_Percent_All] += 0.20f;
break;
case 209656: //OneWithEverything
var maxResist = Math.Max(
Math.Max(
Math.Max(Attributes[GameAttribute.Resistance, DamageType.Physical.AttributeKey],
Attributes[GameAttribute.Resistance, DamageType.Cold.AttributeKey]),
Attributes[GameAttribute.Resistance, DamageType.Fire.AttributeKey]),
Math.Max(
Math.Max(Attributes[GameAttribute.Resistance, DamageType.Arcane.AttributeKey],
Attributes[GameAttribute.Resistance, DamageType.Holy.AttributeKey]),
Math.Max(Attributes[GameAttribute.Resistance, DamageType.Lightning.AttributeKey],
Attributes[GameAttribute.Resistance, DamageType.Poison.AttributeKey]))
);
foreach (var damageType in DamageType.AllTypes)
Attributes[GameAttribute.Resistance, damageType.AttributeKey] = maxResist;
break;
case 209812: //TheGuardiansPath
try
{
var weapon = Inventory.GetEquippedWeapon();
if (weapon != null && Inventory.GetEquippedOffHand() != null)
{
Attributes[GameAttribute.Dodge_Chance_Bonus] += 0.15f;
}
else if (weapon.ItemDefinition.Name.ToLower().Contains("2h"))
{
World.BuffManager.RemoveBuffs(this, 209812);
World.BuffManager.AddBuff(this, this, new GuardiansPathBuff());
}
}
catch
{
}
break;
case 341559: //Momentum
World.BuffManager.RemoveBuffs(this, 341559);
World.BuffManager.AddBuff(this, this, new MomentumCheckBuff());
break;
case 209813: //Provocation
Attributes[GameAttribute.CrowdControl_Reduction] += 0.25f;
break;
}
break;
case ToonClass.WitchDoctor:
switch (passiveId)
{
case 208569: //SpiritualAttunement
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource] +=
Attributes[GameAttribute.Resource_Max, (int)Toon.HeroTable.PrimaryResource] * 0.2f;
Attributes[GameAttribute.Resource_Regen_Per_Second, (int)Toon.HeroTable.PrimaryResource] =
Toon.HeroTable.PrimaryResourceRegen + (Toon.HeroTable.PrimaryResourceBase +
Attributes[GameAttribute.Resource_Max_Bonus,
(int)Toon.HeroTable.PrimaryResource]) / 100;
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource] =
Toon.HeroTable.PrimaryResourceBase + Attributes[GameAttribute.Resource_Max_Bonus,
(int)Toon.HeroTable.PrimaryResource];
break;
case 340910: //PhysicalAttunement
World.BuffManager.RemoveBuffs(this, 340910);
World.BuffManager.AddBuff(this, this, new PhysicalAttunementBuff());
break;
case 208568: //BloodRitual
Attributes[GameAttribute.Hitpoints_Regen_Per_Second] +=
Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
break;
case 208639: //FierceLoyalty
foreach (var minionId in Followers.Keys)
{
var minion = World.GetActorByGlobalId(minionId);
if (minion != null)
minion.Attributes[GameAttribute.Hitpoints_Regen_Per_Second] =
Inventory.GetItemBonus(GameAttribute.Hitpoints_Regen_Per_Second);
}
break;
}
break;
case ToonClass.Wizard:
switch (passiveId)
{
case 208541: //Galvanizing Ward
World.BuffManager.RemoveBuffs(this, 208541);
World.BuffManager.AddBuff(this, this, new GalvanizingBuff());
break;
case 208473: //Evocation
Attributes[GameAttribute.Power_Cooldown_Reduction_Percent_All] += 0.20f;
break;
case 208472: //AstralPresence
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource] += 20;
Attributes[GameAttribute.Resource_Regen_Per_Second, (int)Toon.HeroTable.PrimaryResource] =
Toon.HeroTable.PrimaryResourceRegen + 2;
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource] =
Toon.HeroTable.PrimaryResourceBase + Attributes[GameAttribute.Resource_Max_Bonus,
(int)Toon.HeroTable.PrimaryResource];
break;
case 208468: //Blur (Wizard)
Attributes[GameAttribute.Damage_Percent_Reduction_From_Melee] += 0.17f;
break;
}
break;
case ToonClass.Crusader:
switch (passiveId)
{
case 286177: //HeavenlyStrength
Attributes[GameAttribute.Movement_Scalar_Uncapped_Bonus] -= 0.15f;
Attributes[GameAttribute.Allow_2H_And_Shield] = true;
break;
case 310626: //Vigilant
Attributes[GameAttribute.Hitpoints_Regen_Per_Second] +=
10 + 0.008f * (float)Math.Pow(Attributes[GameAttribute.Level], 3);
break;
case 356147: //Righteousness
Attributes[GameAttribute.Resource_Max_Bonus, (int)Toon.HeroTable.PrimaryResource] += 30;
break;
case 310804: //HolyCause
Attributes[GameAttribute.Damage_Weapon_Min, 6] *= 1.1f;
break;
case 356176: //DivineFortress
World.BuffManager.RemoveBuffs(this, 356176);
World.BuffManager.AddBuff(this, this, new DivineFortressBuff());
break;
case 302500: //HoldYourGround
Attributes[GameAttribute.Cannot_Dodge] = true;
Attributes[GameAttribute.Block_Chance] += 0.15f;
break;
case 310783: //IronMaiden
Attributes[GameAttribute.Thorns_Fixed, 0] += 87.17f * Attributes[GameAttribute.Level];
break;
case 311629: //Finery
World.BuffManager.RemoveBuffs(this, 311629);
World.BuffManager.AddBuff(this, this, new FineryBuff());
break;
case 310640: //Insurmountable
World.BuffManager.RemoveBuffs(this, 310640);
World.BuffManager.AddBuff(this, this, new InsurmountableBuff());
break;
case 309830: //Indesctructible
World.BuffManager.RemoveBuffs(this, 309830);
World.BuffManager.AddBuff(this, this, new IndestructibleBuff());
break;
case 356173: //Renewal
World.BuffManager.RemoveBuffs(this, 356173);
World.BuffManager.AddBuff(this, this, new RenewalBuff());
break;
case 356052: //Towering Shield
World.BuffManager.RemoveBuffs(this, 356052);
World.BuffManager.AddBuff(this, this, new ToweringShieldBuff());
break;
}
break;
case ToonClass.Necromancer:
switch (passiveId)
{
case 470764: //HugeEssense
Attributes[GameAttribute.Resource_Max_Bonus,
Attributes[GameAttribute.Resource_Type_Primary] - 1] += 40;
break;
case 470725:
World.BuffManager.RemoveBuffs(this, 470725);
World.BuffManager.AddBuff(this, this, new OnlyOne());
break;
}
break;
}
SetAttributesSkillSets(); //reapply synergy passives (laws, mantras, summons)
}
public void SetAttributesSkillSets()
{
// unlocking assigned skills
for (var i = 0; i < SkillSet.ActiveSkills.Length; i++)
if (SkillSet.ActiveSkills[i].snoSkill != -1)
{
Attributes[GameAttribute.Skill, SkillSet.ActiveSkills[i].snoSkill] = 1;
//scripted //this.Attributes[GameAttribute.Skill_Total, this.SkillSet.ActiveSkills[i].snoSkill] = 1;
// update rune attributes for new skill
Attributes[GameAttribute.Rune_A, SkillSet.ActiveSkills[i].snoSkill] =
SkillSet.ActiveSkills[i].snoRune == 0 ? 1 : 0;
Attributes[GameAttribute.Rune_B, SkillSet.ActiveSkills[i].snoSkill] =
SkillSet.ActiveSkills[i].snoRune == 1 ? 1 : 0;
Attributes[GameAttribute.Rune_C, SkillSet.ActiveSkills[i].snoSkill] =
SkillSet.ActiveSkills[i].snoRune == 2 ? 1 : 0;
Attributes[GameAttribute.Rune_D, SkillSet.ActiveSkills[i].snoSkill] =
SkillSet.ActiveSkills[i].snoRune == 3 ? 1 : 0;
Attributes[GameAttribute.Rune_E, SkillSet.ActiveSkills[i].snoSkill] =
SkillSet.ActiveSkills[i].snoRune == 4 ? 1 : 0;
var power = PowerLoader.CreateImplementationForPowerSNO(SkillSet.ActiveSkills[i].snoSkill);
if (power != null && power.EvalTag(PowerKeys.SynergyPower) != -1)
World.PowerManager.RunPower(this, power.EvalTag(PowerKeys.SynergyPower)); //SynergyPower buff
}
for (var i = 0; i < SkillSet.PassiveSkills.Length; ++i)
if (SkillSet.PassiveSkills[i] != -1)
{
// switch on passive skill
Attributes[GameAttribute.Trait, SkillSet.PassiveSkills[i]] = 1;
Attributes[GameAttribute.Skill, SkillSet.PassiveSkills[i]] = 1;
//scripted //this.Attributes[GameAttribute.Skill_Total, this.SkillSet.PassiveSkills[i]] = 1;
}
if (Toon.Class == ToonClass.Monk) //Setting power range override
{
Attributes[GameAttribute.PowerBonusAttackRadius, 0x000176C4] = 20f; //Fists of Thunder
if (Attributes[GameAttribute.Rune_A, 0x00017B56] > 0) //Way of the Hundred Fists -> Fists of Fury
Attributes[GameAttribute.PowerBonusAttackRadius, 0x00017B56] = 15f;
}
}
public void SetAttributesOther()
{
//Bonus stats
Attributes[GameAttribute.Hit_Chance] = 1f;
Attributes[GameAttribute.Attacks_Per_Second] = 1.2f;
//this.Attributes[GameAttribute.Attacks_Per_Second_Item] = 1.199219f;
Attributes[GameAttribute.Crit_Percent_Cap] = Toon.HeroTable.CritPercentCap;
//scripted //this.Attributes[GameAttribute.Casting_Speed_Total] = 1f;
Attributes[GameAttribute.Casting_Speed] = 1f;
//Basic stats
Attributes[GameAttribute.Level_Cap] = Program.MaxLevel;
Attributes[GameAttribute.Level] = Level;
Attributes[GameAttribute.Alt_Level] = ParagonLevel;
if (Level == Program.MaxLevel)
{
Attributes[GameAttribute.Alt_Experience_Next_Lo] = (int)(ExperienceNext % uint.MaxValue);
Attributes[GameAttribute.Alt_Experience_Next_Hi] = (int)(ExperienceNext / uint.MaxValue);
}
else
{
Attributes[GameAttribute.Experience_Next_Lo] = (int)(ExperienceNext % uint.MaxValue);
Attributes[GameAttribute.Experience_Next_Hi] = (int)(ExperienceNext / uint.MaxValue);
//this.Attributes[GameAttribute.Alt_Experience_Next] = 0;
}
Attributes[GameAttribute.Experience_Granted_Low] = 1000;
Attributes[GameAttribute.Armor] = Toon.HeroTable.Armor;
Attributes[GameAttribute.Damage_Min, 0] = Toon.HeroTable.Dmg;
//scripted //this.Attributes[GameAttribute.Armor_Total]
Attributes[GameAttribute.Strength] = (int)Strength;
Attributes[GameAttribute.Dexterity] = (int)Dexterity;
Attributes[GameAttribute.Vitality] = (int)Vitality;
Attributes[GameAttribute.Intelligence] = (int)Intelligence;
Attributes[GameAttribute.Core_Attributes_From_Item_Bonus_Multiplier] = 1;
//Hitpoints have to be calculated after Vitality
Attributes[GameAttribute.Hitpoints_Factor_Level] = Toon.HeroTable.HitpointsFactorLevel;
Attributes[GameAttribute.Hitpoints_Factor_Vitality] = 10f + Math.Max(Level - 35, 0);
//this.Attributes[GameAttribute.Hitpoints_Max] = 276f;
Attributes[GameAttribute.Hitpoints_Max_Percent_Bonus_Multiplicative] = (int)1;
Attributes[GameAttribute.Hitpoints_Factor_Level] = (int)Toon.HeroTable.HitpointsFactorLevel;
Attributes[GameAttribute.Hitpoints_Factor_Vitality] = 10f; // + Math.Max(this.Level - 35, 0);
Attributes[GameAttribute.Hitpoints_Max] = (int)Toon.HeroTable.HitpointsMax;
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes[GameAttribute.Corpse_Resurrection_Charges] = 3;
//TestOutPutItemAttributes(); //Activate this only for finding item stats.
Attributes.BroadcastChangedIfRevealed();
}
#endregion
#region game-message handling & consumers
/// <summary>
/// Consumes the given game-message.
/// </summary>
/// <param name="client">The client.</param>
/// <param name="message">The GameMessage.</param>
public void Consume(GameClient client, GameMessage message)
{
if (message is AssignSkillMessage skillMessage) OnAssignActiveSkill(client, skillMessage);
else if (message is AssignTraitsMessage traitsMessage) OnAssignPassiveSkills(client, traitsMessage);
else if (message is UnassignSkillMessage unassignSkillMessage) OnUnassignActiveSkill(client, unassignSkillMessage);
else if (message is TargetMessage targetMessage) OnObjectTargeted(client, targetMessage);
else if (message is ACDClientTranslateMessage translateMessage) OnPlayerMovement(client, translateMessage);
else if (message is TryWaypointMessage waypointMessage) OnTryWaypoint(client, waypointMessage);
else if (message is RequestBuyItemMessage itemMessage) OnRequestBuyItem(client, itemMessage);
else if (message is RequestSellItemMessage sellItemMessage) OnRequestSellItem(client, sellItemMessage);
else if (message is HirelingRequestLearnSkillMessage learnSkillMessage)
OnHirelingRequestLearnSkill(client, learnSkillMessage);
else if (message is HirelingRetrainMessage) OnHirelingRetrainMessage();
else if (message is HirelingSwapAgreeMessage) OnHirelingSwapAgreeMessage();
else if (message is PetAwayMessage awayMessage) OnHirelingDismiss(client, awayMessage);
else if (message is ChangeUsableItemMessage usableItemMessage) OnEquipPotion(client, usableItemMessage);
else if (message is ArtisanWindowClosedMessage) OnArtisanWindowClosed();
else if (message is RequestTrainArtisanMessage artisanMessage) TrainArtisan(client, artisanMessage);
else if (message is RessurectionPlayerMessage playerMessage) OnResurrectOption(client, playerMessage);
else if (message is PlayerTranslateFacingMessage facingMessage)
OnTranslateFacing(client, facingMessage);
else if (message is LoopingAnimationPowerMessage powerMessage)
OnLoopingAnimationPowerMessage(client, powerMessage);
else if (message is SecondaryAnimationPowerMessage animationPowerMessage)
OnSecondaryPowerMessage(client, animationPowerMessage);
else if (message is MiscPowerMessage miscPowerMessage) OnMiscPowerMessage(client, miscPowerMessage);
else if (message is RequestBuffCancelMessage cancelMessage) OnRequestBuffCancel(client, cancelMessage);
else if (message is CancelChanneledSkillMessage channeledSkillMessage)
OnCancelChanneledSkill(client, channeledSkillMessage);
else if (message is TutorialShownMessage shownMessage) OnTutorialShown(client, shownMessage);
else if (message is AcceptConfirmMessage confirmMessage) OnConfirm(client, confirmMessage);
else if (message is SpendParagonPointsMessage pointsMessage)
OnSpendParagonPointsMessage(client, pointsMessage);
else if (message is ResetParagonPointsMessage paragonPointsMessage)
OnResetParagonPointsMessage(client, paragonPointsMessage);
else if (message is MailRetrieveMessage retrieveMessage) OnMailRetrieve(client, retrieveMessage);
else if (message is MailReadMessage readMessage) OnMailRead(client, readMessage);
else if (message is StashIconStateAssignMessage assignMessage)
OnStashIconsAssign(client, assignMessage);
else if (message is TransmuteItemsMessage itemsMessage) TransmuteItemsPlayer(client, itemsMessage);
else if (message is RiftStartAcceptedMessage acceptedMessage) OpenNephalem(client, acceptedMessage);
else if (message is BossEncounterAcceptMessage) AcceptBossEncounter();
else if (message is DeActivateCameraCutsceneMode mode)
DeactivateCamera(client, mode);
else if (message is JewelUpgradeMessage upgradeMessage) JewelUpgrade(client, upgradeMessage);
else if (message is SwitchCosmeticMessage cosmeticMessage) SwitchCosmetic(client, cosmeticMessage);
else return;
}
public void SwitchCosmetic(GameClient client, SwitchCosmeticMessage message)
{
var Definition = ItemGenerator.GetItemDefinition(message.Field0);
;
if (Definition.Name.ToLower().Contains("portrait"))
client.BnetClient.Account.GameAccount.CurrentToon.Cosmetic4 = message.Field0;
var RangeCosmetic = new[]
{
D3.Hero.VisualCosmeticItem.CreateBuilder()
.SetGbid(client.BnetClient.Account.GameAccount.CurrentToon.Cosmetic1).Build(), // Wings
D3.Hero.VisualCosmeticItem.CreateBuilder()
.SetGbid(client.BnetClient.Account.GameAccount.CurrentToon.Cosmetic2).Build(), // Flag
D3.Hero.VisualCosmeticItem.CreateBuilder()
.SetGbid(client.BnetClient.Account.GameAccount.CurrentToon.Cosmetic3).Build(), // Pet
D3.Hero.VisualCosmeticItem.CreateBuilder()
.SetGbid(client.BnetClient.Account.GameAccount.CurrentToon.Cosmetic4).Build() // Frame
};
//RangeCosmetic[request.CosmeticItemType - 1] = D3.Hero.VisualCosmeticItem.CreateBuilder().SetGbid(unchecked((int)request.Gbid)).Build();
client.BnetClient.Account.GameAccount.CurrentToon.StateChanged();
var NewVisual = D3.Hero.VisualEquipment.CreateBuilder()
.AddRangeVisualItem(client.BnetClient.Account.GameAccount.CurrentToon.HeroVisualEquipmentField.Value
.VisualItemList).AddRangeCosmeticItem(RangeCosmetic).Build();
client.BnetClient.Account.GameAccount.CurrentToon.HeroVisualEquipmentField.Value = NewVisual;
client.BnetClient.Account.GameAccount.ChangedFields.SetPresenceFieldValue(client.BnetClient.Account.GameAccount
.CurrentToon.HeroVisualEquipmentField);
client.BnetClient.Account.GameAccount.NotifyUpdate();
}
public void ResetParagonPoints(GameClient client, ResetParagonPointsMessage message)
{
}
public void SpendParagonPoints(GameClient client, SpendParagonPointsMessage message)
{
}
public void JewelUpgrade(GameClient client, JewelUpgradeMessage message)
{
var Jewel = Inventory.GetItemByDynId(this, message.ActorID);
Jewel.Attributes[GameAttribute.Jewel_Rank]++;
Jewel.Attributes.BroadcastChangedIfRevealed();
Attributes[GameAttribute.Jewel_Upgrades_Used]++;
Attributes.BroadcastChangedIfRevealed();
if (Attributes[GameAttribute.Jewel_Upgrades_Used] == Attributes[GameAttribute.Jewel_Upgrades_Max] +
Attributes[GameAttribute.Jewel_Upgrades_Bonus])
{
Attributes[GameAttribute.Jewel_Upgrades_Max] = 0;
Attributes[GameAttribute.Jewel_Upgrades_Bonus] = 0;
Attributes[GameAttribute.Jewel_Upgrades_Used] = 0;
}
InGameClient.SendMessage(new JewelUpgradeResultsMessage()
{
ActorID = message.ActorID,
Field1 = 1
});
}
public void OnHirelingSwapAgreeMessage()
{
Hireling hireling = null;
DiIiS_NA.Core.MPQ.FileFormats.Actor Data = null;
if (World.Game.Players.Count > 1) return;
switch (InGameClient.Game.CurrentQuest)
{
case 72061:
//Templar
Data = (DiIiS_NA.Core.MPQ.FileFormats.Actor)MPQStorage.Data.Assets[SNOGroup.Actor][52693].Data;
hireling = new Templar(World, ActorSno._hireling_templar, Data.TagMap);
hireling.GBHandle.GBID = StringHashHelper.HashItemName("Templar");
break;
case 72738:
//Scoundrel
Data = (DiIiS_NA.Core.MPQ.FileFormats.Actor)MPQStorage.Data.Assets[SNOGroup.Actor][52694].Data;
hireling = new Templar(World, ActorSno._hireling_scoundrel, Data.TagMap);
hireling.GBHandle.GBID = StringHashHelper.HashItemName("Scoundrel");
break;
case 0:
//Enchantress
Data = (DiIiS_NA.Core.MPQ.FileFormats.Actor)MPQStorage.Data.Assets[SNOGroup.Actor][4482].Data;
hireling = new Templar(World, ActorSno._hireling_enchantress, Data.TagMap);
hireling.GBHandle.GBID = StringHashHelper.HashItemName("Enchantress");
break;
}
hireling.SetUpAttributes(this);
hireling.GBHandle.Type = 4;
hireling.Attributes[GameAttribute.Pet_Creator] = PlayerIndex + 1;
hireling.Attributes[GameAttribute.Pet_Type] = 1;
hireling.Attributes[GameAttribute.Pet_Owner] = PlayerIndex + 1;
hireling.Attributes[GameAttribute.Untargetable] = false;
hireling.Attributes[GameAttribute.NPC_Is_Escorting] = true;
hireling.EnterWorld(RandomDirection(Position, 3, 10)); //Random
hireling.Brain = new HirelingBrain(hireling, this);
ActiveHireling = hireling;
SelectedNPC = null;
}
public static Vector3D RandomDirection(Vector3D position, float minRadius, float maxRadius)
{
var angle = (float)(FastRandom.Instance.NextDouble() * Math.PI * 2);
var radius = minRadius + (float)FastRandom.Instance.NextDouble() * (maxRadius - minRadius);
return new Vector3D(position.X + (float)Math.Cos(angle) * radius,
position.Y + (float)Math.Sin(angle) * radius,
position.Z);
}
public void AwayPet(GameClient client, PetAwayMessage message)
{
}
public void DeactivateCamera(GameClient client, DeActivateCameraCutsceneMode message)
{
InGameClient.SendMessage(new BoolDataMessage(Opcodes.CameraTriggerFadeToBlackMessage) { Field0 = true });
InGameClient.SendMessage(new SimpleMessage(Opcodes.CameraSriptedSequenceStopMessage) { });
//this.InGameClient.SendMessage(new ActivateCameraCutsceneMode() { Activate = true });
}
public void AcceptBossEncounter()
{
InGameClient.Game.AcceptBossEncounter();
}
public void DeclineBossEncounter()
{
InGameClient.Game.CurrentEncounter.Activated = false;
}
public void TransmuteItemsPlayer(GameClient client, TransmuteItemsMessage message)
{
var recipeDefinition = ItemGenerator.GetRecipeDefinition(608170752);
for (var i = 0; i < message.CurrenciesCount; i++)
{
var data = ItemGenerator.GetItemDefinition(message.GBIDCurrencies[i]).Name;
switch (data)
{
case "p2_ActBountyReagent_01": break;
case "p2_ActBountyReagent_02": break;
case "p2_ActBountyReagent_03": break;
case "p2_ActBountyReagent_04": break;
case "p2_ActBountyReagent_05": break;
case "Crafting_Looted_Reagent_01": break;
}
}
foreach (var it in message.annItems)
{
var a = Inventory.GetItemByDynId(this, (uint)it);
}
Item ItemPortalToCows = null;
var Items = new List<Item> { };
for (var i = 0; i < message.ItemsCount; i++)
{
Items.Add(Inventory.GetItemByDynId(this, (uint)message.annItems[i]));
if (Items[i].SNO == ActorSno._x1_polearm_norm_unique_05)
ItemPortalToCows = Items[i];
}
//Type - 0 - New property
//Type - 1 - Transmutation
//Type - 2 -
if (ItemPortalToCows != null)
{
InGameClient.SendMessage(new TransmuteResultsMessage()
{
annItem = -1,
Type = -1,
GBIDFakeItem = -1,
GBIDPower = -1,
FakeItemStackCount = -1
});
Inventory.DestroyInventoryItem(ItemPortalToCows);
World.SpawnMonster(ActorSno._p2_totallynotacowlevel_portal,
new Vector3D(Position.X + 5, Position.Y + 5, Position.Z));
}
else
{
InGameClient.SendMessage(new TransmuteResultsMessage()
{
annItem = (int)Items[0].DynamicID(this),
Type = 0,
GBIDFakeItem = -1,
GBIDPower = (int)Items[0].ItemDefinition.Hash,
FakeItemStackCount = -1
});
GrantCriteria(74987245494264);
GrantCriteria(74987258962046);
}
}
private bool WaitToSpawn(TickTimer timer)
{
while (!timer.TimedOut) ;
return true;
}
public void OpenNephalem(GameClient client, RiftStartAcceptedMessage message)
{
//396751 - X1_OpenWorld_Tiered_Rifts_Portal - Великий портал
//345935 - X1_OpenWorld_LootRunPortal - Обычные порталы
//408511 - X1_OpenWorld_Tiered_Rifts_Challenge_Portal
//1073741824 - Первый уровень Великого бафнутого
//0 - Первый уровень Великого
//
var activated = false;
var newTagMap = new TagMap();
World nephalemPWorld = null;
Actor lootRunObelisk = null;
Portal portal = null;
var map = WorldSno.__NONE;
var maps = new WorldSno[]
{
WorldSno.x1_lr_tileset_westmarch, //x1_lr_tileset_Westmarch
WorldSno.x1_lr_tileset_fortress_large, //_x1_lr_tileset_fortress_large
WorldSno.x1_lr_tileset_zoltruins, //x1_lr_tileset_zoltruins
WorldSno.x1_lr_tileset_hexmaze, //x1_lr_tileset_hexmaze
WorldSno.x1_lr_tileset_icecave, //x1_lr_tileset_icecave
WorldSno.x1_lr_tileset_crypt, //x1_lr_tileset_crypt
WorldSno.x1_lr_tileset_corruptspire //x1_lr_tileset_corruptspire
//288843, //x1_lr_tileset_sewers
};
switch (message.Field0)
{
#region Нефалемский портал
case -1:
Logger.Debug("Calling Nephalem Portal (Normal)");
activated = false;
foreach (var oldp in World.GetActorsBySNO(ActorSno._x1_openworld_lootrunportal,
ActorSno._x1_openworld_tiered_rifts_portal)) oldp.Destroy();
map = maps.PickRandom();
//map = 288823;
newTagMap.Add(new TagKeySNO(526850), new TagMapEntry(526850, (int)map, 0)); //World
newTagMap.Add(new TagKeySNO(526853), new TagMapEntry(526853, 288482, 0)); //Zone
newTagMap.Add(new TagKeySNO(526851), new TagMapEntry(526851, 172, 0)); //Entry-Pointа
InGameClient.Game.WorldOfPortalNephalem = map;
while (true)
{
map = maps.PickRandom();
if (map != InGameClient.Game.WorldOfPortalNephalem) break;
}
InGameClient.Game.WorldOfPortalNephalemSec = map;
nephalemPWorld = InGameClient.Game.GetWorld(InGameClient.Game.WorldOfPortalNephalem);
var exitSceneSno = -1;
foreach (var scene in nephalemPWorld.Scenes.Values)
if (scene.SceneSNO.Name.ToLower().Contains("exit"))
exitSceneSno = scene.SceneSNO.Id;
var exitSetted = false;
foreach (var actor in nephalemPWorld.Actors.Values)
if (actor is Portal actor1)
{
if (!actor1.CurrentScene.SceneSNO.Name.ToLower().Contains("entrance"))
{
if (!actor1.CurrentScene.SceneSNO.Name.ToLower().Contains("exit"))
{
actor1.Destroy();
}
else if (!exitSetted)
{
actor1.Destination.DestLevelAreaSNO = 288684;
actor1.Destination.WorldSNO = (int)InGameClient.Game.WorldOfPortalNephalemSec;
exitSetted = true;
var nephalemPWorldS2 =
InGameClient.Game.GetWorld(InGameClient.Game.WorldOfPortalNephalemSec);
foreach (var atr in nephalemPWorldS2.Actors.Values)
if (atr is Portal portal1)
{
if (!portal1.CurrentScene.SceneSNO.Name.ToLower().Contains("entrance"))
{
portal1.Destroy();
}
else
{
portal1.Destination.DestLevelAreaSNO = 332339;
portal1.Destination.WorldSNO =
(int)WorldSno.x1_tristram_adventure_mode_hub;
portal1.Destination.StartingPointActorTag = 172;
}
}
else if (atr is Waypoint)
{
atr.Destroy();
}
}
else
{
actor1.Destroy();
}
}
else
{
actor1.Destination.DestLevelAreaSNO = 332339;
actor1.Destination.WorldSNO = (int)WorldSno.x1_tristram_adventure_mode_hub;
actor1.Destination.StartingPointActorTag = 24;
}
}
else if (actor is Waypoint)
{
actor.Destroy();
}
#region Activation
lootRunObelisk = World.GetActorBySNO(ActorSno._x1_openworld_lootrunobelisk_b);
lootRunObelisk.PlayAnimation(5, (AnimationSno)lootRunObelisk.AnimationSet.TagMapAnimDefault[AnimationSetKeys.Opening]);
lootRunObelisk.Attributes[GameAttribute.Team_Override] = activated ? -1 : 2;
lootRunObelisk.Attributes[GameAttribute.Untargetable] = !activated;
lootRunObelisk.Attributes[GameAttribute.NPC_Is_Operatable] = activated;
lootRunObelisk.Attributes[GameAttribute.Operatable] = activated;
lootRunObelisk.Attributes[GameAttribute.Operatable_Story_Gizmo] = activated;
lootRunObelisk.Attributes[GameAttribute.Disabled] = !activated;
lootRunObelisk.Attributes[GameAttribute.Immunity] = !activated;
lootRunObelisk.Attributes.BroadcastChangedIfRevealed();
lootRunObelisk.CollFlags = 0;
World.BroadcastIfRevealed(plr => new ACDCollFlagsMessage
{
ActorID = lootRunObelisk.DynamicID(plr),
CollFlags = 0
}, lootRunObelisk);
portal = new Portal(World, ActorSno._x1_openworld_lootrunportal, newTagMap);
TickTimer timeout = new SecondsTickTimer(World.Game, 3.5f);
var boom = System.Threading.Tasks.Task<bool>.Factory.StartNew(() => WaitToSpawn(timeout));
boom.ContinueWith(delegate
{
portal.EnterWorld(lootRunObelisk.Position);
//Quest - 382695 - The Great Nephalem
//Quest - 337492 - Just Nephalem
foreach (var plr in InGameClient.Game.Players.Values)
{
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = -1,
DisplayButton = true,
Failed = false
});
plr.InGameClient.SendMessage(new QuestCounterMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = -1,
Checked = 1,
Counter = 1
});
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 1,
DisplayButton = true,
Failed = false
});
plr.InGameClient.Game.ActiveNephalemPortal = true;
plr.InGameClient.SendMessage(new SimpleMessage(Opcodes.RiftStartedMessage));
plr.InGameClient.SendMessage(new GameSyncedDataMessage
{
SyncedData = new GameSyncedData
{
GameSyncedFlags = 6,
Act = 3000, //act id
InitialMonsterLevel = InGameClient.Game.InitialMonsterLevel, //InitialMonsterLevel
MonsterLevel = 0x64E4425E, //MonsterLevel
RandomWeatherSeed = InGameClient.Game.WeatherSeed, //RandomWeatherSeed
OpenWorldMode = -1, //OpenWorldMode
OpenWorldModeAct = -1, //OpenWorldModeAct
OpenWorldModeParam = -1, //OpenWorldModeParam
OpenWorldTransitionTime = 0x00000064, //OpenWorldTransitionTime
OpenWorldDefaultAct = 100, //OpenWorldDefaultAct
OpenWorldBonusAct = -1, //OpenWorldBonusAct
SNODungeonFinderLevelArea = 0x00000001, //SNODungeonFinderLevelArea
LootRunOpen = -1, //LootRunOpen //0 - Великий Портал
OpenLootRunLevel = 0, //OpenLootRunLevel
LootRunBossDead = 0, //LootRunBossDead
HunterPlayerIdx = 0, //HunterPlayerIdx
LootRunBossActive = -1, //LootRunBossActive
TieredLootRunFailed = 0, //TieredLootRunFailed
LootRunChallengeCompleted = 0, //LootRunChallengeCompleted
SetDungeonActive = 0, //SetDungeonActive
Pregame = 0, //Pregame
PregameEnd = 0, //PregameEnd
RoundStart = 0, //RoundStart
RoundEnd = 0, //RoundEnd
PVPGameOver = 0x0, //PVPGameOver
field_v273 = 0x0,
TeamWins = new[] { 0x0, 0x0 }, //TeamWins
TeamScore = new[] { 0x0, 0x0 }, //TeamScore
PVPGameResult = new[] { 0x0, 0x0 }, //PVPGameResult
PartyGuideHeroId =
0x0, //PartyGuideHeroId //new EntityId() { High = 0, Low = (long)this.Players.Values.First().Toon.PersistentID }
TiredRiftPaticipatingHeroID =
new long[] { 0x0, 0x0, 0x0, 0x0 } //TiredRiftPaticipatingHeroID
}
});
}
});
#endregion
break;
#endregion
#region Великий портал
default:
InGameClient.Game.NephalemGreaterLevel = message.Field0;
Logger.Debug("Calling Nephalem Portal (Level: {0})", message.Field0);
activated = false;
foreach (var oldp in World.GetActorsBySNO(ActorSno._x1_openworld_lootrunportal,
ActorSno._x1_openworld_tiered_rifts_portal)) oldp.Destroy();
InGameClient.Game.ActiveNephalemPortal = true;
InGameClient.Game.NephalemGreater = true;
//disable banner while greater is active enable once boss is killed or portal is closed /advocaite
Attributes[GameAttribute.Banner_Usable] = false;
map = maps.PickRandom();
newTagMap.Add(new TagKeySNO(526850), new TagMapEntry(526850, (int)map, 0)); //World
newTagMap.Add(new TagKeySNO(526853), new TagMapEntry(526853, 288482, 0)); //Zone
newTagMap.Add(new TagKeySNO(526851), new TagMapEntry(526851, 172, 0)); //Entry-Pointа
InGameClient.Game.WorldOfPortalNephalem = map;
nephalemPWorld = InGameClient.Game.GetWorld(map);
foreach (var actor in nephalemPWorld.Actors.Values)
if (actor is Portal portal1)
{
if (!portal1.CurrentScene.SceneSNO.Name.ToLower().Contains("entrance"))
{
portal1.Destroy();
}
else
{
portal1.Destination.DestLevelAreaSNO = 332339;
portal1.Destination.WorldSNO = (int)WorldSno.x1_tristram_adventure_mode_hub;
portal1.Destination.StartingPointActorTag = 24;
}
}
else if (actor is Waypoint)
{
actor.Destroy();
}
#region Активация
lootRunObelisk = World.GetActorBySNO(ActorSno._x1_openworld_lootrunobelisk_b);
lootRunObelisk.PlayAnimation(5, (AnimationSno)lootRunObelisk.AnimationSet.TagMapAnimDefault[AnimationSetKeys.Opening]);
lootRunObelisk.Attributes[GameAttribute.Team_Override] = activated ? -1 : 2;
lootRunObelisk.Attributes[GameAttribute.Untargetable] = !activated;
lootRunObelisk.Attributes[GameAttribute.NPC_Is_Operatable] = activated;
lootRunObelisk.Attributes[GameAttribute.Operatable] = activated;
lootRunObelisk.Attributes[GameAttribute.Operatable_Story_Gizmo] = activated;
lootRunObelisk.Attributes[GameAttribute.Disabled] = !activated;
lootRunObelisk.Attributes[GameAttribute.Immunity] = !activated;
lootRunObelisk.Attributes.BroadcastChangedIfRevealed();
lootRunObelisk.CollFlags = 0;
World.BroadcastIfRevealed(plr => new ACDCollFlagsMessage
{
ActorID = lootRunObelisk.DynamicID(plr),
CollFlags = 0
}, lootRunObelisk);
portal = new Portal(World, ActorSno._x1_openworld_tiered_rifts_portal, newTagMap);
TickTimer altTimeout = new SecondsTickTimer(World.Game, 3.5f);
var altBoom = System.Threading.Tasks.Task<bool>.Factory.StartNew(() => WaitToSpawn(altTimeout));
altBoom.ContinueWith(delegate
{
portal.EnterWorld(lootRunObelisk.Position);
//Quest - 382695 - Великий Нефалемский
//Quest - 337492 - Просто Нефалемский
//this.ChangeWorld(NephalemPWorld, NephalemPWorld.GetStartingPointById(172).Position);
foreach (var plr in InGameClient.Game.Players.Values)
{
plr.InGameClient.SendMessage(new SimpleMessage(Opcodes.RiftStartedMessage));
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 337492,
snoLevelArea = 0x000466E2,
StepID = -1,
DisplayButton = true,
Failed = false
});
plr.InGameClient.SendMessage(new QuestCounterMessage()
{
snoQuest = 337492,
snoLevelArea = 0x000466E2,
StepID = -1,
Checked = 1,
Counter = 1
});
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 337492,
snoLevelArea = 0x000466E2,
StepID = 13,
DisplayButton = true,
Failed = false
});
plr.InGameClient.SendMessage(new GameSyncedDataMessage
{
SyncedData = new GameSyncedData
{
GameSyncedFlags = 6,
Act = 3000, //act id
InitialMonsterLevel = InGameClient.Game.InitialMonsterLevel, //InitialMonsterLevel
MonsterLevel = 0x64E4425E, //MonsterLevel
RandomWeatherSeed = InGameClient.Game.WeatherSeed, //RandomWeatherSeed
OpenWorldMode = -1, //OpenWorldMode
OpenWorldModeAct = -1, //OpenWorldModeAct
OpenWorldModeParam = -1, //OpenWorldModeParam
OpenWorldTransitionTime = 0x00000064, //OpenWorldTransitionTime
OpenWorldDefaultAct = 100, //OpenWorldDefaultAct
OpenWorldBonusAct = -1, //OpenWorldBonusAct
SNODungeonFinderLevelArea = 0x00000001, //SNODungeonFinderLevelArea
LootRunOpen = 44, //LootRunOpen //0 - Великий Портал
OpenLootRunLevel = 0, //OpenLootRunLevel
LootRunBossDead = 0, //LootRunBossDead
HunterPlayerIdx = 0, //HunterPlayerIdx
LootRunBossActive = -1, //LootRunBossActive
TieredLootRunFailed = 0, //TieredLootRunFailed
LootRunChallengeCompleted = 0, //LootRunChallengeCompleted
SetDungeonActive = 0, //SetDungeonActive
Pregame = 0, //Pregame
PregameEnd = 0, //PregameEnd
RoundStart = 0, //RoundStart
RoundEnd = 0, //RoundEnd
PVPGameOver = 0x0, //PVPGameOver
field_v273 = 0x0,
TeamWins = new[] { 0x0, 0x0 }, //TeamWins
TeamScore = new[] { 0x0, 0x0 }, //TeamScore
PVPGameResult = new[] { 0x0, 0x0 }, //PVPGameResult
PartyGuideHeroId =
0x0, //PartyGuideHeroId //new EntityId() { High = 0, Low = (long)this.Players.Values.First().Toon.PersistentID }
TiredRiftPaticipatingHeroID =
new long[] { 0x0, 0x0, 0x0, 0x0 } //TiredRiftPaticipatingHeroID
}
});
plr.InGameClient.SendMessage(new IntDataMessage(Opcodes.DungeonFinderSeedMessage)
{
Field0 = 0x3E0FC64C
});
plr.InGameClient.SendMessage(new IntDataMessage(Opcodes.DungeonFinderParticipatingPlayerCount)
{
Field0 = 1
});
plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DungeonFinderProgressMessage)
{
Field0 = 0
});
plr.InGameClient.SendMessage(new SNODataMessage(Opcodes.DungeonFinderSetTimedEvent)
{
Field0 = -1
});
plr.Attributes[GameAttribute.Tiered_Loot_Run_Death_Count] = 0;
}
});
#endregion
break;
#endregion
}
}
private void OnTutorialShown(GameClient client, TutorialShownMessage message)
{
// Server has to save what tutorials are shown, so the player
// does not have to see them over and over...
var index = ItemGenerator.Tutorials.IndexOf(message.SNOTutorial);
if (index == -1) return;
var seenTutorials = Toon.GameAccount.DBGameAccount.SeenTutorials;
if (seenTutorials.Length <= 34)
seenTutorials = new byte[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
seenTutorials[index / 8] |= (byte)(1 << (index % 8));
lock (Toon.GameAccount.DBGameAccount)
{
var gameAccount = Toon.GameAccount.DBGameAccount;
gameAccount.SeenTutorials = seenTutorials;
DBSessions.SessionUpdate(gameAccount);
}
//*/
}
private void OnConfirm(GameClient client, AcceptConfirmMessage message)
{
if (ConfirmationResult != null)
{
ConfirmationResult.Invoke();
ConfirmationResult = null;
}
}
private void OnSpendParagonPointsMessage(GameClient client, SpendParagonPointsMessage message)
{
var bonus = ItemGenerator.GetParagonBonusTable(Toon.Class).FirstOrDefault(b => b.Hash == message.BonusGBID);
if (bonus == null) return;
if (message.Amount > Attributes[GameAttribute.Paragon_Bonus_Points_Available, bonus.Category]) return;
//if (this.ParagonBonuses[(bonus.Category * 4) + bonus.Index - 1] + (byte)message.Amount > bonus.Limit) return;
// message.Amount have the value send to add on attr of Paragon tabs.
ParagonBonuses[bonus.Category * 4 + bonus.Index - 1] += (ushort)message.Amount;
var dbToon = Toon.DBToon;
dbToon.ParagonBonuses = ParagonBonuses;
World.Game.GameDbSession.SessionUpdate(dbToon);
SetAttributesByItems();
SetAttributesByItemProcs();
SetAttributesByGems();
SetAttributesByItemSets();
SetAttributesByPassives();
SetAttributesByParagon();
Attributes.BroadcastChangedIfRevealed();
UpdatePercentageHP(PercHPbeforeChange);
}
private void OnResetParagonPointsMessage(GameClient client, ResetParagonPointsMessage message)
{
ParagonBonuses = new ushort[]
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
var dbToon = Toon.DBToon;
dbToon.ParagonBonuses = ParagonBonuses;
World.Game.GameDbSession.SessionUpdate(dbToon);
SetAttributesByItems();
SetAttributesByItemProcs();
SetAttributesByGems();
SetAttributesByItemSets();
SetAttributesByPassives();
SetAttributesByParagon();
Attributes.BroadcastChangedIfRevealed();
UpdatePercentageHP(PercHPbeforeChange);
}
private void OnMailRead(GameClient client, MailReadMessage message)
{
//does it make sense?
}
private void OnMailRetrieve(GameClient client, MailRetrieveMessage message)
{
var dbMail = World.Game.GameDbSession.SessionGet<DBMail>((ulong)message.MailId);
if (dbMail == null || dbMail.DBToon.Id != Toon.PersistentID) return;
dbMail.Claimed = true;
World.Game.GameDbSession.SessionUpdate(dbMail);
if (dbMail.ItemGBID != -1)
Inventory.PickUp(ItemGenerator.CookFromDefinition(World, ItemGenerator.GetItemDefinition(dbMail.ItemGBID),
-1, true));
LoadMailData();
}
private void OnStashIconsAssign(GameClient client, StashIconStateAssignMessage message)
{
if (message.StashIcons.Length != 4) return;
lock (Toon.GameAccount.DBGameAccount)
{
var dbGAcc = Toon.GameAccount.DBGameAccount;
dbGAcc.StashIcons = message.StashIcons;
DBSessions.SessionUpdate(dbGAcc);
}
//LoadStashIconsData();
}
public void PlayCutscene(int cutsceneId)
{
InGameClient.SendMessage(new PlayCutsceneMessage()
{
Index = cutsceneId
});
}
private void OnTranslateFacing(GameClient client, PlayerTranslateFacingMessage message)
{
SetFacingRotation(message.Angle);
World.BroadcastExclusive(plr => new ACDTranslateFacingMessage
{
ActorId = DynamicID(plr),
Angle = message.Angle,
TurnImmediately = message.TurnImmediately
}, this);
}
private void OnAssignActiveSkill(GameClient client, AssignSkillMessage message)
{
var old_skills = SkillSet.ActiveSkills.Select(s => s.snoSkill).ToList();
foreach (var skill in old_skills)
{
var power = PowerLoader.CreateImplementationForPowerSNO(skill);
if (power != null && power.EvalTag(PowerKeys.SynergyPower) != -1)
World.BuffManager.RemoveBuffs(this, power.EvalTag(PowerKeys.SynergyPower));
}
var oldSNOSkill = SkillSet.ActiveSkills[message.SkillIndex].snoSkill; // find replaced skills SNO.
if (oldSNOSkill != -1)
{
Attributes[GameAttribute.Skill, oldSNOSkill] = 0;
World.BuffManager.RemoveBuffs(this, oldSNOSkill);
var rem = new List<uint>();
foreach (var fol in Followers.Where(f =>
World.GetActorByGlobalId(f.Key) == null ||
World.GetActorByGlobalId(f.Key).Attributes[GameAttribute.Summoned_By_SNO] == oldSNOSkill))
rem.Add(fol.Key);
foreach (var rm in rem)
DestroyFollowerById(rm);
}
Attributes[GameAttribute.Skill, message.SNOSkill] = 1;
//scripted //this.Attributes[GameAttribute.Skill_Total, message.SNOSkill] = 1;
SkillSet.ActiveSkills[message.SkillIndex].snoSkill = message.SNOSkill;
SkillSet.ActiveSkills[message.SkillIndex].snoRune = message.RuneIndex;
SkillSet.SwitchUpdateSkills(message.SkillIndex, message.SNOSkill, message.RuneIndex, Toon);
SetAttributesSkillSets();
Attributes.BroadcastChangedIfRevealed();
UpdateHeroState();
var cooldownskill = SkillSet.ActiveSkills.GetValue(message.SkillIndex);
if (SkillSet.HasSkill(460757))
foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 460757)
if (skill.snoRune == 3)
World.BuffManager.AddBuff(this, this, new P6_Necro_Devour_Aura());
else
World.BuffManager.RemoveBuffs(this, 474325);
if (SkillSet.HasSkill(460870))
foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 460870)
if (skill.snoRune == 4)
World.BuffManager.AddBuff(this, this, new P6_Necro_Frailty_Aura());
else
World.BuffManager.RemoveBuffs(this, 473992);
//_StartSkillCooldown((cooldownskill as ActiveSkillSavedData).snoSkill, SkillChangeCooldownLength);
}
private void OnAssignPassiveSkills(GameClient client, AssignTraitsMessage message)
{
for (var i = 0; i < message.SNOPowers.Length; ++i)
{
var oldSNOSkill = SkillSet.PassiveSkills[i]; // find replaced skills SNO.
if (message.SNOPowers[i] != oldSNOSkill)
{
if (oldSNOSkill != -1)
{
World.BuffManager.RemoveAllBuffs(this);
// switch off old passive skill
Attributes[GameAttribute.Trait, oldSNOSkill] = 0;
Attributes[GameAttribute.Skill, oldSNOSkill] = 0;
//scripted //this.Attributes[GameAttribute.Skill_Total, oldSNOSkill] = 0;
}
if (message.SNOPowers[i] != -1)
{
// switch on new passive skill
Attributes[GameAttribute.Trait, message.SNOPowers[i]] = 1;
Attributes[GameAttribute.Skill, message.SNOPowers[i]] = 1;
//scripted //this.Attributes[GameAttribute.Skill_Total, message.SNOPowers[i]] = 1;
}
SkillSet.PassiveSkills[i] = message.SNOPowers[i];
}
}
SkillSet.UpdatePassiveSkills(Toon);
var skills = SkillSet.ActiveSkills.Select(s => s.snoSkill).ToList();
foreach (var skill in skills)
_StartSkillCooldown(skill, SkillChangeCooldownLength);
SetAttributesByItems();
SetAttributesByGems();
SetAttributesByItemSets();
SetAttributesByPassives();
SetAttributesByParagon();
SetAttributesSkillSets();
Inventory.CheckWeapons(); //Handles removal of Heavenly Strength
Attributes.BroadcastChangedIfRevealed();
UpdateHeroState();
UpdatePercentageHP(PercHPbeforeChange);
}
private void OnUnassignActiveSkill(GameClient client, UnassignSkillMessage message)
{
var oldSNOSkill = SkillSet.ActiveSkills[message.SkillIndex].snoSkill; // find replaced skills SNO.
if (oldSNOSkill != -1)
{
Attributes[GameAttribute.Skill, oldSNOSkill] = 0;
World.BuffManager.RemoveBuffs(this, oldSNOSkill);
var rem = new List<uint>();
foreach (var fol in Followers.Where(f =>
Math.Abs(World.GetActorByGlobalId(f.Key).Attributes[GameAttribute.Summoned_By_SNO] -
oldSNOSkill) < 0.001))
rem.Add(fol.Key);
foreach (var rm in rem)
DestroyFollowerById(rm);
}
SkillSet.ActiveSkills[message.SkillIndex].snoSkill = -1;
SkillSet.ActiveSkills[message.SkillIndex].snoRune = -1;
SkillSet.SwitchUpdateSkills(message.SkillIndex, -1, -1, Toon);
SetAttributesSkillSets();
Attributes.BroadcastChangedIfRevealed();
UpdateHeroState();
}
public void SetNewAttributes()
{
//this.Attributes[GameAttribute.Attacks_Per_Second] = 1.0f;
//this.Attributes[GameAttribute.Attacks_Per_Second_Bonus] = 1.0f;
//this.Attributes[GameAttribute.Gold] = 1;
//[GameAttribute.Damage_Weapon_Min_Total, 0]
Attributes[GameAttribute.Attacks_Per_Second_Percent] = 0;
Attributes[GameAttribute.Attacks_Per_Second_Percent_Uncapped] = 0;
Attributes[GameAttribute.Attacks_Per_Second_Percent_Reduction] = 0;
Attributes[GameAttribute.Attacks_Per_Second_Percent_Cap] = 0;
//this.Attributes[GameAttribute.Gold_PickUp_Radius] = 5f;
/*
this.Attributes[GameAttribute.Experience_Bonus_Percent_Anniversary_Buff] = 100;
this.Attributes[GameAttribute.Experience_Bonus_Percent_Community_Buff] = 100;
this.Attributes[GameAttribute.Experience_Bonus_Percent_Handicap] = 100;
this.Attributes[GameAttribute.Experience_Bonus_Percent_IGR_Buff] = 100;
this.Attributes[GameAttribute.Experience_Bonus_Percent_Potion_Buff] = 1;
//*/
/*
this.InGameClient.SendMessage(new PlayerSkillsMessage()
{
PlayerIndex = this.PlayerIndex,
ActiveSkills = this.SkillSet.ActiveSkills,
Traits = new int[4] { 0x00032E5E, -1, -1, -1 },
LegendaryPowers = new int[4] { -1, -1, -1, -1 }
});
//*/
}
private void _StartSkillCooldown(int snoPower, float seconds)
{
World.BuffManager.AddBuff(this, this,
new CooldownBuff(snoPower, seconds));
}
//private void OnPlayerChangeHotbarButtonMessage(GameClient client, PlayerChangeHotbarButtonMessage message)
//{
// this.SkillSet.HotBarSkills[message.BarIndex] = message.ButtonData;
//}
private void OnObjectTargeted(GameClient client, TargetMessage message)
{
if (message.TargetID != 0xffffffff)
message.TargetID = World.GetGlobalId(this, message.TargetID);
if (Toon.Class == ToonClass.Crusader)
if (World.BuffManager.HasBuff<CrusaderSteedCharge.PonyBuff>(this)) //Crusader -> cancel Steed Charge
World.BuffManager.RemoveBuffs(this, 243853);
var powerHandled =
World.PowerManager.RunPower(this, message.PowerSNO, message.TargetID, message.Place.Position, message);
if (!powerHandled)
{
var actor = World.GetActorByGlobalId(message.TargetID);
if (actor == null) return;
#if DEBUG
Logger.Warn("OnTargetedActor ID: {0}, Name: {1}, NumInWorld: {2}", actor.SNO, actor.Name,
actor.NumberInWorld);
#else
#endif
if (actor.GBHandle.Type == 1 && actor.Attributes[GameAttribute.TeamID] == 10)
ExpBonusData.MonsterAttacked(InGameClient.Game.TickCounter);
actor.OnTargeted(this, message);
}
ExpBonusData.Check(2);
}
private int _hackCounter = 0;
public bool SpeedCheckDisabled = false;
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
public int i = 0;
private void OnPlayerMovement(GameClient client, ACDClientTranslateMessage message)
{
Attributes.BroadcastChangedIfRevealed();
var a = GetActorsInRange(15f);
#region
//UpdateExp(5000000);
/*
this.Attributes[GameAttribute.Jewel_Upgrades_Max] = 3;
this.Attributes[GameAttribute.Jewel_Upgrades_Bonus] = 2;
this.Attributes[GameAttribute.Jewel_Upgrades_Used] = 0;
Attributes[GameAttribute.Currencies_Discovered] = 20;
this.Attributes.BroadcastChangedIfRevealed();
var Quest = DiIiS_NA.Core.MPQ.MPQStorage.Data.Assets[Core.Types.SNO.SNOGroup.Quest][337492].Data;
//*/
//this.Toon.BigPortalKey++;
//this.Toon.CraftItem4++;
/*
//Приглашение на великий портал
InGameClient.SendMessage(new MessageSystem.Message.Definitions.Encounter.RiftJoinMessage()
{
PlayerIndex = 0,
RiftStartServerTime = this.InGameClient.Game.TickCounter,
RiftTier = 0
});
/*
//Результаты прохождения подземелья
InGameClient.SendMessage(new MessageSystem.Message.Definitions.Dungeon.SetDungeonResultsMessage()
{
SNOQuestKill = -1,
QuestKillMonsterCounter = 0,
SNOQuestBonus1 = -1,
QuestBonus1Success = false,
SNOQuestBonus2 = -1,
QuestBonus2Success = false,
SNOQuestMastery = -1,
QuestMasterySuccess = false,
QuestKillSuccess = false,
ShowTotalTime = true,
TimeTaken = 120,
TargetTime = 200
});
/*
//Приглашение в комплектное подземелье
InGameClient.SendMessage(new MessageSystem.Message.Definitions.Dungeon.SetDungeonDialogMessage()
{
PlayerIndex = 0,
LabelDescription = 1,
LabelTitle = 1
}) ;
/*
InGameClient.SendMessage(new BroadcastTextMessage()
{
Field0 = "Тест"
});
/*
this.InGameClient.SendMessage(new DisplayGameTextMessage(Opcodes.DisplayGameTextMessage)
{
Message = "Пампам"
});
//*/
#endregion
if (World == null) return;
if (Dead)
{
World.BroadcastIfRevealed(ACDWorldPositionMessage, this);
return;
}
if (World.Game.Paused || BetweenWorlds) return;
if (message.MovementSpeed > Attributes[GameAttribute.Running_Rate_Total] * 1.5f && !SpeedCheckDisabled)
{
_hackCounter++;
if (_hackCounter > 5) _hackCounter = 0;
World.BroadcastIfRevealed(ACDWorldPositionMessage, this);
return;
}
if (message.Position != null)
{
if (PowerMath.Distance2D(message.Position, Position) > 300f)
{
World.BroadcastIfRevealed(ACDWorldPositionMessage, this);
InGameClient.SendMessage(new ACDTranslateSyncMessage()
{
ActorId = DynamicID(this),
Position = Position
});
return;
}
Position = message.Position;
}
SetFacingRotation(message.Angle);
if (IsCasting) StopCasting();
World.BuffManager.RemoveBuffs(this, 298038);
RevealScenesToPlayer();
RevealPlayersToPlayer();
RevealActorsToPlayer();
World.BroadcastExclusive(plr => new ACDTranslateNormalMessage
{
ActorId = DynamicID(plr),
Position = Position,
Angle = message.Angle,
SnapFacing = false,
MovementSpeed = message.MovementSpeed,
AnimationTag = message.AnimationTag
}, this, true);
foreach (var actor in GetActorsInRange())
actor.OnPlayerApproaching(this);
VacuumPickup();
if (World.Game.OnLoadWorldActions.ContainsKey(World.SNO))
{
Logger.MethodTrace($"OnLoadWorldActions: {World.SNO}");
lock (World.Game.OnLoadWorldActions[World.SNO])
{
foreach (var action in World.Game.OnLoadWorldActions[World.SNO])
{
try
{
action();
}
catch (Exception ex)
{
Logger.WarnException(ex, "OnLoadWorldActions");
}
}
World.Game.OnLoadWorldActions[World.SNO].Clear();
}
}
if (World.Game.OnLoadSceneActions.ContainsKey(CurrentScene.SceneSNO.Id))
{
Logger.MethodTrace($"OnLoadSceneActions: {CurrentScene.SceneSNO.Id}");
Logger.MethodTrace(World.SNO.ToString());
lock (World.Game.OnLoadSceneActions[CurrentScene.SceneSNO.Id])
{
foreach (var action in World.Game.OnLoadSceneActions[CurrentScene.SceneSNO.Id])
{
try
{
action();
}
catch (Exception ex)
{
Logger.WarnException(ex, "OnLoadSceneActions");
}
}
World.Game.OnLoadSceneActions[CurrentScene.SceneSNO.Id].Clear();
}
}
if (CurrentScene.SceneSNO.Id != PreSceneId)
{
PreSceneId = CurrentScene.SceneSNO.Id;
var levelArea = CurrentScene.Specification.SNOLevelAreas[0];
if (World.Game.QuestProgress.QuestTriggers.ContainsKey(levelArea)) //EnterLevelArea
{
var trigger = World.Game.QuestProgress.QuestTriggers[levelArea];
if (trigger.triggerType == DiIiS_NA.Core.MPQ.FileFormats.QuestStepObjectiveType.EnterLevelArea)
try
{
Logger.MethodTrace($"EnterLevelArea: {levelArea}");
trigger.questEvent.Execute(World); // launch a questEvent
}
catch (Exception e)
{
Logger.WarnException(e, "questEvent()");
}
}
// Reset resurrection charges on zone change - TODO: do not reset charges on reentering the same zone
Attributes[GameAttribute.Corpse_Resurrection_Charges] = Config.Instance.ResurrectionCharges;
#if DEBUG
Logger.Warn($"Player Location {Toon.Name}, Scene: {CurrentScene.SceneSNO.Name} SNO: {CurrentScene.SceneSNO.Id} LevelArea: {CurrentScene.Specification.SNOLevelAreas[0]}");
#endif
}
LastMovementTick = World.Game.TickCounter;
}
private void OnCancelChanneledSkill(GameClient client, CancelChanneledSkillMessage message)
{
World.PowerManager.CancelChanneledSkill(this, message.PowerSNO);
}
private void OnRequestBuffCancel(GameClient client, RequestBuffCancelMessage message)
{
World.BuffManager.RemoveBuffs(this, message.PowerSNOId);
}
private void OnSecondaryPowerMessage(GameClient client, SecondaryAnimationPowerMessage message)
{
World.PowerManager.RunPower(this, message.PowerSNO, (uint)message.annTarget);
}
private void OnMiscPowerMessage(GameClient client, MiscPowerMessage message)
{
World.PowerManager.RunPower(this, message.PowerSNO);
}
private void OnLoopingAnimationPowerMessage(GameClient client, LoopingAnimationPowerMessage message)
{
StartCasting(150, new Action(() =>
{
try
{
World.PowerManager.RunPower(this, message.snoPower);
}
catch
{
}
}), message.snoPower);
}
private void OnTryWaypoint(GameClient client, TryWaypointMessage tryWaypointMessage)
{
var wpWorld = World.Game.GetWayPointWorldById(tryWaypointMessage.nWaypoint);
var wayPoint = wpWorld.GetWayPointById(tryWaypointMessage.nWaypoint);
if (wayPoint == null) return;
Logger.Debug("---Waypoint Debug---");
var proximity = new RectangleF(wayPoint.Position.X - 1f, wayPoint.Position.Y - 1f, 2f, 2f);
var scenes = wpWorld.QuadTree.Query<Scene>(proximity);
if (scenes.Count == 0) return; // cork (is it real?)
var scene = scenes[0]; // Parent scene /fasbat
if (scenes.Count == 2) // What if it's a subscene?
if (scenes[1].ParentChunkID != 0xFFFFFFFF)
scene = scenes[1];
var levelArea = scene.Specification.SNOLevelAreas[0];
Logger.Debug(
$"OnTryWaypoint: Id: {tryWaypointMessage.nWaypoint}, WorldId: {wpWorld.SNO}, levelArea: {levelArea}");
Logger.Debug($"WpWorld: {wpWorld}, wayPoint: {wayPoint}");
InGameClient.SendMessage(new SimpleMessage(Opcodes.LoadingWarping));
if (wpWorld == World)
Teleport(wayPoint.Position);
else
ChangeWorld(wpWorld, wayPoint.Position);
//handling quest triggers
if (World.Game.QuestProgress.QuestTriggers.ContainsKey(levelArea)) //EnterLevelArea
{
var trigger = World.Game.QuestProgress.QuestTriggers[levelArea];
if (trigger.triggerType == DiIiS_NA.Core.MPQ.FileFormats.QuestStepObjectiveType.EnterLevelArea)
try
{
trigger.questEvent.Execute(World); // launch a questEvent
}
catch (Exception e)
{
Logger.WarnException(e, "questEvent()");
}
}
foreach (var bounty in World.Game.QuestManager.Bounties)
bounty.CheckLevelArea(levelArea);
InGameClient.SendMessage(new PortedToWaypointMessage
{
PlayerIndex = PlayerIndex,
LevelAreaSNO = levelArea
});
Logger.Debug("---Waypoint Debug End---");
}
public void RefreshReveal()
{
var range = 200f;
if (InGameClient.Game.CurrentEncounter.Activated)
range = 360f;
foreach (var actor in GetActorsInRange(range).Where(actor => actor is not Player))
actor.Unreveal(this);
RevealActorsToPlayer();
}
private void OnRequestBuyItem(GameClient client, RequestBuyItemMessage requestBuyItemMessage)
{
var vendor = SelectedNPC as Vendor;
if (vendor == null)
return;
vendor.OnRequestBuyItem(this, requestBuyItemMessage.ItemId);
}
private void OnRequestSellItem(GameClient client, RequestSellItemMessage requestSellItemMessage)
{
var vendor = SelectedNPC as Vendor;
if (vendor == null)
return;
vendor.OnRequestSellItem(this, (int)requestSellItemMessage.ItemId);
}
private void OnHirelingRetrainMessage()
{
if (ActiveHireling == null) return;
switch (ActiveHireling.Attributes[GameAttribute.Hireling_Class])
{
case 1:
if (ActiveHireling is Templar)
(ActiveHireling as Templar).Retrain(this);
break;
case 2:
if (ActiveHireling is Scoundrel)
(ActiveHireling as Scoundrel).Retrain(this);
break;
case 3:
if (ActiveHireling is Enchantress)
(ActiveHireling as Enchantress).Retrain(this);
break;
default:
return;
}
}
//*
private void OnHirelingDismiss(GameClient client, PetAwayMessage message)
{
Logger.MethodTrace(message.ActorID.ToString());
var petId = World.GetGlobalId(this, message.ActorID);
var pet = World.GetActorByGlobalId(petId);
if (pet is Hireling)
ActiveHireling = null;
else
DestroyFollowersBySnoId(pet.SNO);
}
private void OnHirelingRequestLearnSkill(GameClient client, HirelingRequestLearnSkillMessage message)
{
Logger.MethodTrace($"{message.HirelingID} - {message.PowerSNOId}");
var hireling = World.GetActorByGlobalId(World.GetGlobalId(this, message.HirelingID));
if (hireling == null) return;
switch (hireling.Attributes[GameAttribute.Hireling_Class])
{
case 1:
if (hireling is not Templar templar) return;
templar.SetSkill(this, message.PowerSNOId);
break;
case 2:
if (hireling is not Scoundrel scoundrel) return;
scoundrel.SetSkill(this, message.PowerSNOId);
break;
case 3:
if (hireling is not Enchantress enchantress) return;
enchantress.SetSkill(this, message.PowerSNOId);
break;
default:
break;
}
}
//*/
private void OnResurrectOption(GameClient client, RessurectionPlayerMessage message)
{
Logger.Trace("Resurrect option: {0}", message.Choice);
switch (message.Choice)
{
case 0:
Revive(Position);
ChangeWorld(World.Game.StartingWorld, World.Game.StartPosition);
break;
case 1:
Revive(CheckPointPosition);
break;
case 2:
if (Attributes[GameAttribute.Corpse_Resurrection_Charges] > 0)
{
Revive(Position);
Attributes[GameAttribute.Corpse_Resurrection_Charges]--;
}
break;
}
}
//*/
private void OnEquipPotion(GameClient client, ChangeUsableItemMessage message)
{
var activeSkills = Toon.DBActiveSkills;
activeSkills.PotionGBID = message.Field1;
World.Game.GameDbSession.SessionUpdate(activeSkills);
}
public void ToonStateChanged()
{
try
{
ClientSystem.GameServer.GSBackend.ToonStateChanged(Toon.PersistentID);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on ToonStateChanged(): ");
}
}
private void OnArtisanWindowClosed()
{
CurrentArtisan = null;
}
//*
private void TrainArtisan(GameClient client, RequestTrainArtisanMessage message)
{
if (CurrentArtisan == null || !artisanTrainHelpers.ContainsKey(CurrentArtisan.Value))
{
Logger.Warn("Training for artisan {} is not supported", CurrentArtisan);
return;
}
var trainHelper = artisanTrainHelpers[CurrentArtisan.Value];
if (trainHelper.HasMaxLevel)
return;
var recipeDefinition = ItemGenerator.GetRecipeDefinition(trainHelper.TrainRecipeName);
if (Inventory.GetGoldAmount() < recipeDefinition.Gold)
return;
var requiredIngridients = recipeDefinition.Ingredients.Where(x => x.ItemsGBID > 0);
// FIXME: Inventory.HaveEnough doesn't work for some craft consumables
var haveEnoughIngredients = requiredIngridients.All(x => Inventory.HaveEnough(x.ItemsGBID, x.Count));
if (!haveEnoughIngredients)
return;
Inventory.RemoveGoldAmount(recipeDefinition.Gold);
foreach (var ingr in requiredIngridients)
// FIXME: Inventory.GrabSomeItems doesn't work for some craft consumables
Inventory.GrabSomeItems(ingr.ItemsGBID, ingr.Count);
trainHelper.DbRef.Level++;
World.Game.GameDbSession.SessionUpdate(trainHelper.DbRef);
if (trainHelper.Achievement is not null)
GrantAchievement(trainHelper.Achievement.Value);
if (trainHelper.Criteria is not null)
GrantCriteria(trainHelper.Criteria.Value);
if (artisanTrainHelpers.All(x => x.Value.HasMaxLevel))
GrantCriteria(74987249993545);
client.SendMessage(new CrafterLevelUpMessage
{
Type = trainHelper.Type,
AnimTag = trainHelper.AnimationTag,
NewIdle = trainHelper.IdleAnimationTag,
Level = trainHelper.DbRef.Level
});
LoadCrafterData();
/**/
}
public void UnlockTransmog(int transmogGBID)
{
if (learnedTransmogs.Contains(transmogGBID)) return;
InGameClient.SendMessage(new UnlockTransmogMessage() { TransmogGBID = transmogGBID });
Logger.Trace("Learning transmog #{0}", transmogGBID);
learnedTransmogs.Add(transmogGBID);
mystic_data.LearnedRecipes = SerializeBytes(learnedTransmogs);
World.Game.GameDbSession.SessionUpdate(mystic_data);
LoadCrafterData();
}
#endregion
#region update-logic
private int PreviousLevelArea = -1;
private List<TickTimer> TimedActions = new();
public int VaultsDone = 0;
public int SpikeTrapsKilled = 0;
public void AddTimedAction(float seconds, Action<int> onTimeout)
{
TimedActions.Add(TickTimer.WaitSeconds(World.Game, seconds, onTimeout));
}
public void Update(int tickCounter)
{
if (BetweenWorlds) return;
#if DEBUG
#else
if ((this.InGameClient.Game.TickCounter - this.LastMovementTick) > 54000) //15m AFK
{
this.InGameClient.SendMessage(new SimpleMessage(Opcodes.CloseGameMessage));
}
#endif
// Check the gold
if (InGameClient.Game.TickCounter % 120 == 0 && World != null && GoldCollectedTempCount > 0)
{
Toon.GameAccount.Gold += (ulong)GoldCollectedTempCount;
Toon.CollectedGold += (ulong)GoldCollectedTempCount;
if (World.Game.IsHardcore)
Toon.CollectedGoldSeasonal += GoldCollectedTempCount;
UpdateAchievementCounter(10, (uint)GoldCollectedTempCount);
GoldCollectedTempCount = 0;
}
// Check the blood shards
if (InGameClient.Game.TickCounter % 120 == 0 && World != null && BloodShardsCollectedTempCount > 0)
{
Toon.GameAccount.BloodShards += BloodShardsCollectedTempCount;
Toon.GameAccount.TotalBloodShards += BloodShardsCollectedTempCount;
BloodShardsCollectedTempCount = 0;
}
if (World != null && SkillSet.HasPassive(298038) && InGameClient.Game.TickCounter - LastMovementTick > 90)
World.BuffManager.AddBuff(this, this, new UnwaveringWillBuff());
if (World != null && SkillSet.HasSkill(312736) && InGameClient.Game.TickCounter - LastMovementTick > 90)
World.BuffManager.AddBuff(this, this, new MonkDashingStrike.DashingStrikeCountBuff());
else if (!SkillSet.HasSkill(312736))
Attributes[GameAttribute.Skill_Charges, 312736] = 0;
if (World != null && SkillSet.HasSkill(129217) && InGameClient.Game.TickCounter - LastMovementTick > 90)
World.BuffManager.AddBuff(this, this, new Sentry.SentryCountBuff());
else if (!SkillSet.HasSkill(129217))
Attributes[GameAttribute.Skill_Charges, 129217] = 0;
if (World != null && SkillSet.HasSkill(75301) && InGameClient.Game.TickCounter - LastMovementTick > 90)
World.BuffManager.AddBuff(this, this, new SpikeTrap.SpikeCountBuff());
else if (!SkillSet.HasSkill(75301))
Attributes[GameAttribute.Skill_Charges, 75301] = 0;
if (World != null && SkillSet.HasSkill(464896) && InGameClient.Game.TickCounter - LastMovementTick > 90)
World.BuffManager.AddBuff(this, this, new BoneSpirit.SpiritCountBuff());
else if (!SkillSet.HasSkill(464896))
Attributes[GameAttribute.Skill_Charges, 464896] = 0;
if (World != null && SkillSet.HasSkill(97435) && InGameClient.Game.TickCounter - LastMovementTick > 90)
World.BuffManager.AddBuff(this, this, new FuriousCharge.FuriousChargeCountBuff());
else if (!SkillSet.HasSkill(97435))
Attributes[GameAttribute.Skill_Charges, 97435] = 0;
Attributes.BroadcastChangedIfRevealed();
lock (TimedActions)
{
foreach (var timed_action in TimedActions)
timed_action.Update(tickCounter);
}
foreach (var timed_out in TimedActions.Where(t => t.TimedOut).ToList())
TimedActions.Remove(timed_out);
// Check the Killstreaks
ExpBonusData.Check(0);
ExpBonusData.Check(1);
// Check if there is an conversation to close in this tick
Conversations.Update(World.Game.TickCounter);
foreach (var proximityGizmo in GetObjectsInRange<Actor>(20f, true))
{
if (proximityGizmo == null || proximityGizmo.SNO == ActorSno.__NONE) continue;
if (World.Game.QuestProgress.QuestTriggers.ContainsKey((int)proximityGizmo.SNO) &&
proximityGizmo.Visible) //EnterTrigger
{
var trigger = World.Game.QuestProgress.QuestTriggers[(int)proximityGizmo.SNO];
if (trigger.triggerType == DiIiS_NA.Core.MPQ.FileFormats.QuestStepObjectiveType.EnterTrigger)
//this.World.Game.Quests.NotifyQuest(this.World.Game.CurrentQuest, Mooege.Common.MPQ.FileFormats.QuestStepObjectiveType.EnterTrigger, proximityGizmo.ActorSNO.Id);
try
{
trigger.questEvent.Execute(World); // launch a questEvent
}
catch (Exception e)
{
Logger.WarnException(e, "questEvent()");
}
}
else if (World.Game.SideQuestProgress.QuestTriggers.ContainsKey((int)proximityGizmo.SNO))
{
var trigger = World.Game.SideQuestProgress.QuestTriggers[(int)proximityGizmo.SNO];
if (trigger.triggerType == DiIiS_NA.Core.MPQ.FileFormats.QuestStepObjectiveType.EnterTrigger)
{
World.Game.SideQuestProgress.UpdateSideCounter((int)proximityGizmo.SNO);
if (trigger.count == World.Game.SideQuestProgress.QuestTriggers[(int)proximityGizmo.SNO].counter)
trigger.questEvent.Execute(World); // launch a questEvent
}
}
if (World.Game.SideQuestProgress.GlobalQuestTriggers.ContainsKey((int)proximityGizmo.SNO) &&
proximityGizmo.Visible) //EnterTrigger
{
var trigger = World.Game.SideQuestProgress.GlobalQuestTriggers[(int)proximityGizmo.SNO];
if (trigger.triggerType == DiIiS_NA.Core.MPQ.FileFormats.QuestStepObjectiveType.EnterTrigger)
//this.World.Game.Quests.NotifyQuest(this.World.Game.CurrentQuest, Mooege.Common.MPQ.FileFormats.QuestStepObjectiveType.EnterTrigger, proximityGizmo.ActorSNO.Id);
try
{
trigger.questEvent.Execute(World); // launch a questEvent
World.Game.SideQuestProgress.GlobalQuestTriggers.Remove((int)proximityGizmo.SNO);
}
catch (Exception e)
{
Logger.WarnException(e, "questEvent()");
}
}
}
_UpdateResources();
if (IsCasting) UpdateCastState();
if (InGameClient.Game.TickCounter % 60 == 0 && World != null)
{
var proximity = new RectangleF(Position.X - 1f, Position.Y - 1f, 2f, 2f);
var scenes = World.QuadTree.Query<Scene>(proximity);
if (scenes.Count == 0) return;
var scene = scenes[0];
if (PreviousLevelArea != scene.Specification.SNOLevelAreas[0])
{
PreviousLevelArea = scene.Specification.SNOLevelAreas[0];
World.Game.WorldGenerator.CheckLevelArea(World, PreviousLevelArea);
if (InGameClient.Game.TickCounter % 600 == 0)
CheckLevelAreaCriteria(PreviousLevelArea);
}
}
if (InGameClient.Game.TickCounter % 600 == 0 && World != null)
{
if (KilledMonstersTempCount != 0)
{
Toon.TotalKilled += (ulong)KilledMonstersTempCount;
KilledMonstersTempCount = 0;
if (KilledElitesTempCount != 0)
{
Toon.ElitesKilled += (ulong)KilledElitesTempCount;
KilledElitesTempCount = 0;
}
if (KilledSeasonalTempCount != 0)
{
Toon.SeasonalKills += KilledSeasonalTempCount;
KilledSeasonalTempCount = 0;
}
}
CheckAchievementCounters();
}
#region Necromancer summons
var switchertobool = false;
var switchertoboolTwo = false;
ActiveSkillSavedData NowSkillGolem = null;
foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 453801)
switchertobool = true;
foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 451537)
{
switchertoboolTwo = true;
NowSkillGolem = skill;
}
ActiveSkeletons = switchertobool;
EnableGolem = switchertoboolTwo;
var Killer = new PowerContext();
Killer.User = this;
Killer.World = World;
Killer.PowerSNO = -1;
if (ActiveSkeletons)
{
while (NecroSkeletons.Count < 7)
{
var Skeleton = new NecromancerSkeleton_A(World, ActorSno._p6_necro_commandskeletons_a, this);
Skeleton.Brain.DeActivate();
Skeleton.Scale = 1.2f;
Skeleton.EnterWorld(PowerContext.RandomDirection(Position, 3f, 8f));
NecroSkeletons.Add(Skeleton);
/*this.InGameClient.SendMessage(new PetMessage()
{
Owner = this.PlayerIndex,
Index = this.CountFollowers(473147),
PetId = Skeleton.DynamicID(this),
Type = 70,
});
//*/
Skeleton.Brain.Activate();
}
}
else
{
foreach (var skel in NecroSkeletons)
{
InGameClient.SendMessage(new PetDetachMessage()
{
PetId = skel.GlobalID
});
World.Leave(skel);
}
NecroSkeletons.Clear();
}
if (EnableGolem || ActiveGolem != null)
{
var runeActorSno = RuneSelect(451537, ActorSno._p6_necro_revive_golem, ActorSno._p6_bonegolem,
ActorSno._p6_bloodgolem, ActorSno._p6_consumefleshgolem, ActorSno._p6_decaygolem,
ActorSno._p6_icegolem);
if (ActiveGolem != null)
{
if (ActiveGolem.SNO != runeActorSno || !SkillSet.HasSkill(451537))
{
if (ActiveGolem.World != null)
{
if (!ActiveGolem.IsRevealedToPlayer(this))
InGameClient.SendMessage(new PetDetachMessage()
{
PetId = ActiveGolem.GlobalID
});
Killer.Target = ActiveGolem;
(ActiveGolem as Minion).Kill(Killer);
}
ActiveGolem = null;
}
}
else
{
if (Attributes[GameAttribute.Power_Cooldown, 451537] > InGameClient.Game.TickCounter)
{
}
else
{
switch (runeActorSno)
{
case ActorSno._p6_necro_revive_golem:
var NGolem = new BaseGolem(World, this);
NGolem.Brain.DeActivate();
NGolem.Position =
RandomDirection(Position, 3f,
8f); //Kind of hacky until we get proper collisiondetection
NGolem.Attributes[GameAttribute.Untargetable] = true;
NGolem.EnterWorld(NGolem.Position);
//(NGolem as BaseGolem).Brain.Activate();
NGolem.Attributes[GameAttribute.Untargetable] = false;
NGolem.Attributes.BroadcastChangedIfRevealed();
ActiveGolem = NGolem;
break;
case ActorSno._p6_consumefleshgolem:
var CFGolem = new ConsumeFleshGolem(World, this);
CFGolem.Brain.DeActivate();
CFGolem.Position =
RandomDirection(Position, 3f,
8f); //Kind of hacky until we get proper collisiondetection
CFGolem.Attributes[GameAttribute.Untargetable] = true;
CFGolem.EnterWorld(CFGolem.Position);
//(CFGolem as ConsumeFleshGolem).Brain.Activate();
CFGolem.Attributes[GameAttribute.Untargetable] = false;
CFGolem.Attributes.BroadcastChangedIfRevealed();
ActiveGolem = CFGolem;
break;
case ActorSno._p6_icegolem:
var IGolem = new IceGolem(World, this);
IGolem.Brain.DeActivate();
IGolem.Position =
RandomDirection(Position, 3f,
8f); //Kind of hacky until we get proper collisiondetection
IGolem.Attributes[GameAttribute.Untargetable] = true;
IGolem.EnterWorld(IGolem.Position);
//(IGolem as IceGolem).Brain.Activate();
IGolem.Attributes[GameAttribute.Untargetable] = false;
IGolem.Attributes.BroadcastChangedIfRevealed();
ActiveGolem = IGolem;
break;
case ActorSno._p6_bonegolem:
var BGolem = new BoneGolem(World, this);
BGolem.Brain.DeActivate();
BGolem.Position =
RandomDirection(Position, 3f,
8f); //Kind of hacky until we get proper collisiondetection
BGolem.Attributes[GameAttribute.Untargetable] = true;
BGolem.EnterWorld(BGolem.Position);
//(BGolem as BoneGolem).Brain.Activate();
BGolem.Attributes[GameAttribute.Untargetable] = false;
BGolem.Attributes.BroadcastChangedIfRevealed();
ActiveGolem = BGolem;
break;
case ActorSno._p6_decaygolem:
var DGolem = new DecayGolem(World, this);
DGolem.Brain.DeActivate();
DGolem.Position =
RandomDirection(Position, 3f,
8f); //Kind of hacky until we get proper collisiondetection
DGolem.Attributes[GameAttribute.Untargetable] = true;
DGolem.EnterWorld(DGolem.Position);
//(DGolem as DecayGolem).Brain.Activate();
DGolem.Attributes[GameAttribute.Untargetable] = false;
DGolem.Attributes.BroadcastChangedIfRevealed();
ActiveGolem = DGolem;
break;
case ActorSno._p6_bloodgolem:
var BlGolem = new BloodGolem(World, this);
BlGolem.Brain.DeActivate();
BlGolem.Position =
RandomDirection(Position, 3f,
8f); //Kind of hacky until we get proper collisiondetection
BlGolem.Attributes[GameAttribute.Untargetable] = true;
BlGolem.EnterWorld(BlGolem.Position);
//(BlGolem as BloodGolem).Brain.Activate();
BlGolem.Attributes[GameAttribute.Untargetable] = false;
BlGolem.Attributes.BroadcastChangedIfRevealed();
ActiveGolem = BlGolem;
break;
}
(ActiveGolem as Minion).Brain.Activate();
ActiveGolem.Attributes[GameAttribute.Untargetable] = false;
ActiveGolem.Attributes.BroadcastChangedIfRevealed();
ActiveGolem.PlayActionAnimation(AnimationSno.p6_bloodgolem_spawn_01);
}
}
}
else
{
if (ActiveGolem != null)
{
if (ActiveGolem.World != null)
(ActiveGolem as Minion).Kill();
ActiveGolem = null;
}
}
#endregion
}
#endregion
public T RuneSelect<T>(int PowerSNO, T none, T runeA, T runeB, T runeC, T runeD, T runeE)
{
var Rune_A = Attributes[GameAttribute.Rune_A, PowerSNO];
var Rune_B = Attributes[GameAttribute.Rune_B, PowerSNO];
var Rune_C = Attributes[GameAttribute.Rune_C, PowerSNO];
var Rune_D = Attributes[GameAttribute.Rune_D, PowerSNO];
var Rune_E = Attributes[GameAttribute.Rune_E, PowerSNO];
if (Rune_A > 0) return runeA;
else if (Rune_B > 0) return runeB;
else if (Rune_C > 0) return runeC;
else if (Rune_D > 0) return runeD;
else if (Rune_E > 0) return runeE;
else return none;
}
#region enter, leave, reveal handling
/// <summary>
/// Revals scenes in player's proximity.
/// </summary>
public void RevealScenesToPlayer()
{
//List<Scene> scenes_around = this.GetScenesInRegion(DefaultQueryProximityLenght * 2);
var scenes_around = World.Scenes.Values.ToList();
if (!World.worldData.DynamicWorld)
scenes_around = GetScenesInRegion(DefaultQueryProximityLenght * 3);
foreach (var scene in scenes_around) // reveal scenes in player's proximity.
{
if (scene.IsRevealedToPlayer(this)) // if the actors is already revealed skip it.
continue; // if the scene is already revealed, skip it.
if (scene.Parent !=
null) // if it's a subscene, always make sure it's parent get reveals first and then it reveals his childs.
scene.Parent.Reveal(this);
else
scene.Reveal(this);
}
foreach (var scene in World.Scenes.Values) // unreveal far scenes
{
if (!scene.IsRevealedToPlayer(this) || scenes_around.Contains(scene))
continue;
if (scene.Parent !=
null) // if it's a subscene, always make sure it's parent get reveals first and then it reveals his childs.
scene.Parent.Unreveal(this);
else
scene.Unreveal(this);
}
}
/// <summary>
/// Reveals actors in player's proximity.
/// </summary>
public void RevealActorsToPlayer()
{
var Range = 200f;
if (InGameClient.Game.CurrentEncounter.Activated)
Range = 360f;
var specialWorlds = new WorldSno[]
{
WorldSno.x1_pand_batteringram,
WorldSno.gluttony_boss,
WorldSno.a3dun_hub_adria_tower,
WorldSno.x1_malthael_boss_arena,
WorldSno.a1trdun_level05_templar
};
var actors_around = specialWorlds.Contains(World.SNO) ? World.Actors.Values.ToList() : GetActorsInRange(Range);
foreach (var actor in actors_around) // reveal actors in player's proximity.
{
if (actor is Player) // if the actors is already revealed, skip it.
continue;
if (World.SNO == WorldSno.x1_tristram_adventure_mode_hub && actor is Portal portal)
if (portal.Destination.WorldSNO == (int)WorldSno.x1_tristram_adventure_mode_hub)
continue;
if (World.SNO == WorldSno.trout_town && actor is Portal portal1)
if (portal1.Destination.WorldSNO == (int)WorldSno.trout_town &&
portal1.Destination.DestLevelAreaSNO == 19947)
{
portal1.Destination.WorldSNO = (int)WorldSno.x1_tristram_adventure_mode_hub;
portal1.Destination.StartingPointActorTag = 483;
}
if (actor.ActorType != ActorType.ClientEffect && actor.ActorType != ActorType.AxeSymbol &&
actor.ActorType != ActorType.CustomBrain) actor.Reveal(this);
}
foreach (var actor in World.Actors.Values) // unreveal far actors
{
if ((actor is Player && (!World.IsPvP || actor == this)) ||
actors_around.Contains(actor)) // if the actors is already revealed, skip it.
continue;
actor.Unreveal(this);
}
}
/// <summary>
/// Reveals other players in player's proximity.
/// </summary>
public void RevealPlayersToPlayer()
{
var actors = GetActorsInRange<Player>(100f);
foreach (var actor in actors) // reveal actors in player's proximity.
{
if (actor.IsRevealedToPlayer(this)) // if the actors is already revealed, skip it.
continue;
actor.Reveal(this);
if (!IsRevealedToPlayer(actor))
Reveal(actor);
}
}
public void ReRevealPlayersToPlayer()
{
var actors = GetActorsInRange<Player>(100f);
foreach (var actor in actors) // reveal actors in player's proximity.
{
if (actor.IsRevealedToPlayer(this)) // if the actors is already revealed, skip it.
actor.Unreveal(this);
actor.Reveal(this);
if (!IsRevealedToPlayer(actor))
{
Reveal(actor);
}
else
{
Unreveal(actor);
Reveal(actor);
}
}
}
public void ClearDoorAnimations()
{
var doors = GetActorsInRange<Door>(100f);
foreach (var door in doors)
if (door.IsRevealedToPlayer(this))
InGameClient.SendMessage(new SetIdleAnimationMessage
{
ActorID = door.DynamicID(this),
AnimationSNO = AnimationSetKeys.Open.ID
});
}
public override void OnEnter(World world)
{
world.Reveal(this);
Unreveal(this);
if (_CurrentHPValue == -1f)
DefaultQueryProximityRadius = 60;
InGameClient.SendMessage(new EnterWorldMessage()
{
EnterPosition = Position,
WorldID = world.GlobalID,
WorldSNO = (int)world.SNO,
PlayerIndex = PlayerIndex,
EnterLookUsed = true,
EnterKnownLookOverrides = new EnterKnownLookOverrides { Field0 = new int[] { -1, -1, -1, -1, -1, -1 } }
});
switch (world.SNO)
{
case WorldSno.x1_westmarch_overlook_d:
InGameClient.SendMessage(new PlayerSetCameraObserverMessage()
{
Field0 = 309026,
Field1 = new WorldPlace() { Position = new Vector3D(), WorldID = 0 }
});
break;
case WorldSno.x1_westm_intro:
InGameClient.SendMessage(new PlayerSetCameraObserverMessage()
{
Field0 = 1541,
Field1 = new WorldPlace() { Position = new Vector3D(), WorldID = 0 }
});
break;
}
if (_CurrentHPValue == -1f)
AddPercentageHP(100);
DefaultQueryProximityRadius = 100;
RevealScenesToPlayer();
RevealPlayersToPlayer();
// load all inventory items
if (!Inventory.Loaded)
{
//why reload if already loaded?
Inventory.LoadFromDB();
Inventory.LoadStashFromDB();
}
else
{
Inventory.RefreshInventoryToClient();
}
// generate visual update message
//this.Inventory.SendVisualInventory(this);
SetAllStatsInCorrectOrder();
SetAttributesSkillSets();
if (World.IsPvP)
DisableStoneOfRecall();
else
EnableStoneOfRecall();
Reveal(this);
System.Threading.Tasks.Task.Delay(3).Wait();
RevealActorsToPlayer();
//
}
public override void OnTeleport()
{
Unreveal(this);
BeforeChangeWorld();
RevealScenesToPlayer(); // reveal scenes in players proximity.
RevealPlayersToPlayer();
RevealActorsToPlayer(); // reveal actors in players proximity.
//TickTimer.WaitSeconds(this.World.Game, 5.0f, new Action<int>((x) => Logger.Debug("Timer")));
Reveal(this);
AfterChangeWorld();
// load all inventory items
if (!Inventory.Loaded)
{
//why reload if already loaded?
Inventory.LoadFromDB();
Inventory.LoadStashFromDB();
}
else
{
Inventory.RefreshInventoryToClient();
}
}
public override void OnLeave(World world)
{
Conversations.StopAll();
// save visual equipment
Toon.HeroVisualEquipmentField.Value = Inventory.GetVisualEquipment();
//this.Toon.HeroLevelField.Value = this.Attributes[GameAttribute.Level];
Toon.GameAccount.ChangedFields.SetPresenceFieldValue(Toon.HeroVisualEquipmentField);
Toon.GameAccount.ChangedFields.SetPresenceFieldValue(Toon.HeroLevelField);
Toon.GameAccount.ChangedFields.SetPresenceFieldValue(Toon.HeroParagonLevelField);
world.Unreveal(this);
}
public override bool Reveal(Player player)
{
if (!base.Reveal(player))
return false;
if (!World.IsPvP || this == player)
player.InGameClient.SendMessage(new PlayerEnterKnownMessage()
{
PlayerIndex = PlayerIndex,
ActorId = DynamicID(player)
});
Inventory.SendVisualInventory(player);
if (this == player) // only send this to player itself. Warning: don't remove this check or you'll make the game start crashing! /raist.
player.InGameClient.SendMessage(new PlayerActorSetInitialMessage()
{
ActorId = DynamicID(player),
PlayerIndex = PlayerIndex
});
if (!base.Reveal(player))
Inventory.Reveal(player);
if (this == player) // only send this when player's own actor being is revealed. /raist.
player.InGameClient.SendMessage(new PlayerWarpedMessage()
{
WarpReason = 9,
WarpFadeInSecods = 0f
});
if (SkillSet.HasSkill(460757))
foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 460757)
if (skill.snoRune == 3)
World.BuffManager.AddBuff(this, this, new P6_Necro_Devour_Aura());
else
World.BuffManager.RemoveBuffs(this, 474325);
return true;
}
public override bool Unreveal(Player player)
{
if (!base.Unreveal(player))
return false;
Inventory.Unreveal(player);
return true;
}
public Dictionary<Buff, int> AllBuffs = new();
public bool BetweenWorlds = false;
public override void BeforeChangeWorld()
{
ClearDoorAnimations();
World.Game.QuestManager.UnsetBountyMarker(this);
BetweenWorlds = true;
AllBuffs = World.BuffManager.GetAllBuffs(this);
World.BuffManager.RemoveAllBuffs(this);
//this.Inventory.Unreveal(this);
//this.InGameClient.TickingEnabled = false;
/*this.InGameClient.SendMessage(new FreezeGameMessage
{
Field0 = true
});*/
InGameClient.SendMessage(new ACDTranslateSyncMessage()
{
ActorId = DynamicID(this),
Position = Position
});
_CurrentHPValue = Attributes[GameAttribute.Hitpoints_Cur];
_CurrentResourceValue = Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource + 1];
}
public override void AfterChangeWorld()
{
//this.InGameClient.TickingEnabled = true;
/*
this.InGameClient.SendMessage(new FreezeGameMessage
{
Field0 = false
});
*/
Inventory.Reveal(this);
foreach (var buff in AllBuffs)
World.BuffManager.CopyBuff(this, this, buff.Key, buff.Value);
AllBuffs.Clear();
BetweenWorlds = false;
if (_CurrentHPValue != -1)
{
Attributes[GameAttribute.Hitpoints_Cur] = _CurrentHPValue;
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource + 1] = _CurrentResourceValue;
Attributes.BroadcastChangedIfRevealed();
_CurrentHPValue = -1;
}
World.Game.QuestManager.SetBountyMarker(this);
//System.Threading.Tasks.Task.Delay(1000).ContinueWith(a => {this.BetweenWorlds = false;});
}
#endregion
#region hero-state
public void WTF()
{
Attributes[GameAttribute.Power_Buff_0_Visual_Effect_None, 208468] = true;
Attributes[GameAttribute.Thorns_Fixed_Total, 0] = 0;
Attributes[GameAttribute.Damage_Delta_Total, 0] = 0;
Attributes[GameAttribute.UnequippedTime, 4] = 0;
Attributes[GameAttribute.Experience_Next_Lo] = 717;
Attributes[GameAttribute.Skill_Total, 93395] = 1;
Attributes[GameAttribute.Strength] = 0;
Attributes[GameAttribute.Attacks_Per_Second_Percent_Cap] = 0;
Attributes[GameAttribute.Invulnerable] = true;
Attributes[GameAttribute.UnequippedTime, 7] = 0;
Attributes[GameAttribute.Damage_Min, 0] = 0;
Attributes[GameAttribute.Damage_Weapon_Min_Total_All] = 0;
Attributes[GameAttribute.Damage_Delta_Total, 3] = 0;
Attributes[GameAttribute.General_Cooldown] = 0;
Attributes[GameAttribute.Attacks_Per_Second_Total] = 0;
Attributes[GameAttribute.Resource_Cur, 1] = 0;
Attributes[GameAttribute.UnequippedTime, 6] = 0;
Attributes[GameAttribute.Backpack_Slots] = 60;
Attributes[GameAttribute.Corpse_Resurrection_Charges] = 3;
Attributes[GameAttribute.Skill, 93395] = 1;
Attributes[GameAttribute.Trait, 451242] = 2;
Attributes[GameAttribute.UnequippedTime, 9] = 0;
Attributes[GameAttribute.Attacks_Per_Second] = 0;
Attributes[GameAttribute.TeamID] = 2;
Attributes[GameAttribute.Resource_Degeneration_Stop_Point, 1048575] = 0;
Attributes[GameAttribute.Resource_Max_Bonus, 1] = 0;
Attributes[GameAttribute.Armor_Total] = 0;
Attributes[GameAttribute.Skill_Total, 1759] = 1;
Attributes[GameAttribute.SkillKit] = 35584;
Attributes[GameAttribute.Armor_Item_Total] = 0;
Attributes[GameAttribute.Resistance_Total, 5] = 0;
Attributes[GameAttribute.Skill, 30718] = 1;
Attributes[GameAttribute.CantStartDisplayedPowers] = true;
Attributes[GameAttribute.Seasononlyitemsunlocked] = true;
Attributes[GameAttribute.UnequippedTime, 10] = 0;
Attributes[GameAttribute.Damage_Weapon_Delta_Total_All] = 0;
Attributes[GameAttribute.Damage_Min_Total, 3] = 0;
Attributes[GameAttribute.Resource_Cost_Reduction_Percent_All] = 0;
Attributes[GameAttribute.Get_Hit_Recovery] = 0;
Attributes[GameAttribute.Skill, 1759] = 1;
Attributes[GameAttribute.Buff_Icon_Start_Tick0, 439438] = 155;
Attributes[GameAttribute.Buff_Icon_End_Tick0, 439438] = 3755;
Attributes[GameAttribute.Skill, 30744] = 1;
Attributes[GameAttribute.Get_Hit_Recovery_Per_Level] = 0;
Attributes[GameAttribute.Requirement, 57] = 0;
Attributes[GameAttribute.Damage_Weapon_Delta, 3] = 0;
Attributes[GameAttribute.Attacks_Per_Second_Item_CurrentHand] = 0;
Attributes[GameAttribute.Get_Hit_Recovery_Base] = 0;
Attributes[GameAttribute.Resistance_From_Intelligence] = 0;
Attributes[GameAttribute.Damage_Weapon_Delta, 0] = 0;
Attributes[GameAttribute.Get_Hit_Max] = 0;
Attributes[GameAttribute.Crit_Damage_Cap] = 0;
Attributes[GameAttribute.Class_Damage_Reduction_Percent_PVP] = 0;
Attributes[GameAttribute.Buff_Icon_Count0, 212032] = 1;
Attributes[GameAttribute.Hit_Chance] = 0;
Attributes[GameAttribute.Crit_Percent_Cap] = 0;
Attributes[GameAttribute.Get_Hit_Max_Per_Level] = 0;
Attributes[GameAttribute.Resource_Regen_Per_Second, 1] = 0;
Attributes[GameAttribute.Buff_Icon_Count0, 134334] = 1;
Attributes[GameAttribute.Buff_Icon_End_Tick0, 134334] = 2101;
Attributes[GameAttribute.Buff_Icon_Start_Tick0, 134334] = 301;
Attributes[GameAttribute.Banter_Cooldown, 1048575] = 0;
Attributes[GameAttribute.Hidden] = false;
Attributes[GameAttribute.Buff_Icon_Count0, 439438] = 0;
Attributes[GameAttribute.Buff_Icon_Start_Tick0, 212032] = 0;
Attributes[GameAttribute.Buff_Icon_End_Tick0, 212032] = 0;
Attributes[GameAttribute.Immobolize] = false;
Attributes[GameAttribute.Untargetable] = false;
Attributes[GameAttribute.Loading] = false;
Attributes[GameAttribute.Invulnerable] = false;
Attributes[GameAttribute.Resource_Degeneration_Stop_Point, 1048575] = 0;
Attributes[GameAttribute.CantStartDisplayedPowers] = false;
Attributes[GameAttribute.Buff_Icon_Start_Tick0, 439438] = 0;
Attributes[GameAttribute.Buff_Icon_End_Tick0, 439438] = 0;
Attributes[GameAttribute.Buff_Icon_Count0, 212032] = 0;
Attributes.BroadcastChangedIfRevealed();
}
/// <summary>
/// Allows hero state message to be sent when hero's some property get's updated.
/// </summary>
public void UpdateHeroState()
{
InGameClient.SendMessage(new HeroStateMessage
{
State = GetStateData(),
PlayerIndex = PlayerIndex
});
}
public HeroStateData GetStateData()
{
return new HeroStateData()
{
LastPlayedAct = 400, //LastPlayedAct
HighestUnlockedAct = 400, //HighestUnlockedAct
PlayedFlags = (int)Toon.Flags,
PlayerSavedData = GetSavedData(),
//QuestRewardHistoryEntriesCount = QuestRewardHistory.Count,
tQuestRewardHistory = QuestRewardHistory.ToArray()
};
}
#endregion
#region player attribute handling
public void QueueDeath(bool state)
{
//this.World.BroadcastIfRevealed(this.ACDWorldPositionMessage, this);
InGameClient.SendMessage(new ACDTranslateSyncMessage()
{
ActorId = DynamicID(this),
Position = Position
});
Attributes[GameAttribute.QueueDeath] = state;
Attributes[GameAttribute.Disabled] = state;
Attributes[GameAttribute.Waiting_To_Accept_Resurrection] = false;
Attributes[GameAttribute.Invulnerable] = state;
//this.Attributes[GameAttribute.Stunned] = state;
Attributes[GameAttribute.Immobolize] = state;
Attributes[GameAttribute.Hidden] = state;
Attributes[GameAttribute.Untargetable] = state;
Attributes[GameAttribute.CantStartDisplayedPowers] = state;
Attributes[GameAttribute.IsContentRestrictedActor] = state;
Attributes[GameAttribute.Rest_Experience_Lo] = 0;
Attributes[GameAttribute.Rest_Experience_Bonus_Percent] = 0;
Attributes.BroadcastChangedIfRevealed();
if (World.Game.PvP) Attributes[GameAttribute.Resurrect_As_Observer] = state;
//this.Attributes[GameAttribute.Observer] = !state;
//this.Attributes[GameAttribute.Corpse_Resurrection_Charges] = 1; // Enable this to allow unlimited resurrection at corpse
//this.Attributes[GameAttribute.Corpse_Resurrection_Allowed_Game_Time] = this.World.Game.TickCounter + 300; // Timer for auto-revive (seems to be broken?)
Attributes.BroadcastChangedIfRevealed();
}
public void Resurrect()
{
Attributes[GameAttribute.Waiting_To_Accept_Resurrection] = true;
Attributes.BroadcastChangedIfRevealed();
}
public void Revive(Vector3D spawnPosition)
{
if (World == null) return;
/*if (this.World.Game.IsHardcore)
{
this.InGameClient.SendMessage(new LogoutTickTimeMessage()
{
Field0 = false, // true - logout with party?
Ticks = 0, // delay 1, make this equal to 0 for instant logout
Field2 = 0, // delay 2
});
} else
{*/
QueueDeath(false);
Dead = false;
AddPercentageHP(100);
World.BroadcastIfRevealed(plr => new SetIdleAnimationMessage
{
ActorID = DynamicID(plr),
AnimationSNO = AnimationSetKeys.IdleDefault.ID
}, this);
//removing tomb
try
{
GetObjectsInRange<Headstone>(100.0f).Where(h => h.playerIndex == PlayerIndex).First().Destroy();
}
catch
{
}
Teleport(spawnPosition);
World.BuffManager.AddBuff(this, this, new ActorGhostedBuff());
var old_skills = SkillSet.ActiveSkills.Select(s => s.snoSkill).ToList();
foreach (var skill in old_skills)
{
var power = PowerLoader.CreateImplementationForPowerSNO(skill);
if (power != null && power.EvalTag(PowerKeys.SynergyPower) != -1)
World.BuffManager.RemoveBuffs(this, power.EvalTag(PowerKeys.SynergyPower));
}
SetAttributesByItems();
SetAttributesByItemProcs();
SetAttributesByGems();
SetAttributesByItemSets();
SetAttributesByPassives();
SetAttributesByParagon();
SetAttributesSkillSets();
Attributes[GameAttribute.Resource_Cur, PrimaryResourceID] = 0f;
if (Toon.Class == ToonClass.DemonHunter)
Attributes[GameAttribute.Resource_Cur, SecondaryResourceID] = 0f;
Attributes.BroadcastChangedIfRevealed();
var skills = SkillSet.ActiveSkills.Select(s => s.snoSkill).ToList();
var cooldowns = World.BuffManager.GetBuffs<CooldownBuff>(this);
foreach (var skill in skills)
{
var inCooldown = false;
CooldownBuff skillcd = null;
foreach (var cooldown in cooldowns)
if (cooldown.TargetPowerSNO == skill)
{
skillcd = cooldown;
inCooldown = true;
break;
}
if (inCooldown && skillcd != null) skillcd.Extend((int)3 * 60);
else _StartSkillCooldown(skill, 3f);
}
Inventory.RefreshInventoryToClient();
UpdatePercentageHP(PercHPbeforeChange);
}
public float Strength
{
get
{
var baseStrength = 0.0f;
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Strength)
baseStrength = Toon.HeroTable.Strength + (Level - 1) * 3;
else
baseStrength = Toon.HeroTable.Strength + (Level - 1);
return baseStrength;
}
}
public float TotalStrength =>
Attributes[GameAttribute.Strength] + Inventory.GetItemBonus(GameAttribute.Strength_Item);
public float Dexterity
{
get
{
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Dexterity)
return Toon.HeroTable.Dexterity + (Level - 1) * 3;
else
return Toon.HeroTable.Dexterity + (Level - 1);
}
}
public float TotalDexterity =>
Attributes[GameAttribute.Dexterity] + Inventory.GetItemBonus(GameAttribute.Dexterity_Item);
public float Vitality => Toon.HeroTable.Vitality + (Level - 1) * 2;
public float TotalVitality =>
Attributes[GameAttribute.Vitality] + Inventory.GetItemBonus(GameAttribute.Vitality_Item);
public float Intelligence
{
get
{
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Intelligence)
return Toon.HeroTable.Intelligence + (Level - 1) * 3;
else
return Toon.HeroTable.Intelligence + (Level - 1);
}
}
public float TotalIntelligence => Attributes[GameAttribute.Intelligence] +
Inventory.GetItemBonus(GameAttribute.Intelligence_Item);
public float PrimaryAttribute
{
get
{
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Strength) return TotalStrength;
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Dexterity) return TotalDexterity;
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Intelligence) return TotalIntelligence;
return 0f;
}
}
public float DodgeChance
{
get
{
var dex = TotalDexterity;
var dodgeChance = dex / (250f * Attributes[GameAttribute.Level] + dex);
if (dex > 7500f) dodgeChance += 0.04f;
else if (dex > 6500f) dodgeChance += 0.02f;
else if (dex > 5500f) dodgeChance += 0.01f;
dodgeChance = 1f - (1f - dodgeChance) * (1f - Attributes[GameAttribute.Dodge_Chance_Bonus]);
return Math.Min(dodgeChance, 0.75f);
}
}
#endregion
#region saved-data
private PlayerSavedData GetSavedData()
{
var item = StringHashHelper.HashItemName("HealthPotionBottomless");
return new PlayerSavedData()
{
HotBarButtons = SkillSet.HotBarSkills,
HotBarButton = new HotbarButtonData
{
SNOSkill = -1, RuneType = -1, ItemGBId =
StringHashHelper.HashItemName(
"HealthPotionBottomless") //2142362846//this.Toon.DBActiveSkills.PotionGBID
,
ItemAnn = -1
},
SkillSlotEverAssigned = 0x0F, //0xB4,
PlaytimeTotal = Toon.TimePlayed,
#if DEBUG
WaypointFlags = 0x0000ffff,
#else
WaypointFlags = this.World.Game.WaypointFlags,
#endif
HirelingData = new HirelingSavedData()
{
HirelingInfos = HirelingInfo,
ActiveHireling = 0x00000000,
AvailableHirelings = 0x00000004
},
TimeLastLevel = 0,
LearnedLore = LearnedLore,
ActiveSkills = SkillSet.ActiveSkills,
snoTraits = SkillSet.PassiveSkills,
GBIDLegendaryPowers = new int[4] { -1, -1, -1, -1 },
SavePointData = new SavePointData { snoWorld = -1, SavepointId = -1 },
EventFlags = 0
};
}
public SavePointData SavePointData { get; set; }
public LearnedLore LearnedLore = new()
{
Count = 0x00000000,
m_snoLoreLearned = new int[512]
{
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
}
};
public void SaveStats() //Save 6 primary stats into DB for showing on hero screen
{
//Logger.MethodTrace("Strength {0}", this.Inventory.GetItemBonus(GameAttribute.Strength_Item).ToString("F0"));
var damageFromWeapon =
(Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Min_Total, 0) +
Inventory.GetItemBonus(GameAttribute.Damage_Weapon_Delta_Total, 0)) * (1f + PrimaryAttribute / 100f);
var totalDamage =
(damageFromWeapon
+ damageFromWeapon * Inventory.GetItemBonus(GameAttribute.Weapon_Crit_Chance) *
(1.5f + Inventory.GetItemBonus(GameAttribute.Crit_Damage_Percent)))
* Inventory.GetItemBonus(GameAttribute.Attacks_Per_Second_Total);
var serialized = "";
serialized += Inventory.GetItemBonus(GameAttribute.Strength_Item).ToString("F0");
serialized += ";";
serialized += Inventory.GetItemBonus(GameAttribute.Dexterity_Item).ToString("F0");
serialized += ";";
serialized += Inventory.GetItemBonus(GameAttribute.Intelligence_Item).ToString("F0");
serialized += ";";
serialized += Inventory.GetItemBonus(GameAttribute.Vitality_Item).ToString("F0");
serialized += ";";
serialized += Inventory.GetItemBonus(GameAttribute.Armor_Item).ToString("F0");
serialized += ";";
serialized += totalDamage.ToString("F0");
var dbStats = Toon.DBToon;
dbStats.Stats = serialized;
World.Game.GameDbSession.SessionUpdate(dbStats);
}
public List<PlayerQuestRewardHistoryEntry> QuestRewardHistory
{
get
{
var result = new List<PlayerQuestRewardHistoryEntry>();
var quests = InGameClient.Game.QuestManager.Quests.Where(q => q.Value.Completed).ToList();
foreach (var quest in quests)
{
InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = quest.Key,
snoLevelArea = -1,
StepID = quest.Value.Steps.Last().Key,
DisplayButton = false,
Failed = false
});
result.Add(new PlayerQuestRewardHistoryEntry()
{
snoQuest = quest.Key,
Field1 = 0,
Field2 = (PlayerQuestRewardHistoryEntry.Difficulty)InGameClient.Game.Difficulty
});
}
return result;
}
}
private HirelingInfo[] _hirelingInfo = null;
public HirelingInfo[] HirelingInfo
{
get
{
if (_hirelingInfo == null)
{
_hirelingInfo = new HirelingInfo[4];
for (var i = 0; i < 4; i++)
_hirelingInfo[i] = GetHirelingInfo(i);
}
return _hirelingInfo;
}
set => _hirelingInfo = value;
}
#endregion
#region cooked messages
public void StopMoving()
{
World.BroadcastIfRevealed(plr => new ACDTranslateNormalMessage
{
ActorId = DynamicID(plr),
Position = Position,
SnapFacing = false,
MovementSpeed = 0,
AnimationTag = -1
}, this);
}
public void CheckBonusSets()
{
var sets = World.Game.GameDbSession
.SessionQueryWhere<DBBonusSets>(dbi => dbi.DBAccount.Id == Toon.GameAccount.AccountId).ToList();
foreach (var bonusSet in sets)
{
if (World.Game.IsHardcore)
{
if (bonusSet.ClaimedHardcore) continue;
}
else
{
if (bonusSet.Claimed) continue;
}
//if (!BonusSetsList.CollectionEditions.ContainsKey(bonusSet.SetId)) continue;
if (bonusSet.SetId == 6 && World.Game.IsHardcore) continue;
//if (!(bonusSet.Claimed || bonusSet.ClaimedHardcore))
// BonusSetsList.CollectionEditions[bonusSet.SetId].ClaimOnce(this);
if (World.Game.IsHardcore)
{
bonusSet.ClaimedHardcore = true;
}
else
{
bonusSet.Claimed = true;
bonusSet.ClaimedToon = Toon.DBToon;
}
//BonusSetsList.CollectionEditions[bonusSet.SetId].Claim(this);
World.Game.GameDbSession.SessionUpdate(bonusSet);
//this.InGameClient.SendMessage(new BroadcastTextMessage() { Field0 = "You have been granted with gifts from bonus pack!" });
}
}
public HirelingInfo GetHirelingInfo(int type)
{
var query = World.Game.GameDbSession
.SessionQueryWhere<DBHireling>(dbh => dbh.DBToon.Id == Toon.PersistentID && dbh.Class == type).ToList();
if (query.Count == 0)
{
//returns empty data
var hireling_empty = new HirelingInfo
{
HirelingIndex = type, GbidName = 0x0000, Dead = false, Skill1SNOId = -1, Skill2SNOId = -1,
Skill3SNOId = -1, Skill4SNOId = -1, annItems = -1
};
return hireling_empty;
}
var hireling_full = new HirelingInfo
{
HirelingIndex = type,
GbidName = 0x0000,
Dead = false,
Skill1SNOId = query.First().Skill1SNOId,
Skill2SNOId = query.First().Skill2SNOId,
Skill3SNOId = query.First().Skill3SNOId,
Skill4SNOId = query.First().Skill4SNOId,
annItems = -1
};
return hireling_full;
}
private List<int> Unserialize(string data)
{
var recparts = data.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
var ret = new List<int>();
foreach (var recid in recparts) ret.Add(Convert.ToInt32(recid, 10));
return ret;
}
private string Serialize(List<int> data)
{
var serialized = "";
foreach (var id in data)
{
serialized += id;
serialized += ";";
}
return serialized;
}
private List<int> UnserializeBytes(byte[] data)
{
return Enumerable.Range(0, data.Length / 4).Select(i => BitConverter.ToInt32(data, i * 4)).ToList();
}
private byte[] SerializeBytes(List<int> data)
{
return data.SelectMany(BitConverter.GetBytes).ToArray();
}
public void LearnRecipe(ArtisanType? artisan, int recipe)
{
Logger.Trace("Learning recipe #{0}, Artisan type: {1}", recipe, artisan);
/*var query = this.World.Game.GameDBSession.SessionQuerySingle<DBCraft>(
dbi =>
dbi.DBGameAccount.Id == this.Toon.GameAccount.PersistentID &&
dbi.Artisan == artisan &&
dbi.isHardcore == this.World.Game.IsHardcore);*/
if (artisan == ArtisanType.Blacksmith)
{
learnedBlacksmithRecipes.Add(recipe);
blacksmith_data.LearnedRecipes = SerializeBytes(learnedBlacksmithRecipes);
World.Game.GameDbSession.SessionUpdate(blacksmith_data);
UpdateAchievementCounter(404, 1, 0);
}
else if (artisan == ArtisanType.Jeweler)
{
learnedJewelerRecipes.Add(recipe);
jeweler_data.LearnedRecipes = SerializeBytes(learnedJewelerRecipes);
World.Game.GameDbSession.SessionUpdate(jeweler_data);
UpdateAchievementCounter(404, 1, 1);
}
LoadCrafterData();
}
public bool RecipeAvailable(GameBalance.RecipeTable recipe_definition)
{
if (recipe_definition.Flags == 0) return true;
return learnedBlacksmithRecipes.Contains(recipe_definition.Hash) ||
learnedJewelerRecipes.Contains(recipe_definition.Hash);
}
public PlayerBannerMessage GetPlayerBanner()
{
var playerBanner = D3.GameMessage.PlayerBanner.CreateBuilder()
.SetPlayerIndex((uint)PlayerIndex)
.SetBanner(Toon.GameAccount.BannerConfigurationField.Value)
.Build();
return new PlayerBannerMessage() { PlayerBanner = playerBanner };
}
private List<int> learnedBlacksmithRecipes = new();
private List<int> learnedJewelerRecipes = new();
private List<int> learnedTransmogs = new();
private DBCraft blacksmith_data = null;
private DBCraft jeweler_data = null;
private DBCraft mystic_data = null;
private Dictionary<ArtisanType, ArtisanTrainHelper> artisanTrainHelpers = new();
public void LoadCrafterData()
{
if (blacksmith_data == null)
{
var craft_data =
World.Game.GameDbSession.SessionQueryWhere<DBCraft>(dbc =>
dbc.DBGameAccount.Id == Toon.GameAccount.PersistentID);
blacksmith_data = craft_data.Single(dbc =>
dbc.Artisan == "Blacksmith" && dbc.isHardcore == World.Game.IsHardcore &&
dbc.isSeasoned == World.Game.IsSeasoned);
jeweler_data = craft_data.Single(dbc =>
dbc.Artisan == "Jeweler" && dbc.isHardcore == World.Game.IsHardcore &&
dbc.isSeasoned == World.Game.IsSeasoned);
mystic_data = craft_data.Single(dbc =>
dbc.Artisan == "Mystic" && dbc.isHardcore == World.Game.IsHardcore &&
dbc.isSeasoned == World.Game.IsSeasoned);
artisanTrainHelpers[ArtisanType.Blacksmith] =
new ArtisanTrainHelper(blacksmith_data, ArtisanType.Blacksmith);
artisanTrainHelpers[ArtisanType.Jeweler] = new ArtisanTrainHelper(jeweler_data, ArtisanType.Jeweler);
artisanTrainHelpers[ArtisanType.Mystic] = new ArtisanTrainHelper(mystic_data, ArtisanType.Mystic);
}
var blacksmith = D3.ItemCrafting.CrafterData.CreateBuilder()
.SetLevel(InGameClient.Game.CurrentAct == 3000
? BlacksmithUnlocked == false && blacksmith_data.Level < 1 ? 1 : blacksmith_data.Level
: blacksmith_data.Level)
.SetCooldownEnd(0)
.AddRangeRecipes(UnserializeBytes(blacksmith_data.LearnedRecipes))
.Build();
learnedBlacksmithRecipes = UnserializeBytes(blacksmith_data.LearnedRecipes);
var jeweler = D3.ItemCrafting.CrafterData.CreateBuilder()
.SetLevel(InGameClient.Game.CurrentAct == 3000
? JewelerUnlocked == false && jeweler_data.Level < 1 ? 1 : jeweler_data.Level
: jeweler_data.Level)
.SetCooldownEnd(0)
.AddRangeRecipes(UnserializeBytes(jeweler_data.LearnedRecipes))
.Build();
learnedJewelerRecipes = UnserializeBytes(jeweler_data.LearnedRecipes);
var mystic = D3.ItemCrafting.CrafterData.CreateBuilder()
.SetLevel(InGameClient.Game.CurrentAct == 3000
? MysticUnlocked == false && mystic_data.Level < 1 ? 1 : mystic_data.Level
: mystic_data.Level)
.SetCooldownEnd(0)
.Build();
var transmog = D3.ItemCrafting.CrafterSavedData.CreateBuilder()
.SetTransmogData(D3.GameBalance.BitPackedGbidArray.CreateBuilder()
.SetBitfield(ByteString.CopyFrom(mystic_data.LearnedRecipes)))
//.AddRangeUnlockedTransmogs(this.UnserializeBytes(mystic_data.LearnedRecipes))
.Build();
learnedTransmogs = UnserializeBytes(mystic_data.LearnedRecipes);
if (BlacksmithUnlocked || InGameClient.Game.CurrentAct == 3000)
InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataBlacksmithInitialMessage)
{ Data = blacksmith.ToByteArray() });
if (JewelerUnlocked || InGameClient.Game.CurrentAct == 3000)
InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataJewelerInitialMessage)
{ Data = jeweler.ToByteArray() });
if (MysticUnlocked || InGameClient.Game.CurrentAct == 3000)
{
InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataMysticInitialMessage)
{ Data = mystic.ToByteArray() });
InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataTransmogInitialMessage)
{ Data = transmog.ToByteArray() });
}
}
public void LoadCurrencyData()
{
var bloodShards = 0;
bloodShards = Toon.GameAccount.BloodShards;
Inventory.UpdateCurrencies();
}
public void LoadMailData()
{
var mail_data =
World.Game.GameDbSession.SessionQueryWhere<DBMail>(dbm =>
dbm.DBToon.Id == Toon.PersistentID && dbm.Claimed == false);
var mails = D3.Items.Mails.CreateBuilder();
foreach (var mail in mail_data)
{
var mail_row = D3.Items.Mail.CreateBuilder()
.SetAccountTo(Toon.D3EntityID)
.SetAccountFrom(Toon.D3EntityID)
.SetMailId(mail.Id)
.SetTitle(mail.Title)
.SetBody(mail.Body);
if (mail.ItemGBID != -1)
mail_row.SetAttachments(D3.Items.MailAttachments.CreateBuilder()
.SetItems(D3.Items.ItemList.CreateBuilder()
.AddItems(D3.Items.SavedItem.CreateBuilder()
.SetId(D3.OnlineService.ItemId.CreateBuilder().SetIdLow(0).SetIdHigh(0x3C000002517A294))
.SetHirelingClass(0)
.SetItemSlot(0)
.SetSquareIndex(0)
.SetUsedSocketCount(0)
.SetGenerator(D3.Items.Generator.CreateBuilder()
.SetGbHandle(D3.GameBalance.Handle.CreateBuilder().SetGbid(mail.ItemGBID)
.SetGameBalanceType(2))
.SetFlags(2147483647)
.SetSeed(0)
.SetDurability(0)
.SetStackSize(0)
)
)
)
);
mails.AddMailsProp(mail_row);
}
var mail_contents = D3.GameMessage.MailContents.CreateBuilder()
.SetAppendMessages(false)
.SetMails(mails)
.Build();
InGameClient.SendMessage(new MailDigestMessage() { MailContents = mail_contents });
}
//*/
public void LoadStashIconsData()
{
var dbGAcc = Toon.GameAccount.DBGameAccount;
if (dbGAcc.StashIcons == null) return;
//this.InGameClient.SendMessage(new StashIconStateMessage() { StashIcons = dbGAcc.StashIcons });
}
public void NotifyMaintenance()
{
if (GameServer.ClientSystem.GameServer.MaintenanceTime > 0 &&
GameServer.ClientSystem.GameServer.MaintenanceTime > (int)DateTime.Now.ToUnixTime())
InGameClient.SendMessage(new LogoutTickTimeMessage()
{
Field0 = false, // true - logout with party?
Ticks = 0, // delay 1, make this equal to 0 for instant logout
Field2 = 10000, // delay 2
Field3 = (GameServer.ClientSystem.GameServer.MaintenanceTime - (int)DateTime.Now.ToUnixTime()) *
60 //maintenance counter
});
}
public void LoadShownTutorials()
{
var tutorials = new List<byte>();
tutorials.Add(64);
for (var i = 0; i < 15; i++)
tutorials.Add(0);
var seenTutorials = Toon.GameAccount.DBGameAccount.SeenTutorials;
var state = D3.GameMessage.TutorialState.CreateBuilder()
.SetSeenTutorials(ByteString.CopyFrom(seenTutorials))
.Build();
InGameClient.SendMessage(new GenericBlobMessage(Opcodes.TutorialStateMessage) { Data = state.ToByteArray() });
}
private List<ulong> _unlockedAchievements = new();
private List<ulong> _unlockedCriterias = new();
private Dictionary<ulong, uint> AchievementCounters = new();
public int DodgesInARow = 0;
public int BlocksInARow = 0;
public void GrantAchievement(ulong id)
{
if (_unlockedAchievements.Contains(id)) return;
if (InGameClient.BnetClient.Account.GameAccount.Achievements.Any(a => a.AchievementId == id && a.Completion != -1)) return;
if (_unlockedAchievements.Contains(id)) return;
_unlockedAchievements.Add(id);
try
{
var Achievement = AchievementSystem.AchievementManager.GetAchievementById(id);
long Platinum = -1;
foreach (var attr in Achievement.AttributesList)
if (attr.Key == "Reward Currency Quantity")
Platinum = long.Parse(attr.Value);
InGameClient.SendMessage(new MessageSystem.Message.Definitions.Platinum.PlatinumAchievementAwardedMessage
{
CurrentPlatinum = InGameClient.BnetClient.Account.GameAccount.Platinum,
idAchievement = id,
PlatinumIncrement = Platinum
});
if (Platinum > 0)
{
InGameClient.BnetClient.Account.GameAccount.Platinum += (int)Platinum;
Inventory.UpdateCurrencies();
}
ClientSystem.GameServer.GSBackend.GrantAchievement(Toon.GameAccount.PersistentID, id);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on GrantAchievement(): ");
}
}
public void AddAchievementCounter(ulong id, uint count)
{
lock (AchievementCounters)
{
if (!AchievementCounters.ContainsKey(id))
AchievementCounters.Add(id, count);
else
AchievementCounters[id] += count;
}
}
public void CheckAchievementCounters()
{
lock (AchievementCounters)
{
foreach (var counter in AchievementCounters)
{
if (counter.Value == 0) continue;
UpdateSingleAchievementCounter(counter.Key, counter.Value);
}
AchievementCounters.Clear();
}
}
public void GrantCriteria(ulong id)
{
if (_unlockedCriterias.Contains(id)) return;
_unlockedCriterias.Add(id);
try
{
GameServer.ClientSystem.GameServer.GSBackend.GrantCriteria(Toon.GameAccount.PersistentID, id);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on GrantCriteria(): ");
}
}
public void UpdateQuantity(ulong id, uint counter)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.UpdateQuantity(Toon.GameAccount.PersistentID, id, counter);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on UpdateQuantity(): ");
}
}
public void UpdateAchievementCounter(int type, uint addCounter, int comparand = -1, ulong achiId = 0)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.UpdateAchievementCounter(Toon.GameAccount.PersistentID, type,
addCounter, comparand, achiId);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on UpdateAchievementCounter(): ");
}
}
public void UpdateSingleAchievementCounter(ulong achievementId, uint addCounter)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.UpdateSingleAchievementCounter(Toon.GameAccount.PersistentID,
achievementId, addCounter);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on UpdateSingleAchievementCounter(): ");
}
}
public void CheckQuestCriteria(int questId)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.CheckQuestCriteria(Toon.GameAccount.PersistentID, questId,
World.Game.Players.Count > 1);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on CheckQuestCriteria(): ");
}
}
public void CheckKillMonsterCriteria(ActorSno actorSno, int type)
{
try
{
ClientSystem.GameServer.GSBackend.CheckKillMonsterCriteria(Toon.GameAccount.PersistentID, (int)actorSno,
type, World.Game.IsHardcore);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on CheckKillMonsterCriteria(): ");
}
}
public void CheckLevelCap()
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.CheckLevelCap(Toon.GameAccount.PersistentID);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on CheckLevelCap(): ");
}
}
public void CheckSalvageItemCriteria(int itemId)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.CheckSalvageItemCriteria(Toon.GameAccount.PersistentID,
itemId);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on CheckSalvageItemCriteria(): ");
}
}
public void CheckConversationCriteria(int convId)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.CheckConversationCriteria(Toon.GameAccount.PersistentID,
convId);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on CheckConversationCriteria(): ");
}
}
public void CheckLevelAreaCriteria(int laId)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.CheckLevelAreaCriteria(Toon.GameAccount.PersistentID, laId);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on CheckLevelAreaCriteria(): ");
}
}
public void ParagonLevelUp()
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.ParagonLevelUp(Toon.GameAccount.PersistentID);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on ParagonLevelUp(): ");
}
}
public void UniqueItemIdentified(ulong itemId)
{
try
{
GameServer.ClientSystem.GameServer.GSBackend.UniqueItemIdentified(Toon.GameAccount.PersistentID, itemId);
}
catch (Exception e)
{
Logger.WarnException(e, "Exception on UniqueItemIdentified(): ");
}
}
public void SetProgress(int act, int difficulty)
{
if (act > 400) return;
var dbGAcc = World.Game.GameDbSession.SessionGet<DBGameAccount>(Toon.GameAccount.PersistentID);
var progress = dbGAcc.BossProgress;
if (progress[act / 100] == 0xff || progress[act / 100] < (byte)difficulty)
{
progress[act / 100] = (byte)difficulty;
dbGAcc.BossProgress = progress;
World.Game.GameDbSession.SessionUpdate(dbGAcc);
}
}
public int CastingSnoPower = -1;
public void StartCasting(int durationTicks, Action result, int skillsno = -1)
{
IsCasting = true;
CastResult = result;
Attributes[GameAttribute.Looping_Animation_Start_Time] = World.Game.TickCounter;
Attributes[GameAttribute.Looping_Animation_End_Time] = World.Game.TickCounter + durationTicks;
CastingSnoPower = skillsno;
if (CastingSnoPower != -1)
{
Attributes[GameAttribute.Buff_Icon_Start_Tick0, CastingSnoPower] = World.Game.TickCounter;
Attributes[GameAttribute.Buff_Icon_End_Tick0, CastingSnoPower] = World.Game.TickCounter + durationTicks;
Attributes[GameAttribute.Buff_Icon_Count0, CastingSnoPower] = 1;
Attributes[GameAttribute.Power_Buff_0_Visual_Effect_None, CastingSnoPower] = true;
}
Attributes.BroadcastChangedIfRevealed();
}
public void StopCasting()
{
IsCasting = false;
Attributes[GameAttribute.Looping_Animation_Start_Time] = -1;
Attributes[GameAttribute.Looping_Animation_End_Time] = -1;
if (CastingSnoPower != -1)
{
Attributes[GameAttribute.Buff_Icon_Start_Tick0, CastingSnoPower] = -1;
Attributes[GameAttribute.Buff_Icon_End_Tick0, CastingSnoPower] = -1;
Attributes[GameAttribute.Buff_Icon_Count0, CastingSnoPower] = 0;
Attributes[GameAttribute.Power_Buff_0_Visual_Effect_None, CastingSnoPower] = false;
}
Attributes.BroadcastChangedIfRevealed();
}
private void UpdateCastState()
{
if (Attributes[GameAttribute.Looping_Animation_End_Time] <= World.Game.TickCounter)
{
StopCasting();
CastResult.Invoke();
CastResult = null;
}
}
public void ShowConfirmation(uint actorId, Action result)
{
ConfirmationResult = result;
InGameClient.SendMessage(new ConfirmMessage()
{
ActorID = actorId
});
}
#endregion
#region generic properties
public int ClassSNO => Toon.Gender == 0 ? Toon.HeroTable.SNOMaleActor : Toon.HeroTable.SNOFemaleActor;
public int AdditionalLootItems
{
get
{
if (World.BuffManager.HasBuff<NephalemValorBuff>(this))
return Math.Max(World.BuffManager.GetFirstBuff<NephalemValorBuff>(this).StackCount - 3, 0);
else return 0;
}
}
public float ModelScale =>
Toon.Class switch
{
ToonClass.Barbarian => 1.2f,
ToonClass.Crusader => 1.2f,
ToonClass.DemonHunter => 1.35f,
ToonClass.Monk => 1.43f,
ToonClass.WitchDoctor => 1.1f,
ToonClass.Wizard => 1.3f,
_ => 1.43f
};
public int PrimaryResourceID => (int)Toon.HeroTable.PrimaryResource;
public int SecondaryResourceID => (int)Toon.HeroTable.SecondaryResource;
[Obsolete]
public bool IsInTown
{
get
{
var townAreas = new List<int> { 19947, 168314, 92945, 197101 };
var proximity = new RectangleF(Position.X - 1f, Position.Y - 1f, 2f, 2f);
var scenes = World.QuadTree.Query<Scene>(proximity);
if (scenes.Count == 0) return false;
var scene = scenes[0];
if (scenes.Count == 2) // What if it's a subscene?
if (scenes[1].ParentChunkID != 0xFFFFFFFF)
scene = scenes[1];
return townAreas.Contains(scene.Specification.SNOLevelAreas[0]);
}
}
#endregion
#region experience handling
//Max((Resource_Max + ((Level#NONE - 1) * Resource_Factor_Level) + Resource_Max_Bonus) * (Resource_Max_Percent_Bonus + 1), 0)
private float GetMaxResource(int resourceId)
{
if (resourceId == 2) return 0;
return Math.Max(
(Attributes[GameAttribute.Resource_Max, resourceId] +
(Attributes[GameAttribute.Level] - 1) * Attributes[GameAttribute.Resource_Factor_Level, resourceId] +
Attributes[GameAttribute.Resource_Max_Bonus, resourceId]) *
(Attributes[GameAttribute.Resource_Max_Percent_Bonus, resourceId] + 1), 0);
}
public static List<long> LevelBorders = new()
{
0, 280, 2700, 4500, 6600, 9000, 11700, 14000, 16500, 19200, 22100, /* Level 0-10 */
25200, 28500, 32000, 35700, 39600, 43700, 48000, 52500, 57200, 62100, /* Level 11-20 */
67200, 72500, 78000, 83700, 89600, 95700, 102000, 108500, 115200, 122100, /* Level 21-30 */
150000, 157500, 180000, 203500, 228000, 273000, 320000, 369000, 420000, 473000, /* Level 31-40 */
528000, 585000, 644000, 705000, 768000, 833000, 900000, 1453500, 2080000, 3180000, /* Level 41-50 */
4050000, 5005000, 6048000, 7980000, 10092000, 12390000, 14880000, 17019000, 20150000,
24586000, /* Level 51-60 */
27000000, 29400000, 31900000, 39100000, 46800000, 55000000, 63700000, 72900000, 82600000,
100000000 /* Level 61-70 */
};
public static List<long> ParagonLevelBorders = new()
{
//7200000,8640000,10800000,11520000,12960000,14400000,15840000,17280000,18720000,20160000,21600000,23040000,24480000,25920000,27360000,
//28800000,30240000,31680000,33120000,34560000,36000000,37440000,38880000,40320,41760000,43200000,41760000,43200000,44640000,46080000,
//47520000,48960000,50400000,51840000,53280000,54720000,56160000,57600000,59040000,60480000,61920000,63360000,64800000,66240000,67680000,
//69120000,70560000,72000000,73440000,76320000,77760000,79200000,80640000,82080000,83520000,84960000,86400000,87840000
};
public static void GeneratePLB()
{
long previousExp = 7200000;
ParagonLevelBorders.Add(7200000);
for (var i = 0; i < 59; i++)
{
previousExp += 1440000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 10; i++)
{
previousExp += 2880000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 3; i++)
{
previousExp += 5040000;
ParagonLevelBorders.Add(previousExp);
}
previousExp += 3660000;
ParagonLevelBorders.Add(previousExp);
for (var i = 0; i < 75; i++)
{
previousExp += 1020000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 101; i++)
{
previousExp += 2040000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 100; i++)
{
previousExp += 4080000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 99; i++)
{
previousExp += 6120000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 51; i++)
{
previousExp += 8160000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 50; i++)
{
previousExp += 20400000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 50; i++)
{
previousExp += 40800000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 50; i++)
{
previousExp += 61200000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 50; i++)
{
previousExp += 81600000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 50; i++)
{
previousExp += 102000000;
ParagonLevelBorders.Add(previousExp);
}
for (var i = 0; i < 1500; i++)
{
previousExp += 122400000;
ParagonLevelBorders.Add(previousExp);
}
long boosterofup = 229500000;
for (var i = 0; i < 17750; i++)
{
boosterofup += 102000;
previousExp += boosterofup;
ParagonLevelBorders.Add(previousExp);
}
}
//public static List<long> ParagonLevelBorders = ((GameBalance)DiIiS_NA.Core.MPQ.MPQStorage.Data.Assets[SNOGroup.GameBalance][252616].Data).Experience.Select(row => row.DeltaXP).ToList();
public static int[] LevelUpEffects =
{
85186, 85186, 85186, 85186, 85186, 85190, 85190, 85190, 85190, 85190, /* Level 1-10 */
85187, 85187, 85187, 85187, 85187, 85187, 85187, 85187, 85187, 85187, /* Level 11-20 */
85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, /* Level 21-30 */
85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, /* Level 31-40 */
85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, 85192, /* Level 41-50 */
85194, 85194, 85194, 85194, 85194, 85194, 85194, 85194, 85194, 85194, /* Level 51-60 */
85194, 85194, 85194, 85194, 85194, 85194, 85194, 85194, 85194, 85194 /* Level 61-70 */
};
public void AddRestExperience()
{
long exp_needed = 0;
if (Attributes[GameAttribute.Level] == Attributes[GameAttribute.Level_Cap])
exp_needed = ParagonLevelBorders[Attributes[GameAttribute.Alt_Level]];
else
exp_needed = LevelBorders[Attributes[GameAttribute.Level]];
Attributes[GameAttribute.Rest_Experience_Lo] =
Math.Min(Attributes[GameAttribute.Rest_Experience_Lo] + (int)(exp_needed / 10), (int)exp_needed);
Attributes[GameAttribute.Rest_Experience_Bonus_Percent] = 0.25f;
Attributes.BroadcastChangedIfRevealed();
}
private object _XPlock = new();
public void UpdateExp(int addedExp)
{
lock (_XPlock)
{
if (Dead) return;
if (World.Game.IsHardcore && Attributes[GameAttribute.Level] >= 70)
addedExp *= 5;
if (Attributes[GameAttribute.Alt_Level] >= 515)
{
var XPcap = 91.262575239831f * Math.Pow(Attributes[GameAttribute.Alt_Level], 3) -
44301.083380565047f * Math.Pow(Attributes[GameAttribute.Alt_Level], 2) +
3829010.395566940308f * Attributes[GameAttribute.Alt_Level] + 322795582.543823242188f;
addedExp = (int)((float)(ParagonLevelBorders[Attributes[GameAttribute.Alt_Level]] / XPcap) * addedExp);
}
if (Attributes[GameAttribute.Rest_Experience_Lo] > 0)
{
var multipliedExp = (int)Math.Min(addedExp * Attributes[GameAttribute.Rest_Experience_Bonus_Percent],
Attributes[GameAttribute.Rest_Experience_Lo]);
addedExp += multipliedExp;
Attributes[GameAttribute.Rest_Experience_Lo] -= multipliedExp;
}
if (Attributes[GameAttribute.Level] == Attributes[GameAttribute.Level_Cap])
Attributes[GameAttribute.Alt_Experience_Next_Lo] -= addedExp;
else
Attributes[GameAttribute.Experience_Next_Lo] -= addedExp;
// Levelup
while (Attributes[GameAttribute.Level] >= Attributes[GameAttribute.Level_Cap]
? Attributes[GameAttribute.Alt_Experience_Next_Lo] <= 0
: Attributes[GameAttribute.Experience_Next_Lo] <= 0)
{
// No more levelup at Level_Cap
if (Attributes[GameAttribute.Level] >= Attributes[GameAttribute.Level_Cap])
{
ParagonLevel++;
Toon.ParagonLevelUp();
ParagonLevelUp();
Attributes[GameAttribute.Alt_Level]++;
InGameClient.SendMessage(new ParagonLevel()
{
PlayerIndex = PlayerIndex,
Level = ParagonLevel
});
Conversations.StartConversation(0x0002A777); //LevelUp Conversation
Attributes[GameAttribute.Alt_Experience_Next_Lo] =
Attributes[GameAttribute.Alt_Experience_Next_Lo] +
(int)ParagonLevelBorders[Attributes[GameAttribute.Alt_Level]];
// On level up, health is set to max
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
// set resources to max as well
Attributes[GameAttribute.Resource_Cur, Attributes[GameAttribute.Resource_Type_Primary] - 1] =
Attributes[GameAttribute.Resource_Max_Total,
Attributes[GameAttribute.Resource_Type_Primary] - 1];
Attributes[GameAttribute.Resource_Cur, Attributes[GameAttribute.Resource_Type_Secondary] - 1] =
Attributes[GameAttribute.Resource_Max_Total,
Attributes[GameAttribute.Resource_Type_Secondary] - 1];
ExperienceNext = Attributes[GameAttribute.Alt_Experience_Next_Lo];
Attributes.BroadcastChangedIfRevealed();
PlayEffect(Effect.ParagonLevelUp, null, false);
World.PowerManager.RunPower(this, 252038); //g_LevelUp_AA.pow 252038
return;
}
Level++;
Attributes[GameAttribute.Level]++;
Toon.LevelUp();
if (World.Game.MonsterLevel + 1 ==
Attributes[GameAttribute.Level]) //if this is suitable level to update
World.Game.UpdateLevel(Attributes[GameAttribute.Level]);
InGameClient.SendMessage(new PlayerLevel()
{
PlayerIndex = PlayerIndex,
Level = Level
});
//Test Update Monster Level
if (PlayerIndex == 0)
{
InGameClient.Game.InitialMonsterLevel = Level;
InGameClient.SendMessage(new GameSyncedDataMessage
{
SyncedData = new GameSyncedData
{
GameSyncedFlags = InGameClient.Game.IsSeasoned ? InGameClient.Game.IsHardcore ? 3 : 2 :
InGameClient.Game.IsHardcore ? 1 : 0,
Act = Math.Min(InGameClient.Game.CurrentAct, 3000), //act id
InitialMonsterLevel = InGameClient.Game.InitialMonsterLevel, //InitialMonsterLevel
MonsterLevel = 0x64E4425E, //MonsterLevel
RandomWeatherSeed = InGameClient.Game.WeatherSeed, //RandomWeatherSeed
OpenWorldMode = InGameClient.Game.CurrentAct == 3000 ? 1 : 0, //OpenWorldMode
OpenWorldModeAct = -1, //OpenWorldModeAct
OpenWorldModeParam = -1, //OpenWorldModeParam
OpenWorldTransitionTime = 0x00000064, //OpenWorldTransitionTime
OpenWorldDefaultAct = 100, //OpenWorldDefaultAct
OpenWorldBonusAct = -1, //OpenWorldBonusAct
SNODungeonFinderLevelArea = 0x00000001, //SNODungeonFinderLevelArea
LootRunOpen =
InGameClient.Game.GameMode == Game.Mode.Portals
? 0
: -1, //LootRunOpen //0 - Великий Портал
OpenLootRunLevel = 1, //OpenLootRunLevel
LootRunBossDead = 0, //LootRunBossDead
HunterPlayerIdx = 0, //HunterPlayerIdx
LootRunBossActive = -1, //LootRunBossActive
TieredLootRunFailed = -1, //TieredLootRunFailed
LootRunChallengeCompleted = -1, //LootRunChallengeCompleted
SetDungeonActive = -1, //SetDungeonActive
Pregame = 0, //Pregame
PregameEnd = 0, //PregameEnd
RoundStart = 0, //RoundStart
RoundEnd = 0, //RoundEnd
PVPGameOver = 0x0, //PVPGameOver
field_v273 = 0x0,
TeamWins = new[] { 0x0, 0x0 }, //TeamWins
TeamScore = new[] { 0x0, 0x0 }, //TeamScore
PVPGameResult = new[] { 0x0, 0x0 }, //PVPGameResult
PartyGuideHeroId =
0x0, //PartyGuideHeroId //new EntityId() { High = 0, Low = (long)this.Players.Values.First().Toon.PersistentID }
TiredRiftPaticipatingHeroID =
new long[] { 0x0, 0x0, 0x0, 0x0 } //TiredRiftPaticipatingHeroID
}
});
}
Conversations.StartConversation(0x0002A777); //LevelUp Conversation
if (Attributes[GameAttribute.Level] >= Attributes[GameAttribute.Level_Cap])
{
Attributes[GameAttribute.Alt_Experience_Next_Lo] = (int)ParagonLevelBorders[Toon.ParagonLevel];
Toon.ExperienceNext = (int)ParagonLevelBorders[Toon.ParagonLevel];
}
else
{
Attributes[GameAttribute.Experience_Next_Lo] += (int)LevelBorders[Attributes[GameAttribute.Level]];
Toon.ExperienceNext = Attributes[GameAttribute.Experience_Next_Lo];
}
// 4 main attributes are incremented according to class
Attributes[GameAttribute.Strength] = Strength;
Attributes[GameAttribute.Intelligence] = Intelligence;
Attributes[GameAttribute.Vitality] = Vitality;
Attributes[GameAttribute.Dexterity] = Dexterity;
// On level up, health is set to max
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
// force GameAttributeMap to re-calc resources for the active resource types
Attributes[GameAttribute.Resource_Max, Attributes[GameAttribute.Resource_Type_Primary] - 1] =
Attributes[GameAttribute.Resource_Max, Attributes[GameAttribute.Resource_Type_Primary] - 1];
Attributes[GameAttribute.Resource_Max, Attributes[GameAttribute.Resource_Type_Secondary] - 1] =
Attributes[GameAttribute.Resource_Max, Attributes[GameAttribute.Resource_Type_Secondary] - 1];
// set resources to max as well
Attributes[GameAttribute.Resource_Cur, Attributes[GameAttribute.Resource_Type_Primary] - 1] =
Attributes[GameAttribute.Resource_Max_Total, Attributes[GameAttribute.Resource_Type_Primary] - 1];
Attributes[GameAttribute.Resource_Cur, Attributes[GameAttribute.Resource_Type_Secondary] - 1] =
Attributes[GameAttribute.Resource_Max_Total, Attributes[GameAttribute.Resource_Type_Secondary] - 1];
Attributes[GameAttribute.Hitpoints_Factor_Vitality] = 10f + Math.Max(Level - 35, 0);
Attributes.BroadcastChangedIfRevealed();
PlayEffect(Effect.LevelUp, null, false);
World.PowerManager.RunPower(this, 85954); //g_LevelUp.pow 85954
switch (Level)
{
case 10:
GrantAchievement(World.Game.IsHardcore ? (ulong)74987243307034 : (ulong)74987243307105);
break;
case 20:
GrantAchievement(World.Game.IsHardcore ? (ulong)74987243307035 : (ulong)74987243307104);
break;
case 30:
GrantAchievement(World.Game.IsHardcore ? (ulong)74987243307036 : (ulong)74987243307103);
break;
case 40:
GrantAchievement(World.Game.IsHardcore ? (ulong)74987243307037 : (ulong)74987243307102);
break;
case 50:
GrantAchievement(World.Game.IsHardcore ? (ulong)74987243307038 : (ulong)74987243307101);
if (World.Game.IsSeasoned)
GrantCriteria(74987250038929);
break;
case 60:
if (World.Game.IsHardcore)
{
GrantAchievement(74987243307039);
if (!Toon.GameAccount.Flags.HasFlag(GameAccount.GameAccountFlags.HardcoreTormentUnlocked))
Toon.GameAccount.Flags |= GameAccount.GameAccountFlags.HardcoreTormentUnlocked;
}
else
{
GrantAchievement(74987243307100);
if (!Toon.GameAccount.Flags.HasFlag(GameAccount.GameAccountFlags.TormentUnlocked))
Toon.GameAccount.Flags |= GameAccount.GameAccountFlags.TormentUnlocked;
}
CheckLevelCap();
break;
case 70:
GrantCriteria(74987254853541);
break;
default:
break;
}
}
ExperienceNext = Attributes[GameAttribute.Level] == 70
? Attributes[GameAttribute.Alt_Experience_Next_Lo]
: Attributes[GameAttribute.Experience_Next_Lo];
Attributes.BroadcastChangedIfRevealed();
Toon.GameAccount.NotifyUpdate();
//this.Attributes.SendMessage(this.InGameClient, this.DynamicID); kills the player atm
}
}
#endregion
#region gold, heath-glob collection
public void VacuumPickupHealthOrb(float radius = -1)
{
if (Math.Abs(radius - -1) < 0.001)
radius = Attributes[GameAttribute.Gold_PickUp_Radius];
var itemList = GetItemsInRange(radius);
foreach (var item in itemList)
if (Item.IsHealthGlobe(item.ItemType))
{
var playersAffected = GetPlayersInRange(26f);
foreach (var player in playersAffected)
{
foreach (var targetAffected in playersAffected)
player.InGameClient.SendMessage(new PlayEffectMessage()
{
ActorId = targetAffected.DynamicID(player),
Effect = Effect.HealthOrbPickup
});
//every summon and mercenary owned by you must broadcast their green text to you /H_DANILO
player.AddPercentageHP((int)item.Attributes[GameAttribute.Health_Globe_Bonus_Health]);
//passive abilities
if (player.SkillSet.HasPassive(208478)) //wizard PowerHungry
player.World.BuffManager.AddBuff(this, this, new HungryBuff());
if (player.SkillSet.HasPassive(208594)) //wd GruesomeFeast
{
player.GeneratePrimaryResource(player.Attributes[GameAttribute.Resource_Max_Total,
(int)player.Toon.HeroTable.PrimaryResource + 1] * 0.1f);
player.World.BuffManager.AddBuff(player, player, new GruesomeFeastIntBuff());
}
if (player.SkillSet.HasPassive(205205)) //barbarian PoundOfFlesh
player.AddPercentageHP((int)(item.Attributes[GameAttribute.Health_Globe_Bonus_Health] * 0.5f));
if (player.SkillSet.HasPassive(155714)) //dh Vengeance
{
player.GeneratePrimaryResource(20f);
player.GenerateSecondaryResource(2f);
}
}
item.Destroy();
}
}
public void VacuumPickup()
{
var itemList = GetItemsInRange(Attributes[GameAttribute.Gold_PickUp_Radius]);
foreach (var item in itemList)
if (Item.IsGold(item.ItemType))
{
if (!GroundItems.ContainsKey(item.GlobalID)) continue;
InGameClient.SendMessage(new FloatingAmountMessage()
{
Place = new WorldPlace()
{
Position = Position,
WorldID = World.DynamicID(this)
},
Amount = item.Attributes[GameAttribute.Gold],
Type = FloatingAmountMessage.FloatType.Gold
});
InGameClient.SendMessage(new PlayEffectMessage()
{
ActorId = DynamicID(this),
Effect = Effect.GoldPickup,
PlayerId = 0
});
PlayEffect(Effect.Sound, 36726);
Inventory.PickUpGold(item);
GroundItems.Remove(item.GlobalID);
item.Destroy();
}
else if (Item.IsBloodShard(item.ItemType) || item.ItemDefinition.Name == "HoradricRelic")
{
if (!GroundItems.ContainsKey(item.GlobalID)) continue;
InGameClient.SendMessage(new FloatingAmountMessage()
{
Place = new WorldPlace()
{
Position = Position,
WorldID = World.DynamicID(this)
},
Amount = item.Attributes[GameAttribute.ItemStackQuantityLo],
Type = FloatingAmountMessage.FloatType.BloodStone
});
Inventory.PickUpBloodShard(item);
GroundItems.Remove(item.GlobalID);
item.Destroy();
}
else if (item.ItemDefinition.Name == "Platinum")
{
InGameClient.SendMessage(new FloatingAmountMessage()
{
Place = new WorldPlace()
{
Position = Position,
WorldID = World.DynamicID(this)
},
Amount = item.Attributes[GameAttribute.ItemStackQuantityLo],
Type = FloatingAmountMessage.FloatType.Platinum
});
PlayEffect(Effect.Sound, 433266);
Inventory.PickUpPlatinum(item);
GroundItems.Remove(item.GlobalID);
item.Destroy();
}
else if (item.ItemDefinition.Name == "Crafting_Looted_Reagent_01")
{
/*
this.InGameClient.SendMessage(new FloatingAmountMessage()
{
Place = new WorldPlace()
{
Position = this.Position,
WorldID = this.World.DynamicID(this),
},
Amount = item.Attributes[GameAttribute.ItemStackQuantityLo],
Type = (FloatingAmountMessage.FloatType)22,
});
//*/
Toon.GameAccount.CraftItem4++;
Inventory.UpdateCurrencies();
item.Destroy();
}
else if (Item.IsHealthGlobe(item.ItemType))
{
var playersAffected = GetPlayersInRange(26f);
foreach (var player in playersAffected)
{
foreach (var targetAffected in playersAffected)
player.InGameClient.SendMessage(new PlayEffectMessage()
{
ActorId = targetAffected.DynamicID(player),
Effect = Effect.HealthOrbPickup
});
//every summon and mercenary owned by you must broadcast their green text to you /H_DANILO
player.AddPercentageHP((int)item.Attributes[GameAttribute.Health_Globe_Bonus_Health]);
//passive abilities
if (player.SkillSet.HasPassive(208478)) //wizard PowerHungry
player.World.BuffManager.AddBuff(this, this, new HungryBuff());
if (player.SkillSet.HasPassive(208594)) //wd GruesomeFeast
{
player.GeneratePrimaryResource(player.Attributes[GameAttribute.Resource_Max_Total,
(int)player.Toon.HeroTable.PrimaryResource + 1] * 0.1f);
player.World.BuffManager.AddBuff(player, player, new GruesomeFeastIntBuff());
}
if (player.SkillSet.HasPassive(205205)) //barbarian PoundOfFlesh
player.AddPercentageHP((int)(item.Attributes[GameAttribute.Health_Globe_Bonus_Health] * 0.5f));
if (player.SkillSet.HasPassive(155714)) //dh Vengeance
{
player.GeneratePrimaryResource(20f);
player.GenerateSecondaryResource(2f);
}
}
item.Destroy();
}
else if (item.ItemDefinition.Name == "ArcaneGlobe" && Toon.Class == ToonClass.Wizard)
{
GeneratePrimaryResource(50f);
item.Destroy();
}
else if (item.ItemDefinition.Name == "p1_normal_rifts_Orb" ||
item.ItemDefinition.Name == "p1_tiered_rifts_Orb")
{
if (InGameClient.Game.ActiveNephalemTimer && InGameClient.Game.ActiveNephalemKilledMobs == false)
{
InGameClient.Game.ActiveNephalemProgress += 15f;
foreach (var plr in InGameClient.Game.Players.Values)
{
plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DunggeonFinderProgressGlyphPickUp)
{
Field0 = InGameClient.Game.ActiveNephalemProgress
});
plr.InGameClient.SendMessage(new SimpleMessage(Opcodes.KillCounterRefresh)
{
});
plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DungeonFinderProgressMessage)
{
Field0 = InGameClient.Game.ActiveNephalemProgress
});
}
if (InGameClient.Game.ActiveNephalemProgress > 650)
{
InGameClient.Game.ActiveNephalemKilledMobs = true;
foreach (var plr in InGameClient.Game.Players.Values)
{
if (InGameClient.Game.NephalemGreater)
{
plr.InGameClient.SendMessage(new QuestCounterMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 13,
TaskIndex = 0,
Checked = 1,
Counter = 1
});
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 16,
DisplayButton = true,
Failed = false
});
}
else
{
plr.InGameClient.SendMessage(new QuestCounterMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 1,
TaskIndex = 0,
Checked = 1,
Counter = 1
});
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 3,
DisplayButton = true,
Failed = false
});
}
plr.InGameClient.SendMessage(new PlayMusicMessage(Opcodes.PlayMusicMessage)
{
SNO = 0x0005BBD8
});
plr.InGameClient.SendMessage(new DisplayGameTextMessage(Opcodes.DisplayGameChatTextMessage)
{ Message = "Messages:LR_BossSpawned" });
plr.InGameClient.SendMessage(new DisplayGameTextMessage(Opcodes.DisplayGameTextMessage)
{ Message = "Messages:LR_BossSpawned" });
}
StartConversation(World, 366542);
SpawnNephalemBoss(World);
//358489
}
}
item.Destroy();
}
else if (item.ItemDefinition.Name == "PowerGlobe_v2_x1_NoFlippy")
{
World.BuffManager.AddBuff(this, this, new NephalemValorBuff());
item.Destroy();
}
else if (Item.IsPotion(item.ItemType))
{
if ((!GroundItems.ContainsKey(item.GlobalID) && World.Game.Players.Count > 1) ||
!Inventory.HasInventorySpace(item)) continue;
Inventory.PickUp(item);
}
//
foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 460757 && skill.snoRune == 3)
{
//Play Aura - 472217
//this.PlayEffectGroup(472217);
var Fleshes =
GetActorsInRange<NecromancerFlesh>(15f + Attributes[GameAttribute.Gold_PickUp_Radius] *
0.5f); //454066
foreach (var flesh in Fleshes)
{
InGameClient.SendMessage(new EffectGroupACDToACDMessage()
{
EffectSNOId = 470480,
TargetID = DynamicID(this),
ActorID = flesh.DynamicID(this)
});
flesh.PlayEffectGroup(470482);
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource] += 11f;
Attributes.BroadcastChangedIfRevealed();
flesh.Destroy();
}
}
}
public Actor SpawnNephalemBoss(World world)
{
var Boss = world.SpawnMonster(
ActorSnoExtensions.nephalemPortalBosses[
RandomHelper.Next(0, ActorSnoExtensions.nephalemPortalBosses.Length - 1)], Position);
Boss.Attributes[GameAttribute.Bounty_Objective] = true;
Boss.Attributes[GameAttribute.Is_Loot_Run_Boss] = true;
Boss.Attributes.BroadcastChangedIfRevealed();
foreach (var plr in world.Players.Values)
plr.InGameClient.SendMessage(new WorldSyncedDataMessage()
{
WorldID = world.GlobalID,
SyncedData = new WorldSyncedData()
{
SnoWeatherOverride = 362462,
WeatherIntensityOverride = 0,
WeatherIntensityOverrideEnd = 0
}
});
return Boss;
}
public bool StartConversation(World world, int conversationId)
{
foreach (var plr in world.Players)
plr.Value.Conversations.StartConversation(conversationId);
return true;
}
public void AddPercentageHP(int percentage, bool GuidingLight = false)
{
var quantity = percentage * Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
AddHP(quantity, GuidingLight);
}
public void AddPercentageHP(float percentage, bool GuidingLight = false)
{
var quantity = percentage * Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
AddHP(quantity, GuidingLight);
}
public override void AddHP(float quantity, bool guidingLight = false)
{
if (Dead) return;
if (quantity == 0) return;
if (quantity > 0)
{
if (Attributes[GameAttribute.Hitpoints_Cur] < Attributes[GameAttribute.Hitpoints_Max_Total])
{
if (Toon.Class == ToonClass.Barbarian)
if (SkillSet.HasPassive(205217))
quantity += 0.01f * Attributes[GameAttribute.Health_Globe_Bonus_Health];
if (guidingLight) //Monk -> Guiding Light
{
var missingHP =
(Attributes[GameAttribute.Hitpoints_Max_Total] - Attributes[GameAttribute.Hitpoints_Cur]) /
Attributes[GameAttribute.Hitpoints_Max_Total];
if (missingHP > 0.05f)
if (!World.BuffManager.HasBuff<GuidingLightBuff>(this))
World.BuffManager.AddBuff(this, this,
new GuidingLightBuff(Math.Min(missingHP, 0.3f),
TickTimer.WaitSeconds(World.Game, 10.0f)));
}
Attributes[GameAttribute.Hitpoints_Cur] = Math.Min(
Attributes[GameAttribute.Hitpoints_Cur] + quantity,
Attributes[GameAttribute.Hitpoints_Max_Total]);
Attributes.BroadcastChangedIfRevealed();
InGameClient.SendMessage(new FloatingNumberMessage
{
ActorID = DynamicID(this),
Number = quantity,
Type = FloatingNumberMessage.FloatType.Green
});
}
}
else
{
Attributes[GameAttribute.Hitpoints_Cur] = Math.Max(
Attributes[GameAttribute.Hitpoints_Cur] + quantity,
0);
Attributes.BroadcastChangedIfRevealed();
}
}
//only for WD passive
public void RestoreMana(float quantity, int secs)
{
Attributes[GameAttribute.Resource_Regen_Per_Second, 0] += quantity / secs;
System.Threading.Tasks.Task.Delay(1000 * secs).ContinueWith(t =>
{
Attributes[GameAttribute.Resource_Regen_Per_Second, 0] -= quantity / secs;
});
}
#endregion
#region Resource Generate/Use
private int _DisciplineSpent = 0;
private int _HatredSpent = 0;
private int _WrathSpent = 0;
public void GeneratePrimaryResource(float amount)
{
if (Toon.Class == ToonClass.Barbarian)
if (World.BuffManager.HasBuff<WrathOfTheBerserker.BerserkerBuff>(this))
World.BuffManager.GetFirstBuff<WrathOfTheBerserker.BerserkerBuff>(this).GainedFury += amount;
if (Toon.Class == ToonClass.Monk)
if (World.BuffManager.HasBuff<GuardiansPathBuff>(this)) //Monk -> The Guardian's Path 2H
amount *= 1.35f;
_ModifyResourceAttribute(PrimaryResourceID, amount);
}
public void UsePrimaryResource(float amount, bool tick = false)
{
amount = Math.Max(
(amount - Attributes[GameAttribute.Resource_Cost_Reduction_Amount]) * (1f -
Attributes[GameAttribute.Resource_Cost_Reduction_Percent_Total,
(int)Toon.HeroTable.PrimaryResource + 1]), 0);
amount = amount * (1f - DecreaseUseResourcePercent);
if (Toon.Class == ToonClass.Crusader)
{
_WrathSpent += (int)amount;
if (!tick && SkillSet.HasPassive(310775)) //Wrathful passive
AddHP(_WrathSpent * 15f * Attributes[GameAttribute.Level]);
//Laws of Hope -> Faith's reward
if (!tick && World.BuffManager.HasBuff<CrusaderLawsOfHope.LawsShieldBuff>(this))
if (World.BuffManager.GetFirstBuff<CrusaderLawsOfHope.LawsShieldBuff>(this).HealPerWrath)
AddHP(_WrathSpent * 15f * Attributes[GameAttribute.Level]);
if (_WrathSpent >= 20) //Akarat Champion -> Fire Starter
if (!tick && World.BuffManager.HasBuff<CrusaderAkaratChampion.AkaratBuff>(this))
World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(this).wrathBlast = true;
}
if (Toon.Class == ToonClass.DemonHunter)
{
_HatredSpent += (int)amount;
if (_HatredSpent >= 150 && _DisciplineSpent >= 50)
GrantAchievement(74987243307068);
AddTimedAction(6f, new Action<int>((q) => _HatredSpent -= (int)amount));
}
if (Toon.Class == ToonClass.Barbarian)
{
if (SkillSet.HasPassive(105217) && !tick) //Bloodthirst (Burb)
AddHP(amount * 1.93f * Attributes[GameAttribute.Level]);
if (!tick && World.BuffManager.HasBuff<IgnorePain.IgnorePainBuff>(this))
if (Attributes[GameAttribute.Rune_E, 79528] > 0) //IgnorePain
AddHP(amount * 13.76f * Attributes[GameAttribute.Level]);
}
if (Toon.Class == ToonClass.Wizard)
if (World.BuffManager.HasBuff<HungryBuff>(this)) //Power Hungry
{
amount = 0f;
World.BuffManager.RemoveStackFromBuff(this, World.BuffManager.GetFirstBuff<HungryBuff>(this));
}
if (Toon.Class == ToonClass.Monk)
if (SkillSet.HasPassive(209250)) //Transcendence (Monk)
AddHP(amount * (50f + Attributes[GameAttribute.Health_Globe_Bonus_Health] * 0.004f));
if (SkillSet.HasPassive(208628)) //PierceTheVeil (WD)
amount *= 1.3f;
if (SkillSet.HasPassive(208568)) //BloodRitual (WD)
{
amount *= 0.9f;
AddHP(amount * -0.1f);
}
if (SkillSet.HasPassive(205398) && Attributes[GameAttribute.Hitpoints_Cur] <
Attributes[GameAttribute.Hitpoints_Max_Total] * 0.35f) //Relentless (Barbarian)
amount *= 0.25f;
_ModifyResourceAttribute(PrimaryResourceID, -amount);
}
public void GenerateSecondaryResource(float amount)
{
_ModifyResourceAttribute(SecondaryResourceID, amount);
}
public void UseSecondaryResource(float amount)
{
amount = Math.Max(
(amount - Attributes[GameAttribute.Resource_Cost_Reduction_Amount]) * (1f -
Attributes[GameAttribute.Resource_Cost_Reduction_Percent_Total, (int)Toon.HeroTable.SecondaryResource]),
0);
if (SkillSet.HasPassive(155722)) //dh - Perfectionist
amount *= 0.9f;
if (Toon.Class == ToonClass.DemonHunter)
{
_DisciplineSpent += (int)amount;
if (_HatredSpent >= 150 && _DisciplineSpent >= 50)
GrantAchievement(74987243307068);
AddTimedAction(6f, new Action<int>((q) => _DisciplineSpent -= (int)amount));
}
_ModifyResourceAttribute(SecondaryResourceID, -amount);
}
private void _ModifyResourceAttribute(int resourceID, float amount)
{
if (resourceID == -1 || amount == 0) return;
var current = Attributes[GameAttribute.Resource_Cur, resourceID];
if (amount > 0f)
Attributes[GameAttribute.Resource_Cur, resourceID] = Math.Min(
Attributes[GameAttribute.Resource_Cur, resourceID] + amount,
Attributes[GameAttribute.Resource_Max_Total, resourceID]);
else
Attributes[GameAttribute.Resource_Cur, resourceID] = Math.Max(
Attributes[GameAttribute.Resource_Cur, resourceID] + amount,
0f);
if (current == Attributes[GameAttribute.Resource_Cur, resourceID]) return;
Attributes.BroadcastChangedIfRevealed();
}
private int _fullFuryFirstTick = 0;
private int _ArmorFirstTick = 0;
private void _UpdateResources()
{
// will crash client when loading if you try to update resources too early
if (World == null) return;
if (InGameClient.Game.Paused) return;
if (!(InGameClient.Game.TickCounter % 30 == 0)) return;
if (InGameClient.Game.TickCounter % 60 == 0)
LastSecondCasts = 0;
if (Toon.Class == ToonClass.Barbarian)
{
if (Attributes[GameAttribute.Resource_Cur, 2] < Attributes[GameAttribute.Resource_Max_Total, 2])
_fullFuryFirstTick = InGameClient.Game.TickCounter;
if (InGameClient.Game.TickCounter - _fullFuryFirstTick >= 18000)
GrantAchievement(74987243307047);
}
if (Toon.Class == ToonClass.Wizard)
{
if (!World.BuffManager.HasBuff<IceArmor.IceArmorBuff>(this) &&
!World.BuffManager.HasBuff<StormArmor.StormArmorBuff>(this) &&
!World.BuffManager.HasBuff<EnergyArmor.EnergyArmorBuff>(this))
_ArmorFirstTick = InGameClient.Game.TickCounter;
if (InGameClient.Game.TickCounter - _ArmorFirstTick >= 72000)
GrantAchievement(74987243307588);
}
// 1 tick = 1/60s, so multiply ticks in seconds against resource regen per-second to get the amount to update
var tickSeconds = 1f / 60f * (InGameClient.Game.TickCounter - _lastResourceUpdateTick);
_lastResourceUpdateTick = InGameClient.Game.TickCounter;
GeneratePrimaryResource(Math.Max(
tickSeconds * Attributes[GameAttribute.Resource_Regen_Total,
Attributes[GameAttribute.Resource_Type_Primary] - 1], 0));
GenerateSecondaryResource(Math.Max(
tickSeconds * Attributes[GameAttribute.Resource_Regen_Total,
Attributes[GameAttribute.Resource_Type_Secondary] - 1], 0));
var totalHPregen = //(this.Attributes[GameAttribute.Hitpoints_Regen_Per_Second] +
Attributes[GameAttribute.Hitpoints_Regen_Per_Second_Bonus] //)
* (1 + Attributes[GameAttribute.Hitpoints_Regen_Bonus_Percent]);
if (!Dead && !World.Game.PvP) AddHP(Math.Max(tickSeconds * totalHPregen, 0));
if (Toon.Class == ToonClass.Barbarian)
if (SkillSet.HasPassive(205300)) //barbarian fury
GeneratePrimaryResource(tickSeconds * 1.80f);
else
UsePrimaryResource(tickSeconds * 0.90f, true);
}
#endregion
#region lore
/// <summary>
/// Checks if player has lore
/// </summary>
/// <param name="loreSNOId"></param>
/// <returns></returns>
public bool HasLore(int loreSNOId)
{
return LearnedLore.m_snoLoreLearned.Contains(loreSNOId);
}
/// <summary>
/// Plays lore to player
/// </summary>
/// <param name="loreSNOId"></param>
/// <param name="immediately">if false, lore will have new lore button</param>
public void PlayLore(int loreSNOId, bool immediately)
{
// play lore to player
InGameClient.SendMessage(new LoreMessage
{
LoreSNOId = loreSNOId
});
if (!HasLore(loreSNOId))
{
AddLore(loreSNOId);
if (MPQStorage.Data.Assets[SNOGroup.Lore].ContainsKey(loreSNOId))
CheckConversationCriteria(
(MPQStorage.Data.Assets[SNOGroup.Lore][loreSNOId].Data as DiIiS_NA.Core.MPQ.FileFormats.Lore)
.SNOConversation);
}
}
/// <summary>
/// Adds lore to player's state
/// </summary>
/// <param name="loreSNOId"></param>
public void AddLore(int loreSNOId)
{
if (LearnedLore.Count < LearnedLore.m_snoLoreLearned.Length)
{
LearnedLore.m_snoLoreLearned[LearnedLore.Count] = loreSNOId;
LearnedLore.Count++; // Count
UpdateHeroState();
Logger.Trace("Learning lore #{0}", loreSNOId);
var dbToon = Toon.DBToon;
dbToon.Lore = SerializeBytes(LearnedLore.m_snoLoreLearned.Take(LearnedLore.Count).ToList());
World.Game.GameDbSession.SessionUpdate(dbToon);
}
}
#endregion
#region StoneOfRecall
public void EnableStoneOfRecall()
{
Attributes[GameAttribute.Skill, 0x0002EC66] = 1;
Attributes.SendChangedMessage(InGameClient);
}
public void DisableStoneOfRecall()
{
Attributes[GameAttribute.Skill, 0x0002EC66] = 0;
Attributes.SendChangedMessage(InGameClient);
}
#endregion
#region Minions and Hirelings handling
public void AddFollower(Actor source)
{
//Rangged Power - 30599
if (source == null) return;
var minion = new Minion(World, source.SNO, this, source.Tags, true);
minion.SetBrain(new MinionBrain(minion));
minion.Brain.DeActivate();
minion.WalkSpeed *= 4;
minion.Position = Position;
minion.Attributes[GameAttribute.TeamID] = Attributes[GameAttribute.TeamID];
minion.Attributes[GameAttribute.Untargetable] = true;
minion.Attributes[GameAttribute.No_Damage] = true;
minion.Attributes[GameAttribute.Invulnerable] = true;
minion.Attributes[GameAttribute.TeamID] = 2;
minion.Attributes[GameAttribute.NPC_Is_Escorting] = true;
minion.Attributes[GameAttribute.Pet_Creator] = 1;
minion.Attributes[GameAttribute.Pet_Owner] = 1;
minion.Attributes[GameAttribute.Pet_Type] = 25;
//*/
minion.Attributes[GameAttribute.Effect_Owner_ANN] = (int)DynamicID(this);
minion.EnterWorld(minion.Position);
(minion as Minion).Brain.Activate();
source.Hidden = true;
source.SetVisible(false);
minion.SetVisible(true);
minion.Hidden = false;
if (minion.SNO == ActorSno._leah) // (4580) Act I Leah
{
(minion.Brain as MinionBrain).PresetPowers.Clear();
(minion.Brain as MinionBrain).AddPresetPower(30599);
}
if ((Followers.Count >= 6 && ActiveHireling != null) || Followers.Count >= 7)
if (Toon.Class == ToonClass.WitchDoctor)
GrantAchievement(74987243307563);
}
public bool HaveFollower(ActorSno sno)
{
return Followers.ContainsValue(sno);
}
public void DestroyFollower(ActorSno sno)
{
if (Followers.ContainsValue(sno))
{
var dynId = Followers.Where(x => x.Value == sno).First().Key;
var actor = World.GetActorByGlobalId(dynId);
if (actor != null)
actor.Destroy();
Followers.Remove(dynId);
}
}
public void SetFollowerIndex(ActorSno sno)
{
if (!HaveFollower(sno))
for (var i = 1; i < 8; i++)
if (!_followerIndexes.ContainsKey(i))
{
_followerIndexes.Add(i, sno);
return;
}
}
public void FreeFollowerIndex(ActorSno sno)
{
if (!HaveFollower(sno)) _followerIndexes.Remove(FindFollowerIndex(sno));
}
private Dictionary<int, ActorSno> _followerIndexes = new();
public int FindFollowerIndex(ActorSno sno)
{
if (HaveFollower(sno))
return _followerIndexes.FirstOrDefault(i => i.Value == sno).Key;
return 0;
}
public int CountFollowers(ActorSno sno)
{
return Followers.Values.Count(f => f == sno);
}
public int CountAllFollowers()
{
return Followers.Count();
}
public void DestroyFollowerById(uint dynId)
{
if (Followers.ContainsKey(dynId))
{
var actor = World.GetActorByGlobalId(dynId);
Followers.Remove(dynId);
if (actor != null)
{
FreeFollowerIndex(actor.SNO);
actor.Destroy();
}
}
}
public void DestroyFollowersBySnoId(ActorSno sno)
{
var fol_list = Followers.Where(f => f.Value == sno).Select(f => f.Key).ToList();
foreach (var fol in fol_list)
DestroyFollowerById(fol);
}
#endregion
public void Heal()
{
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes[GameAttribute.Hitpoints_Total_From_Level] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes.BroadcastChangedIfRevealed();
}
}