Changelog:

GameServerConfig.cs and Player.cs:
- StrengthMultiplier / StrengthParagonMultipler
- DexterityMultiplier / DexterityParagonMultiplier
- IntelligenceMultiplier / IntelligenceParagonMultiplier
- VitalityMultiplier / VitalityParagonMultiplier
CommandManager.cs and CommandsConfig.cs:
- Added a command group disable parameter (DisabledGroups). A ranking system should be added later on.
RestSession.cs and Http.cs:
- Added battlenet login POST and GET;
- If no page is found on DEBUG, it returns 502 (Bad GW - if on NAT it could be useful for stopping bots of retrying connection with the server) otherwise returns 404
Others:
!drop minor changes
Cleanups
This commit is contained in:
Lucca Faria Ferri 2023-02-09 21:22:41 -08:00
parent 3d123f409f
commit 6657f17730
22 changed files with 696 additions and 630 deletions

View File

@ -107,7 +107,7 @@ namespace DiIiS_NA.Core.Logging
{ {
#if DEBUG #if DEBUG
var fileName = Path.GetFileName(filePath); var fileName = Path.GetFileName(filePath);
Log(Level.MethodTrace, $"$[underline white]${fileName}:{lineNumber}$[/]$ $[darkolivegreen3_2]${methodName}()$[/]$: $[black on white]$" + message + "$[/]$", null); Log(Level.MethodTrace, $"$[underline white]${fileName}:{lineNumber}$[/]$ $[darkolivegreen3_2]${methodName}()$[/]$: " + message, null);
#else #else
Log(Level.MethodTrace, $"$[darkolivegreen3_2]${methodName}()$[/]$: " + message, null); Log(Level.MethodTrace, $"$[darkolivegreen3_2]${methodName}()$[/]$: " + message, null);
#endif #endif

View File

@ -13,23 +13,17 @@ namespace DiIiS_NA.Core.Storage
private static Object _globalSessionLock = new object(); private static Object _globalSessionLock = new object();
private Object _sessionLock = new object(); private Object _sessionLock = new object();
private IStatelessSession _gameSession = null; private IStatelessSession _gameSession = null;
private readonly Logger Logger = LogManager.CreateLogger("DB"); private readonly Logger Logger = LogManager.CreateLogger(nameof(GameDBSession));
public GameDBSession() public GameDBSession()
{ {
lock (_globalSessionLock) lock (_globalSessionLock)
{ {
this._gameSession = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession(); _gameSession = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession();
} }
} }
private IStatelessSession GameSession private IStatelessSession GameSession => _gameSession;
{
get
{
return this._gameSession;
}
}
public void SessionSave(Object obj) public void SessionSave(Object obj)
{ {
@ -39,8 +33,8 @@ namespace DiIiS_NA.Core.Storage
{ {
try try
{ {
using (IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession()) using IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession();
session.Insert(obj); session.Insert(obj);
} }
catch (Exception e) catch (Exception e)
{ {
@ -74,8 +68,8 @@ namespace DiIiS_NA.Core.Storage
{ {
try try
{ {
using (IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession()) using IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession();
session.Update(obj); session.Update(obj);
} }
catch (Exception e) catch (Exception e)
{ {
@ -109,8 +103,8 @@ namespace DiIiS_NA.Core.Storage
{ {
try try
{ {
using (IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession()) using IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession();
session.Delete(obj); session.Delete(obj);
} }
catch (Exception e) catch (Exception e)
{ {
@ -157,8 +151,8 @@ namespace DiIiS_NA.Core.Storage
{ {
try try
{ {
using (IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession()) using IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession();
return session.Query<T>().ToList(); return session.Query<T>().ToList();
} }
catch (Exception e) catch (Exception e)
{ {
@ -189,8 +183,8 @@ namespace DiIiS_NA.Core.Storage
{ {
try try
{ {
using (IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession()) using IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession();
return session.QueryOver<T>().Where(predicate).List().ToList(); return session.QueryOver<T>().Where(predicate).List().ToList();
} }
catch (Exception e) catch (Exception e)
{ {
@ -221,8 +215,8 @@ namespace DiIiS_NA.Core.Storage
{ {
try try
{ {
using (IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession()) using IStatelessSession session = AccountDataBase.SessionProvider.SessionFactory.OpenStatelessSession();
return (T)session.QueryOver<T>().Where(predicate).List().FirstOrDefault(); return (T)session.QueryOver<T>().Where(predicate).List().FirstOrDefault();
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -24,17 +24,28 @@ namespace DiIiS_NA.GameServer.CommandManager
foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{ {
if (!type.IsSubclassOf(typeof(CommandGroup))) continue; if (!type.IsSubclassOf(typeof(CommandGroup))) continue;
var attributes = (CommandGroupAttribute[])type.GetCustomAttributes(typeof(CommandGroupAttribute), true); var attributes = (CommandGroupAttribute[])type.GetCustomAttributes(typeof(CommandGroupAttribute), true);
if (attributes.Length == 0) continue; if (attributes.Length == 0) continue;
var groupAttribute = attributes[0]; var groupAttribute = attributes[0];
if (groupAttribute.Name == null) continue;
if (CommandsConfig.Instance.DisabledGroupsData.Contains(groupAttribute.Name))
{
Logger.Trace($"Command group {groupAttribute.Name} is disabled.");
continue;
}
if (CommandGroups.ContainsKey(groupAttribute)) if (CommandGroups.ContainsKey(groupAttribute))
Logger.Warn("There exists an already registered command group named '{0}'.", groupAttribute.Name); Logger.Warn("There exists an already registered command group named '{0}'.", groupAttribute.Name);
var commandGroup = (CommandGroup)Activator.CreateInstance(type); var commandGroup = (CommandGroup)Activator.CreateInstance(type);
commandGroup.Register(groupAttribute); if (commandGroup != null)
CommandGroups.Add(groupAttribute, commandGroup); {
commandGroup.Register(groupAttribute);
CommandGroups.Add(groupAttribute, commandGroup);
}
else
{
Logger.Warn("Failed to create an instance of command group '{0}'.", groupAttribute.Name);
}
} }
} }

View File

@ -4,8 +4,7 @@ using DiIiS_NA.LoginServer.Battle;
namespace DiIiS_NA.GameServer.CommandManager; namespace DiIiS_NA.GameServer.CommandManager;
[CommandGroup("drop", "Drops an epic item for your class.\nOptionally specify the number of items: !drop [1-20]", [CommandGroup("drop", "Drops an epic item for your class.\nOptionally specify the number of items: !drop [1-20]", Account.UserLevels.Owner)]
Account.UserLevels.Owner)]
public class DropCommand : CommandGroup public class DropCommand : CommandGroup
{ {
[DefaultCommand] [DefaultCommand]
@ -29,16 +28,16 @@ public class DropCommand : CommandGroup
try try
{ {
for (var i = 0; i < amount; i++) for (var i = 0; i < amount; i++)
player.World.SpawnRandomEquip(player, player, 11, player.Level, toonClass: player.Toon.Class, player.World.SpawnRandomEquip(player, player, 11, /*player.Level,*/ toonClass: player.Toon.Class,
canBeUnidentified: false); canBeUnidentified: false);
} }
catch catch
{ {
for (var i = 0; i < amount; i++) for (var i = 0; i < amount; i++)
player.World.SpawnRandomEquip(player, player, 8, player.Level, toonClass: player.Toon.Class, player.World.SpawnRandomEquip(player, player, 8, /*player.Level,*/ toonClass: player.Toon.Class,
canBeUnidentified: false); canBeUnidentified: false);
} }
return $"Dropped {amount} random equipment."; return $"Dropped {amount} random epic equipment.";
} }
} }

View File

@ -13,8 +13,20 @@ namespace DiIiS_NA.GameServer.CommandManager
get => GetString(nameof(CommandPrefix), "!")[0]; get => GetString(nameof(CommandPrefix), "!")[0];
set => Set(nameof(CommandPrefix), value); set => Set(nameof(CommandPrefix), value);
} }
public string DisabledGroups
{
get => GetString(nameof(DisabledGroups), "");
set => Set(nameof(DisabledGroups), value);
}
public static CommandsConfig Instance = new(); public string[] DisabledGroupsData
=> DisabledGroups
.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.Select(s=>s.Replace(CommandPrefix.ToString(), ""))
.ToArray();
public static readonly CommandsConfig Instance = new();
private CommandsConfig() : base("Commands") { } private CommandsConfig() : base("Commands") { }
} }
} }

View File

@ -113,41 +113,24 @@ namespace DiIiS_NA.GameServer.Core.Types.Math
return ((x * x) + (y * y)) + (z * z); return ((x * x) + (y * y)) + (z * z);
} }
public static bool operator ==(Vector3D a, Vector3D b) public static bool operator ==(Vector3D a, Vector3D b) => a?.Equals(b) ?? ReferenceEquals(null, b);
{
if (ReferenceEquals(null, a))
return ReferenceEquals(null, b);
return a.Equals(b);
}
public static bool operator !=(Vector3D a, Vector3D b) public static bool operator !=(Vector3D a, Vector3D b) => !(a == b);
{
return !(a == b);
}
public static bool operator >(Vector3D a, Vector3D b) public static bool operator >(Vector3D a, Vector3D b)
{ {
if (ReferenceEquals(null, a)) return ReferenceEquals(null, a)
return !ReferenceEquals(null, b); ? !ReferenceEquals(null, b)
return a.X > b.X : a.X > b.X
&& a.Y > b.Y && a.Y > b.Y
&& a.Z > b.Z; && a.Z > b.Z;
} }
public static Vector3D operator +(Vector3D a, Vector3D b) public static Vector3D operator +(Vector3D a, Vector3D b) => new Vector3D(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
{
return new Vector3D(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
public static Vector3D operator -(Vector3D a, Vector3D b) public static Vector3D operator -(Vector3D a, Vector3D b) => new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
{
return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
}
public static bool operator <(Vector3D a, Vector3D b) public static bool operator <(Vector3D a, Vector3D b) => !(a > b);
{
return !(a > b);
}
public static bool operator >=(Vector3D a, Vector3D b) public static bool operator >=(Vector3D a, Vector3D b)
{ {
@ -174,9 +157,9 @@ namespace DiIiS_NA.GameServer.Core.Types.Math
var v = o as Vector3D; var v = o as Vector3D;
if (v != null) if (v != null)
{ {
return System.Math.Abs(X - v.X) < 0.0001 return System.Math.Abs(X - v.X) < Globals.FLOAT_TOLERANCE
&& System.Math.Abs(Y - v.Y) < 0.0001 && System.Math.Abs(Y - v.Y) < Globals.FLOAT_TOLERANCE
&& System.Math.Abs(Z - v.Z) < 0.0001; && System.Math.Abs(Z - v.Z) < Globals.FLOAT_TOLERANCE;
} }
return false; return false;
} }

View File

@ -20690,7 +20690,7 @@ namespace DiIiS_NA.D3_GameServer.Core.Types.SNO
ActorSno._p73_fallenlunatic_a_nonspawner, ActorSno._p73_fallenlunatic_a_nonspawner,
}; };
// all '_vo' and 'voiceo' actors except 'voodoomask` and and cosmetic pets // all '_vo' and 'voiceo' actors except 'voodoomask` and and cosmetic pets
private static readonly ActorSno[] soundActors = new ActorSno[] private static readonly ActorSno[] _soundActors = new ActorSno[]
{ {
ActorSno._lustmissle_volume, ActorSno._lustmissle_volume,
ActorSno._a1dun_caves_nephalem_altar_volume, ActorSno._a1dun_caves_nephalem_altar_volume,
@ -20713,7 +20713,7 @@ namespace DiIiS_NA.D3_GameServer.Core.Types.SNO
ActorSno._p43_ad_valor_bloodstone_volume, ActorSno._p43_ad_valor_bloodstone_volume,
}; };
// all 'door' actors // all 'door' actors
private static readonly ActorSno[] doors = new ActorSno[] private static readonly ActorSno[] _doors = new ActorSno[]
{ {
ActorSno._trdun_cath_wooddoor_a, ActorSno._trdun_cath_wooddoor_a,
ActorSno._door_intactc_caout_towns, ActorSno._door_intactc_caout_towns,
@ -21156,7 +21156,7 @@ namespace DiIiS_NA.D3_GameServer.Core.Types.SNO
ActorSno._kanai_cube_uber_fx, ActorSno._kanai_cube_uber_fx,
}; };
// all 'adventuremode' actors // all 'adventuremode' actors
private static readonly ActorSno[] adventureModeActors = new ActorSno[] private static readonly ActorSno[] AdventureModeActors = new ActorSno[]
{ {
ActorSno._x1_lore_adventuremode_zknephalem, ActorSno._x1_lore_adventuremode_zknephalem,
ActorSno._x1_lore_adventuremode_zkplans, ActorSno._x1_lore_adventuremode_zkplans,
@ -21168,7 +21168,7 @@ namespace DiIiS_NA.D3_GameServer.Core.Types.SNO
ActorSno._x1_adventuremode_hubbantertrigger, ActorSno._x1_adventuremode_hubbantertrigger,
}; };
#endregion #endregion
public static readonly ActorSno[] nephalemPortalBosses = new ActorSno[] public static readonly ActorSno[] NephalemPortalBosses = new ActorSno[]
{ {
ActorSno._x1_lr_boss_mistressofpain, ActorSno._x1_lr_boss_mistressofpain,
ActorSno._x1_lr_boss_angel_corrupt_a, ActorSno._x1_lr_boss_angel_corrupt_a,
@ -21227,17 +21227,17 @@ namespace DiIiS_NA.D3_GameServer.Core.Types.SNO
public static bool IsAdventureModeActor(this ActorSno actorSno) public static bool IsAdventureModeActor(this ActorSno actorSno)
{ {
return adventureModeActors.Contains(actorSno); return AdventureModeActors.Contains(actorSno);
} }
public static bool IsTargetable(this ActorSno actorSno) public static bool IsTargetable(this ActorSno actorSno)
{ {
return !spawners.Contains(actorSno) && !soundActors.Contains(actorSno); return !spawners.Contains(actorSno) && !_soundActors.Contains(actorSno);
} }
public static bool IsDoorOrBarricade(this ActorSno actorSno) public static bool IsDoorOrBarricade(this ActorSno actorSno)
{ {
return doors.Contains(actorSno) || barricades.Contains(actorSno); return _doors.Contains(actorSno) || barricades.Contains(actorSno);
} }
public static bool IsWoodwraithOrWasp(this ActorSno actorSno) public static bool IsWoodwraithOrWasp(this ActorSno actorSno)

View File

@ -50,11 +50,5 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
base.OnCraft(player); base.OnCraft(player);
player.CurrentArtisan = ArtisanType.Nephalem; player.CurrentArtisan = ArtisanType.Nephalem;
} }
public override bool Reveal(Player player)
{
return base.Reveal(player);
}
} }
} }

View File

@ -88,7 +88,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
public void UpdateStats() public void UpdateStats()
{ {
var monsterLevels = (GameBalance)DiIiS_NA.Core.MPQ.MPQStorage.Data.Assets[SNOGroup.GameBalance][19760].Data; var monsterLevels = (GameBalance)DiIiS_NA.Core.MPQ.MPQStorage.Data.Assets[SNOGroup.GameBalance][19760].Data;
bool fullHp = (Math.Abs(Attributes[GameAttribute.Hitpoints_Cur] - Attributes[GameAttribute.Hitpoints_Max_Total]) < 0.001); bool fullHp = (Math.Abs(Attributes[GameAttribute.Hitpoints_Cur] - Attributes[GameAttribute.Hitpoints_Max_Total]) < Globals.FLOAT_TOLERANCE);
Attributes[GameAttribute.Level] = World.Game.MonsterLevel; Attributes[GameAttribute.Level] = World.Game.MonsterLevel;
//this.Attributes[GameAttribute.Hitpoints_Max] = (int)monsterLevels.MonsterLevel[this.World.Game.MonsterLevel - 1].HPMin * (int)this.HPMultiplier * (int)this.World.Game.HPModifier; //this.Attributes[GameAttribute.Hitpoints_Max] = (int)monsterLevels.MonsterLevel[this.World.Game.MonsterLevel - 1].HPMin * (int)this.HPMultiplier * (int)this.World.Game.HPModifier;
int monsterLevel = 1; int monsterLevel = 1;

View File

@ -1256,7 +1256,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem
GameAccountId = new GameAccountHandle() { ID = (uint)joinedPlayer.Toon.GameAccount.BnetEntityId.Low, Program = 0x00004433, Region = 1 }, GameAccountId = new GameAccountHandle() { ID = (uint)joinedPlayer.Toon.GameAccount.BnetEntityId.Low, Program = 0x00004433, Region = 1 },
ToonName = joinedPlayer.Toon.Name, ToonName = joinedPlayer.Toon.Name,
Team = 0x00000002, Team = 0x00000002,
Class = joinedPlayer.ClassSNO, Class = joinedPlayer.ClassSno,
snoActorPortrait = joinedPlayer.Toon.DBToon.Cosmetic4, snoActorPortrait = joinedPlayer.Toon.DBToon.Cosmetic4,
Level = joinedPlayer.Toon.Level, Level = joinedPlayer.Toon.Level,
AltLevel = (ushort)joinedPlayer.Toon.ParagonLevel, AltLevel = (ushort)joinedPlayer.Toon.ParagonLevel,

View File

@ -386,8 +386,8 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
RandomSpawnInWorldWithLevelArea(world, ActorSno._x1_deathmaiden_unique_fire_a); RandomSpawnInWorldWithLevelArea(world, ActorSno._x1_deathmaiden_unique_fire_a);
break; break;
case WorldSno.trdun_leoric_level03: //Setting portal to the third floor of the Agony's Halls near the entrance to the Butcher. case WorldSno.trdun_leoric_level03: //Setting portal to the third floor of the Agony's Halls near the entrance to the Butcher.
Vector3D Scene0Pos = world.GetSceneBySnoId(78824).Position; Vector3D sceneOfPos = world.GetSceneBySnoId(78824).Position;
world.SpawnMonster(ActorSno._waypoint, new Vector3D(Scene0Pos.X + 149.0907f, Scene0Pos.Y + 106.7075f, Scene0Pos.Z)); world.SpawnMonster(ActorSno._waypoint, new Vector3D(sceneOfPos.X + 149.0907f, sceneOfPos.Y + 106.7075f, sceneOfPos.Z));
break; break;
case WorldSno.x1_westm_graveyard_deathorb: case WorldSno.x1_westm_graveyard_deathorb:
FilterWaypoints(world); FilterWaypoints(world);
@ -402,9 +402,9 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
break; break;
case WorldSno.trout_town: //mercenary case WorldSno.trout_town: //mercenary
var templar = world.GetActorBySNO(ActorSno._templar); var templar = world.GetActorBySNO(ActorSno._templar);
var hasmalth = world.GetActorBySNO(ActorSno._x1_malthael_npc); var hasMalthaelNpc = world.GetActorBySNO(ActorSno._x1_malthael_npc);
if (hasmalth == null) if (hasMalthaelNpc == null)
{ {
ActorSystem.Implementations.Hirelings.MalthaelHireling malthaelHire = new ActorSystem.Implementations.Hirelings.MalthaelHireling(world, ActorSno._x1_malthael_npc_nocollision, templar.Tags) ActorSystem.Implementations.Hirelings.MalthaelHireling malthaelHire = new ActorSystem.Implementations.Hirelings.MalthaelHireling(world, ActorSno._x1_malthael_npc_nocollision, templar.Tags)
{ {
@ -419,17 +419,17 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
} }
foreach (var door in world.GetActorsBySNO(ActorSno._house_door_trout_newtristram)) foreach (var door in world.GetActorsBySNO(ActorSno._house_door_trout_newtristram))
door.Destroy(); door.Destroy();
if (Game.CurrentAct == 3000) if (Game.CurrentActEnum == ActEnum.OpenWorld)
{ {
var TownDoor = world.GetActorBySNO(ActorSno._trout_newtristram_gate_town); var townDoor = world.GetActorBySNO(ActorSno._trout_newtristram_gate_town);
TownDoor.Attributes[GameAttribute.Team_Override] = 2; townDoor.Attributes[GameAttribute.Team_Override] = 2;
TownDoor.Attributes[GameAttribute.Untargetable] = true; townDoor.Attributes[GameAttribute.Untargetable] = true;
TownDoor.Attributes[GameAttribute.NPC_Is_Operatable] = false; townDoor.Attributes[GameAttribute.NPC_Is_Operatable] = false;
TownDoor.Attributes[GameAttribute.Operatable] = false; townDoor.Attributes[GameAttribute.Operatable] = false;
TownDoor.Attributes[GameAttribute.Operatable_Story_Gizmo] = false; townDoor.Attributes[GameAttribute.Operatable_Story_Gizmo] = false;
TownDoor.Attributes[GameAttribute.Disabled] = true; townDoor.Attributes[GameAttribute.Disabled] = true;
TownDoor.Attributes[GameAttribute.Immunity] = true; townDoor.Attributes[GameAttribute.Immunity] = true;
TownDoor.Attributes.BroadcastChangedIfRevealed(); townDoor.Attributes.BroadcastChangedIfRevealed();
} }
break; break;
case WorldSno.a1trdun_level04: //Cathedral Level 2 case WorldSno.a1trdun_level04: //Cathedral Level 2
@ -504,10 +504,12 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
zoltunGhost.Attributes.BroadcastChangedIfRevealed(); zoltunGhost.Attributes.BroadcastChangedIfRevealed();
break; break;
case WorldSno.a3dun_ruins_frost_city_a_02: case WorldSno.a3dun_ruins_frost_city_a_02:
foreach (var waypoint in world.GetActorsBySNO(ActorSno._waypoint)) waypoint.Destroy(); foreach (var waypoint in world.GetActorsBySNO(ActorSno._waypoint))
waypoint.Destroy();
break; break;
case WorldSno.p43_ad_oldtristram: case WorldSno.p43_ad_oldtristram:
foreach (var waypoint in world.GetActorsBySNO(ActorSno._trout_oldtristram_exit_gate)) waypoint.Destroy(); foreach (var waypoint in world.GetActorsBySNO(ActorSno._trout_oldtristram_exit_gate))
waypoint.Destroy();
break; break;
case WorldSno.x1_tristram_adventure_mode_hub: case WorldSno.x1_tristram_adventure_mode_hub:
@ -561,14 +563,15 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
public void RandomSpawnInWorldWithLevelArea(World world, ActorSno monsterSno, int levelArea = -1) public void RandomSpawnInWorldWithLevelArea(World world, ActorSno monsterSno, int levelArea = -1)
{ {
List<Scene> scenes = world.Scenes.Values.ToList(); List<Scene> scenes = world.Scenes.Values.ToList();
if (levelArea != -1) scenes = scenes.Where(sc => sc.Specification.SNOLevelAreas[0] == levelArea && !sc.SceneSNO.Name.ToLower().Contains("filler")).ToList(); scenes = levelArea != -1
else scenes = scenes.Where(sc => !sc.SceneSNO.Name.ToLower().Contains("filler")).ToList(); ? scenes.Where(sc => sc.Specification.SNOLevelAreas[0] == levelArea && !sc.SceneSNO.Name.ToLower().Contains("filler")).ToList()
Vector3D SSV = scenes.PickRandom().Position; : scenes.Where(sc => !sc.SceneSNO.Name.ToLower().Contains("filler")).ToList();
Vector3D randomScene = scenes.PickRandom().Position;
Vector3D startingPoint = null; Vector3D startingPoint = null;
while (true) while (true)
{ {
startingPoint = new Vector3D(SSV.X + RandomHelper.Next(0, 240), SSV.Y + RandomHelper.Next(0, 240), SSV.Z); startingPoint = new Vector3D(randomScene.X + RandomHelper.Next(0, 240), randomScene.Y + RandomHelper.Next(0, 240), randomScene.Z);
if (world.CheckLocationForFlag(startingPoint, DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk)) if (world.CheckLocationForFlag(startingPoint, DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk))
break; break;
} }
@ -1591,7 +1594,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
{ {
bool busy = false; bool busy = false;
foreach (var chunk in world.worldData.SceneParams.SceneChunks) foreach (var chunk in world.worldData.SceneParams.SceneChunks)
if (Math.Abs(chunk.PRTransform.Vector3D.X - x) < 0.001 & Math.Abs(chunk.PRTransform.Vector3D.Y - y) < 0.001) if (Math.Abs(chunk.PRTransform.Vector3D.X - x) < Globals.FLOAT_TOLERANCE & Math.Abs(chunk.PRTransform.Vector3D.Y - y) < Globals.FLOAT_TOLERANCE)
{ {
busy = true; busy = true;
break; break;

View File

@ -552,8 +552,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
if (ratio > 1f) ratio = 1f; if (ratio > 1f) ratio = 1f;
Attributes[GameAttribute.Block_Amount_Item_Min] += Attributes[GameAttribute.Block_Amount_Item_Min] +=
Math.Abs(scaleCapMin * ratio - Attributes[GameAttribute.Block_Amount_Item_Min, 0]); Math.Abs(scaleCapMin * ratio - Attributes[GameAttribute.Block_Amount_Item_Min, 0]);
Attributes[GameAttribute.Block_Amount_Item_Delta] += Math.Abs(scaleCapDelta * ratio - Attributes[GameAttribute.Block_Amount_Item_Delta] += Math.Abs(scaleCapDelta * ratio - Attributes[GameAttribute.Block_Amount_Item_Delta, 0]);
Attributes[GameAttribute.Block_Amount_Item_Delta, 0]);
} }
} }
} }

View File

@ -590,41 +590,36 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem
public Actor SpawnMonster(ActorSno monsterSno, Vector3D position) public Actor SpawnMonster(ActorSno monsterSno, Vector3D position)
{ {
if (monsterSno == ActorSno.__NONE) if (monsterSno == ActorSno.__NONE) return null;
{ Logger.MethodTrace($"Spawning monster {monsterSno} at {position}");
return null;
}
var monster = ActorFactory.Create(this, monsterSno, new TagMap()); var monster = ActorFactory.Create(this, monsterSno, new TagMap());
if (monster != null) if (monster == null) return null;
monster.EnterWorld(position);
if (monster.AnimationSet == null) return monster;
var animationTag = new[] { AnimationSetKeys.Spawn, AnimationSetKeys.Spawn2 }.FirstOrDefault(x => monster.AnimationSet.TagMapAnimDefault.ContainsKey(x));
if (animationTag != null)
{ {
monster.EnterWorld(position); monster.World.BroadcastIfRevealed(plr => new PlayAnimationMessage
if (monster.AnimationSet != null) {
{ ActorID = monster.DynamicID(plr),
var animationTag = new[] { AnimationSetKeys.Spawn, AnimationSetKeys.Spawn2 }.FirstOrDefault(x => monster.AnimationSet.TagMapAnimDefault.ContainsKey(x)); AnimReason = 5,
UnitAniimStartTime = 0,
tAnim = new PlayAnimationMessageSpec[]
{
new()
{
Duration = 150,
AnimationSNO = monster.AnimationSet.TagMapAnimDefault[animationTag],
PermutationIndex = 0,
Speed = 1
}
}
if (animationTag != null) }, monster);
{
monster.World.BroadcastIfRevealed(plr => new PlayAnimationMessage
{
ActorID = monster.DynamicID(plr),
AnimReason = 5,
UnitAniimStartTime = 0,
tAnim = new PlayAnimationMessageSpec[]
{
new()
{
Duration = 150,
AnimationSNO = monster.AnimationSet.TagMapAnimDefault[animationTag],
PermutationIndex = 0,
Speed = 1
}
}
}, monster);
}
}
} }
return monster; return monster;
} }
private Queue<Queue<Action>> _flippyTimers = new(); private Queue<Queue<Action>> _flippyTimers = new();
@ -640,19 +635,21 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem
player.GroundItems[item.GlobalID] = item; // FIXME: Hacky. /komiga player.GroundItems[item.GlobalID] = item; // FIXME: Hacky. /komiga
DropItem(source, null, item); DropItem(source, null, item);
} }
public void PlayPieAnimation(Actor actor, Actor User, int PowerSNO, Vector3D TargetPosition)
[Obsolete("Isn't used anymore. Is it useful?")]
public void PlayPieAnimation(Actor actor, Actor user, int powerSNO, Vector3D targetPosition)
{ {
BroadcastIfRevealed(plr => new ACDTranslateDetPathPieWedgeMessage BroadcastIfRevealed(plr => new ACDTranslateDetPathPieWedgeMessage
{ {
ann = (int)actor.DynamicID(plr), ann = (int)actor.DynamicID(plr),
StartPos = User.Position, StartPos = user.Position,
FirstTagetPos = User.Position, FirstTagetPos = user.Position,
MoveFlags = 9, MoveFlags = 9,
AnimTag = 1, AnimTag = 1,
PieData = new DPathPieData PieData = new DPathPieData
{ {
Field0 = TargetPosition, Field0 = targetPosition,
Field1 = 1, Field1 = 1,
Field2 = 1, Field2 = 1,
Field3 = 1 Field3 = 1

View File

@ -2395,7 +2395,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
var rem = new List<uint>(); var rem = new List<uint>();
foreach (var fol in Followers.Where(f => foreach (var fol in Followers.Where(f =>
Math.Abs(World.GetActorByGlobalId(f.Key).Attributes[GameAttribute.Summoned_By_SNO] - Math.Abs(World.GetActorByGlobalId(f.Key).Attributes[GameAttribute.Summoned_By_SNO] -
oldSNOSkill) < 0.001)) oldSNOSkill) < Globals.FLOAT_TOLERANCE))
rem.Add(fol.Key); rem.Add(fol.Key);
foreach (var rm in rem) foreach (var rm in rem)
DestroyFollowerById(rm); DestroyFollowerById(rm);
@ -2914,13 +2914,13 @@ public class Player : Actor, IMessageConsumer, IUpdateable
//* //*
private void TrainArtisan(GameClient client, RequestTrainArtisanMessage message) private void TrainArtisan(GameClient client, RequestTrainArtisanMessage message)
{ {
if (CurrentArtisan == null || !artisanTrainHelpers.ContainsKey(CurrentArtisan.Value)) if (CurrentArtisan == null || !_artisanTrainHelpers.ContainsKey(CurrentArtisan.Value))
{ {
Logger.Warn("Training for artisan {} is not supported", CurrentArtisan); Logger.Warn("Training for artisan {} is not supported", CurrentArtisan);
return; return;
} }
var trainHelper = artisanTrainHelpers[CurrentArtisan.Value]; var trainHelper = _artisanTrainHelpers[CurrentArtisan.Value];
if (trainHelper.HasMaxLevel) if (trainHelper.HasMaxLevel)
return; return;
@ -2947,7 +2947,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
if (trainHelper.Criteria is not null) if (trainHelper.Criteria is not null)
GrantCriteria(trainHelper.Criteria.Value); GrantCriteria(trainHelper.Criteria.Value);
if (artisanTrainHelpers.All(x => x.Value.HasMaxLevel)) if (_artisanTrainHelpers.All(x => x.Value.HasMaxLevel))
GrantCriteria(74987249993545); GrantCriteria(74987249993545);
client.SendMessage(new CrafterLevelUpMessage client.SendMessage(new CrafterLevelUpMessage
@ -2966,13 +2966,13 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void UnlockTransmog(int transmogGBID) public void UnlockTransmog(int transmogGBID)
{ {
if (learnedTransmogs.Contains(transmogGBID)) return; if (_learnedTransmogs.Contains(transmogGBID)) return;
InGameClient.SendMessage(new UnlockTransmogMessage() { TransmogGBID = transmogGBID }); InGameClient.SendMessage(new UnlockTransmogMessage() { TransmogGBID = transmogGBID });
Logger.Trace("Learning transmog #{0}", transmogGBID); Logger.Trace("Learning transmog #{0}", transmogGBID);
learnedTransmogs.Add(transmogGBID); _learnedTransmogs.Add(transmogGBID);
mystic_data.LearnedRecipes = SerializeBytes(learnedTransmogs); _mysticData.LearnedRecipes = SerializeBytes(_learnedTransmogs);
World.Game.GameDbSession.SessionUpdate(mystic_data); World.Game.GameDbSession.SessionUpdate(_mysticData);
LoadCrafterData(); LoadCrafterData();
} }
@ -3067,7 +3067,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
foreach (var timed_out in TimedActions.Where(t => t.TimedOut).ToList()) foreach (var timed_out in TimedActions.Where(t => t.TimedOut).ToList())
TimedActions.Remove(timed_out); TimedActions.Remove(timed_out);
// Check the Killstreaks // Check the kill streaks
ExpBonusData.Check(0); ExpBonusData.Check(0);
ExpBonusData.Check(1); ExpBonusData.Check(1);
@ -3165,27 +3165,29 @@ public class Player : Actor, IMessageConsumer, IUpdateable
#region Necromancer summons #region Necromancer summons
var switchertobool = false; var switcherToBool = false;
var switchertoboolTwo = false; var switcherToBool2 = false;
ActiveSkillSavedData NowSkillGolem = null; ActiveSkillSavedData nowSkillGolen = null;
foreach (var skill in SkillSet.ActiveSkills) foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 453801) if (skill.snoSkill == 453801)
switchertobool = true; switcherToBool = true;
foreach (var skill in SkillSet.ActiveSkills) foreach (var skill in SkillSet.ActiveSkills)
if (skill.snoSkill == 451537) if (skill.snoSkill == 451537)
{ {
switchertoboolTwo = true; switcherToBool2 = true;
NowSkillGolem = skill; nowSkillGolen = skill;
} }
ActiveSkeletons = switchertobool; ActiveSkeletons = switcherToBool;
EnableGolem = switchertoboolTwo; EnableGolem = switcherToBool2;
var Killer = new PowerContext(); var killer = new PowerContext
Killer.User = this; {
Killer.World = World; User = this,
Killer.PowerSNO = -1; World = World,
PowerSNO = -1
};
if (ActiveSkeletons) if (ActiveSkeletons)
{ {
@ -3255,8 +3257,8 @@ public class Player : Actor, IMessageConsumer, IUpdateable
{ {
PetId = ActiveGolem.GlobalID PetId = ActiveGolem.GlobalID
}); });
Killer.Target = ActiveGolem; killer.Target = ActiveGolem;
(ActiveGolem as Minion).Kill(Killer); (ActiveGolem as Minion).Kill(killer);
} }
ActiveGolem = null; ActiveGolem = null;
@ -3386,20 +3388,14 @@ public class Player : Actor, IMessageConsumer, IUpdateable
#endregion #endregion
public T RuneSelect<T>(int PowerSNO, T none, T runeA, T runeB, T runeC, T runeD, T runeE) 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]; if (Attributes[GameAttribute.Rune_A, powerSno] > 0) return runeA;
var Rune_B = Attributes[GameAttribute.Rune_B, PowerSNO]; if (Attributes[GameAttribute.Rune_B, powerSno] > 0) return runeB;
var Rune_C = Attributes[GameAttribute.Rune_C, PowerSNO]; if (Attributes[GameAttribute.Rune_C, powerSno] > 0) return runeC;
var Rune_D = Attributes[GameAttribute.Rune_D, PowerSNO]; if (Attributes[GameAttribute.Rune_D, powerSno] > 0) return runeD;
var Rune_E = Attributes[GameAttribute.Rune_E, PowerSNO]; if (Attributes[GameAttribute.Rune_E, powerSno] > 0) return runeE;
return none;
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 #region enter, leave, reveal handling
@ -3410,11 +3406,11 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void RevealScenesToPlayer() public void RevealScenesToPlayer()
{ {
//List<Scene> scenes_around = this.GetScenesInRegion(DefaultQueryProximityLenght * 2); //List<Scene> scenes_around = this.GetScenesInRegion(DefaultQueryProximityLenght * 2);
var scenes_around = World.Scenes.Values.ToList(); var scenesAround = World.Scenes.Values.ToList();
if (!World.worldData.DynamicWorld) if (!World.worldData.DynamicWorld)
scenes_around = GetScenesInRegion(DefaultQueryProximityLenght * 3); scenesAround = GetScenesInRegion(DefaultQueryProximityLenght * 3);
foreach (var scene in scenes_around) // reveal scenes in player's proximity. foreach (var scene in scenesAround) // reveal scenes in player's proximity.
{ {
if (scene.IsRevealedToPlayer(this)) // if the actors is already revealed skip it. if (scene.IsRevealedToPlayer(this)) // if the actors is already revealed skip it.
continue; // if the scene is already revealed, skip it. continue; // if the scene is already revealed, skip it.
@ -3428,7 +3424,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
foreach (var scene in World.Scenes.Values) // unreveal far scenes foreach (var scene in World.Scenes.Values) // unreveal far scenes
{ {
if (!scene.IsRevealedToPlayer(this) || scenes_around.Contains(scene)) if (!scene.IsRevealedToPlayer(this) || scenesAround.Contains(scene))
continue; continue;
if (scene.Parent != if (scene.Parent !=
@ -3444,9 +3440,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable
/// </summary> /// </summary>
public void RevealActorsToPlayer() public void RevealActorsToPlayer()
{ {
var Range = 200f; var range = 200f;
if (InGameClient.Game.CurrentEncounter.Activated) if (InGameClient.Game.CurrentEncounter.Activated)
Range = 360f; range = 360f;
var specialWorlds = new WorldSno[] var specialWorlds = new WorldSno[]
{ {
@ -3457,9 +3453,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable
WorldSno.a1trdun_level05_templar WorldSno.a1trdun_level05_templar
}; };
var actors_around = specialWorlds.Contains(World.SNO) ? World.Actors.Values.ToList() : GetActorsInRange(Range); var actorsAround = specialWorlds.Contains(World.SNO) ? World.Actors.Values.ToList() : GetActorsInRange(range);
foreach (var actor in actors_around) // reveal actors in player's proximity. foreach (var actor in actorsAround) // reveal actors in player's proximity.
{ {
if (actor is Player) // if the actors is already revealed, skip it. if (actor is Player) // if the actors is already revealed, skip it.
continue; continue;
@ -3482,7 +3478,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
foreach (var actor in World.Actors.Values) // unreveal far actors foreach (var actor in World.Actors.Values) // unreveal far actors
{ {
if ((actor is Player && (!World.IsPvP || actor == this)) || if ((actor is Player && (!World.IsPvP || actor == this)) ||
actors_around.Contains(actor)) // if the actors is already revealed, skip it. actorsAround.Contains(actor)) // if the actors is already revealed, skip it.
continue; continue;
actor.Unreveal(this); actor.Unreveal(this);
@ -3549,7 +3545,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
world.Reveal(this); world.Reveal(this);
Unreveal(this); Unreveal(this);
if (_CurrentHPValue == -1f) if (Math.Abs(_CurrentHPValue - (-1f)) < Globals.FLOAT_TOLERANCE)
DefaultQueryProximityRadius = 60; DefaultQueryProximityRadius = 60;
InGameClient.SendMessage(new EnterWorldMessage() InGameClient.SendMessage(new EnterWorldMessage()
@ -3580,7 +3576,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
break; break;
} }
if (_CurrentHPValue == -1f) if (Math.Abs(_CurrentHPValue - (-1f)) < Globals.FLOAT_TOLERANCE)
AddPercentageHP(100); AddPercentageHP(100);
DefaultQueryProximityRadius = 100; DefaultQueryProximityRadius = 100;
@ -3750,7 +3746,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
AllBuffs.Clear(); AllBuffs.Clear();
BetweenWorlds = false; BetweenWorlds = false;
if (Math.Abs(_CurrentHPValue - (-1)) > 0.0001) if (Math.Abs(_CurrentHPValue - (-1)) > Globals.FLOAT_TOLERANCE)
{ {
Attributes[GameAttribute.Hitpoints_Cur] = _CurrentHPValue; Attributes[GameAttribute.Hitpoints_Cur] = _CurrentHPValue;
Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource + 1] = _CurrentResourceValue; Attributes[GameAttribute.Resource_Cur, (int)Toon.HeroTable.PrimaryResource + 1] = _CurrentResourceValue;
@ -3850,7 +3846,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
} }
/// <summary> /// <summary>
/// Allows hero state message to be sent when hero's some property get's updated. /// Allows hero state message to be sent when hero's some property gets updated.
/// </summary> /// </summary>
public void UpdateHeroState() public void UpdateHeroState()
{ {
@ -3940,7 +3936,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
//removing tomb //removing tomb
try try
{ {
GetObjectsInRange<Headstone>(100.0f).Where(h => h.playerIndex == PlayerIndex).First().Destroy(); GetObjectsInRange<Headstone>(100.0f).First(h => h.playerIndex == PlayerIndex).Destroy();
} }
catch catch
{ {
@ -3949,8 +3945,8 @@ public class Player : Actor, IMessageConsumer, IUpdateable
Teleport(spawnPosition); Teleport(spawnPosition);
World.BuffManager.AddBuff(this, this, new ActorGhostedBuff()); World.BuffManager.AddBuff(this, this, new ActorGhostedBuff());
var old_skills = SkillSet.ActiveSkills.Select(s => s.snoSkill).ToList(); var oldSkills = SkillSet.ActiveSkills.Select(s => s.snoSkill).ToList();
foreach (var skill in old_skills) foreach (var skill in oldSkills)
{ {
var power = PowerLoader.CreateImplementationForPowerSNO(skill); var power = PowerLoader.CreateImplementationForPowerSNO(skill);
if (power != null && power.EvalTag(PowerKeys.SynergyPower) != -1) if (power != null && power.EvalTag(PowerKeys.SynergyPower) != -1)
@ -3998,13 +3994,12 @@ public class Player : Actor, IMessageConsumer, IUpdateable
get get
{ {
var baseStrength = 0.0f; var baseStrength = 0.0f;
var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.StrengthParagonMultiplier : GameServerConfig.Instance.StrengthMultiplier;
baseStrength = Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Strength
? Toon.HeroTable.Strength + (Level - 1) * 3
: Toon.HeroTable.Strength + (Level - 1);
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Strength) return baseStrength * multiplier;
baseStrength = Toon.HeroTable.Strength + (Level - 1) * 3;
else
baseStrength = Toon.HeroTable.Strength + (Level - 1);
return baseStrength;
} }
} }
@ -4015,17 +4010,18 @@ public class Player : Actor, IMessageConsumer, IUpdateable
{ {
get get
{ {
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Dexterity) var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.DexterityParagonMultiplier : GameServerConfig.Instance.DexterityMultiplier;
return Toon.HeroTable.Dexterity + (Level - 1) * 3;
else return Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Dexterity
return Toon.HeroTable.Dexterity + (Level - 1); ? Toon.HeroTable.Dexterity + (Level - 1) * 3 * multiplier
: Toon.HeroTable.Dexterity + (Level - 1) * multiplier;
} }
} }
public float TotalDexterity => public float TotalDexterity =>
Attributes[GameAttribute.Dexterity] + Inventory.GetItemBonus(GameAttribute.Dexterity_Item); Attributes[GameAttribute.Dexterity] + Inventory.GetItemBonus(GameAttribute.Dexterity_Item);
public float Vitality => Toon.HeroTable.Vitality + (Level - 1) * 2; public float Vitality => Toon.HeroTable.Vitality + (Level - 1) * 2 * (ParagonLevel > 0 ? GameServerConfig.Instance.VitalityParagonMultiplier : GameServerConfig.Instance.VitalityMultiplier);
public float TotalVitality => public float TotalVitality =>
Attributes[GameAttribute.Vitality] + Inventory.GetItemBonus(GameAttribute.Vitality_Item); Attributes[GameAttribute.Vitality] + Inventory.GetItemBonus(GameAttribute.Vitality_Item);
@ -4034,10 +4030,10 @@ public class Player : Actor, IMessageConsumer, IUpdateable
{ {
get get
{ {
if (Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Intelligence) var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.IntelligenceParagonMultiplier : GameServerConfig.Instance.IntelligenceMultiplier;
return Toon.HeroTable.Intelligence + (Level - 1) * 3; return Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Intelligence
else ? Toon.HeroTable.Intelligence + (Level - 1) * 3 * multiplier
return Toon.HeroTable.Intelligence + (Level - 1); : Toon.HeroTable.Intelligence + (Level - 1) * multiplier;
} }
} }
@ -4325,15 +4321,15 @@ public class Player : Actor, IMessageConsumer, IUpdateable
if (query.Count == 0) if (query.Count == 0)
{ {
//returns empty data //returns empty data
var hireling_empty = new HirelingInfo var emptyHireling = new HirelingInfo
{ {
HirelingIndex = type, GbidName = 0x0000, Dead = false, Skill1SNOId = -1, Skill2SNOId = -1, HirelingIndex = type, GbidName = 0x0000, Dead = false, Skill1SNOId = -1, Skill2SNOId = -1,
Skill3SNOId = -1, Skill4SNOId = -1, annItems = -1 Skill3SNOId = -1, Skill4SNOId = -1, annItems = -1
}; };
return hireling_empty; return emptyHireling;
} }
var hireling_full = new HirelingInfo return new HirelingInfo
{ {
HirelingIndex = type, HirelingIndex = type,
GbidName = 0x0000, GbidName = 0x0000,
@ -4344,14 +4340,13 @@ public class Player : Actor, IMessageConsumer, IUpdateable
Skill4SNOId = query.First().Skill4SNOId, Skill4SNOId = query.First().Skill4SNOId,
annItems = -1 annItems = -1
}; };
return hireling_full;
} }
private List<int> Unserialize(string data) private List<int> Unserialize(string data)
{ {
var recparts = data.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); var parts = data.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
var ret = new List<int>(); var ret = new List<int>();
foreach (var recid in recparts) ret.Add(Convert.ToInt32(recid, 10)); foreach (var part in parts) ret.Add(Convert.ToInt32(part, 10));
return ret; return ret;
} }
@ -4380,34 +4375,35 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void LearnRecipe(ArtisanType? artisan, int recipe) public void LearnRecipe(ArtisanType? artisan, int recipe)
{ {
Logger.Trace("Learning recipe #{0}, Artisan type: {1}", recipe, artisan); Logger.Trace("Learning recipe #{0}, Artisan type: {1}", recipe, artisan);
/*var query = this.World.Game.GameDBSession.SessionQuerySingle<DBCraft>( /*var query = this.World.Game.GameDBSession.SessionQuerySingle<DBCraft>(
dbi => dbi =>
dbi.DBGameAccount.Id == this.Toon.GameAccount.PersistentID && dbi.DBGameAccount.Id == this.Toon.GameAccount.PersistentID &&
dbi.Artisan == artisan && dbi.Artisan == artisan &&
dbi.isHardcore == this.World.Game.IsHardcore);*/ dbi.isHardcore == this.World.Game.IsHardcore);*/
if (artisan == ArtisanType.Blacksmith) switch (artisan)
{ {
learnedBlacksmithRecipes.Add(recipe); case ArtisanType.Blacksmith:
blacksmith_data.LearnedRecipes = SerializeBytes(learnedBlacksmithRecipes); _learnedBlacksmithRecipes.Add(recipe);
World.Game.GameDbSession.SessionUpdate(blacksmith_data); _blacksmithData.LearnedRecipes = SerializeBytes(_learnedBlacksmithRecipes);
UpdateAchievementCounter(404, 1, 0); World.Game.GameDbSession.SessionUpdate(_blacksmithData);
} UpdateAchievementCounter(404, 1, 0);
else if (artisan == ArtisanType.Jeweler) break;
{ case ArtisanType.Jeweler:
learnedJewelerRecipes.Add(recipe); _learnedJewelerRecipes.Add(recipe);
jeweler_data.LearnedRecipes = SerializeBytes(learnedJewelerRecipes); _jewelerData.LearnedRecipes = SerializeBytes(_learnedJewelerRecipes);
World.Game.GameDbSession.SessionUpdate(jeweler_data); World.Game.GameDbSession.SessionUpdate(_jewelerData);
UpdateAchievementCounter(404, 1, 1); UpdateAchievementCounter(404, 1, 1);
break;
} }
LoadCrafterData(); LoadCrafterData();
} }
public bool RecipeAvailable(GameBalance.RecipeTable recipe_definition) public bool RecipeAvailable(GameBalance.RecipeTable recipeDefinition)
{ {
if (recipe_definition.Flags == 0) return true; if (recipeDefinition.Flags == 0) return true;
return learnedBlacksmithRecipes.Contains(recipe_definition.Hash) || return _learnedBlacksmithRecipes.Contains(recipeDefinition.Hash) || _learnedJewelerRecipes.Contains(recipeDefinition.Hash);
learnedJewelerRecipes.Contains(recipe_definition.Hash);
} }
public PlayerBannerMessage GetPlayerBanner() public PlayerBannerMessage GetPlayerBanner()
@ -4420,69 +4416,69 @@ public class Player : Actor, IMessageConsumer, IUpdateable
return new PlayerBannerMessage() { PlayerBanner = playerBanner }; return new PlayerBannerMessage() { PlayerBanner = playerBanner };
} }
private List<int> learnedBlacksmithRecipes = new(); private List<int> _learnedBlacksmithRecipes = new();
private List<int> learnedJewelerRecipes = new(); private List<int> _learnedJewelerRecipes = new();
private List<int> learnedTransmogs = new(); private List<int> _learnedTransmogs = new();
private DBCraft blacksmith_data = null; private DBCraft _blacksmithData = null;
private DBCraft jeweler_data = null; private DBCraft _jewelerData = null;
private DBCraft mystic_data = null; private DBCraft _mysticData = null;
private Dictionary<ArtisanType, ArtisanTrainHelper> artisanTrainHelpers = new(); private readonly Dictionary<ArtisanType, ArtisanTrainHelper> _artisanTrainHelpers = new();
public void LoadCrafterData() public void LoadCrafterData()
{ {
if (blacksmith_data == null) if (_blacksmithData == null)
{ {
var craft_data = var craft_data =
World.Game.GameDbSession.SessionQueryWhere<DBCraft>(dbc => World.Game.GameDbSession.SessionQueryWhere<DBCraft>(dbc =>
dbc.DBGameAccount.Id == Toon.GameAccount.PersistentID); dbc.DBGameAccount.Id == Toon.GameAccount.PersistentID);
blacksmith_data = craft_data.Single(dbc => _blacksmithData = craft_data.Single(dbc =>
dbc.Artisan == "Blacksmith" && dbc.isHardcore == World.Game.IsHardcore && dbc.Artisan == "Blacksmith" && dbc.isHardcore == World.Game.IsHardcore &&
dbc.isSeasoned == World.Game.IsSeasoned); dbc.isSeasoned == World.Game.IsSeasoned);
jeweler_data = craft_data.Single(dbc => _jewelerData = craft_data.Single(dbc =>
dbc.Artisan == "Jeweler" && dbc.isHardcore == World.Game.IsHardcore && dbc.Artisan == "Jeweler" && dbc.isHardcore == World.Game.IsHardcore &&
dbc.isSeasoned == World.Game.IsSeasoned); dbc.isSeasoned == World.Game.IsSeasoned);
mystic_data = craft_data.Single(dbc => _mysticData = craft_data.Single(dbc =>
dbc.Artisan == "Mystic" && dbc.isHardcore == World.Game.IsHardcore && dbc.Artisan == "Mystic" && dbc.isHardcore == World.Game.IsHardcore &&
dbc.isSeasoned == World.Game.IsSeasoned); dbc.isSeasoned == World.Game.IsSeasoned);
artisanTrainHelpers[ArtisanType.Blacksmith] = _artisanTrainHelpers[ArtisanType.Blacksmith] =
new ArtisanTrainHelper(blacksmith_data, ArtisanType.Blacksmith); new ArtisanTrainHelper(_blacksmithData, ArtisanType.Blacksmith);
artisanTrainHelpers[ArtisanType.Jeweler] = new ArtisanTrainHelper(jeweler_data, ArtisanType.Jeweler); _artisanTrainHelpers[ArtisanType.Jeweler] = new ArtisanTrainHelper(_jewelerData, ArtisanType.Jeweler);
artisanTrainHelpers[ArtisanType.Mystic] = new ArtisanTrainHelper(mystic_data, ArtisanType.Mystic); _artisanTrainHelpers[ArtisanType.Mystic] = new ArtisanTrainHelper(_mysticData, ArtisanType.Mystic);
} }
var blacksmith = D3.ItemCrafting.CrafterData.CreateBuilder() var blacksmith = D3.ItemCrafting.CrafterData.CreateBuilder()
.SetLevel(InGameClient.Game.CurrentAct == 3000 .SetLevel(InGameClient.Game.CurrentAct == 3000
? BlacksmithUnlocked == false && blacksmith_data.Level < 1 ? 1 : blacksmith_data.Level ? BlacksmithUnlocked == false && _blacksmithData.Level < 1 ? 1 : _blacksmithData.Level
: blacksmith_data.Level) : _blacksmithData.Level)
.SetCooldownEnd(0) .SetCooldownEnd(0)
.AddRangeRecipes(UnserializeBytes(blacksmith_data.LearnedRecipes)) .AddRangeRecipes(UnserializeBytes(_blacksmithData.LearnedRecipes))
.Build(); .Build();
learnedBlacksmithRecipes = UnserializeBytes(blacksmith_data.LearnedRecipes); _learnedBlacksmithRecipes = UnserializeBytes(_blacksmithData.LearnedRecipes);
var jeweler = D3.ItemCrafting.CrafterData.CreateBuilder() var jeweler = D3.ItemCrafting.CrafterData.CreateBuilder()
.SetLevel(InGameClient.Game.CurrentAct == 3000 .SetLevel(InGameClient.Game.CurrentAct == 3000
? JewelerUnlocked == false && jeweler_data.Level < 1 ? 1 : jeweler_data.Level ? JewelerUnlocked == false && _jewelerData.Level < 1 ? 1 : _jewelerData.Level
: jeweler_data.Level) : _jewelerData.Level)
.SetCooldownEnd(0) .SetCooldownEnd(0)
.AddRangeRecipes(UnserializeBytes(jeweler_data.LearnedRecipes)) .AddRangeRecipes(UnserializeBytes(_jewelerData.LearnedRecipes))
.Build(); .Build();
learnedJewelerRecipes = UnserializeBytes(jeweler_data.LearnedRecipes); _learnedJewelerRecipes = UnserializeBytes(_jewelerData.LearnedRecipes);
var mystic = D3.ItemCrafting.CrafterData.CreateBuilder() var mystic = D3.ItemCrafting.CrafterData.CreateBuilder()
.SetLevel(InGameClient.Game.CurrentAct == 3000 .SetLevel(InGameClient.Game.CurrentAct == 3000
? MysticUnlocked == false && mystic_data.Level < 1 ? 1 : mystic_data.Level ? MysticUnlocked == false && _mysticData.Level < 1 ? 1 : _mysticData.Level
: mystic_data.Level) : _mysticData.Level)
.SetCooldownEnd(0) .SetCooldownEnd(0)
.Build(); .Build();
var transmog = D3.ItemCrafting.CrafterSavedData.CreateBuilder() var transmog = D3.ItemCrafting.CrafterSavedData.CreateBuilder()
.SetTransmogData(D3.GameBalance.BitPackedGbidArray.CreateBuilder() .SetTransmogData(D3.GameBalance.BitPackedGbidArray.CreateBuilder()
.SetBitfield(ByteString.CopyFrom(mystic_data.LearnedRecipes))) .SetBitfield(ByteString.CopyFrom(_mysticData.LearnedRecipes)))
//.AddRangeUnlockedTransmogs(this.UnserializeBytes(mystic_data.LearnedRecipes)) //.AddRangeUnlockedTransmogs(this.UnserializeBytes(mystic_data.LearnedRecipes))
.Build(); .Build();
learnedTransmogs = UnserializeBytes(mystic_data.LearnedRecipes); _learnedTransmogs = UnserializeBytes(_mysticData.LearnedRecipes);
if (BlacksmithUnlocked || InGameClient.Game.CurrentAct == 3000) if (BlacksmithUnlocked || InGameClient.Game.CurrentAct == 3000)
InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataBlacksmithInitialMessage) InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataBlacksmithInitialMessage)
@ -4503,27 +4499,26 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void LoadCurrencyData() public void LoadCurrencyData()
{ {
var bloodShards = 0; var bloodShards = Toon.GameAccount.BloodShards; // TODO: is this needed? @iamdroppy
bloodShards = Toon.GameAccount.BloodShards;
Inventory.UpdateCurrencies(); Inventory.UpdateCurrencies();
} }
public void LoadMailData() public void LoadMailData()
{ {
var mail_data = var mailData =
World.Game.GameDbSession.SessionQueryWhere<DBMail>(dbm => World.Game.GameDbSession.SessionQueryWhere<DBMail>(dbm =>
dbm.DBToon.Id == Toon.PersistentID && dbm.Claimed == false); dbm.DBToon.Id == Toon.PersistentID && dbm.Claimed == false);
var mails = D3.Items.Mails.CreateBuilder(); var mails = D3.Items.Mails.CreateBuilder();
foreach (var mail in mail_data) foreach (var mail in mailData)
{ {
var mail_row = D3.Items.Mail.CreateBuilder() var mailRow = D3.Items.Mail.CreateBuilder()
.SetAccountTo(Toon.D3EntityID) .SetAccountTo(Toon.D3EntityID)
.SetAccountFrom(Toon.D3EntityID) .SetAccountFrom(Toon.D3EntityID)
.SetMailId(mail.Id) .SetMailId(mail.Id)
.SetTitle(mail.Title) .SetTitle(mail.Title)
.SetBody(mail.Body); .SetBody(mail.Body);
if (mail.ItemGBID != -1) if (mail.ItemGBID != -1)
mail_row.SetAttachments(D3.Items.MailAttachments.CreateBuilder() mailRow.SetAttachments(D3.Items.MailAttachments.CreateBuilder()
.SetItems(D3.Items.ItemList.CreateBuilder() .SetItems(D3.Items.ItemList.CreateBuilder()
.AddItems(D3.Items.SavedItem.CreateBuilder() .AddItems(D3.Items.SavedItem.CreateBuilder()
.SetId(D3.OnlineService.ItemId.CreateBuilder().SetIdLow(0).SetIdHigh(0x3C000002517A294)) .SetId(D3.OnlineService.ItemId.CreateBuilder().SetIdLow(0).SetIdHigh(0x3C000002517A294))
@ -4542,15 +4537,16 @@ public class Player : Actor, IMessageConsumer, IUpdateable
) )
) )
); );
mails.AddMailsProp(mail_row); mails.AddMailsProp(mailRow);
} }
var mail_contents = D3.GameMessage.MailContents.CreateBuilder() InGameClient.SendMessage(new MailDigestMessage()
.SetAppendMessages(false) {
.SetMails(mails) MailContents = D3.GameMessage.MailContents.CreateBuilder()
.Build(); .SetAppendMessages(false)
.SetMails(mails)
InGameClient.SendMessage(new MailDigestMessage() { MailContents = mail_contents }); .Build()
});
} }
//*/ //*/
@ -4578,10 +4574,10 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void LoadShownTutorials() public void LoadShownTutorials()
{ {
var tutorials = new List<byte>(); // var tutorials = new List<byte>();
tutorials.Add(64); // tutorials.Add(64);
for (var i = 0; i < 15; i++) // for (var i = 0; i < 15; i++)
tutorials.Add(0); // tutorials.Add(0);
var seenTutorials = Toon.GameAccount.DBGameAccount.SeenTutorials; var seenTutorials = Toon.GameAccount.DBGameAccount.SeenTutorials;
var state = D3.GameMessage.TutorialState.CreateBuilder() var state = D3.GameMessage.TutorialState.CreateBuilder()
@ -4590,13 +4586,13 @@ public class Player : Actor, IMessageConsumer, IUpdateable
InGameClient.SendMessage(new GenericBlobMessage(Opcodes.TutorialStateMessage) { Data = state.ToByteArray() }); InGameClient.SendMessage(new GenericBlobMessage(Opcodes.TutorialStateMessage) { Data = state.ToByteArray() });
} }
private List<ulong> _unlockedAchievements = new(); private readonly List<ulong> _unlockedAchievements = new();
private List<ulong> _unlockedCriterias = new(); private readonly List<ulong> _unlockCriteria = new();
private Dictionary<ulong, uint> AchievementCounters = new(); private readonly Dictionary<ulong, uint> _achievementCounters = new();
public int DodgesInARow = 0; public int DodgesInARow { get; set; } = 0;
public int BlocksInARow = 0; public int BlocksInARow { get; set; }= 0;
public void GrantAchievement(ulong id) public void GrantAchievement(ulong id)
{ {
@ -4606,20 +4602,20 @@ public class Player : Actor, IMessageConsumer, IUpdateable
_unlockedAchievements.Add(id); _unlockedAchievements.Add(id);
try try
{ {
var Achievement = AchievementSystem.AchievementManager.GetAchievementById(id); var achievement = AchievementSystem.AchievementManager.GetAchievementById(id);
long Platinum = -1; long platinum = -1;
foreach (var attr in Achievement.AttributesList) foreach (var attr in achievement.AttributesList)
if (attr.Key == "Reward Currency Quantity") if (attr.Key == "Reward Currency Quantity")
Platinum = long.Parse(attr.Value); platinum = long.Parse(attr.Value);
InGameClient.SendMessage(new MessageSystem.Message.Definitions.Platinum.PlatinumAchievementAwardedMessage InGameClient.SendMessage(new MessageSystem.Message.Definitions.Platinum.PlatinumAchievementAwardedMessage
{ {
CurrentPlatinum = InGameClient.BnetClient.Account.GameAccount.Platinum, CurrentPlatinum = InGameClient.BnetClient.Account.GameAccount.Platinum,
idAchievement = id, idAchievement = id,
PlatinumIncrement = Platinum PlatinumIncrement = platinum
}); });
if (Platinum > 0) if (platinum > 0)
{ {
InGameClient.BnetClient.Account.GameAccount.Platinum += (int)Platinum; InGameClient.BnetClient.Account.GameAccount.Platinum += (int)platinum;
Inventory.UpdateCurrencies(); Inventory.UpdateCurrencies();
} }
@ -4633,33 +4629,33 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void AddAchievementCounter(ulong id, uint count) public void AddAchievementCounter(ulong id, uint count)
{ {
lock (AchievementCounters) lock (_achievementCounters)
{ {
if (!AchievementCounters.ContainsKey(id)) if (!_achievementCounters.ContainsKey(id))
AchievementCounters.Add(id, count); _achievementCounters.Add(id, count);
else else
AchievementCounters[id] += count; _achievementCounters[id] += count;
} }
} }
public void CheckAchievementCounters() public void CheckAchievementCounters()
{ {
lock (AchievementCounters) lock (_achievementCounters)
{ {
foreach (var counter in AchievementCounters) foreach (var counter in _achievementCounters)
{ {
if (counter.Value == 0) continue; if (counter.Value == 0) continue;
UpdateSingleAchievementCounter(counter.Key, counter.Value); UpdateSingleAchievementCounter(counter.Key, counter.Value);
} }
AchievementCounters.Clear(); _achievementCounters.Clear();
} }
} }
public void GrantCriteria(ulong id) public void GrantCriteria(ulong id)
{ {
if (_unlockedCriterias.Contains(id)) return; if (_unlockCriteria.Contains(id)) return;
_unlockedCriterias.Add(id); _unlockCriteria.Add(id);
try try
{ {
GameServer.ClientSystem.GameServer.GSBackend.GrantCriteria(Toon.GameAccount.PersistentID, id); GameServer.ClientSystem.GameServer.GSBackend.GrantCriteria(Toon.GameAccount.PersistentID, id);
@ -4824,13 +4820,13 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public int CastingSnoPower = -1; public int CastingSnoPower = -1;
public void StartCasting(int durationTicks, Action result, int skillsno = -1) public void StartCasting(int durationTicks, Action result, int skillSno = -1)
{ {
IsCasting = true; IsCasting = true;
CastResult = result; CastResult = result;
Attributes[GameAttribute.Looping_Animation_Start_Time] = World.Game.TickCounter; Attributes[GameAttribute.Looping_Animation_Start_Time] = World.Game.TickCounter;
Attributes[GameAttribute.Looping_Animation_End_Time] = World.Game.TickCounter + durationTicks; Attributes[GameAttribute.Looping_Animation_End_Time] = World.Game.TickCounter + durationTicks;
CastingSnoPower = skillsno; CastingSnoPower = skillSno;
if (CastingSnoPower != -1) if (CastingSnoPower != -1)
{ {
Attributes[GameAttribute.Buff_Icon_Start_Tick0, CastingSnoPower] = World.Game.TickCounter; Attributes[GameAttribute.Buff_Icon_Start_Tick0, CastingSnoPower] = World.Game.TickCounter;
@ -4882,7 +4878,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
#region generic properties #region generic properties
public int ClassSNO => Toon.Gender == 0 ? Toon.HeroTable.SNOMaleActor : Toon.HeroTable.SNOFemaleActor; public int ClassSno => Toon.Gender == 0 ? Toon.HeroTable.SNOMaleActor : Toon.HeroTable.SNOFemaleActor;
public int AdditionalLootItems public int AdditionalLootItems
{ {
@ -4910,7 +4906,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public int SecondaryResourceID => (int)Toon.HeroTable.SecondaryResource; public int SecondaryResourceID => (int)Toon.HeroTable.SecondaryResource;
[Obsolete] [Obsolete("Not used anymore. Should it be removed?")]
public bool IsInTown public bool IsInTown
{ {
get get
@ -4945,7 +4941,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
(Attributes[GameAttribute.Resource_Max_Percent_Bonus, resourceId] + 1), 0); (Attributes[GameAttribute.Resource_Max_Percent_Bonus, resourceId] + 1), 0);
} }
public static List<long> LevelBorders = new() public static readonly List<long> LevelBorders = new()
{ {
0, 280, 2700, 4500, 6600, 9000, 11700, 14000, 16500, 19200, 22100, /* Level 0-10 */ 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 */ 25200, 28500, 32000, 35700, 39600, 43700, 48000, 52500, 57200, 62100, /* Level 11-20 */
@ -4958,7 +4954,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
100000000 /* Level 61-70 */ 100000000 /* Level 61-70 */
}; };
public static List<long> ParagonLevelBorders = new() public static readonly List<long> ParagonLevelBorders = new()
{ {
//7200000,8640000,10800000,11520000,12960000,14400000,15840000,17280000,18720000,20160000,21600000,23040000,24480000,25920000,27360000, //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, //28800000,30240000,31680000,33120000,34560000,36000000,37440000,38880000,40320,41760000,43200000,41760000,43200000,44640000,46080000,
@ -5141,9 +5137,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
}); });
Conversations.StartConversation(0x0002A777); //LevelUp Conversation Conversations.StartConversation(0x0002A777); //LevelUp Conversation
Attributes[GameAttribute.Alt_Experience_Next_Lo] = Attributes[GameAttribute.Alt_Experience_Next_Lo] += (int)ParagonLevelBorders[Attributes[GameAttribute.Alt_Level]];
Attributes[GameAttribute.Alt_Experience_Next_Lo] +
(int)ParagonLevelBorders[Attributes[GameAttribute.Alt_Level]];
// On level up, health is set to max // On level up, health is set to max
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total]; Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
// set resources to max as well // set resources to max as well
@ -5165,8 +5159,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
Level++; Level++;
Attributes[GameAttribute.Level]++; Attributes[GameAttribute.Level]++;
Toon.LevelUp(); Toon.LevelUp();
if (World.Game.MonsterLevel + 1 == if (World.Game.MonsterLevel + 1 == Attributes[GameAttribute.Level]) //if this is suitable level to update
Attributes[GameAttribute.Level]) //if this is suitable level to update
World.Game.UpdateLevel(Attributes[GameAttribute.Level]); World.Game.UpdateLevel(Attributes[GameAttribute.Level]);
InGameClient.SendMessage(new PlayerLevel() InGameClient.SendMessage(new PlayerLevel()
@ -5326,7 +5319,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void VacuumPickupHealthOrb(float radius = -1) public void VacuumPickupHealthOrb(float radius = -1)
{ {
if (Math.Abs(radius - -1) < 0.001) if (Math.Abs(radius - -1) < Globals.FLOAT_TOLERANCE)
radius = Attributes[GameAttribute.Gold_PickUp_Radius]; radius = Attributes[GameAttribute.Gold_PickUp_Radius];
var itemList = GetItemsInRange(radius); var itemList = GetItemsInRange(radius);
foreach (var item in itemList) foreach (var item in itemList)
@ -5501,12 +5494,11 @@ public class Player : Actor, IMessageConsumer, IUpdateable
item.Destroy(); item.Destroy();
} }
else if (item.ItemDefinition.Name == "p1_normal_rifts_Orb" || else if (item.ItemDefinition.Name is "p1_normal_rifts_Orb" or "p1_tiered_rifts_Orb")
item.ItemDefinition.Name == "p1_tiered_rifts_Orb")
{ {
if (InGameClient.Game.ActiveNephalemTimer && InGameClient.Game.ActiveNephalemKilledMobs == false) if (InGameClient.Game.ActiveNephalemTimer && InGameClient.Game.ActiveNephalemKilledMobs == false)
{ {
InGameClient.Game.ActiveNephalemProgress += 15f; InGameClient.Game.ActiveNephalemProgress += 15f * GameServerConfig.Instance.NephalemRiftProgressMultiplier;
foreach (var plr in InGameClient.Game.Players.Values) foreach (var plr in InGameClient.Game.Players.Values)
{ {
plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DunggeonFinderProgressGlyphPickUp) plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DunggeonFinderProgressGlyphPickUp)
@ -5630,7 +5622,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public Actor SpawnNephalemBoss(World world) public Actor SpawnNephalemBoss(World world)
{ {
var boss = world.SpawnMonster(ActorSnoExtensions.nephalemPortalBosses.PickRandom(), Position); var boss = world.SpawnMonster(ActorSnoExtensions.NephalemPortalBosses.PickRandom(), Position);
boss.Attributes[GameAttribute.Bounty_Objective] = true; boss.Attributes[GameAttribute.Bounty_Objective] = true;
boss.Attributes[GameAttribute.Is_Loot_Run_Boss] = true; boss.Attributes[GameAttribute.Is_Loot_Run_Boss] = true;
boss.Attributes.BroadcastChangedIfRevealed(); boss.Attributes.BroadcastChangedIfRevealed();
@ -5658,62 +5650,67 @@ public class Player : Actor, IMessageConsumer, IUpdateable
return true; return true;
} }
public void AddPercentageHP(int percentage, bool GuidingLight = false) public void AddPercentageHP(int percentage, bool guidingLight = false)
{ {
var quantity = percentage * Attributes[GameAttribute.Hitpoints_Max_Total] / 100; var quantity = percentage * Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
AddHP(quantity, GuidingLight); AddHP(quantity, guidingLight);
} }
public void AddPercentageHP(float percentage, bool GuidingLight = false) public void AddPercentageHP(float percentage, bool guidingLight = false)
{ {
var quantity = percentage * Attributes[GameAttribute.Hitpoints_Max_Total] / 100; var quantity = percentage * Attributes[GameAttribute.Hitpoints_Max_Total] / 100;
AddHP(quantity, GuidingLight); AddHP(quantity, guidingLight);
} }
public override void AddHP(float quantity, bool guidingLight = false) public override void AddHP(float quantity, bool guidingLight = false)
{ {
if (Dead) return; if (Dead) return;
if (quantity == 0) return; switch (quantity)
if (quantity > 0)
{ {
if (Attributes[GameAttribute.Hitpoints_Cur] < Attributes[GameAttribute.Hitpoints_Max_Total]) case 0:
return;
case > 0:
{ {
if (Toon.Class == ToonClass.Barbarian) if (Attributes[GameAttribute.Hitpoints_Cur] < Attributes[GameAttribute.Hitpoints_Max_Total])
if (SkillSet.HasPassive(205217))
quantity += 0.01f * Attributes[GameAttribute.Health_Globe_Bonus_Health];
if (guidingLight) //Monk -> Guiding Light
{ {
var missingHP = if (Toon.Class == ToonClass.Barbarian)
(Attributes[GameAttribute.Hitpoints_Max_Total] - Attributes[GameAttribute.Hitpoints_Cur]) / if (SkillSet.HasPassive(205217))
Attributes[GameAttribute.Hitpoints_Max_Total]; quantity += 0.01f * Attributes[GameAttribute.Health_Globe_Bonus_Health];
if (missingHP > 0.05f)
if (!World.BuffManager.HasBuff<GuidingLightBuff>(this)) if (guidingLight) //Monk -> Guiding Light
World.BuffManager.AddBuff(this, this, {
new GuidingLightBuff(Math.Min(missingHP, 0.3f), var missingHP =
TickTimer.WaitSeconds(World.Game, 10.0f))); (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
});
} }
Attributes[GameAttribute.Hitpoints_Cur] = Math.Min( break;
}
default:
Attributes[GameAttribute.Hitpoints_Cur] = Math.Max(
Attributes[GameAttribute.Hitpoints_Cur] + quantity, Attributes[GameAttribute.Hitpoints_Cur] + quantity,
Attributes[GameAttribute.Hitpoints_Max_Total]); 0);
Attributes.BroadcastChangedIfRevealed(); Attributes.BroadcastChangedIfRevealed();
InGameClient.SendMessage(new FloatingNumberMessage break;
{
ActorID = DynamicID(this),
Number = quantity,
Type = FloatingNumberMessage.FloatType.Green
});
}
}
else
{
Attributes[GameAttribute.Hitpoints_Cur] = Math.Max(
Attributes[GameAttribute.Hitpoints_Cur] + quantity,
0);
Attributes.BroadcastChangedIfRevealed();
} }
} }
@ -5731,9 +5728,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable
#region Resource Generate/Use #region Resource Generate/Use
private int _DisciplineSpent = 0; private int _disciplineSpent = 0;
private int _HatredSpent = 0; private int _hatredSpent = 0;
private int _WrathSpent = 0; private int _wrathSpent = 0;
public void GeneratePrimaryResource(float amount) public void GeneratePrimaryResource(float amount)
{ {
@ -5745,7 +5742,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
if (World.BuffManager.HasBuff<GuardiansPathBuff>(this)) //Monk -> The Guardian's Path 2H if (World.BuffManager.HasBuff<GuardiansPathBuff>(this)) //Monk -> The Guardian's Path 2H
amount *= 1.35f; amount *= 1.35f;
_ModifyResourceAttribute(PrimaryResourceID, amount); ModifyResourceAttribute(PrimaryResourceID, amount);
} }
public void UsePrimaryResource(float amount, bool tick = false) public void UsePrimaryResource(float amount, bool tick = false)
@ -5757,28 +5754,28 @@ public class Player : Actor, IMessageConsumer, IUpdateable
amount = amount * (1f - DecreaseUseResourcePercent); amount = amount * (1f - DecreaseUseResourcePercent);
if (Toon.Class == ToonClass.Crusader) if (Toon.Class == ToonClass.Crusader)
{ {
_WrathSpent += (int)amount; _wrathSpent += (int)amount;
if (!tick && SkillSet.HasPassive(310775)) //Wrathful passive if (!tick && SkillSet.HasPassive(310775)) //Wrathful passive
AddHP(_WrathSpent * 15f * Attributes[GameAttribute.Level]); AddHP(_wrathSpent * 15f * Attributes[GameAttribute.Level]);
//Laws of Hope -> Faith's reward //Laws of Hope -> Faith's reward
if (!tick && World.BuffManager.HasBuff<CrusaderLawsOfHope.LawsShieldBuff>(this)) if (!tick && World.BuffManager.HasBuff<CrusaderLawsOfHope.LawsShieldBuff>(this))
if (World.BuffManager.GetFirstBuff<CrusaderLawsOfHope.LawsShieldBuff>(this).HealPerWrath) if (World.BuffManager.GetFirstBuff<CrusaderLawsOfHope.LawsShieldBuff>(this).HealPerWrath)
AddHP(_WrathSpent * 15f * Attributes[GameAttribute.Level]); AddHP(_wrathSpent * 15f * Attributes[GameAttribute.Level]);
if (_WrathSpent >= 20) //Akarat Champion -> Fire Starter if (_wrathSpent >= 20) //Akarat Champion -> Fire Starter
if (!tick && World.BuffManager.HasBuff<CrusaderAkaratChampion.AkaratBuff>(this)) if (!tick && World.BuffManager.HasBuff<CrusaderAkaratChampion.AkaratBuff>(this))
World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(this).wrathBlast = true; World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(this).wrathBlast = true;
} }
if (Toon.Class == ToonClass.DemonHunter) if (Toon.Class == ToonClass.DemonHunter)
{ {
_HatredSpent += (int)amount; _hatredSpent += (int)amount;
if (_HatredSpent >= 150 && _DisciplineSpent >= 50) if (_hatredSpent >= 150 && _disciplineSpent >= 50)
GrantAchievement(74987243307068); GrantAchievement(74987243307068);
AddTimedAction(6f, new Action<int>((q) => _HatredSpent -= (int)amount)); AddTimedAction(6f, new Action<int>((q) => _hatredSpent -= (int)amount));
} }
if (Toon.Class == ToonClass.Barbarian) if (Toon.Class == ToonClass.Barbarian)
@ -5813,12 +5810,12 @@ public class Player : Actor, IMessageConsumer, IUpdateable
if (SkillSet.HasPassive(205398) && Attributes[GameAttribute.Hitpoints_Cur] < if (SkillSet.HasPassive(205398) && Attributes[GameAttribute.Hitpoints_Cur] <
Attributes[GameAttribute.Hitpoints_Max_Total] * 0.35f) //Relentless (Barbarian) Attributes[GameAttribute.Hitpoints_Max_Total] * 0.35f) //Relentless (Barbarian)
amount *= 0.25f; amount *= 0.25f;
_ModifyResourceAttribute(PrimaryResourceID, -amount); ModifyResourceAttribute(PrimaryResourceID, -amount);
} }
public void GenerateSecondaryResource(float amount) public void GenerateSecondaryResource(float amount)
{ {
_ModifyResourceAttribute(SecondaryResourceID, amount); ModifyResourceAttribute(SecondaryResourceID, amount);
} }
public void UseSecondaryResource(float amount) public void UseSecondaryResource(float amount)
@ -5833,18 +5830,18 @@ public class Player : Actor, IMessageConsumer, IUpdateable
if (Toon.Class == ToonClass.DemonHunter) if (Toon.Class == ToonClass.DemonHunter)
{ {
_DisciplineSpent += (int)amount; _disciplineSpent += (int)amount;
if (_HatredSpent >= 150 && _DisciplineSpent >= 50) if (_hatredSpent >= 150 && _disciplineSpent >= 50)
GrantAchievement(74987243307068); GrantAchievement(74987243307068);
AddTimedAction(6f, new Action<int>((q) => _DisciplineSpent -= (int)amount)); AddTimedAction(6f, new Action<int>((q) => _disciplineSpent -= (int)amount));
} }
_ModifyResourceAttribute(SecondaryResourceID, -amount); ModifyResourceAttribute(SecondaryResourceID, -amount);
} }
private void _ModifyResourceAttribute(int resourceID, float amount) private void ModifyResourceAttribute(int resourceID, float amount)
{ {
if (resourceID == -1 || amount == 0) return; if (resourceID == -1 || amount == 0) return;
var current = Attributes[GameAttribute.Resource_Cur, resourceID]; var current = Attributes[GameAttribute.Resource_Cur, resourceID];
@ -5857,7 +5854,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
Attributes[GameAttribute.Resource_Cur, resourceID] + amount, Attributes[GameAttribute.Resource_Cur, resourceID] + amount,
0f); 0f);
if (current == Attributes[GameAttribute.Resource_Cur, resourceID]) return; if (Math.Abs(current - Attributes[GameAttribute.Resource_Cur, resourceID]) < Globals.FLOAT_TOLERANCE) return;
Attributes.BroadcastChangedIfRevealed(); Attributes.BroadcastChangedIfRevealed();
} }

View File

@ -266,9 +266,9 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
}, Target); }, Target);
if (Context?.User != null) if (Context?.User != null)
if (Math.Abs(Context.User.Attributes[GameAttribute.Item_Power_Passive, 247640] - 1) < 0.001 || if (Math.Abs(Context.User.Attributes[GameAttribute.Item_Power_Passive, 247640] - 1) < Globals.FLOAT_TOLERANCE ||
Math.Abs(Context.User.Attributes[GameAttribute.Item_Power_Passive, 249963] - 1) < 0.001 || Math.Abs(Context.User.Attributes[GameAttribute.Item_Power_Passive, 249963] - 1) < Globals.FLOAT_TOLERANCE ||
Math.Abs(Context.User.Attributes[GameAttribute.Item_Power_Passive, 249954] - 1) < 0.001 || Math.Abs(Context.User.Attributes[GameAttribute.Item_Power_Passive, 249954] - 1) < Globals.FLOAT_TOLERANCE ||
(float)FastRandom.Instance.NextDouble() < 0.1f || (float)FastRandom.Instance.NextDouble() < 0.1f ||
Target.World.SNO == WorldSno.a1dun_random_level01) Target.World.SNO == WorldSno.a1dun_random_level01)
switch ((int)DeathDamageType.HitEffect) switch ((int)DeathDamageType.HitEffect)
@ -1066,7 +1066,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
{ {
//death implementation //death implementation
Player player = (Player)Target; Player player = (Player)Target;
if (Math.Abs(player.Attributes[GameAttribute.Item_Power_Passive, 248629] - 1) < 0.001) if (Math.Abs(player.Attributes[GameAttribute.Item_Power_Passive, 248629] - 1) < Globals.FLOAT_TOLERANCE)
player.PlayEffectGroup(248680); player.PlayEffectGroup(248680);
player.StopCasting(); player.StopCasting();
Target.World.BuffManager.RemoveAllBuffs(Target, false); Target.World.BuffManager.RemoveAllBuffs(Target, false);

View File

@ -24,25 +24,22 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
public class HitPayload : Payload public class HitPayload : Payload
{ {
public static readonly Logger Logger = LogManager.CreateLogger(); public static readonly Logger Logger = LogManager.CreateLogger();
public float TotalDamage; public float TotalDamage { get; set; }
public DamageType DominantDamageType; public DamageType DominantDamageType { get; set; }
public Dictionary<DamageType, float> ElementDamages; public Dictionary<DamageType, float> ElementDamages { get; set; }
public bool IsCriticalHit; public bool IsCriticalHit { get; set; }
public bool IsDodged; public bool IsDodged { get; set; }
public bool IsWeaponDamage; public bool IsWeaponDamage { get; set; }
public bool Successful = false; public bool Successful { get; set; }
public bool Blocked = false; public bool Blocked { get; set; }
public bool AutomaticHitEffects = true; public bool AutomaticHitEffects = true;
public Action<DeathPayload> OnDeath = null; public Action<DeathPayload> OnDeath = null;
private bool WaitTo(TickTimer timer) private bool WaitTo(TickTimer timer)
{ {
while (timer.TimedOut != true) while (timer.TimedOut != true) ;
{
}
return true; return true;
} }
@ -144,7 +141,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
if (criticalHit) if (criticalHit)
{ {
TotalDamage *= (1f + Context.User.Attributes[GameAttribute.Crit_Damage_Percent]); TotalDamage *= (1f + Context.User.Attributes[GameAttribute.Crit_Damage_Percent]);
if (Context.User is Player && (Context.User as Player).Toon.Class == ToonClass.Wizard && Context.User.Attributes[GameAttribute.Resource_On_Crit, 1] > 0) if (Context.User is Player player && player.Toon.Class == ToonClass.Wizard && player.Attributes[GameAttribute.Resource_On_Crit, 1] > 0)
if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient()) if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient())
(Context.User as Player).GeneratePrimaryResource(Context.User.Attributes[GameAttribute.Resource_On_Crit, 1]); (Context.User as Player).GeneratePrimaryResource(Context.User.Attributes[GameAttribute.Resource_On_Crit, 1]);
} }
@ -170,10 +167,9 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
switch (Context.User) switch (Context.User)
{ {
case Player: case Player plr:
if (IsWeaponDamage) if (IsWeaponDamage)
{ {
var plr = Context.User as Player;
TotalDamage = TotalDamage * (1 + (plr.PrimaryAttribute / 100f)); TotalDamage = TotalDamage * (1 + (plr.PrimaryAttribute / 100f));
if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient()) if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient())
plr.GeneratePrimaryResource(plr.Attributes[GameAttribute.Resource_On_Hit]); plr.GeneratePrimaryResource(plr.Attributes[GameAttribute.Resource_On_Hit]);
@ -224,7 +220,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient()) if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient())
plr.GenerateSecondaryResource(1f); plr.GenerateSecondaryResource(1f);
if (plr.SkillSet.HasPassive(155721) && Target.Attributes[GameAttribute.Slow] == true) if (plr.SkillSet.HasPassive(155721) && Target.Attributes[GameAttribute.Slow])
TotalDamage *= 1.20f; TotalDamage *= 1.20f;
if (plr.SkillSet.HasPassive(155725)) if (plr.SkillSet.HasPassive(155725))
@ -239,12 +235,12 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
if (criticalHit) if (criticalHit)
{ {
plr.AddTimedAction(1f, new Action<int>((q) => plr.World.BuffManager.RemoveBuffs(plr, 155715))); plr.AddTimedAction(1f, _ => plr.World.BuffManager.RemoveBuffs(plr, 155715));
plr.AddTimedAction(2f, new Action<int>((q) => plr.AddTimedAction(2f, _ =>
{ {
if (plr.SkillSet.HasPassive(155715)) if (plr.SkillSet.HasPassive(155715))
plr.World.BuffManager.AddBuff(plr, plr, new SharpshooterBuff()); plr.World.BuffManager.AddBuff(plr, plr, new SharpshooterBuff());
})); });
} }
break; break;
case ToonClass.Wizard: case ToonClass.Wizard:
@ -373,17 +369,17 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
if (plr.World.BuffManager.HasBuff<CrusaderAkaratChampion.AkaratBuff>(plr)) //AkaratChampion -> Rally if (plr.World.BuffManager.HasBuff<CrusaderAkaratChampion.AkaratBuff>(plr)) //AkaratChampion -> Rally
if (plr.World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(plr).CDRActive) if (plr.World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(plr).CDRActive)
if (FastRandom.Instance.NextDouble() < 0.5f * Context.GetProcCoefficient()) if (FastRandom.Instance.NextDouble() < 0.5f * Context.GetProcCoefficient())
foreach (var cdBuff in plr.World.BuffManager.GetBuffs<CooldownBuff>(plr)) foreach (var cooldownBuff in plr.World.BuffManager.GetBuffs<CooldownBuff>(plr))
if (!(cdBuff.TargetPowerSNO == 269032)) //do not CDR AkaratChampionBuff if (cooldownBuff.TargetPowerSNO != 269032) //do not CDR AkaratChampionBuff
cdBuff.Reduce(60); cooldownBuff.Reduce(60);
break; break;
} }
if (Target is Monster) if (Target is Monster monster)
{ {
TotalDamage *= 1 + plr.Attributes[GameAttribute.Damage_Percent_Bonus_Vs_Monster_Type, (Target as Monster).MonsterType]; TotalDamage *= 1 + plr.Attributes[GameAttribute.Damage_Percent_Bonus_Vs_Monster_Type, monster.MonsterType];
if ((Target as Monster).Quality > 0) if (monster.Quality > 0)
TotalDamage *= 1 + plr.Attributes[GameAttribute.Damage_Percent_Bonus_Vs_Elites]; TotalDamage *= 1 + plr.Attributes[GameAttribute.Damage_Percent_Bonus_Vs_Elites];
if (attackPayload.Targets.Actors.Count == 1 && !(attackPayload.Context is Buff) && attackPayload.AutomaticHitEffects) if (attackPayload.Targets.Actors.Count == 1 && !(attackPayload.Context is Buff) && attackPayload.AutomaticHitEffects)
@ -391,40 +387,37 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
float procCoeff = Context.GetProcCoefficient(); float procCoeff = Context.GetProcCoefficient();
if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Fear_Proc_Chance] * procCoeff) if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Fear_Proc_Chance] * procCoeff)
plr.World.BuffManager.AddBuff(plr, Target, new DebuffFeared(TickTimer.WaitSeconds(plr.World.Game, 1.5f))); plr.World.BuffManager.AddBuff(plr, monster, new DebuffFeared(TickTimer.WaitSeconds(plr.World.Game, 1.5f)));
if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Stun_Proc_Chance] * procCoeff) if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Stun_Proc_Chance] * procCoeff)
plr.World.BuffManager.AddBuff(plr, Target, new DebuffStunned(TickTimer.WaitSeconds(plr.World.Game, 1.5f))); plr.World.BuffManager.AddBuff(plr, monster, new DebuffStunned(TickTimer.WaitSeconds(plr.World.Game, 1.5f)));
if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Blind_Proc_Chance] * procCoeff) if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Blind_Proc_Chance] * procCoeff)
plr.World.BuffManager.AddBuff(plr, Target, new DebuffBlind(TickTimer.WaitSeconds(plr.World.Game, 1.5f))); plr.World.BuffManager.AddBuff(plr, monster, new DebuffBlind(TickTimer.WaitSeconds(plr.World.Game, 1.5f)));
if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Freeze_Proc_Chance] * procCoeff) if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Freeze_Proc_Chance] * procCoeff)
plr.World.BuffManager.AddBuff(plr, Target, new DebuffFrozen(TickTimer.WaitSeconds(plr.World.Game, 1.5f))); plr.World.BuffManager.AddBuff(plr, monster, new DebuffFrozen(TickTimer.WaitSeconds(plr.World.Game, 1.5f)));
if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Chill_Proc_Chance] * procCoeff) if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Chill_Proc_Chance] * procCoeff)
plr.World.BuffManager.AddBuff(plr, Target, new DebuffChilled(0.3f, TickTimer.WaitSeconds(plr.World.Game, 2f))); plr.World.BuffManager.AddBuff(plr, monster, new DebuffChilled(0.3f, TickTimer.WaitSeconds(plr.World.Game, 2f)));
if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Slow_Proc_Chance] * procCoeff) if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Slow_Proc_Chance] * procCoeff)
plr.World.BuffManager.AddBuff(plr, Target, new DebuffSlowed(0.3f, TickTimer.WaitSeconds(plr.World.Game, 2f))); plr.World.BuffManager.AddBuff(plr, monster, new DebuffSlowed(0.3f, TickTimer.WaitSeconds(plr.World.Game, 2f)));
if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Knockback_Proc_Chance] * procCoeff) if (FastRandom.Instance.NextDouble() < plr.Attributes[GameAttribute.On_Hit_Knockback_Proc_Chance] * procCoeff)
plr.World.BuffManager.AddBuff(plr, Target, new KnockbackBuff(3f)); plr.World.BuffManager.AddBuff(plr, monster, new KnockbackBuff(3f));
} }
} }
} }
break; break;
case Minion: case Minion mn:
var mn = Context.User as Minion;
TotalDamage *= (1 + (mn.PrimaryAttribute / 100f)); TotalDamage *= (1 + (mn.PrimaryAttribute / 100f));
TotalDamage *= mn.Master.Attributes[GameAttribute.Attacks_Per_Second_Total]; TotalDamage *= mn.Master.Attributes[GameAttribute.Attacks_Per_Second_Total];
if (mn.Master is Player) if (mn.Master is Player mstr)
{ {
var mstr = mn.Master as Player; if (mstr.SkillSet.HasPassive(209041) && mn is CorpseSpider or CorpseSpiderQueen)
if (mstr.SkillSet.HasPassive(209041) && (mn is CorpseSpider || mn is CorpseSpiderQueen))
mstr.World.BuffManager.AddBuff(mstr, mstr, new VisionQuestBuff()); mstr.World.BuffManager.AddBuff(mstr, mstr, new VisionQuestBuff());
if (mn.SNO == ActorSno._dh_companion_spider) if (mn.SNO == ActorSno._dh_companion_spider)
@ -438,137 +431,149 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
} }
if (Target is Player playerTarget) //check for passives here (incoming damage) switch (Target)
{ {
if (!playerTarget.Attributes[GameAttribute.Cannot_Dodge] && FastRandom.Instance.NextDouble() < playerTarget.DodgeChance) //check for passives here (incoming damage)
IsDodged = true; case Player playerTarget:
if (playerTarget.Toon.Class == ToonClass.Monk) //Monk defensive passives
{ {
TotalDamage *= 0.7f; //Class damage reduction bonus if (!playerTarget.Attributes[GameAttribute.Cannot_Dodge] && FastRandom.Instance.NextDouble() < playerTarget.DodgeChance)
IsDodged = true;
if (playerTarget.World.BuffManager.HasBuff<TempestRush.TempestEffect>(playerTarget)) //Tempest rush -> Slipstream switch (playerTarget.Toon.Class)
if (playerTarget.World.BuffManager.GetFirstBuff<TempestRush.TempestEffect>(playerTarget)._slipStream)
TotalDamage *= 0.8f;
if (playerTarget.World.BuffManager.HasBuff<Epiphany.EpiphanyBuff>(playerTarget)) //Epiphany -> Desert Shroud
if (playerTarget.World.BuffManager.GetFirstBuff<Epiphany.EpiphanyBuff>(playerTarget).DesertShroud)
TotalDamage *= 0.5f;
if (IsDodged) //Mantra of Evasion -> Backlash
if (playerTarget.World.BuffManager.HasBuff<MantraOfEvasionPassive.MantraOfEvasionBuff>(playerTarget))
if (playerTarget.World.BuffManager.GetFirstBuff<MantraOfEvasionPassive.MantraOfEvasionBuff>(playerTarget).Backlash)
playerTarget.World.BuffManager.GetFirstBuff<MantraOfEvasionPassive.MantraOfEvasionBuff>(playerTarget).BacklashTrigger = true;
}
if (playerTarget.Toon.Class == ToonClass.Barbarian) //Barb defensive passives
{
TotalDamage *= 0.7f; //Class damage reduction bonus
if (playerTarget.SkillSet.HasPassive(205491) && PowerMath.Distance2D(Context.User.Position, playerTarget.Position) > 6f) //Superstition (barbarian)
if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient())
playerTarget.GeneratePrimaryResource(2f);
if (playerTarget.SkillSet.HasPassive(205398) && (playerTarget.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage) < (playerTarget.Attributes[GameAttribute.Hitpoints_Max_Total] * 0.2f)) //Relentless (barbarian)
TotalDamage *= 0.5f;
}
if (playerTarget.Toon.Class == ToonClass.Wizard) //Wizard defensive passives
{
if (playerTarget.SkillSet.HasPassive(208471)) //GlassCannon (Wizard)
TotalDamage *= 1.1f;
if (playerTarget.SkillSet.HasPassive(208547) && TotalDamage > (playerTarget.Attributes[GameAttribute.Hitpoints_Max_Total] * 0.15f)) //Illusionist (Wizard)
{ {
foreach (var cdBuff in playerTarget.World.BuffManager.GetBuffs<CooldownBuff>(playerTarget)) //Monk defensive passives
if (cdBuff.TargetPowerSNO == 1769 || cdBuff.TargetPowerSNO == 168344) case ToonClass.Monk:
cdBuff.Remove();
}
if (playerTarget.SkillSet.HasPassive(208474) && (playerTarget.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage) <= 0) //UnstableAnomaly (wizard)
{
if (playerTarget.World.BuffManager.GetFirstBuff<UnstableAnomalyCooldownBuff>(playerTarget) == null)
{ {
playerTarget.AddPercentageHP(45); TotalDamage *= 0.7f; //Class damage reduction bonus
playerTarget.World.BuffManager.AddBuff(playerTarget, playerTarget, new UnstableAnomalyCooldownBuff());
playerTarget.World.PowerManager.RunPower(playerTarget, 30796); if (playerTarget.World.BuffManager.HasBuff<TempestRush.TempestEffect>(playerTarget)) //Tempest rush -> Slipstream
playerTarget.GenerateSecondaryResource(25f); if (playerTarget.World.BuffManager.GetFirstBuff<TempestRush.TempestEffect>(playerTarget)._slipStream)
foreach (var cdBuff in playerTarget.World.BuffManager.GetBuffs<CooldownBuff>(playerTarget)) TotalDamage *= 0.8f;
if (cdBuff.TargetPowerSNO == 30796)
cdBuff.Remove(); if (playerTarget.World.BuffManager.HasBuff<Epiphany.EpiphanyBuff>(playerTarget)) //Epiphany -> Desert Shroud
if (playerTarget.World.BuffManager.GetFirstBuff<Epiphany.EpiphanyBuff>(playerTarget).DesertShroud)
TotalDamage *= 0.5f;
if (IsDodged) //Mantra of Evasion -> Backlash
if (playerTarget.World.BuffManager.HasBuff<MantraOfEvasionPassive.MantraOfEvasionBuff>(playerTarget))
if (playerTarget.World.BuffManager.GetFirstBuff<MantraOfEvasionPassive.MantraOfEvasionBuff>(playerTarget).Backlash)
playerTarget.World.BuffManager.GetFirstBuff<MantraOfEvasionPassive.MantraOfEvasionBuff>(playerTarget).BacklashTrigger = true;
break;
} }
} //Barb defensive passives
} case ToonClass.Barbarian:
{
TotalDamage *= 0.7f; //Class damage reduction bonus
if (playerTarget.Toon.Class == ToonClass.WitchDoctor) //Witch Doctor defensive passives if (playerTarget.SkillSet.HasPassive(205491) && PowerMath.Distance2D(Context.User.Position, playerTarget.Position) > 6f) //Superstition (barbarian)
{ if (FastRandom.Instance.NextDouble() < Context.GetProcCoefficient())
if (playerTarget.SkillSet.HasPassive(217968)) //JungleFortitude (WD) playerTarget.GeneratePrimaryResource(2f);
TotalDamage *= 0.85f;
}
if (playerTarget.Toon.Class == ToonClass.DemonHunter) //DH defensive passives if (playerTarget.SkillSet.HasPassive(205398) && (playerTarget.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage) < (playerTarget.Attributes[GameAttribute.Hitpoints_Max_Total] * 0.2f)) //Relentless (barbarian)
{ TotalDamage *= 0.5f;
if (playerTarget.SkillSet.HasPassive(210801) && playerTarget.World.BuffManager.GetFirstBuff<BroodingCooldownBuff>(playerTarget) == null) //Brooding (DH) break;
playerTarget.World.BuffManager.AddBuff(playerTarget, playerTarget, new BroodingCooldownBuff()); }
} //Wizard defensive passives
case ToonClass.Wizard:
{
if (playerTarget.SkillSet.HasPassive(208471)) //GlassCannon (Wizard)
TotalDamage *= 1.1f;
if (playerTarget.Toon.Class == ToonClass.Crusader) //Crusader defensive passives if (playerTarget.SkillSet.HasPassive(208547) && TotalDamage > (playerTarget.Attributes[GameAttribute.Hitpoints_Max_Total] * 0.15f)) //Illusionist (Wizard)
{
TotalDamage *= 0.7f; //Class damage reduction bonus
if (playerTarget.SkillSet.HasPassive(310626)) //Vigilant
if (DominantDamageType != DamageType.Physical)
TotalDamage *= 0.95f;
if (playerTarget.World.BuffManager.HasBuff<CrusaderAkaratChampion.AkaratBuff>(playerTarget)) //AkaratChampion resurrect once
if (playerTarget.World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(playerTarget).resurrectActive)
if ((playerTarget.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage) <= 0)
{ {
playerTarget.World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(playerTarget).resurrectActive = false; foreach (var cdBuff in playerTarget.World.BuffManager.GetBuffs<CooldownBuff>(playerTarget))
playerTarget.AddPercentageHP(100); if (cdBuff.TargetPowerSNO == 1769 || cdBuff.TargetPowerSNO == 168344)
cdBuff.Remove();
} }
if (playerTarget.World.BuffManager.HasBuff<CrusaderLawsOfJustice.LawsResBuff>(playerTarget)) //Protect the Innocent if (playerTarget.SkillSet.HasPassive(208474) && (playerTarget.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage) <= 0) //UnstableAnomaly (wizard)
if (!playerTarget.World.BuffManager.GetFirstBuff<CrusaderLawsOfJustice.LawsResBuff>(playerTarget).Primary) {
if (playerTarget.World.BuffManager.GetFirstBuff<CrusaderLawsOfJustice.LawsResBuff>(playerTarget).Redirect) if (playerTarget.World.BuffManager.GetFirstBuff<UnstableAnomalyCooldownBuff>(playerTarget) == null)
TotalDamage *= 0.8f; {
playerTarget.AddPercentageHP(45);
playerTarget.World.BuffManager.AddBuff(playerTarget, playerTarget, new UnstableAnomalyCooldownBuff());
playerTarget.World.PowerManager.RunPower(playerTarget, 30796);
playerTarget.GenerateSecondaryResource(25f);
foreach (var cdBuff in playerTarget.World.BuffManager.GetBuffs<CooldownBuff>(playerTarget))
if (cdBuff.TargetPowerSNO == 30796)
cdBuff.Remove();
}
}
break;
}
//Witch Doctor defensive passives
case ToonClass.WitchDoctor:
{
if (playerTarget.SkillSet.HasPassive(217968)) //JungleFortitude (WD)
TotalDamage *= 0.85f;
break;
}
//DH defensive passives
case ToonClass.DemonHunter:
{
if (playerTarget.SkillSet.HasPassive(210801) && playerTarget.World.BuffManager.GetFirstBuff<BroodingCooldownBuff>(playerTarget) == null) //Brooding (DH)
playerTarget.World.BuffManager.AddBuff(playerTarget, playerTarget, new BroodingCooldownBuff());
break;
}
//Crusader defensive passives
case ToonClass.Crusader:
{
TotalDamage *= 0.7f; //Class damage reduction bonus
if (playerTarget.SkillSet.HasPassive(310626)) //Vigilant
if (DominantDamageType != DamageType.Physical)
TotalDamage *= 0.95f;
if (playerTarget.World.BuffManager.HasBuff<CrusaderAkaratChampion.AkaratBuff>(playerTarget)) //AkaratChampion resurrect once
if (playerTarget.World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(playerTarget).resurrectActive)
if ((playerTarget.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage) <= 0)
{
playerTarget.World.BuffManager.GetFirstBuff<CrusaderAkaratChampion.AkaratBuff>(playerTarget).resurrectActive = false;
playerTarget.AddPercentageHP(100);
}
if (playerTarget.World.BuffManager.HasBuff<CrusaderLawsOfJustice.LawsResBuff>(playerTarget)) //Protect the Innocent
if (!playerTarget.World.BuffManager.GetFirstBuff<CrusaderLawsOfJustice.LawsResBuff>(playerTarget).Primary)
if (playerTarget.World.BuffManager.GetFirstBuff<CrusaderLawsOfJustice.LawsResBuff>(playerTarget).Redirect)
TotalDamage *= 0.8f;
break;
}
}
TotalDamage *= 0.1f;
break;
} }
//check for passives here (incoming damage, minions)
case Minion { Master: Player playerOwner }:
{
var plr = playerOwner;
TotalDamage *= 0.1f; var masterArmor = plr.Attributes[GameAttribute.Armor_Total];
} var attackLevel = attackPayload.Context.User.Attributes[GameAttribute.Level];
else if (Target is Minion { Master: Player playerOwner }) //check for passives here (incoming damage, minions)
{
var plr = playerOwner;
var masterArmor = plr.Attributes[GameAttribute.Armor_Total]; TotalDamage *= ReductionFromArmor(masterArmor, attackLevel);
var attackLevel = attackPayload.Context.User.Attributes[GameAttribute.Level];
TotalDamage *= ReductionFromArmor(masterArmor, attackLevel); if (plr.SkillSet.HasPassive(217968)) //JungleFortitude (WD)
TotalDamage *= 0.85f;
if (plr.SkillSet.HasPassive(217968)) //JungleFortitude (WD) TotalDamage *= 0.1f; //hack for unkillable minions
TotalDamage *= 0.85f; break;
}
TotalDamage *= 0.1f; //hack for unkillable minions
} }
} }
private static float ReductionFromResistance(float resistance, int attackerLevel) private static float ReductionFromResistance(float resistance, int attackerLevel) => 1f - (resistance / ((5 * attackerLevel) + resistance));
{
return 1f - (resistance / ((5 * attackerLevel) + resistance));
}
private static float ReductionFromArmor(float armor, int attackerLevel) private static float ReductionFromArmor(float armor, int attackerLevel) => 1f - (armor / ((50 * attackerLevel) + armor));
{
return 1f - (armor / ((50 * attackerLevel) + armor));
}
private void CheckItemProcs(Player user) private void CheckItemProcs(Player user)
{ {
if (Math.Abs(user.Attributes[GameAttribute.Item_Power_Passive, 247724] - 1) < 0.001 && FastRandom.Instance.NextDouble() < 0.2) if (Math.Abs(user.Attributes[GameAttribute.Item_Power_Passive, 247724] - 1) < Globals.FLOAT_TOLERANCE && FastRandom.Instance.NextDouble() < 0.2)
{ {
user.PlayEffectGroup(247770); user.PlayEffectGroup(247770);
} }
if (Math.Abs(user.Attributes[GameAttribute.Item_Power_Passive, 245741] - 1) < 0.001 && FastRandom.Instance.NextDouble() < 0.2) if (Math.Abs(user.Attributes[GameAttribute.Item_Power_Passive, 245741] - 1) < Globals.FLOAT_TOLERANCE && FastRandom.Instance.NextDouble() < 0.2)
{ {
user.PlayEffectGroup(245747); user.PlayEffectGroup(245747);
} }
@ -625,12 +630,12 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
else if (plr.Toon.Class == ToonClass.DemonHunter) //Awareness else if (plr.Toon.Class == ToonClass.DemonHunter) //Awareness
{ {
plr.AddTimedAction(1f, new Action<int>((q) => plr.World.BuffManager.RemoveBuffs(plr, 324770))); plr.AddTimedAction(1f, _ => plr.World.BuffManager.RemoveBuffs(plr, 324770));
plr.AddTimedAction(2f, new Action<int>((q) => plr.AddTimedAction(2f, _ =>
{ {
if (plr.SkillSet.HasPassive(324770)) if (plr.SkillSet.HasPassive(324770))
plr.World.BuffManager.AddBuff(plr, plr, new AwarenessBuff()); plr.World.BuffManager.AddBuff(plr, plr, new AwarenessBuff());
})); });
} }
return; return;
} }
@ -675,12 +680,11 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
} }
} }
if (Target.World != null) Target.World?.BuffManager?.SendTargetPayload(Target, this);
Target.World.BuffManager.SendTargetPayload(Target, this);
if (Context.User != null) if (Context.User != null)
Target.World.BuffManager.SendTargetPayload(Context.User, this); Target.World?.BuffManager?.SendTargetPayload(Context.User, this);
if (Target == null || Target.World == null) return; //in case Target was killed in OnPayload if (Target?.World == null) return; //in case Target was killed in OnPayload
if (Context.User is Player player) if (Context.User is Player player)
{ {
@ -702,20 +706,18 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
if (hireling.Attributes[GameAttribute.Hitpoints_On_Hit] > 0) if (hireling.Attributes[GameAttribute.Hitpoints_On_Hit] > 0)
hireling.AddHP(hireling.Attributes[GameAttribute.Hitpoints_On_Hit]); hireling.AddHP(hireling.Attributes[GameAttribute.Hitpoints_On_Hit]);
} }
// floating damage number // make player damage red, all other damage white
if (Target.World != null) var type = Target is Player ?
IsCriticalHit ? FloatingNumberMessage.FloatType.RedCritical : FloatingNumberMessage.FloatType.Red :
IsCriticalHit ? FloatingNumberMessage.FloatType.Golden : FloatingNumberMessage.FloatType.White;
if (Target.World is { } world)
{ {
Target.World.BroadcastIfRevealed(plr => new FloatingNumberMessage world.BroadcastIfRevealed(plr => new FloatingNumberMessage
{ {
ActorID = Target.DynamicID(plr), ActorID = Target.DynamicID(plr),
Number = TotalDamage, Number = TotalDamage,
// make player damage red, all other damage white Type = type
Type = IsCriticalHit ?
(Target is Player) ? FloatingNumberMessage.FloatType.RedCritical : FloatingNumberMessage.FloatType.Golden
:
(Target is Player) ? FloatingNumberMessage.FloatType.Red : FloatingNumberMessage.FloatType.White
}, Target); }, Target);
} }
@ -737,15 +739,15 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
{ {
// play override hitsound if any, otherwise just default to playing metal weapon hit for now // play override hitsound if any, otherwise just default to playing metal weapon hit for now
int overridenSound = Context.EvalTag(PowerKeys.HitsoundOverride); int overridenSound = Context.EvalTag(PowerKeys.HitsoundOverride);
int hitsound = overridenSound != -1 ? overridenSound : 1; int hitSound = overridenSound != -1 ? overridenSound : 1;
if (hitsound > 0) if (hitSound > 0)
Target.PlayEffect(Effect.Hit, hitsound); Target.PlayEffect(Effect.Hit, hitSound);
} }
} }
// update hp // update hp
float new_hp = Math.Max(Target.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage, 0f); float newHp = Math.Max(Target.Attributes[GameAttribute.Hitpoints_Cur] - TotalDamage, 0f);
Target.Attributes[GameAttribute.Hitpoints_Cur] = new_hp; Target.Attributes[GameAttribute.Hitpoints_Cur] = newHp;
Target.Attributes.BroadcastChangedIfRevealed(); Target.Attributes.BroadcastChangedIfRevealed();
//thorns //thorns
@ -766,21 +768,23 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
*/ */
// if hp=0 do death // if hp=0 do death
if (new_hp <= 0f) if (newHp <= 0f)
{ {
var deathload = new DeathPayload(Context, DominantDamageType, Target, Target.HasLoot); var deathPayload = new DeathPayload(Context, DominantDamageType, Target, Target.HasLoot)
deathload.AutomaticHitEffects = AutomaticHitEffects; {
AutomaticHitEffects = AutomaticHitEffects
};
if (deathload.Successful) if (deathPayload.Successful)
{ {
Target.Dead = true; Target.Dead = true;
try try
{ {
if (OnDeath != null && AutomaticHitEffects) if (OnDeath != null && AutomaticHitEffects)
OnDeath(deathload); OnDeath(deathPayload);
} }
catch { } catch { }
deathload.Apply(); deathPayload.Apply();
} }
} }
else if (AutomaticHitEffects && Target.World != null && Target is not Player) else if (AutomaticHitEffects && Target.World != null && Target is not Player)
@ -800,13 +804,13 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads
{ {
if (Target.IsRevealedToPlayer(plr)) if (Target.IsRevealedToPlayer(plr))
{ {
float BackSpeed = Target.WalkSpeed; float backSpeed = Target.WalkSpeed;
Target.WalkSpeed = 0f; Target.WalkSpeed = 0f;
TickTimer Timeout = new SecondsTickTimer(Target.World.Game, 0.3f); TickTimer timeout = new SecondsTickTimer(Target.World.Game, 0.3f);
var Boom = Task<bool>.Factory.StartNew(() => WaitTo(Timeout)); var boom = Task<bool>.Factory.StartNew(() => WaitTo(timeout));
Boom.ContinueWith(delegate boom.ContinueWith(_ =>
{ {
Target.WalkSpeed = BackSpeed; Target.WalkSpeed = backSpeed;
}); });
} }
} }

View File

@ -178,20 +178,17 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem
public EffectActor SpawnEffect(ActorSno actorSNO, Vector3D position, float angle = 0, TickTimer timeout = null) public EffectActor SpawnEffect(ActorSno actorSNO, Vector3D position, float angle = 0, TickTimer timeout = null)
{ {
if (Math.Abs(angle - (-1)) < 0.0001) if (Math.Abs(angle - -1) < Globals.FLOAT_TOLERANCE)
angle = (float)(Rand.NextDouble() * (Math.PI * 2)); angle = (float)(Rand.NextDouble() * (Math.PI * 2));
if (timeout == null) if (timeout == null)
{ {
if (_defaultEffectTimeout == null) _defaultEffectTimeout ??= new SecondsTickTimer(World.Game, 2f);
_defaultEffectTimeout = new SecondsTickTimer(World.Game, 2f); // default timeout of 2 seconds for now
timeout = _defaultEffectTimeout; timeout = _defaultEffectTimeout;
} }
var actor = new EffectActor(this, actorSNO, position); var actor = new EffectActor(this, actorSNO, position);
actor.Timeout = timeout; actor.Timeout = timeout;
actor.Spawn(angle); actor.Spawn(angle);
//187359
return actor; return actor;
} }

View File

@ -11,35 +11,54 @@ namespace DiIiS_NA.GameServer.GSSystem.SkillsSystem
{ {
public class SkillSet public class SkillSet
{ {
public ToonClass @Class; public ToonClass ToonClass { get; }
public Toon Toon { get; private set; } public Toon Toon { get; }
public Player Player { get; private set; } public Player Player { get; }
public ActiveSkillSavedData[] ActiveSkills; public ActiveSkillSavedData[] ActiveSkills { get; }
public HotbarButtonData[] HotBarSkills; public HotbarButtonData[] HotBarSkills { get; }
public int[] PassiveSkills; public int[] PassiveSkills { get; }
protected static readonly Logger Logger = LogManager.CreateLogger(); protected static readonly Logger Logger = LogManager.CreateLogger();
public SkillSet(Player player, ToonClass @class, Toon toon) public SkillSet(Player player, ToonClass toonClass, Toon toon)
{ {
@Class = @class; ToonClass = toonClass;
Player = player; Player = player;
var dbToon = player.Toon.DBToon; // var dbToon = player.Toon.DBToon;
var dbActiveSkills = player.Toon.DBActiveSkills; var dbActiveSkills = player.Toon.DBActiveSkills;
ActiveSkills = new ActiveSkillSavedData[6] { ActiveSkills = new ActiveSkillSavedData[6]
new ActiveSkillSavedData { snoSkill = dbActiveSkills.Skill0, {
snoRune = dbActiveSkills.Rune0 }, new()
new ActiveSkillSavedData { snoSkill = dbActiveSkills.Skill1, {
snoRune = dbActiveSkills.Rune1 }, snoSkill = dbActiveSkills.Skill0,
new ActiveSkillSavedData { snoSkill = dbActiveSkills.Skill2, snoRune = dbActiveSkills.Rune0
snoRune = dbActiveSkills.Rune2 }, },
new ActiveSkillSavedData { snoSkill = dbActiveSkills.Skill3, new()
snoRune = dbActiveSkills.Rune3 }, {
new ActiveSkillSavedData { snoSkill = dbActiveSkills.Skill4, snoSkill = dbActiveSkills.Skill1,
snoRune = dbActiveSkills.Rune4 }, snoRune = dbActiveSkills.Rune1
new ActiveSkillSavedData { snoSkill = dbActiveSkills.Skill5, },
snoRune = dbActiveSkills.Rune5 }, new()
{
snoSkill = dbActiveSkills.Skill2,
snoRune = dbActiveSkills.Rune2
},
new()
{
snoSkill = dbActiveSkills.Skill3,
snoRune = dbActiveSkills.Rune3
},
new()
{
snoSkill = dbActiveSkills.Skill4,
snoRune = dbActiveSkills.Rune4
},
new()
{
snoSkill = dbActiveSkills.Skill5,
snoRune = dbActiveSkills.Rune5
},
}; };
PassiveSkills = new int[4] { PassiveSkills = new int[4] {
@ -51,18 +70,18 @@ namespace DiIiS_NA.GameServer.GSSystem.SkillsSystem
//} //}
HotBarSkills = new HotbarButtonData[6] { HotBarSkills = new HotbarButtonData[6] {
new HotbarButtonData { SNOSkill = ActiveSkills[0].snoSkill, ItemAnn = ActiveSkills[0].snoRune, ItemGBId = -1, RuneType = -1 }, // left-click new() { SNOSkill = ActiveSkills[0].snoSkill, ItemAnn = ActiveSkills[0].snoRune, ItemGBId = -1, RuneType = -1 }, // left-click
new HotbarButtonData { SNOSkill = ActiveSkills[1].snoSkill, ItemAnn = ActiveSkills[1].snoRune, ItemGBId = -1, RuneType = -1 }, // right-click new() { SNOSkill = ActiveSkills[1].snoSkill, ItemAnn = ActiveSkills[1].snoRune, ItemGBId = -1, RuneType = -1 }, // right-click
new HotbarButtonData { SNOSkill = ActiveSkills[2].snoSkill, ItemAnn = ActiveSkills[2].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-1 new() { SNOSkill = ActiveSkills[2].snoSkill, ItemAnn = ActiveSkills[2].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-1
new HotbarButtonData { SNOSkill = ActiveSkills[3].snoSkill, ItemAnn = ActiveSkills[3].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-2 new() { SNOSkill = ActiveSkills[3].snoSkill, ItemAnn = ActiveSkills[3].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-2
new HotbarButtonData { SNOSkill = ActiveSkills[4].snoSkill, ItemAnn = ActiveSkills[4].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-3 new() { SNOSkill = ActiveSkills[4].snoSkill, ItemAnn = ActiveSkills[4].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-3
new HotbarButtonData { SNOSkill = ActiveSkills[5].snoSkill, ItemAnn = ActiveSkills[5].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-4 new() { SNOSkill = ActiveSkills[5].snoSkill, ItemAnn = ActiveSkills[5].snoRune, ItemGBId = -1, RuneType = -1 }, // bar-4
}; };
} }
public void UpdateSkills(int hotBarIndex, int SNOSkill, int SNORune, Toon toon) public void UpdateSkills(int hotBarIndex, int SNOSkill, int SNORune, Toon toon)
{ {
Logger.Debug("Update index {0} skill {1} rune {2}", hotBarIndex, SNOSkill, SNORune); Logger.MethodTrace(string.Format("Update index {0} skill {1} rune {2}", hotBarIndex, SNOSkill, SNORune));
var dbActiveSkills = Player.Toon.DBActiveSkills; var dbActiveSkills = Player.Toon.DBActiveSkills;
switch (hotBarIndex) switch (hotBarIndex)
{ {
@ -119,31 +138,12 @@ namespace DiIiS_NA.GameServer.GSSystem.SkillsSystem
} }
} }
public bool HasPassive(int passiveId) public bool HasPassive(int passiveId) => PassiveSkills.Contains(passiveId);
{
if (PassiveSkills.Contains(passiveId))
return true;
else
return false;
}
public bool HasSkill(int skillId) public bool HasSkill(int skillId) => ActiveSkills.Any(s => s.snoSkill == skillId);
{
return ActiveSkills.Any(s => s.snoSkill == skillId);
}
public bool HasSkillWithRune(int skillId, int runeId) public bool HasSkillWithRune(int skillId, int runeId) => ActiveSkills.Any(s => s.snoSkill == skillId && s.snoRune == runeId);
{
return ActiveSkills.Any(s => s.snoSkill == skillId && s.snoRune == runeId); public bool HasItemPassiveProc(int passiveId) => (float)FastRandom.Instance.NextDouble() < Player.Attributes[GameAttribute.Item_Power_Passive, passiveId];
}
public bool HasItemPassiveProc(int passiveId)
{
if ((float)FastRandom.Instance.NextDouble() < Player.Attributes[GameAttribute.Item_Power_Passive, passiveId])
return true;
else
return false;
}
} }
} }

View File

@ -49,6 +49,14 @@ namespace DiIiS_NA.GameServer
get => GetBoolean(nameof(CoreActive), true); get => GetBoolean(nameof(CoreActive), true);
set => Set(nameof(CoreActive), value); set => Set(nameof(CoreActive), value);
} }
public bool IWServer
{
get => GetBoolean(nameof(IWServer), true);
set => Set(nameof(IWServer), value);
}
#region Game Mods
/// <summary> /// <summary>
/// Rate of experience gain. /// Rate of experience gain.
@ -100,12 +108,6 @@ namespace DiIiS_NA.GameServer
get => GetFloat(nameof(RateMonsterDMG), 1); get => GetFloat(nameof(RateMonsterDMG), 1);
set => Set(nameof(RateMonsterDMG), value); set => Set(nameof(RateMonsterDMG), value);
} }
public bool IWServer
{
get => GetBoolean(nameof(IWServer), true);
set => Set(nameof(IWServer), value);
}
/// <summary> /// <summary>
/// Percentage that a unique, legendary, set or special item created is unidentified /// Percentage that a unique, legendary, set or special item created is unidentified
@ -196,7 +198,80 @@ namespace DiIiS_NA.GameServer
get => GetBoolean(nameof(UnlockAllWaypoints), false); get => GetBoolean(nameof(UnlockAllWaypoints), false);
set => Set(nameof(UnlockAllWaypoints), value); set => Set(nameof(UnlockAllWaypoints), value);
} }
/// <summary>
/// Strength multiplier when you're not a paragon.
/// </summary>
public float StrengthMultiplier
{
get => GetFloat(nameof(StrengthMultiplier), 1f);
set => Set(nameof(StrengthMultiplier), value);
}
/// <summary>
/// Strength multiplier when you're a paragon.
/// </summary>
public float StrengthParagonMultiplier
{
get => GetFloat(nameof(StrengthParagonMultiplier), 1f);
set => Set(nameof(StrengthParagonMultiplier), value);
}
/// <summary>
/// Dexterity multiplier when you're not a paragon.
/// </summary>
public float DexterityMultiplier
{
get => GetFloat(nameof(DexterityMultiplier), 1f);
set => Set(nameof(DexterityMultiplier), value);
}
/// <summary>
/// Dexterity multiplier when you're a paragon.
/// </summary>
public float DexterityParagonMultiplier
{
get => GetFloat(nameof(DexterityParagonMultiplier), 1f);
set => Set(nameof(DexterityParagonMultiplier), value);
}
/// <summary>
/// Intelligence multiplier when you're not a paragon.
/// </summary>
public float IntelligenceMultiplier
{
get => GetFloat(nameof(IntelligenceMultiplier), 1f);
set => Set(nameof(IntelligenceMultiplier), value);
}
/// <summary>
/// Intelligence multiplier when you're a paragon.
/// </summary>
public float IntelligenceParagonMultiplier
{
get => GetFloat(nameof(IntelligenceParagonMultiplier), 1f);
set => Set(nameof(IntelligenceParagonMultiplier), value);
}
/// <summary>
/// Vitality multiplier when you're not a paragon.
/// </summary>
public float VitalityMultiplier
{
get => GetFloat(nameof(VitalityMultiplier), 1f);
set => Set(nameof(VitalityMultiplier), value);
}
/// <summary>
/// Vitality multiplier when you're a paragon.
/// </summary>
public float VitalityParagonMultiplier
{
get => GetFloat(nameof(VitalityParagonMultiplier), 1f);
set => Set(nameof(VitalityParagonMultiplier), value);
}
#endregion
public static GameServerConfig Instance { get; } = new(); public static GameServerConfig Instance { get; } = new();

View File

@ -4,7 +4,8 @@ using System.Configuration;
namespace DiIiS_NA namespace DiIiS_NA
{ {
public static class Extensions internal static class Globals
{ {
public const float FLOAT_TOLERANCE = 0.0001f;
} }
} }

View File

@ -30,7 +30,8 @@ namespace DiIiS_NA.REST.Http
Found = 302, Found = 302,
BadRequest = 400, BadRequest = 400,
NotFound = 404, NotFound = 404,
InternalServerError = 500 InternalServerError = 500,
BadGateway = 502
} }
public class HttpHelper public class HttpHelper

View File

@ -12,6 +12,7 @@ using DiIiS_NA.REST.Data.Authentication;
using DiIiS_NA.REST.JSON; using DiIiS_NA.REST.JSON;
using DiIiS_NA.LoginServer.AccountsSystem; using DiIiS_NA.LoginServer.AccountsSystem;
using System.IO; using System.IO;
using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Web; using System.Web;
using DiIiS_NA.GameServer.MessageSystem; using DiIiS_NA.GameServer.MessageSystem;
@ -41,26 +42,19 @@ namespace DiIiS_NA.REST
} }
else else
{ {
Logger.Info($"$[yellow]$REST Request: $[/]$ {httpRequest.Method} {httpRequest.Path}"); Logger.Debug($"$[yellow]$REST Request: $[/]$ {httpRequest.Method} {httpRequest.Path}");
if (httpRequest.Path == "200") if (httpRequest.Path == "200")
{ {
} }
else if (httpRequest.Path.Contains("/client/alert")) else if (httpRequest.Path.Contains("/client/alert"))
{ {
switch (httpRequest.Method) HandleInfoRequest(httpRequest);
{
case "GET":
default:
HandleInfoRequest(httpRequest);
break;
}
} }
else else if (httpRequest.Path.Contains("/battlenet/login"))
{ {
switch (httpRequest.Method) switch (httpRequest.Method)
{ {
case "GET":
default: default:
HandleConnectRequest(httpRequest); HandleConnectRequest(httpRequest);
break; break;
@ -69,30 +63,34 @@ namespace DiIiS_NA.REST
return; return;
} }
} }
else
{
#if DEBUG
Logger.Info($"$[red]$[404] REST Request: $[/]$ {httpRequest.Method} {httpRequest.Path}");
SendResponseHtml(HttpCode.NotFound, "404 Not Found");
#else
// sends 502 Bad Gateway to the client to prevent the client from trying to connect to the server again - in case it's a crawler or bad bot.
Logger.Info($"$[red]$[404/502] REST Request: $[/]$ {httpRequest.Method} {httpRequest.Path}");
SendResponseHtml(HttpCode.BadGateway, "502 Bad Gateway");
return;
#endif
}
} }
AsyncRead(); AsyncRead();
} }
public void HandleConnectRequest(HttpHeader request) void HandleConnectRequest(HttpHeader request)
{ {
SendResponse(HttpCode.OK, SessionManager.Instance.GetFormInput()); SendResponse(HttpCode.OK, SessionManager.Instance.GetFormInput());
} }
public void HandleInfoRequest(HttpHeader request) void HandleInfoRequest(HttpHeader request)
{ {
SendResponseHtml(HttpCode.OK, "Welcome to BlizzLess.Net" + SendResponseHtml(HttpCode.OK, "Welcome to BlizzLess.Net" +
"\nBuild " + Program.Build + "\nBuild " + Program.Build +
"\nSupport: 2.7.4"); "\nSupport: 2.7.4");
} }
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();
}
void SendResponse<T>(HttpCode code, T response) void SendResponse<T>(HttpCode code, T response)
{ {
AsyncWrite(HttpHelper.CreateResponse(code, JSON.Json.CreateString(response))); AsyncWrite(HttpHelper.CreateResponse(code, JSON.Json.CreateString(response)));
@ -107,7 +105,8 @@ namespace DiIiS_NA.REST
{ {
AsyncRead(); AsyncRead();
} }
public void HandleLoginRequest(HttpHeader request)
void HandleLoginRequest(HttpHeader request)
{ {
LogonData loginForm = Json.CreateObject<LogonData>(request.Content); LogonData loginForm = Json.CreateObject<LogonData>(request.Content);
LogonResult loginResult = new LogonResult(); LogonResult loginResult = new LogonResult();