mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-12-25 11:36:26 -05:00
Load Enemy Type Info from monstats.txt (#48)
* EnemyConfig loading from monstats.txt * removed some unneeded comments * Added difficulty flag to enemystate * Fix renaming issue
This commit is contained in:
parent
21666ed4f4
commit
6b40c30b5c
@ -49,6 +49,7 @@
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="UT_EnemyState.cs" />
|
||||
<Compile Include="UT_MobState.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UT_PlayerState.cs" />
|
||||
|
200
OpenDiablo2.Common.UT/UT_EnemyState.cs
Normal file
200
OpenDiablo2.Common.UT/UT_EnemyState.cs
Normal file
@ -0,0 +1,200 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Enums.Mobs;
|
||||
using OpenDiablo2.Common.Models.Mobs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.UT
|
||||
{
|
||||
[TestClass]
|
||||
public class UT_EnemyState
|
||||
{
|
||||
public EnemyState MakeEnemyState(int id, eDifficulty difficulty, Random rand)
|
||||
{
|
||||
// does not correspond to any particular enemy in the actual data, just for testing
|
||||
EnemyTypeConfig config = new EnemyTypeConfig(
|
||||
InternalName: "TestEnemy",
|
||||
Name: "TestEnemy1",
|
||||
Type: "Skeleton",
|
||||
Descriptor: "",
|
||||
BaseId: 1,
|
||||
PopulateId: 1,
|
||||
Spawned: true,
|
||||
Beta: false,
|
||||
Code: "SK",
|
||||
ClientOnly: false,
|
||||
NoMap: false,
|
||||
SizeX: 2,
|
||||
SizeY: 2,
|
||||
Height: 3,
|
||||
NoOverlays: false,
|
||||
OverlayHeight: 2,
|
||||
Velocity: 3,
|
||||
RunVelocity: 6,
|
||||
CanStealFrom: false,
|
||||
ColdEffect: 50,
|
||||
Rarity: true,
|
||||
MinimumGrouping: 2,
|
||||
MaximumGrouping: 5,
|
||||
BaseWeapon: "1hs",
|
||||
AIParams: new int[] {75, 85, 9, 50, 0 },
|
||||
Allied: false,
|
||||
IsNPC: false,
|
||||
IsCritter: false,
|
||||
CanEnterTown: false,
|
||||
HealthRegen: 80,
|
||||
IsDemon: false,
|
||||
IsLarge: false,
|
||||
IsSmall: false,
|
||||
IsFlying: false,
|
||||
CanOpenDoors: false,
|
||||
SpawningColumn: 0,
|
||||
IsBoss: false,
|
||||
IsInteractable: false,
|
||||
IsKillable: true,
|
||||
CanBeConverted: true,
|
||||
HitClass: 3,
|
||||
HasSpecialEndDeath: false,
|
||||
DeadCollision: false,
|
||||
CanBeRevivedByOtherMonsters: true,
|
||||
AppearanceConfig: new EnemyTypeAppearanceConfig(
|
||||
HasDeathAnimation: true,
|
||||
HasNeutralAnimation: true,
|
||||
HasWalkAnimation: true,
|
||||
HasGetHitAnimation: true,
|
||||
HasAttack1Animation: true,
|
||||
HasAttack2Animation: false,
|
||||
HasBlockAnimation: true,
|
||||
HasCastAnimation: false,
|
||||
HasSkillAnimation: new bool[] { false, false, false, false },
|
||||
HasCorpseAnimation: false,
|
||||
HasKnockbackAnimation: true,
|
||||
HasRunAnimation: true,
|
||||
HasLifeBar: true,
|
||||
HasNameBar: false,
|
||||
CannotBeSelected: false,
|
||||
CanCorpseBeSelected: false,
|
||||
BleedType: 0,
|
||||
HasShadow: true,
|
||||
LightRadius: 0,
|
||||
HasUniqueBossColors: false,
|
||||
CompositeDeath: true,
|
||||
LightRGB: new byte[] { 255, 255, 255 }
|
||||
),
|
||||
CombatConfig: new EnemyTypeCombatConfig(
|
||||
ElementalAttackMode: 4,
|
||||
ElementalAttackType: eDamageTypes.PHYSICAL,
|
||||
ElementalOverlayId: 0,
|
||||
ElementalChance: 0,
|
||||
ElementalMinDamage: 0,
|
||||
ElementalMaxDamage: 0,
|
||||
ElementalDuration: 0,
|
||||
MissileForAttack: new int[] { 0, 0 },
|
||||
MissileForSkill: new int[] { 0, 0, 0, 0, },
|
||||
MissileForCase: 0,
|
||||
MissileForSequence: 0,
|
||||
CanMoveAttack: new bool[] { false, false },
|
||||
CanMoveSkill: new bool[] { false, false, false, false },
|
||||
CanMoveCast: false,
|
||||
IsMelee: true,
|
||||
IsAttackable: true,
|
||||
MeleeRange: 0,
|
||||
SkillType: new int[] { 0, 0, 0, 0 },
|
||||
SkillSequence: new int[] { 0, 0, 0, 0 },
|
||||
SkillLevel: new int[] { 0, 0, 0, 0 },
|
||||
IsUndeadWithPhysicalAttacks: true,
|
||||
IsUndeadWithMagicAttacks: false,
|
||||
UsesMagicAttacks: false,
|
||||
ChanceToBlock: 20,
|
||||
DoesDeathDamage: false,
|
||||
IgnoredBySummons: false
|
||||
),
|
||||
NormalDifficultyConfig: new EnemyTypeDifficultyConfig(
|
||||
Level: 5,
|
||||
DamageResist: 0,
|
||||
MagicResist: 0,
|
||||
FireResist: 0.5,
|
||||
LightResist: 0,
|
||||
ColdResist: 0,
|
||||
PoisonResist: 0,
|
||||
MinHP: 10,
|
||||
MaxHP: 15,
|
||||
AC: 3,
|
||||
Exp: 100,
|
||||
AttackMinDamage: new int[] { 5, 0 },
|
||||
AttackMaxDamage: new int[] { 10, 0 },
|
||||
AttackChanceToHit: new int[] { 35, 0 },
|
||||
Skill1MinDamage: 0,
|
||||
Skill1MaxDamage: 0,
|
||||
Skill1ChanceToHit: 0,
|
||||
TreasureClass: new string[] { "Swarm 1", "Act 2 Champ A", "Act 2 Unique A", "" }
|
||||
),
|
||||
NightmareDifficultyConfig: new EnemyTypeDifficultyConfig(
|
||||
Level: 10,
|
||||
DamageResist: 0,
|
||||
MagicResist: 0,
|
||||
FireResist: 0.5,
|
||||
LightResist: 0.5,
|
||||
ColdResist: 0,
|
||||
PoisonResist: 0,
|
||||
MinHP: 20,
|
||||
MaxHP: 25,
|
||||
AC: 3,
|
||||
Exp: 1000,
|
||||
AttackMinDamage: new int[] { 5, 0 },
|
||||
AttackMaxDamage: new int[] { 10, 0 },
|
||||
AttackChanceToHit: new int[] { 35, 0 },
|
||||
Skill1MinDamage: 0,
|
||||
Skill1MaxDamage: 0,
|
||||
Skill1ChanceToHit: 0,
|
||||
TreasureClass: new string[] { "Swarm 1", "Act 3 Champ A", "Act 3 Unique A", "" }
|
||||
),
|
||||
HellDifficultyConfig: new EnemyTypeDifficultyConfig(
|
||||
Level: 15,
|
||||
DamageResist: 0,
|
||||
MagicResist: 0,
|
||||
FireResist: 0.5,
|
||||
LightResist: 0.5,
|
||||
ColdResist: 0.5,
|
||||
PoisonResist: 0,
|
||||
MinHP: 30,
|
||||
MaxHP: 45,
|
||||
AC: 3,
|
||||
Exp: 10000,
|
||||
AttackMinDamage: new int[] { 5, 0 },
|
||||
AttackMaxDamage: new int[] { 10, 0 },
|
||||
AttackChanceToHit: new int[] { 35, 0 },
|
||||
Skill1MinDamage: 0,
|
||||
Skill1MaxDamage: 0,
|
||||
Skill1ChanceToHit: 0,
|
||||
TreasureClass: new string[] { "Swarm 2", "Act 4 Champ A", "Act 4 Unique A", "" }
|
||||
)
|
||||
);
|
||||
|
||||
EnemyState en = new EnemyState("Fallen", id, 0, 0, config, difficulty, rand);
|
||||
|
||||
return en;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EnemyDifficultyTest()
|
||||
{
|
||||
Random rand = new Random();
|
||||
EnemyState en = MakeEnemyState(1, eDifficulty.NORMAL, rand);
|
||||
Assert.AreEqual(5, en.Level);
|
||||
Assert.AreEqual(100, en.ExperienceGiven);
|
||||
|
||||
EnemyState en2 = MakeEnemyState(2, eDifficulty.NIGHTMARE, rand);
|
||||
Assert.AreEqual(10, en2.Level);
|
||||
Assert.AreEqual(1000, en2.ExperienceGiven);
|
||||
|
||||
EnemyState en3 = MakeEnemyState(3, eDifficulty.HELL, rand);
|
||||
Assert.AreEqual(15, en3.Level);
|
||||
Assert.AreEqual(10000, en3.ExperienceGiven);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,12 +8,19 @@ namespace OpenDiablo2.Common.Enums.Mobs
|
||||
{
|
||||
public enum eDamageTypes
|
||||
{
|
||||
NONE, // no resistances apply
|
||||
PHYSICAL,
|
||||
MAGIC,
|
||||
FIRE,
|
||||
COLD,
|
||||
LIGHTNING,
|
||||
POISON,
|
||||
NONE = -1, // no resistances apply
|
||||
PHYSICAL = 0,
|
||||
MAGIC = 3, //1=fire, 2=lightning, 4=cold, 5=poison
|
||||
FIRE = 1,
|
||||
COLD = 4,
|
||||
LIGHTNING = 2,
|
||||
POISON = 5,
|
||||
LIFE_STEAL = 6,
|
||||
MANA_STEAL = 7,
|
||||
STAMINA_STEAL = 8,
|
||||
STUN = 9,
|
||||
RANDOM = 10, // random between fire/cold/lightning/poison
|
||||
BURN = 11,
|
||||
FREEZE = 12,
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,14 @@ namespace OpenDiablo2.Common.Enums.Mobs
|
||||
{
|
||||
PLAYER,
|
||||
ENEMY,
|
||||
INVULNERABLE
|
||||
INVULNERABLE,
|
||||
BOSS,
|
||||
NPC,
|
||||
CRITTER,
|
||||
LARGE,
|
||||
SMALL,
|
||||
INTERACTABLE,
|
||||
DEMON,
|
||||
IGNORED_BY_SUMMONS,
|
||||
}
|
||||
}
|
||||
|
15
OpenDiablo2.Common/Enums/eDifficulty.cs
Normal file
15
OpenDiablo2.Common/Enums/eDifficulty.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Enums
|
||||
{
|
||||
public enum eDifficulty
|
||||
{
|
||||
NORMAL,
|
||||
NIGHTMARE,
|
||||
HELL,
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ namespace OpenDiablo2.Common.Interfaces.Drawing
|
||||
eHero Hero { get; set; }
|
||||
PlayerEquipment Equipment { get; set; }
|
||||
eMobMode MobMode { get; set; }
|
||||
|
||||
void Update(long ms);
|
||||
void Render(int pixelOffsetX, int pixelOffsetY);
|
||||
void ResetAnimationData();
|
||||
|
@ -14,5 +14,6 @@ namespace OpenDiablo2.Common.Interfaces
|
||||
ImmutableList<Item> Items { get; }
|
||||
ImmutableDictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; }
|
||||
ImmutableDictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; }
|
||||
ImmutableList<IEnemyTypeConfig> EnemyTypeConfigs { get; }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces.Mobs
|
||||
{
|
||||
public interface IEnemyTypeAppearanceConfig
|
||||
{
|
||||
bool HasDeathAnimation { get; }
|
||||
bool HasNeutralAnimation { get; }
|
||||
bool HasWalkAnimation { get; }
|
||||
bool HasGetHitAnimation { get; }
|
||||
bool[] HasAttackAnimation { get; } // 1-2
|
||||
bool HasBlockAnimation { get; }
|
||||
bool HasCastAnimation { get; }
|
||||
bool[] HasSkillAnimation { get; } // 1-4
|
||||
bool HasCorpseAnimation { get; }
|
||||
bool HasKnockbackAnimation { get; }
|
||||
// HasSkillSequenceAnimation skipped due to being unused
|
||||
bool HasRunAnimation { get; }
|
||||
|
||||
bool HasLifeBar { get; } // does this monster show a lifebar when you scroll over it
|
||||
bool HasNameBar { get; } // does this monster show a name when you scroll over it
|
||||
bool CannotBeSelected { get; } // if true, monster can never be highlighted
|
||||
bool CanCorpseBeSelected { get; } // if true, the corpse can be highlighted
|
||||
|
||||
int BleedType { get; } // how does this monster bleed when hit?
|
||||
// 0 = it doesn't, 1 = small blood, 2 = large blood, 3+ = random missiles from missiles.txt, the larger
|
||||
// the number, the more missiles (??? this needs to be tested...)
|
||||
bool HasShadow { get; } // does this have a shadow?
|
||||
int LightRadius { get; } // how large of a light does this emit?
|
||||
bool HasUniqueBossColors { get; } // if true, has unique colors when spawned
|
||||
// as a boss.
|
||||
bool CompositeDeath { get; } // if true, death animation uses multiple components
|
||||
// (not clear if this is just for reference or if it actually has an effect...)
|
||||
|
||||
byte[] LightRGB { get; } // 0: R, 1: G, 2: B
|
||||
}
|
||||
}
|
54
OpenDiablo2.Common/Interfaces/Mobs/IEnemyTypeCombatConfig.cs
Normal file
54
OpenDiablo2.Common/Interfaces/Mobs/IEnemyTypeCombatConfig.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using OpenDiablo2.Common.Enums.Mobs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces.Mobs
|
||||
{
|
||||
public interface IEnemyTypeCombatConfig
|
||||
{
|
||||
int ElementalAttackMode { get;} // 4 = on hit, rest are unknown?
|
||||
eDamageTypes ElementalAttackType { get;} // 1=fire, 2=lightning, 4=cold, 5=poison
|
||||
int ElementalOverlayId { get;} // see overlays.txt, corresponds to a row number -2
|
||||
int ElementalChance { get;} // chance of use on a normal attack, 0 = never 100 = always
|
||||
int ElementalMinDamage { get;}
|
||||
int ElementalMaxDamage { get;}
|
||||
int ElementalDuration { get;} // duration of effects like cold and poison
|
||||
|
||||
// TODO: these could be switched to SHORTS, is there any benefit to that?
|
||||
int[] MissileForAttack { get;} // 1-2, which missile is used per attack
|
||||
// important note: 65535 = NONE. See missiles.txt, corresponds to a row number -2
|
||||
int[] MissileForSkill { get;} // 1-4, which missile is used for a skill
|
||||
// important note: 65535 = NONE. See missiles.txt, corresponds to a row number -2
|
||||
int MissileForCase { get;} // see above, specifies a missile for Case
|
||||
int MissileForSequence { get;} // see above, specifies a missile for Sequence
|
||||
|
||||
bool[] CanMoveAttack { get;} // 1-2, can move while using attack 1 / 2
|
||||
bool[] CanMoveSkill { get;} // 1-4, can move while using skill 1/2/3/4
|
||||
bool CanMoveCast { get;} // can move while casting?
|
||||
|
||||
bool IsMelee { get;} // is this a melee attacker?
|
||||
bool IsAttackable { get;} // is this monster attackable?
|
||||
|
||||
int MeleeRange { get; }
|
||||
|
||||
int[] SkillType { get;} // 1-5, what type of skill is it? 0 = none
|
||||
int[] SkillSequence { get;} // 1-5 animation sequence number
|
||||
// should not be 0 if skill is not 0; see animation column in skills.txt
|
||||
int[] SkillLevel { get;} // 1-5, level of the skill
|
||||
|
||||
bool IsUndeadWithPhysicalAttacks { get;} // if true, is an undead attacking with physical attacks
|
||||
bool IsUndeadWithMagicAttacks { get;} // if true '' magic atttacks
|
||||
bool UsesMagicAttacks { get;}
|
||||
|
||||
int ChanceToBlock { get;}
|
||||
|
||||
bool DoesDeathDamage { get;} // if true, does damage when it dies
|
||||
// like undead flayers (TODO: understand exactly how this works)
|
||||
|
||||
bool IgnoredBySummons { get;} // if true, is ignored by summons in combat
|
||||
|
||||
}
|
||||
}
|
88
OpenDiablo2.Common/Interfaces/Mobs/IEnemyTypeConfig.cs
Normal file
88
OpenDiablo2.Common/Interfaces/Mobs/IEnemyTypeConfig.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces.Mobs
|
||||
{
|
||||
public interface IEnemyTypeConfig
|
||||
{
|
||||
string InternalName { get; }
|
||||
string DisplayName { get; } // Note the distinction here; the second column
|
||||
// in the monstats is a unique identifier string, whereas the first is non-unique
|
||||
string Type { get; }
|
||||
string Descriptor { get; }
|
||||
|
||||
int BaseId { get; }
|
||||
int PopulateId { get; }
|
||||
bool Spawned { get; }
|
||||
bool Beta { get; }
|
||||
string Code { get; }
|
||||
bool ClientOnly { get; }
|
||||
bool NoMap { get; }
|
||||
|
||||
int SizeX { get; }
|
||||
int SizeY { get; }
|
||||
int Height { get; }
|
||||
bool NoOverlays { get; }
|
||||
int OverlayHeight { get; }
|
||||
|
||||
int Velocity { get; }
|
||||
int RunVelocity { get; }
|
||||
|
||||
bool CanStealFrom { get; }
|
||||
int ColdEffect { get; }
|
||||
|
||||
bool Rarity { get; }
|
||||
|
||||
int MinimumGrouping { get; }
|
||||
int MaximumGrouping { get; }
|
||||
|
||||
string BaseWeapon { get; }
|
||||
|
||||
int[] AIParams { get; } // up to 5
|
||||
|
||||
bool Allied { get; } // Is this enemy on the player's side?
|
||||
bool IsNPC { get; } // is this an NPC?
|
||||
bool IsCritter { get; } // is this a critter? (e.g. the chickens)
|
||||
bool CanEnterTown { get; } // can this enter town or not?
|
||||
|
||||
int HealthRegen { get; } // hp regen per minute
|
||||
|
||||
bool IsDemon { get; } // demon?
|
||||
bool IsLarge { get; } // size large (e.g. bosses)
|
||||
bool IsSmall { get; } // size small (e.g. fallen)
|
||||
bool IsFlying { get; } // can move over water for instance
|
||||
bool CanOpenDoors { get; }
|
||||
int SpawningColumn { get; } // is the monster area restricted
|
||||
// 0 = no, spawns through levels.txt, 1-3 unknown?
|
||||
// TODO: understand spawningcolumn
|
||||
bool IsBoss { get; }
|
||||
bool IsInteractable { get; } // can this be interacted with? like an NPC
|
||||
|
||||
bool IsKillable { get; }
|
||||
bool CanBeConverted { get; } // if true, can be switched to Allied by spells like Conversion
|
||||
|
||||
int HitClass { get; } // TODO: find out what this is
|
||||
|
||||
bool HasSpecialEndDeath { get; } // marks if a monster dies a special death
|
||||
bool DeadCollision { get; } // if true, corpse has collision
|
||||
|
||||
bool CanBeRevivedByOtherMonsters { get; }
|
||||
|
||||
// appearance config
|
||||
IEnemyTypeAppearanceConfig AppearanceConfig { get; }
|
||||
|
||||
// combat config
|
||||
IEnemyTypeCombatConfig CombatConfig { get; }
|
||||
|
||||
// difficulty configs
|
||||
IEnemyTypeDifficultyConfig NormalDifficultyConfig { get; }
|
||||
IEnemyTypeDifficultyConfig NightmareDifficultyConfig { get; }
|
||||
IEnemyTypeDifficultyConfig HellDifficultyConfig { get; }
|
||||
|
||||
IEnemyTypeDifficultyConfig GetDifficultyConfig(eDifficulty Difficulty);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces.Mobs
|
||||
{
|
||||
public interface IEnemyTypeDifficultyConfig
|
||||
{
|
||||
int Level { get; }
|
||||
|
||||
double DamageResist { get; }
|
||||
double MagicResist { get; }
|
||||
double FireResist { get; }
|
||||
double LightningResist { get; }
|
||||
double ColdResist { get; }
|
||||
double PoisonResist { get; }
|
||||
|
||||
int MinHP { get; }
|
||||
int MaxHP { get; }
|
||||
int AC { get; } // armor class
|
||||
int Exp { get; }
|
||||
|
||||
int[] AttackMinDamage { get; } // 1-2, min damage attack can roll
|
||||
int[] AttackMaxDamage { get; } // 1-2 max damage attack can roll
|
||||
int[] AttackChanceToHit { get; } // 1-2 chance attack has to hit (out of 100??)
|
||||
int Skill1MinDamage { get; } // min damage skill 1 can do (why only skill 1?)
|
||||
int Skill1MaxDamage { get; } // max damage for skill 1
|
||||
int Skill1ChanceToHit { get; } // chance skill has to hit
|
||||
|
||||
string[] TreasureClass { get; } // 1-4
|
||||
}
|
||||
}
|
@ -1,17 +1,95 @@
|
||||
using OpenDiablo2.Common.Enums.Mobs;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Enums.Mobs;
|
||||
using OpenDiablo2.Common.Interfaces.Mobs;
|
||||
using System;
|
||||
|
||||
namespace OpenDiablo2.Common.Models.Mobs
|
||||
{
|
||||
public class EnemyState : MobState
|
||||
{
|
||||
public IEnemyTypeConfig EnemyConfig { get; protected set; }
|
||||
|
||||
public int ExperienceGiven { get; protected set; }
|
||||
|
||||
public Stat[] AttackRating { get; protected set; }
|
||||
public Stat DefenseRating { get; protected set; }
|
||||
public Stat HealthRegen { get; protected set; }
|
||||
|
||||
public eDifficulty CreatedDifficulty { get; protected set; }
|
||||
|
||||
public EnemyState() : base() { }
|
||||
|
||||
public EnemyState(string name, int id, int level, int maxhealth, float x, float y, int experiencegiven)
|
||||
: base(name, id, level, maxhealth, x, y)
|
||||
public EnemyState(string name, int id, float x, float y,
|
||||
IEnemyTypeConfig EnemyConfig, eDifficulty Difficulty, Random Rand)
|
||||
: base(name, id, 0, 0, x, y)
|
||||
{
|
||||
ExperienceGiven = experiencegiven;
|
||||
this.EnemyConfig = EnemyConfig;
|
||||
IEnemyTypeDifficultyConfig difficultyConfig = EnemyConfig.GetDifficultyConfig(Difficulty);
|
||||
CreatedDifficulty = Difficulty;
|
||||
|
||||
int maxhp = Rand.Next(difficultyConfig.MinHP, difficultyConfig.MaxHP + 1);
|
||||
Health = new Stat(0, maxhp, maxhp, true);
|
||||
ExperienceGiven = difficultyConfig.Exp;
|
||||
Level = difficultyConfig.Level;
|
||||
|
||||
// stats
|
||||
AttackRating = new Stat[2];
|
||||
AttackRating[0] = new Stat(0, difficultyConfig.AttackChanceToHit[0], difficultyConfig.AttackChanceToHit[0], false);
|
||||
AttackRating[1] = new Stat(0, difficultyConfig.AttackChanceToHit[1], difficultyConfig.AttackChanceToHit[1], false);
|
||||
|
||||
DefenseRating = new Stat(0, EnemyConfig.CombatConfig.ChanceToBlock, EnemyConfig.CombatConfig.ChanceToBlock, false);
|
||||
|
||||
HealthRegen = new Stat(0, EnemyConfig.HealthRegen, EnemyConfig.HealthRegen, true);
|
||||
|
||||
// handle immunities / resistances
|
||||
SetResistance(eDamageTypes.COLD, difficultyConfig.ColdResist);
|
||||
SetResistance(eDamageTypes.FIRE, difficultyConfig.FireResist);
|
||||
SetResistance(eDamageTypes.MAGIC, difficultyConfig.MagicResist);
|
||||
SetResistance(eDamageTypes.PHYSICAL, difficultyConfig.DamageResist);
|
||||
SetResistance(eDamageTypes.POISON, difficultyConfig.PoisonResist);
|
||||
SetResistance(eDamageTypes.LIGHTNING, difficultyConfig.LightningResist);
|
||||
// interestingly, monsters don't actually have immunity flags
|
||||
// TODO: should we treat a resistance of 1 differently?
|
||||
// should a resistance of 1 be an immunity (e.g. the main difference is that
|
||||
// effects / debuffs couldn't reduce the resistance below 100%)
|
||||
|
||||
// handle flags
|
||||
if (EnemyConfig.IsBoss)
|
||||
{
|
||||
AddFlag(eMobFlags.BOSS);
|
||||
}
|
||||
if (EnemyConfig.IsCritter)
|
||||
{
|
||||
AddFlag(eMobFlags.CRITTER);
|
||||
}
|
||||
if (EnemyConfig.IsNPC)
|
||||
{
|
||||
AddFlag(eMobFlags.NPC);
|
||||
}
|
||||
if (EnemyConfig.IsLarge)
|
||||
{
|
||||
AddFlag(eMobFlags.LARGE);
|
||||
}
|
||||
if (EnemyConfig.IsSmall)
|
||||
{
|
||||
AddFlag(eMobFlags.SMALL);
|
||||
}
|
||||
if (EnemyConfig.IsInteractable)
|
||||
{
|
||||
AddFlag(eMobFlags.INTERACTABLE);
|
||||
}
|
||||
if (!EnemyConfig.IsKillable)
|
||||
{
|
||||
AddFlag(eMobFlags.INVULNERABLE);
|
||||
}
|
||||
if (EnemyConfig.IsDemon)
|
||||
{
|
||||
AddFlag(eMobFlags.DEMON);
|
||||
}
|
||||
if (EnemyConfig.CombatConfig.IgnoredBySummons)
|
||||
{
|
||||
AddFlag(eMobFlags.IGNORED_BY_SUMMONS);
|
||||
}
|
||||
AddFlag(eMobFlags.ENEMY);
|
||||
}
|
||||
}
|
||||
|
77
OpenDiablo2.Common/Models/Mobs/EnemyTypeAppearanceConfig.cs
Normal file
77
OpenDiablo2.Common/Models/Mobs/EnemyTypeAppearanceConfig.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using OpenDiablo2.Common.Interfaces.Mobs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Models.Mobs
|
||||
{
|
||||
public class EnemyTypeAppearanceConfig : IEnemyTypeAppearanceConfig
|
||||
{
|
||||
public bool HasDeathAnimation { get; private set; }
|
||||
public bool HasNeutralAnimation { get; private set; }
|
||||
public bool HasWalkAnimation { get; private set; }
|
||||
public bool HasGetHitAnimation { get; private set; }
|
||||
public bool[] HasAttackAnimation { get; private set; } // 1-2
|
||||
public bool HasBlockAnimation { get; private set; }
|
||||
public bool HasCastAnimation { get; private set; }
|
||||
public bool[] HasSkillAnimation { get; private set; } // 1-4
|
||||
public bool HasCorpseAnimation { get; private set; }
|
||||
public bool HasKnockbackAnimation { get; private set; }
|
||||
// HasSkillSequenceAnimation skipped due to being unused
|
||||
public bool HasRunAnimation { get; private set; }
|
||||
|
||||
public bool HasLifeBar { get; private set; } // does this monster show a lifebar when you scroll over it
|
||||
public bool HasNameBar { get; private set; } // does this monster show a name when you scroll over it
|
||||
public bool CannotBeSelected { get; private set; } // if true, monster can never be highlighted
|
||||
public bool CanCorpseBeSelected { get; private set; } // if true, the corpse can be highlighted
|
||||
|
||||
public int BleedType { get; private set; } // how does this monster bleed when hit?
|
||||
// 0 = it doesn't, 1 = small blood, 2 = large blood, 3+ = random missiles from missiles.txt, the larger
|
||||
// the number, the more missiles (??? this needs to be tested...)
|
||||
public bool HasShadow { get; private set; } // does this have a shadow?
|
||||
public int LightRadius { get; private set; } // how large of a light does this emit?
|
||||
public bool HasUniqueBossColors { get; private set; } // if true, has unique colors when spawned
|
||||
// as a boss.
|
||||
public bool CompositeDeath { get; private set; } // if true, death animation uses multiple components
|
||||
// (not clear if this is just for reference or if it actually has an effect...)
|
||||
|
||||
public byte[] LightRGB { get; private set; } // 0: R, 1: G, 2: B
|
||||
|
||||
public EnemyTypeAppearanceConfig(bool HasDeathAnimation, bool HasNeutralAnimation,
|
||||
bool HasWalkAnimation, bool HasGetHitAnimation, bool HasAttack1Animation,
|
||||
bool HasAttack2Animation, bool HasBlockAnimation, bool HasCastAnimation,
|
||||
bool[] HasSkillAnimation, bool HasCorpseAnimation, bool HasKnockbackAnimation,
|
||||
bool HasRunAnimation,
|
||||
bool HasLifeBar, bool HasNameBar, bool CannotBeSelected, bool CanCorpseBeSelected,
|
||||
int BleedType, bool HasShadow, int LightRadius, bool HasUniqueBossColors, bool CompositeDeath,
|
||||
byte[] LightRGB)
|
||||
{
|
||||
this.HasDeathAnimation = HasDeathAnimation;
|
||||
this.HasNeutralAnimation = HasNeutralAnimation;
|
||||
this.HasWalkAnimation = HasWalkAnimation;
|
||||
this.HasGetHitAnimation = HasGetHitAnimation;
|
||||
this.HasAttackAnimation = new bool[] { HasAttack1Animation, HasAttack2Animation };
|
||||
this.HasBlockAnimation = HasBlockAnimation;
|
||||
this.HasCastAnimation = HasCastAnimation;
|
||||
this.HasSkillAnimation = HasSkillAnimation;
|
||||
this.HasCorpseAnimation = HasCorpseAnimation;
|
||||
this.HasKnockbackAnimation = HasKnockbackAnimation;
|
||||
this.HasRunAnimation = HasRunAnimation;
|
||||
|
||||
this.HasLifeBar = HasLifeBar;
|
||||
this.HasNameBar = HasNameBar;
|
||||
this.CannotBeSelected = CannotBeSelected;
|
||||
this.CanCorpseBeSelected = CanCorpseBeSelected;
|
||||
|
||||
this.BleedType = BleedType;
|
||||
this.HasShadow = HasShadow;
|
||||
this.LightRadius = LightRadius;
|
||||
this.HasUniqueBossColors = HasUniqueBossColors;
|
||||
this.CompositeDeath = CompositeDeath;
|
||||
|
||||
this.LightRGB = LightRGB;
|
||||
}
|
||||
}
|
||||
}
|
109
OpenDiablo2.Common/Models/Mobs/EnemyTypeCombatConfig.cs
Normal file
109
OpenDiablo2.Common/Models/Mobs/EnemyTypeCombatConfig.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using OpenDiablo2.Common.Enums.Mobs;
|
||||
using OpenDiablo2.Common.Interfaces.Mobs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Models.Mobs
|
||||
{
|
||||
public class EnemyTypeCombatConfig : IEnemyTypeCombatConfig
|
||||
{
|
||||
public int ElementalAttackMode { get; private set; } // 4 = on hit, rest are unknown?
|
||||
public eDamageTypes ElementalAttackType { get; private set; } // 1=fire, 2=lightning, 4=cold, 5=poison
|
||||
public int ElementalOverlayId { get; private set; } // see overlays.txt, corresponds to a row number -2
|
||||
public int ElementalChance { get; private set; } // chance of use on a normal attack, 0 = never 100 = always
|
||||
public int ElementalMinDamage { get; private set; }
|
||||
public int ElementalMaxDamage { get; private set; }
|
||||
public int ElementalDuration { get; private set; } // duration of effects like cold and poison
|
||||
|
||||
// TODO: these could be switched to SHORTS, is there any benefit to that?
|
||||
public int[] MissileForAttack { get; private set; } // 1-2, which missile is used per attack
|
||||
// important note: 65535 = NONE. See missiles.txt, corresponds to a row number -2
|
||||
public int[] MissileForSkill { get; private set; } // 1-4, which missile is used for a skill
|
||||
// important note: 65535 = NONE. See missiles.txt, corresponds to a row number -2
|
||||
public int MissileForCase { get; private set; } // see above, specifies a missile for Case
|
||||
public int MissileForSequence { get; private set; } // see above, specifies a missile for Sequence
|
||||
|
||||
public bool[] CanMoveAttack { get; private set; } // 1-2, can move while using attack 1 / 2
|
||||
public bool[] CanMoveSkill { get; private set; } // 1-4, can move while using skill 1/2/3/4
|
||||
public bool CanMoveCast { get; private set; } // can move while casting?
|
||||
|
||||
public bool IsMelee { get; private set; } // is this a melee attacker?
|
||||
public bool IsAttackable { get; private set; } // is this monster attackable?
|
||||
|
||||
public int MeleeRange { get; private set; }
|
||||
|
||||
public int[] SkillType { get; private set; } // 1-5, what type of skill is it? 0 = none
|
||||
public int[] SkillSequence { get; private set; } // 1-5 animation sequence number
|
||||
// should not be 0 if skill is not 0; see animation column in skills.txt
|
||||
public int[] SkillLevel { get; private set; } // 1-5, level of the skill
|
||||
|
||||
public bool IsUndeadWithPhysicalAttacks { get; private set; } // if true, is an undead attacking with physical attacks
|
||||
public bool IsUndeadWithMagicAttacks { get; private set; } // if true '' magic atttacks
|
||||
public bool UsesMagicAttacks { get; private set; }
|
||||
|
||||
public int ChanceToBlock { get; private set; }
|
||||
|
||||
public bool DoesDeathDamage { get; private set; } // if true, does damage when it dies
|
||||
// like undead flayers (TODO: understand exactly how this works)
|
||||
|
||||
public bool IgnoredBySummons { get; private set; } // if true, is ignored by summons in combat
|
||||
|
||||
// (87) A1Move A2Move S1Move S2Move S3Move S4Move Cmove
|
||||
// (109) Skill1 Skill1Seq Skill1Lvl Skill2 Skill2Seq Skill2Lvl Skill3 Skill3Seq Skill3Lvl Skill4 Skill4Seq Skill4Lvl Skill5 Skill5Seq Skill5Lvl
|
||||
// (146) eLUndead eHUndead eDemon eMagicUsing eLarge eSmall eFlying eOpenDoors eSpawnCol eBoss
|
||||
|
||||
|
||||
public EnemyTypeCombatConfig(int ElementalAttackMode, eDamageTypes ElementalAttackType, int ElementalOverlayId,
|
||||
int ElementalChance, int ElementalMinDamage, int ElementalMaxDamage, int ElementalDuration,
|
||||
int[] MissileForAttack, int[] MissileForSkill, int MissileForCase, int MissileForSequence,
|
||||
bool[] CanMoveAttack, bool[] CanMoveSkill, bool CanMoveCast,
|
||||
bool IsMelee, bool IsAttackable,
|
||||
int MeleeRange,
|
||||
int[] SkillType, int[] SkillSequence, int[] SkillLevel,
|
||||
bool IsUndeadWithPhysicalAttacks, bool IsUndeadWithMagicAttacks, bool UsesMagicAttacks,
|
||||
int ChanceToBlock,
|
||||
bool DoesDeathDamage,
|
||||
bool IgnoredBySummons
|
||||
)
|
||||
{
|
||||
this.ElementalAttackMode = ElementalAttackMode;
|
||||
this.ElementalAttackType = ElementalAttackType;
|
||||
this.ElementalOverlayId = ElementalOverlayId;
|
||||
this.ElementalChance = ElementalChance;
|
||||
this.ElementalMinDamage = ElementalMinDamage;
|
||||
this.ElementalMaxDamage = ElementalMaxDamage;
|
||||
this.ElementalDuration = ElementalDuration;
|
||||
|
||||
this.MissileForAttack = MissileForAttack;
|
||||
this.MissileForSkill = MissileForSkill;
|
||||
this.MissileForCase = MissileForCase;
|
||||
this.MissileForSequence = MissileForSequence;
|
||||
|
||||
this.CanMoveAttack = CanMoveAttack;
|
||||
this.CanMoveSkill = CanMoveSkill;
|
||||
this.CanMoveCast = CanMoveCast;
|
||||
|
||||
this.IsMelee = IsMelee;
|
||||
this.IsAttackable = IsAttackable;
|
||||
|
||||
this.MeleeRange = MeleeRange;
|
||||
|
||||
this.SkillType = SkillType;
|
||||
this.SkillSequence = SkillSequence;
|
||||
this.SkillLevel = SkillLevel;
|
||||
|
||||
this.IsUndeadWithPhysicalAttacks = IsUndeadWithPhysicalAttacks;
|
||||
this.IsUndeadWithMagicAttacks = IsUndeadWithMagicAttacks;
|
||||
this.UsesMagicAttacks = UsesMagicAttacks;
|
||||
|
||||
this.ChanceToBlock = ChanceToBlock;
|
||||
|
||||
this.DoesDeathDamage = DoesDeathDamage;
|
||||
|
||||
this.IgnoredBySummons = IgnoredBySummons;
|
||||
}
|
||||
}
|
||||
}
|
586
OpenDiablo2.Common/Models/Mobs/EnemyTypeConfig.cs
Normal file
586
OpenDiablo2.Common/Models/Mobs/EnemyTypeConfig.cs
Normal file
@ -0,0 +1,586 @@
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Enums.Mobs;
|
||||
using OpenDiablo2.Common.Interfaces.Mobs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Models.Mobs
|
||||
{
|
||||
public class EnemyTypeConfig : IEnemyTypeConfig
|
||||
{
|
||||
public string InternalName { get; private set; }
|
||||
public string DisplayName { get; private set; }
|
||||
public string Type { get; private set; }
|
||||
public string Descriptor { get; private set; }
|
||||
|
||||
public int BaseId { get; private set; }
|
||||
public int PopulateId { get; private set; }
|
||||
public bool Spawned { get; private set; }
|
||||
public bool Beta { get; private set; }
|
||||
public string Code { get; private set; }
|
||||
public bool ClientOnly { get; private set; }
|
||||
public bool NoMap { get; private set; }
|
||||
|
||||
public int SizeX { get; private set; }
|
||||
public int SizeY { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public bool NoOverlays { get; private set; }
|
||||
public int OverlayHeight { get; private set; }
|
||||
|
||||
public int Velocity { get; private set; }
|
||||
public int RunVelocity { get; private set; }
|
||||
|
||||
public bool CanStealFrom { get; private set; }
|
||||
public int ColdEffect { get; private set; }
|
||||
|
||||
public bool Rarity { get; private set; }
|
||||
|
||||
public int MinimumGrouping { get; private set; }
|
||||
public int MaximumGrouping { get; private set; }
|
||||
|
||||
public string BaseWeapon { get; private set; }
|
||||
|
||||
public int[] AIParams { get; private set; } // up to 5
|
||||
|
||||
public bool Allied { get; private set; } // Is this enemy on the player's side?
|
||||
public bool IsNPC { get; private set; } // is this an NPC?
|
||||
public bool IsCritter { get; private set; } // is this a critter? (e.g. the chickens)
|
||||
public bool CanEnterTown { get; private set; } // can this enter town or not?
|
||||
|
||||
public int HealthRegen { get; private set; } // hp regen per minute
|
||||
|
||||
public bool IsDemon { get; private set; } // demon?
|
||||
public bool IsLarge { get; private set; } // size large (e.g. bosses)
|
||||
public bool IsSmall { get; private set; } // size small (e.g. fallen)
|
||||
public bool IsFlying { get; private set; } // can move over water for instance
|
||||
public bool CanOpenDoors { get; private set; }
|
||||
public int SpawningColumn { get; private set; } // is the monster area restricted
|
||||
// 0 = no, spawns through levels.txt, 1-3 unknown?
|
||||
// TODO: understand spawningcolumn
|
||||
public bool IsBoss { get; private set; }
|
||||
public bool IsInteractable { get; private set; } // can this be interacted with? like an NPC
|
||||
|
||||
public bool IsKillable { get; private set; }
|
||||
public bool CanBeConverted { get; private set; } // if true, can be switched to Allied by spells like Conversion
|
||||
|
||||
public int HitClass { get; private set; } // TODO: find out what this is
|
||||
|
||||
public bool HasSpecialEndDeath { get; private set; } // marks if a monster dies a special death
|
||||
public bool DeadCollision { get; private set; } // if true, corpse has collision
|
||||
|
||||
public bool CanBeRevivedByOtherMonsters { get; private set; }
|
||||
|
||||
// appearance config
|
||||
public IEnemyTypeAppearanceConfig AppearanceConfig { get; private set; }
|
||||
|
||||
// combat config
|
||||
public IEnemyTypeCombatConfig CombatConfig { get; private set; }
|
||||
|
||||
// difficulty configs
|
||||
public IEnemyTypeDifficultyConfig NormalDifficultyConfig { get; private set; }
|
||||
public IEnemyTypeDifficultyConfig NightmareDifficultyConfig { get; private set; }
|
||||
public IEnemyTypeDifficultyConfig HellDifficultyConfig { get; private set; }
|
||||
|
||||
public EnemyTypeConfig(string InternalName, string Name, string Type, string Descriptor,
|
||||
int BaseId, int PopulateId, bool Spawned, bool Beta, string Code, bool ClientOnly, bool NoMap,
|
||||
int SizeX, int SizeY, int Height, bool NoOverlays, int OverlayHeight,
|
||||
int Velocity, int RunVelocity,
|
||||
bool CanStealFrom, int ColdEffect,
|
||||
bool Rarity,
|
||||
int MinimumGrouping, int MaximumGrouping,
|
||||
string BaseWeapon,
|
||||
int[] AIParams,
|
||||
bool Allied, bool IsNPC, bool IsCritter, bool CanEnterTown,
|
||||
int HealthRegen,
|
||||
bool IsDemon, bool IsLarge, bool IsSmall, bool IsFlying, bool CanOpenDoors, int SpawningColumn,
|
||||
bool IsBoss, bool IsInteractable,
|
||||
bool IsKillable, bool CanBeConverted,
|
||||
int HitClass,
|
||||
bool HasSpecialEndDeath, bool DeadCollision,
|
||||
bool CanBeRevivedByOtherMonsters,
|
||||
IEnemyTypeAppearanceConfig AppearanceConfig,
|
||||
IEnemyTypeCombatConfig CombatConfig,
|
||||
IEnemyTypeDifficultyConfig NormalDifficultyConfig,
|
||||
IEnemyTypeDifficultyConfig NightmareDifficultyConfig,
|
||||
IEnemyTypeDifficultyConfig HellDifficultyConfig)
|
||||
{
|
||||
this.InternalName = InternalName;
|
||||
this.DisplayName = Name;
|
||||
this.Type = Type;
|
||||
this.Descriptor = Descriptor;
|
||||
|
||||
this.BaseId = BaseId;
|
||||
this.PopulateId = PopulateId;
|
||||
this.Spawned = Spawned;
|
||||
this.Beta = Beta;
|
||||
this.Code = Code;
|
||||
this.ClientOnly = ClientOnly;
|
||||
this.NoMap = NoMap;
|
||||
|
||||
this.SizeX = SizeX;
|
||||
this.SizeY = SizeY;
|
||||
this.Height = Height;
|
||||
this.NoOverlays = NoOverlays;
|
||||
this.OverlayHeight = OverlayHeight;
|
||||
|
||||
this.Velocity = Velocity;
|
||||
this.RunVelocity = RunVelocity;
|
||||
|
||||
this.CanStealFrom = CanStealFrom;
|
||||
this.ColdEffect = ColdEffect;
|
||||
|
||||
this.Rarity = Rarity;
|
||||
|
||||
this.MinimumGrouping = MinimumGrouping;
|
||||
this.MaximumGrouping = MaximumGrouping;
|
||||
|
||||
this.BaseWeapon = BaseWeapon;
|
||||
|
||||
this.AIParams = AIParams;
|
||||
|
||||
this.Allied = Allied;
|
||||
this.IsNPC = IsNPC;
|
||||
this.IsCritter = IsCritter;
|
||||
this.CanEnterTown = CanEnterTown;
|
||||
|
||||
this.HealthRegen = HealthRegen;
|
||||
|
||||
this.IsDemon = IsDemon;
|
||||
this.IsLarge = IsLarge;
|
||||
this.IsSmall = IsSmall;
|
||||
this.IsFlying = IsFlying;
|
||||
this.CanOpenDoors = CanOpenDoors;
|
||||
this.SpawningColumn = SpawningColumn;
|
||||
this.IsBoss = IsBoss;
|
||||
this.IsInteractable = IsInteractable;
|
||||
|
||||
this.IsKillable = IsKillable;
|
||||
this.CanBeConverted = CanBeConverted;
|
||||
|
||||
this.HitClass = HitClass;
|
||||
|
||||
this.HasSpecialEndDeath = HasSpecialEndDeath;
|
||||
this.DeadCollision = DeadCollision;
|
||||
|
||||
this.CanBeRevivedByOtherMonsters = CanBeRevivedByOtherMonsters;
|
||||
|
||||
this.AppearanceConfig = AppearanceConfig;
|
||||
|
||||
this.CombatConfig = CombatConfig;
|
||||
|
||||
this.NormalDifficultyConfig = NormalDifficultyConfig;
|
||||
this.NightmareDifficultyConfig = NightmareDifficultyConfig;
|
||||
this.HellDifficultyConfig = HellDifficultyConfig;
|
||||
}
|
||||
|
||||
public IEnemyTypeDifficultyConfig GetDifficultyConfig(eDifficulty Difficulty)
|
||||
{
|
||||
switch (Difficulty)
|
||||
{
|
||||
case eDifficulty.HELL:
|
||||
return HellDifficultyConfig;
|
||||
case eDifficulty.NIGHTMARE:
|
||||
return NightmareDifficultyConfig;
|
||||
case eDifficulty.NORMAL:
|
||||
return NormalDifficultyConfig;
|
||||
default:
|
||||
return NormalDifficultyConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class EnemyTypeConfigHelper
|
||||
{
|
||||
|
||||
// (0) Class namco Type Descriptor
|
||||
// (4) BaseId PopulateId Spawned Beta Code ClientOnly NoMap
|
||||
// (11) SizeX SizeY Height
|
||||
// (14) NoOverlays OverlayHeight
|
||||
// (16) Velocity Run
|
||||
// (18) CanStealFrom ColdEffect
|
||||
// (20) Rarity Level Level(N) Level(H)
|
||||
// (24) MeleeRng MinGrp MaxGrp
|
||||
// (27) HD TR LG RA LA RH LH SH S1 S2 S3 S4 S5 S6 S7 S8
|
||||
// (43) TotalPieces SpawnComponents BaseW
|
||||
// (46) AIParam1 Comment AIParam2 Comment AIParam3 Comment AIParam4 Comment AIParam5 Comment
|
||||
// (56) ModeDH ModeN ModeW ModeGH ModeA1 ModeA2 ModeB ModeC
|
||||
// (64) ModeS1 ModeS2 ModeS3 ModeS4 ModeDD ModeKB ModeSQ ModeRN
|
||||
// (72) ElMode ElType ElOver ElPct ElMinD ElMaxD ElDur
|
||||
// (79) MissA1 MissA2 MissS1 MissS2 MissS3 MissS4 MissC MissSQ
|
||||
// (87) A1Move A2Move S1Move S2Move S3Move S4Move Cmove
|
||||
// (94) Align
|
||||
// (95) IsMelee IsSel IsSel2 NeverSel CorpseSel IsAtt IsNPC IsCritter InTown
|
||||
// (104) Bleed Shadow Light NoUniqueShift CompositeDeath
|
||||
// (109) Skill1 Skill1Seq Skill1Lvl Skill2 Skill2Seq Skill2Lvl Skill3 Skill3Seq Skill3Lvl Skill4 Skill4Seq Skill4Lvl Skill5 Skill5Seq Skill5Lvl
|
||||
// (124) LightR LightG LightB
|
||||
// (127) DamageResist MagicResist FireResist LightResist ColdResist PoisonResist
|
||||
// (133) DamageResist(N) MagicResist(N) FireResist(N) LightResist(N) ColdResist(N) PoisonResist(N)
|
||||
// (139) DamageResist(H) MagicResist(H) FireResist(H) LightResist(H) ColdResist(H) PoisonResist(H)
|
||||
// (145) DamageRegen
|
||||
// (146) eLUndead eHUndead eDemon eMagicUsing eLarge eSmall eFlying eOpenDoors eSpawnCol eBoss
|
||||
// (156) PixHeight Interact
|
||||
// (158) MinHP MaxHP AC Exp ToBlock
|
||||
// (163) A1MinD A1MaxD A1ToHit A2MinD A2MaxD A2ToHit S1MinD S1MaxD S1ToHit
|
||||
|
||||
|
||||
// (172) MinHP(N) MaxHP(N) AC(N) Exp(N) A1MinD(N) A1MaxD(N) A1ToHit(N) A2MinD(N) A2MaxD(N) A2ToHit(N) S1MinD(N) S1MaxD(N) S1ToHit(N)
|
||||
// (185) MinHP(H) MaxHP(H) AC(H) Exp(H) A1MinD(H) A1MaxD(H) A1ToHit(H) A2MinD(H) A2MaxD(H) A2ToHit(H) S1MinD(H) S1MaxD(H) S1ToHit(H)
|
||||
// (198) TreasureClass1 TreasureClass2 TreasureClass3 TreasureClass4
|
||||
// (202) TreasureClass1(N) TreasureClass2(N) TreasureClass3(N) TreasureClass4(N)
|
||||
// (206) TreasureClass1(H) TreasureClass2(H) TreasureClass3(H) TreasureClass4(H)
|
||||
// (210) SpawnPctBonus Soft Heart BodyPart Killable Switch Restore NeverCount HitClass
|
||||
// (219) SplEndDeath SplGetModeChart SplEndGeneric SplClientEnd
|
||||
// (223) DeadCollision UnflatDead BloodLocal DeathDamage
|
||||
// (227) PetIgnore NoGfxHitTest
|
||||
// (229) HitTestTop HitTestLeft HitTestWidth HitTestHeight
|
||||
// (233) GenericSpawn AutomapCel SparsePopulate Zoo ObjectCollision Inert
|
||||
private static int IntConvert(string s)
|
||||
{
|
||||
// this is a convenience because sometimes they forget to put a 0 in the D2 monstats.txt
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return Convert.ToInt32(s);
|
||||
}
|
||||
|
||||
public static IEnemyTypeConfig ToEnemyTypeConfig(this string[] row)
|
||||
{
|
||||
return new EnemyTypeConfig(
|
||||
InternalName: row[0],
|
||||
Name: row[1],
|
||||
Type: row[2],
|
||||
Descriptor: row[3],
|
||||
|
||||
BaseId: IntConvert(row[4]),
|
||||
PopulateId: IntConvert(row[5]),
|
||||
Spawned: (row[6] == "1"),
|
||||
Beta: (row[7] == "1"),
|
||||
Code: row[8],
|
||||
ClientOnly: (row[9] == "1"),
|
||||
NoMap: (row[10] == "1"),
|
||||
|
||||
SizeX: IntConvert(row[11]),
|
||||
SizeY: IntConvert(row[12]),
|
||||
Height: IntConvert(row[13]),
|
||||
NoOverlays: (row[14] == "1"),
|
||||
OverlayHeight: IntConvert(row[15]),
|
||||
|
||||
Velocity: IntConvert(row[16]),
|
||||
RunVelocity: IntConvert(row[17]),
|
||||
|
||||
CanStealFrom: (row[18] == "1"),
|
||||
ColdEffect: IntConvert(row[19]),
|
||||
|
||||
Rarity: (row[20] == "1"),
|
||||
|
||||
|
||||
MinimumGrouping: IntConvert(row[25]),
|
||||
MaximumGrouping: IntConvert(row[26]),
|
||||
|
||||
BaseWeapon: row[45],
|
||||
|
||||
AIParams: new int[]
|
||||
{
|
||||
IntConvert(row[46]),
|
||||
IntConvert(row[48]),
|
||||
IntConvert(row[50]),
|
||||
IntConvert(row[52]),
|
||||
IntConvert(row[54])
|
||||
},
|
||||
|
||||
Allied: (row[94] == "1"),
|
||||
IsNPC: (row[101] == "1"),
|
||||
IsCritter: (row[102] == "1"),
|
||||
CanEnterTown: (row[103] == "1"),
|
||||
|
||||
HealthRegen: IntConvert(row[145]),
|
||||
|
||||
// (146) eLUndead eHUndead eDemon eMagicUsing eLarge eSmall eFlying eOpenDoors eSpawnCol eBoss
|
||||
IsDemon: (row[148] == "1"),
|
||||
IsLarge: (row[150] == "1"),
|
||||
IsSmall: (row[151] == "1"),
|
||||
IsFlying: (row[152] == "1"),
|
||||
CanOpenDoors: (row[153] == "1"),
|
||||
SpawningColumn: IntConvert(row[154]),
|
||||
IsBoss: (row[155] == "1"),
|
||||
IsInteractable: (row[157] == "1"),
|
||||
|
||||
IsKillable: (row[215] == "1"),
|
||||
CanBeConverted: (row[216] == "1"),
|
||||
|
||||
HitClass: IntConvert(row[218]),
|
||||
|
||||
HasSpecialEndDeath: (row[219] == "1"),
|
||||
DeadCollision: (row[223] == "1"),
|
||||
|
||||
CanBeRevivedByOtherMonsters: (row[236] == "1"),
|
||||
|
||||
// (56) ModeDH ModeN ModeW ModeGH ModeA1 ModeA2 ModeB ModeC
|
||||
// (64) ModeS1 ModeS2 ModeS3 ModeS4 ModeDD ModeKB ModeSQ ModeRN
|
||||
// (95) IsMelee IsSel IsSel2 NeverSel CorpseSel IsAtt IsNPC IsCritter InTown
|
||||
// (104) Bleed Shadow Light NoUniqueShift CompositeDeath
|
||||
// (124) LightR LightG LightB
|
||||
AppearanceConfig: new EnemyTypeAppearanceConfig
|
||||
(
|
||||
HasDeathAnimation: (row[56] == "1"),
|
||||
HasNeutralAnimation: (row[57] == "1"),
|
||||
HasWalkAnimation: (row[58] == "1"),
|
||||
HasGetHitAnimation: (row[59] == "1"),
|
||||
HasAttack1Animation: (row[60] == "1"),
|
||||
HasAttack2Animation: (row[61] == "1"),
|
||||
HasBlockAnimation: (row[62] == "1"),
|
||||
HasCastAnimation: (row[63] == "1"),
|
||||
HasSkillAnimation: new bool[]
|
||||
{
|
||||
(row[64] == "1"),
|
||||
(row[65] == "1"),
|
||||
(row[66] == "1"),
|
||||
(row[67] == "1")
|
||||
},
|
||||
HasCorpseAnimation: (row[68] == "1"),
|
||||
HasKnockbackAnimation: (row[69] == "1"),
|
||||
HasRunAnimation: (row[71] == "1"),
|
||||
|
||||
HasLifeBar: (row[96] == "1"),
|
||||
HasNameBar: (row[97] == "1"),
|
||||
CannotBeSelected: (row[98] == "1"),
|
||||
CanCorpseBeSelected: (row[99] == "1"),
|
||||
|
||||
BleedType: IntConvert(row[104]),
|
||||
HasShadow: (row[105] == "1"),
|
||||
LightRadius: IntConvert(row[106]),
|
||||
HasUniqueBossColors: (row[107] == "0"), // note: inverting the bool here
|
||||
// since in the table it is "NoUniqueShift" but I want to store it as "HasUniqueShift"
|
||||
CompositeDeath: (row[108] == "1"),
|
||||
|
||||
LightRGB: new byte[]
|
||||
{
|
||||
Convert.ToByte(row[124]),
|
||||
Convert.ToByte(row[125]),
|
||||
Convert.ToByte(row[126])
|
||||
}
|
||||
),
|
||||
|
||||
// (72) ElMode ElType ElOver ElPct ElMinD ElMaxD ElDur
|
||||
// (79) MissA1 MissA2 MissS1 MissS2 MissS3 MissS4 MissC MissSQ
|
||||
// (87) A1Move A2Move S1Move S2Move S3Move S4Move Cmove
|
||||
// (95) IsMelee IsSel IsSel2 NeverSel CorpseSel IsAtt IsNPC IsCritter InTown
|
||||
// (109) Skill1 Skill1Seq Skill1Lvl Skill2 Skill2Seq Skill2Lvl Skill3 Skill3Seq Skill3Lvl Skill4 Skill4Seq Skill4Lvl Skill5 Skill5Seq Skill5Lvl
|
||||
CombatConfig: new EnemyTypeCombatConfig
|
||||
(
|
||||
ElementalAttackMode: IntConvert(row[72]),
|
||||
ElementalAttackType: (eDamageTypes)IntConvert(row[73]),
|
||||
ElementalOverlayId: IntConvert(row[74]),
|
||||
ElementalChance: IntConvert(row[75]),
|
||||
ElementalMinDamage: IntConvert(row[76]),
|
||||
ElementalMaxDamage: IntConvert(row[77]),
|
||||
ElementalDuration: IntConvert(row[78]),
|
||||
|
||||
MissileForAttack: new int[]
|
||||
{
|
||||
IntConvert(row[79]),
|
||||
IntConvert(row[80])
|
||||
},
|
||||
MissileForSkill: new int[]
|
||||
{
|
||||
IntConvert(row[81]),
|
||||
IntConvert(row[82]),
|
||||
IntConvert(row[83]),
|
||||
IntConvert(row[84])
|
||||
},
|
||||
MissileForCase: IntConvert(row[85]),
|
||||
MissileForSequence: IntConvert(row[86]),
|
||||
|
||||
CanMoveAttack: new bool[]
|
||||
{
|
||||
(row[87] == "1"),
|
||||
(row[88] == "1")
|
||||
},
|
||||
CanMoveSkill: new bool[]
|
||||
{
|
||||
(row[89] == "1"),
|
||||
(row[90] == "1"),
|
||||
(row[91] == "1"),
|
||||
(row[92] == "1")
|
||||
},
|
||||
CanMoveCast: (row[93] == "1"),
|
||||
|
||||
IsMelee: (row[95] == "1"),
|
||||
IsAttackable: (row[100] == "1"),
|
||||
|
||||
MeleeRange: IntConvert(row[24]),
|
||||
|
||||
SkillType: new int[]
|
||||
{
|
||||
IntConvert(row[109]),
|
||||
IntConvert(row[112]),
|
||||
IntConvert(row[115]),
|
||||
IntConvert(row[118]),
|
||||
IntConvert(row[121]),
|
||||
},
|
||||
SkillSequence: new int[]
|
||||
{
|
||||
IntConvert(row[110]),
|
||||
IntConvert(row[113]),
|
||||
IntConvert(row[116]),
|
||||
IntConvert(row[119]),
|
||||
IntConvert(row[122]),
|
||||
},
|
||||
SkillLevel: new int[]
|
||||
{
|
||||
IntConvert(row[111]),
|
||||
IntConvert(row[114]),
|
||||
IntConvert(row[117]),
|
||||
IntConvert(row[120]),
|
||||
IntConvert(row[123]),
|
||||
},
|
||||
|
||||
IsUndeadWithPhysicalAttacks: (row[146] == "1"),
|
||||
IsUndeadWithMagicAttacks: (row[147] == "1"),
|
||||
UsesMagicAttacks: (row[149] == "1"),
|
||||
|
||||
ChanceToBlock: IntConvert(row[162]),
|
||||
|
||||
DoesDeathDamage: (row[226] == "1"),
|
||||
|
||||
IgnoredBySummons: (row[227] == "1")
|
||||
),
|
||||
|
||||
// (127) DamageResist MagicResist FireResist LightResist ColdResist PoisonResist
|
||||
// (133) DamageResist(N) MagicResist(N) FireResist(N) LightResist(N) ColdResist(N) PoisonResist(N)
|
||||
// (139) DamageResist(H) MagicResist(H) FireResist(H) LightResist(H) ColdResist(H) PoisonResist(H)
|
||||
// (158) MinHP MaxHP AC Exp ToBlock
|
||||
// (163) A1MinD A1MaxD A1ToHit A2MinD A2MaxD A2ToHit S1MinD S1MaxD S1ToHit
|
||||
// (172) MinHP(N) MaxHP(N) AC(N) Exp(N) A1MinD(N) A1MaxD(N) A1ToHit(N) A2MinD(N) A2MaxD(N) A2ToHit(N) S1MinD(N) S1MaxD(N) S1ToHit(N)
|
||||
// (185) MinHP(H) MaxHP(H) AC(H) Exp(H) A1MinD(H) A1MaxD(H) A1ToHit(H) A2MinD(H) A2MaxD(H) A2ToHit(H) S1MinD(H) S1MaxD(H) S1ToHit(H)
|
||||
// (192) TreasureClass1 TreasureClass2 TreasureClass3 TreasureClass4
|
||||
// (202) TreasureClass1(N) TreasureClass2(N) TreasureClass3(N) TreasureClass4(N)
|
||||
// (206) TreasureClass1(H) TreasureClass2(H) TreasureClass3(H) TreasureClass4(H)
|
||||
NormalDifficultyConfig: new EnemyTypeDifficultyConfig
|
||||
(
|
||||
Level: IntConvert(row[21]),
|
||||
|
||||
DamageResist: (IntConvert(row[127]) / 100.0),
|
||||
MagicResist: (IntConvert(row[128]) / 100.0),
|
||||
FireResist: (IntConvert(row[129]) / 100.0),
|
||||
LightResist: (IntConvert(row[130]) / 100.0),
|
||||
ColdResist: (IntConvert(row[131]) / 100.0),
|
||||
PoisonResist: (IntConvert(row[132]) / 100.0),
|
||||
|
||||
MinHP: IntConvert(row[158]),
|
||||
MaxHP: IntConvert(row[159]),
|
||||
AC: IntConvert(row[160]),
|
||||
Exp: IntConvert(row[161]),
|
||||
|
||||
AttackMinDamage: new int[]
|
||||
{
|
||||
IntConvert(row[163]),
|
||||
IntConvert(row[166])
|
||||
},
|
||||
AttackMaxDamage: new int[]
|
||||
{
|
||||
IntConvert(row[164]),
|
||||
IntConvert(row[167])
|
||||
},
|
||||
AttackChanceToHit: new int[]
|
||||
{
|
||||
IntConvert(row[165]),
|
||||
IntConvert(row[168])
|
||||
},
|
||||
Skill1MinDamage: IntConvert(row[169]),
|
||||
Skill1MaxDamage: IntConvert(row[170]),
|
||||
Skill1ChanceToHit: IntConvert(row[171]),
|
||||
|
||||
TreasureClass: new string[]
|
||||
{
|
||||
row[198], row[199], row[200], row[201]
|
||||
}
|
||||
),
|
||||
NightmareDifficultyConfig: new EnemyTypeDifficultyConfig
|
||||
(
|
||||
Level: IntConvert(row[22]),
|
||||
|
||||
DamageResist: (IntConvert(row[133]) / 100.0),
|
||||
MagicResist: (IntConvert(row[134]) / 100.0),
|
||||
FireResist: (IntConvert(row[135]) / 100.0),
|
||||
LightResist: (IntConvert(row[136]) / 100.0),
|
||||
ColdResist: (IntConvert(row[137]) / 100.0),
|
||||
PoisonResist: (IntConvert(row[138]) / 100.0),
|
||||
|
||||
MinHP: IntConvert(row[172]),
|
||||
MaxHP: IntConvert(row[173]),
|
||||
AC: IntConvert(row[174]),
|
||||
Exp: IntConvert(row[175]),
|
||||
|
||||
AttackMinDamage: new int[]
|
||||
{
|
||||
IntConvert(row[176]),
|
||||
IntConvert(row[179])
|
||||
},
|
||||
AttackMaxDamage: new int[]
|
||||
{
|
||||
IntConvert(row[177]),
|
||||
IntConvert(row[180])
|
||||
},
|
||||
AttackChanceToHit: new int[]
|
||||
{
|
||||
IntConvert(row[178]),
|
||||
IntConvert(row[181])
|
||||
},
|
||||
Skill1MinDamage: IntConvert(row[182]),
|
||||
Skill1MaxDamage: IntConvert(row[183]),
|
||||
Skill1ChanceToHit: IntConvert(row[184]),
|
||||
|
||||
TreasureClass: new string[]
|
||||
{
|
||||
row[202], row[203], row[204], row[205]
|
||||
}
|
||||
),
|
||||
HellDifficultyConfig: new EnemyTypeDifficultyConfig
|
||||
(
|
||||
Level: IntConvert(row[23]),
|
||||
|
||||
DamageResist: (IntConvert(row[139]) / 100.0),
|
||||
MagicResist: (IntConvert(row[140]) / 100.0),
|
||||
FireResist: (IntConvert(row[141]) / 100.0),
|
||||
LightResist: (IntConvert(row[142]) / 100.0),
|
||||
ColdResist: (IntConvert(row[143]) / 100.0),
|
||||
PoisonResist: (IntConvert(row[144]) / 100.0),
|
||||
|
||||
MinHP: IntConvert(row[185]),
|
||||
MaxHP: IntConvert(row[186]),
|
||||
AC: IntConvert(row[187]),
|
||||
Exp: IntConvert(row[188]),
|
||||
|
||||
AttackMinDamage: new int[]
|
||||
{
|
||||
IntConvert(row[189]),
|
||||
IntConvert(row[192])
|
||||
},
|
||||
AttackMaxDamage: new int[]
|
||||
{
|
||||
IntConvert(row[190]),
|
||||
IntConvert(row[193])
|
||||
},
|
||||
AttackChanceToHit: new int[]
|
||||
{
|
||||
IntConvert(row[191]),
|
||||
IntConvert(row[194])
|
||||
},
|
||||
Skill1MinDamage: IntConvert(row[195]),
|
||||
Skill1MaxDamage: IntConvert(row[196]),
|
||||
Skill1ChanceToHit: IntConvert(row[197]),
|
||||
|
||||
TreasureClass: new string[]
|
||||
{
|
||||
row[206], row[207], row[208], row[209]
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
68
OpenDiablo2.Common/Models/Mobs/EnemyTypeDifficultyConfig.cs
Normal file
68
OpenDiablo2.Common/Models/Mobs/EnemyTypeDifficultyConfig.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using OpenDiablo2.Common.Interfaces.Mobs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenDiablo2.Common.Models.Mobs
|
||||
{
|
||||
public class EnemyTypeDifficultyConfig : IEnemyTypeDifficultyConfig
|
||||
{
|
||||
|
||||
public int Level { get; private set; }
|
||||
|
||||
public double DamageResist { get; private set; }
|
||||
public double MagicResist { get; private set; }
|
||||
public double FireResist { get; private set; }
|
||||
public double LightningResist { get; private set; }
|
||||
public double ColdResist { get; private set; }
|
||||
public double PoisonResist { get; private set; }
|
||||
|
||||
public int MinHP { get; private set; }
|
||||
public int MaxHP { get; private set; }
|
||||
public int AC { get; private set; } // armor class
|
||||
public int Exp { get; private set; }
|
||||
|
||||
public int[] AttackMinDamage { get; private set; } // 1-2, min damage attack can roll
|
||||
public int[] AttackMaxDamage { get; private set; } // 1-2 max damage attack can roll
|
||||
public int[] AttackChanceToHit { get; private set; } // 1-2 chance attack has to hit (out of 100??)
|
||||
public int Skill1MinDamage { get; private set; } // min damage skill 1 can do (why only skill 1?)
|
||||
public int Skill1MaxDamage { get; private set; } // max damage for skill 1
|
||||
public int Skill1ChanceToHit { get; private set; } // chance skill has to hit
|
||||
|
||||
public string[] TreasureClass { get; private set; } // 1-4
|
||||
|
||||
public EnemyTypeDifficultyConfig (int Level,
|
||||
double DamageResist, double MagicResist, double FireResist, double LightResist,
|
||||
double ColdResist, double PoisonResist,
|
||||
int MinHP, int MaxHP, int AC, int Exp,
|
||||
int[] AttackMinDamage, int[] AttackMaxDamage, int[] AttackChanceToHit,
|
||||
int Skill1MinDamage, int Skill1MaxDamage, int Skill1ChanceToHit,
|
||||
string[] TreasureClass)
|
||||
{
|
||||
this.Level = Level;
|
||||
|
||||
this.DamageResist = DamageResist;
|
||||
this.MagicResist = MagicResist;
|
||||
this.FireResist = FireResist;
|
||||
this.LightningResist = LightResist;
|
||||
this.ColdResist = ColdResist;
|
||||
this.PoisonResist = PoisonResist;
|
||||
|
||||
this.MinHP = MinHP;
|
||||
this.MaxHP = MaxHP;
|
||||
this.AC = AC;
|
||||
this.Exp = Exp;
|
||||
|
||||
this.AttackMinDamage = AttackMinDamage;
|
||||
this.AttackMaxDamage = AttackMaxDamage;
|
||||
this.AttackChanceToHit = AttackChanceToHit;
|
||||
this.Skill1MinDamage = Skill1MinDamage;
|
||||
this.Skill1MaxDamage = Skill1MaxDamage;
|
||||
this.Skill1ChanceToHit = Skill1ChanceToHit;
|
||||
|
||||
this.TreasureClass = TreasureClass;
|
||||
}
|
||||
}
|
||||
}
|
@ -61,6 +61,7 @@
|
||||
<Compile Include="Attributes\RandomizedMapAttribute.cs" />
|
||||
<Compile Include="Attributes\SceneAttribute.cs" />
|
||||
<Compile Include="AutofacModule.cs" />
|
||||
<Compile Include="Enums\eDifficulty.cs" />
|
||||
<Compile Include="Enums\eItemContainerType.cs" />
|
||||
<Compile Include="Enums\eAnimationFrame.cs" />
|
||||
<Compile Include="Enums\eArmorType.cs" />
|
||||
@ -98,6 +99,14 @@
|
||||
<Compile Include="Interfaces\MessageBus\IMessageFrame.cs" />
|
||||
<Compile Include="Interfaces\MessageBus\ISessionManager.cs" />
|
||||
<Compile Include="Interfaces\MessageBus\ISessionServer.cs" />
|
||||
<Compile Include="Interfaces\Mobs\IEnemyTypeAppearanceConfig.cs" />
|
||||
<Compile Include="Interfaces\Mobs\IEnemyTypeCombatConfig.cs" />
|
||||
<Compile Include="Interfaces\Mobs\IEnemyTypeConfig.cs" />
|
||||
<Compile Include="Interfaces\Mobs\IEnemyTypeDifficultyConfig.cs" />
|
||||
<Compile Include="Models\Mobs\EnemyTypeAppearanceConfig.cs" />
|
||||
<Compile Include="Models\Mobs\EnemyTypeCombatConfig.cs" />
|
||||
<Compile Include="Models\Mobs\EnemyTypeConfig.cs" />
|
||||
<Compile Include="Models\Mobs\EnemyTypeDifficultyConfig.cs" />
|
||||
<Compile Include="Interfaces\UI\IGameHUD.cs" />
|
||||
<Compile Include="Interfaces\UI\IPanel.cs" />
|
||||
<Compile Include="Models\AnimationData.cs" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
/* OpenDiablo 2 - An open source re-implementation of Diablo 2 in C#
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -219,6 +219,9 @@ namespace OpenDiablo2.Common
|
||||
public const string SFXSorceressDeselect = @"data\global\sfx\Cursor\intro\sorceress deselect.wav";
|
||||
public const string SFXSorceressSelect = @"data\global\sfx\Cursor\intro\sorceress select.wav";
|
||||
|
||||
// --- Enemy Data ---
|
||||
public static string MonStats = "data\\global\\excel\\monstats.txt";
|
||||
|
||||
public static string GeneratePathForItem(string spriteName)
|
||||
{
|
||||
return $@"data\global\items\{spriteName}.dc6";
|
||||
@ -304,3 +307,4 @@ namespace OpenDiablo2.Common
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ namespace OpenDiablo2.Core
|
||||
public ImmutableList<Item> Items { get; internal set; }
|
||||
public ImmutableDictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; internal set; }
|
||||
public ImmutableDictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; internal set; }
|
||||
public ImmutableList<IEnemyTypeConfig> EnemyTypeConfigs { get; internal set; }
|
||||
|
||||
public EngineDataManager(IMPQProvider mpqProvider)
|
||||
{
|
||||
@ -33,6 +34,7 @@ namespace OpenDiablo2.Core
|
||||
|
||||
LoadLevelDetails();
|
||||
LoadCharacterData();
|
||||
LoadEnemyData();
|
||||
|
||||
Items = LoadItemData();
|
||||
}
|
||||
@ -139,6 +141,23 @@ namespace OpenDiablo2.Core
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Split('\t'))
|
||||
.Where(x => x[0] != "Expansion")
|
||||
.ToArray()
|
||||
.ToImmutableDictionary(x => (eHero)Enum.Parse(typeof(eHero), x[0]), x => x.ToHeroTypeConfig());
|
||||
|
||||
private void LoadEnemyData()
|
||||
{
|
||||
EnemyTypeConfigs = LoadEnemyTypeConfig();
|
||||
}
|
||||
|
||||
private ImmutableList<IEnemyTypeConfig> LoadEnemyTypeConfig()
|
||||
=> mpqProvider
|
||||
.GetTextFile(ResourcePaths.MonStats)
|
||||
.Skip(1)
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Split('\t'))
|
||||
.Where(x => x[0] != "Expansion" && x[0] != "unused")
|
||||
.ToArray()
|
||||
.Select(x => x.ToEnemyTypeConfig())
|
||||
.ToImmutableList();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user