1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-16 04:25:23 +00:00

Merge branch 'master' of github.com:essial/OpenDiablo2

This commit is contained in:
Tim Sarbin 2018-12-05 22:34:19 -05:00
commit 20bacbbb14
35 changed files with 879 additions and 29 deletions

View File

@ -14,11 +14,14 @@ namespace OpenDiablo2.Common.UT
private PlayerState MakePlayer()
{
HeroTypeConfig herotypeconfig = new HeroTypeConfig(vitality: 20, strength: 20, dexterity: 20,
energy: 20, health: 50, mana: 40, stamina: 30,
energy: 20, health: 50, mana: 40, stamina: 30, manaRegen: 20,
perlevelhealth: 3, perlevelmana: 1.5, perlevelstamina: 1,
pervitalityhealth: 2, pervitalitystamina: 1, perenergymana: 1.5,
baseatkrating: -30, basedefrating: -30, perdexterityatkrating: 5, perdexteritydefrating: 4);
LevelExperienceConfig expconfig = new LevelExperienceConfig(new List<int>()
baseatkrating: -30, basedefrating: -30, perdexterityatkrating: 5, perdexteritydefrating: 4,
walkVelocity: 6, runVelocity: 9, runDrain: 20, walkFrames: 8, runFrames: 8, swingFrames: 8,
spellFrames: 8, getHitFrames: 8, bowFrames: 8, startingSkill: 0, baseWeaponClass: "hth",
itemNames: new List<string>(), itemLocs: new List<string>(), itemCounts: new List<int>());
LevelExperienceConfig expconfig = new LevelExperienceConfig(new List<long>()
{
0, // level 0
0, // level 1

View File

@ -0,0 +1,15 @@
namespace OpenDiablo2.Common.Enums
{
public enum eItemContainerType
{
Helm,
Glove,
Armor,
Belt,
Boots,
Weapon,
Amulet,
Ring,
Generic
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace OpenDiablo2.Common.Interfaces
{
public interface ICharacterPanel : IDisposable
{
void Render();
void Update();
}
}

View File

@ -1,4 +1,6 @@
using System.Collections.Generic;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces.Mobs;
using OpenDiablo2.Common.Models;
namespace OpenDiablo2.Common.Interfaces
@ -8,5 +10,8 @@ namespace OpenDiablo2.Common.Interfaces
List<LevelPreset> LevelPresets { get; }
List<LevelType> LevelTypes { get; }
List<LevelDetail> LevelDetails { get; }
List<Item> Items { get; }
Dictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; }
Dictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; }
}
}

View File

@ -22,6 +22,9 @@ namespace OpenDiablo2.Common.Interfaces
bool ToggleShowCharacterPanel();
bool ShowCharacterPanel { get; set; }
Item SelectedItem { get; }
void SelectItem(Item item);
void Initialize(string text, eHero value, eSessionType sessionType);
void Update(long ms);
IEnumerable<MapCellInfo> GetMapCellInfo(int cellX, int cellY, eRenderCellType renderCellType);

View File

@ -0,0 +1,10 @@
using System;
namespace OpenDiablo2.Common.Interfaces
{
public interface IInventoryPanel : IDisposable
{
void Render();
void Update();
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace OpenDiablo2.Common.Interfaces
{
public interface IItem
{
string Name { get; set; }
string Code { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
using OpenDiablo2.Common.Models;
namespace OpenDiablo2.Common.Interfaces
{
public interface IItemManager
{
Item getItem(string code);
}
}

View File

@ -0,0 +1,11 @@
using OpenDiablo2.Common.Enums;
using System;
namespace OpenDiablo2.Common.Interfaces
{
public interface IPanelFrame : IDisposable
{
void Render();
void Update();
}
}

View File

@ -15,6 +15,7 @@ namespace OpenDiablo2.Common.Interfaces.Mobs
int StartingHealth { get; }
int StartingMana { get; }
int StartingStamina { get; }
int StartingManaRegen { get; }
double PerLevelHealth { get; } // NOTE: these are doubles because some classes have
// e.g. 1.5 mana per level, which means they get 1 mana on even levels (e.g. -> 2)
@ -31,5 +32,23 @@ namespace OpenDiablo2.Common.Interfaces.Mobs
int BaseDefenseRating { get; }
int PerDexterityDefenseRating { get; }
int WalkVelocity { get; }
int RunVelocity { get; }
int RunDrain { get; }
int WalkFrames { get; }
int RunFrames { get; }
int SwingFrames { get; }
int SpellFrames { get; }
int GetHitFrames { get; }
int BowFrames { get; }
int StartingSkill { get; }
string BaseWeaponClass { get; }
IEnumerable<string> ItemNames { get; }
IEnumerable<string> ItemLocs { get; }
IEnumerable<int> ItemCounts { get; }
}
}

View File

@ -8,7 +8,7 @@ namespace OpenDiablo2.Common.Interfaces.Mobs
{
public interface ILevelExperienceConfig
{
int GetTotalExperienceForLevel(int level);
long GetTotalExperienceForLevel(int level);
int GetMaxLevel();
}
}

View File

@ -5,6 +5,7 @@
int MouseX { get; }
int MouseY { get; }
bool LeftMouseDown { get; }
bool LeftMousePressed { get; }
bool RightMouseDown { get; }
bool ReserveMouse { get; set; }
}

View File

@ -0,0 +1,16 @@
using OpenDiablo2.Common.Models;
using System;
using System.Drawing;
namespace OpenDiablo2.Common.Interfaces
{
public interface IItemContainer : IDisposable
{
Item ContainedItem { get; }
Point Location { get; set; }
void SetContainedItem(Item containedItem);
void Render();
void Update();
}
}

View File

@ -0,0 +1,25 @@
using OpenDiablo2.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Models
{
public sealed class Armor : Item
{
}
public static class ArmorHelper
{
public static Armor ToArmor(this string[] row)
=> new Armor
{
Name = row[0],
Code = row[17],
InvFile = row[33]
};
}
}

View File

@ -0,0 +1,19 @@
using OpenDiablo2.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Models
{
/**
* Base Item class, contains common attributes for all item types.
**/
public abstract class Item
{
public string Code { get; internal set; } // Internal code
public string Name { get; internal set; } // Item name
public string InvFile { get; internal set; } // Sprite used for the inventory and mouse cursor
}
}

View File

@ -0,0 +1,25 @@
using OpenDiablo2.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Models
{
public sealed class Misc : Item
{
}
public static class MiscHelper
{
public static Misc ToMisc(this string[] row)
=> new Misc
{
Name = row[0],
Code = row[12],
InvFile = row[21]
};
}
}

View File

@ -0,0 +1,25 @@
using OpenDiablo2.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Models
{
public sealed class Weapon : Item
{
}
public static class WeaponHelper
{
public static Weapon ToWeapon(this string[] row)
=> new Weapon
{
Name = row[0],
Code = row[2],
InvFile = row[45]
};
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenDiablo2.Common.Enums;
namespace OpenDiablo2.Common.Models
{
public class ItemContainerLayout
{
public string ResourceName { get; internal set; }
public string PaletteName { get; internal set; } = Palettes.Units;
public int BaseFrame { get; internal set; } = 0;
public static Dictionary<eItemContainerType, ItemContainerLayout> Values = new Dictionary<eItemContainerType, ItemContainerLayout>
{
{eItemContainerType.Helm, new ItemContainerLayout { ResourceName = ResourcePaths.HelmGlovePlaceholder, BaseFrame = 1 } },
{eItemContainerType.Amulet, new ItemContainerLayout{ ResourceName = ResourcePaths.RingAmuletPlaceholder } },
{eItemContainerType.Armor, new ItemContainerLayout { ResourceName = ResourcePaths.ArmorPlaceholder } },
{eItemContainerType.Weapon, new ItemContainerLayout { ResourceName = ResourcePaths.WeaponsPlaceholder } },
{eItemContainerType.Belt, new ItemContainerLayout { ResourceName = ResourcePaths.BeltPlaceholder } },
{eItemContainerType.Ring, new ItemContainerLayout { ResourceName = ResourcePaths.RingAmuletPlaceholder, BaseFrame = 1 } },
{eItemContainerType.Glove, new ItemContainerLayout { ResourceName = ResourcePaths.HelmGlovePlaceholder } },
{eItemContainerType.Boots, new ItemContainerLayout { ResourceName = ResourcePaths.BootsPlaceholder } },
};
}
}

View File

@ -16,6 +16,7 @@ namespace OpenDiablo2.Common.Models.Mobs
public int StartingHealth { get; protected set; }
public int StartingMana { get; protected set; }
public int StartingStamina { get; protected set; }
public int StartingManaRegen { get; protected set; }
public double PerLevelHealth { get; protected set; }
public double PerLevelMana { get; protected set; }
@ -31,11 +32,34 @@ namespace OpenDiablo2.Common.Models.Mobs
public int BaseDefenseRating { get; protected set; }
public int PerDexterityDefenseRating { get; protected set; }
public int WalkVelocity { get; protected set; }
public int RunVelocity { get; protected set; }
public int RunDrain { get; protected set; }
public int WalkFrames { get; protected set; }
public int RunFrames { get; protected set; }
public int SwingFrames { get; protected set; }
public int SpellFrames { get; protected set; }
public int GetHitFrames { get; protected set; }
public int BowFrames { get; protected set; }
public int StartingSkill { get; protected set; }
public string BaseWeaponClass { get; protected set; }
public IEnumerable<string> ItemNames { get; }
public IEnumerable<string> ItemLocs { get; }
public IEnumerable<int> ItemCounts { get; }
public HeroTypeConfig(int vitality, int strength, int dexterity, int energy,
int health, int mana, int stamina,
int health, int mana, int stamina, int manaRegen,
double perlevelhealth, double perlevelmana, double perlevelstamina,
double pervitalityhealth, double pervitalitystamina, double perenergymana,
int baseatkrating, int basedefrating, int perdexterityatkrating, int perdexteritydefrating)
int baseatkrating, int basedefrating, int perdexterityatkrating, int perdexteritydefrating,
int walkVelocity, int runVelocity, int runDrain,
int walkFrames, int runFrames, int swingFrames, int spellFrames, int getHitFrames, int bowFrames,
int startingSkill,
string baseWeaponClass,
List<string> itemNames, List<string> itemLocs, List<int> itemCounts)
{
StartingDexterity = dexterity;
StartingVitality = vitality;
@ -44,6 +68,7 @@ namespace OpenDiablo2.Common.Models.Mobs
StartingMana = mana;
StartingHealth = health;
StartingStamina = stamina;
StartingManaRegen = manaRegen;
PerLevelHealth = perlevelhealth;
PerLevelMana = perlevelmana;
@ -57,6 +82,102 @@ namespace OpenDiablo2.Common.Models.Mobs
BaseDefenseRating = basedefrating;
PerDexterityAttackRating = perdexterityatkrating;
PerDexterityDefenseRating = perdexteritydefrating;
WalkVelocity = walkVelocity;
RunVelocity = runVelocity;
RunDrain = runDrain;
WalkFrames = walkFrames;
RunFrames = runFrames;
SwingFrames = swingFrames;
SpellFrames = spellFrames;
GetHitFrames = getHitFrames;
BowFrames = bowFrames;
StartingSkill = startingSkill;
BaseWeaponClass = baseWeaponClass;
ItemNames = itemNames;
ItemLocs = itemLocs;
ItemCounts = itemCounts;
}
}
public static class HeroTypeConfigHelper
{
public static IHeroTypeConfig ToHeroTypeConfig(this string[] row)
{
// rows:
// 0 1 2 3 4 5 6 7
// class str dex int vit tot stamina hpadd
// 8 9 10 11
// PercentStr PercentDex PercentInt PercentVit
// 12 13 14 15
// ManaRegen ToHitFactor WalkVelocity RunVelocity
// 16 17 18 19 20
// RunDrain Comment LifePerLevel StaminaPerLevel ManaPerLevel
// 21 22 23
// LifePerVitality StaminaPerVitality ManaPerMagic
// 24 25 26 27 28 29
// #walk #run #swing #spell #gethit #bow
// 30 31 32
// BlockFactor StartSkill baseWClass
// 33 34 35 36 37 38
// item1 item1loc item1count item2 item2loc item2count
// 39 40 41 42 43 44
// item3 item3loc item3count item4 item4loc item4count
// 45 46 47 48 49 50
// item5 item5loc item5count item6 item6loc item6count
// 51 52 53 54 55 56
// item7 item7loc item7count item8 item8loc item8count
// 57 58 59 60 61 62
// item9 item9loc item9count item10 item10loc item10count
List<string> itemNames = new List<string>();
List<string> itemLocs = new List<string>();
List<int> itemCounts = new List<int>();
for(int i = 33; i <= 60; i+=3)
{
itemNames.Add(row[i]);
itemLocs.Add(row[i + 1]);
itemCounts.Add(Convert.ToInt32(row[i + 2]));
}
return new HeroTypeConfig(
vitality: Convert.ToInt32(row[4]),
strength: Convert.ToInt32(row[1]),
dexterity: Convert.ToInt32(row[2]),
energy: Convert.ToInt32(row[3]),
health: Convert.ToInt32(row[7]),
mana: 0,
stamina: Convert.ToInt32(row[6]),
manaRegen: Convert.ToInt32(row[12]),
perlevelhealth: Convert.ToInt32(row[18]) / 4.0,
perlevelmana: Convert.ToInt32(row[20]) / 4.0,
perlevelstamina: Convert.ToInt32(row[19]) / 4.0,
pervitalityhealth: Convert.ToInt32(row[21]) / 4.0,
pervitalitystamina: Convert.ToInt32(row[22]) / 4.0,
perenergymana: Convert.ToInt32(row[23]) / 4.0,
baseatkrating: Convert.ToInt32(row[13]),
basedefrating: Convert.ToInt32(row[30]),
perdexterityatkrating: 5,
perdexteritydefrating: 4,
walkVelocity: Convert.ToInt32(row[14]),
runVelocity: Convert.ToInt32(row[15]),
runDrain: Convert.ToInt32(row[16]),
walkFrames: Convert.ToInt32(row[24]),
runFrames: Convert.ToInt32(row[25]),
swingFrames: Convert.ToInt32(row[26]),
spellFrames: Convert.ToInt32(row[27]),
getHitFrames: Convert.ToInt32(row[28]),
bowFrames: Convert.ToInt32(row[29]),
startingSkill: Convert.ToInt32(row[31]),
baseWeaponClass: row[32],
itemNames: itemNames,
itemLocs: itemLocs,
itemCounts: itemCounts);
}
}
}

View File

@ -1,4 +1,5 @@
using OpenDiablo2.Common.Interfaces.Mobs;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces.Mobs;
using System;
using System.Collections.Generic;
using System.Linq;
@ -9,14 +10,14 @@ namespace OpenDiablo2.Common.Models.Mobs
{
public class LevelExperienceConfig : ILevelExperienceConfig
{
private List<int> ExperiencePerLevel = new List<int>();
private List<long> ExperiencePerLevel = new List<long>();
public LevelExperienceConfig(List<int> expperlevel)
public LevelExperienceConfig(List<long> expperlevel)
{
ExperiencePerLevel = expperlevel;
}
public int GetTotalExperienceForLevel(int level)
public long GetTotalExperienceForLevel(int level)
{
if(ExperiencePerLevel.Count <= level)
{
@ -30,4 +31,42 @@ namespace OpenDiablo2.Common.Models.Mobs
return ExperiencePerLevel.Count - 1;
}
}
public static class LevelExperienceConfigHelper
{
public static Dictionary<eHero, ILevelExperienceConfig> ToLevelExperienceConfigs(this string[][] data)
{
Dictionary<eHero, ILevelExperienceConfig> result = new Dictionary<eHero, ILevelExperienceConfig>();
for (int i = 1; i < data[0].Length; i++)
{
// i starts at 1 because we want to skip the first column
// the first column is just the row titles
string heroname = data[i][0]; // first row is the hero name
eHero herotype = default(eHero);
if(!Enum.TryParse<eHero>(heroname, out herotype))
{
continue; // skip this hero if we can't parse the name into a valid hero type
}
int maxlevel = -1;
if(!int.TryParse(data[1][i], out maxlevel))
{
maxlevel = -1;// we don't need to fail in this case since maxlevel
// can be inferred from the number of experience listings
}
List<long> expperlevel = new List<long>();
for (int o = 2; o < data.Length && (o-2 < maxlevel || maxlevel == -1); o++)
{
long exp = 0;
if(!long.TryParse(data[o][i], out exp))
{
throw new Exception("Could not parse experience number '" + data[o][i] + "'.");
}
expperlevel.Add(exp);
}
result.Add(herotype, new LevelExperienceConfig(expperlevel));
}
return result;
}
}
}

View File

@ -25,19 +25,27 @@ namespace OpenDiablo2.Common.Models.Mobs
protected Stat Stamina;
protected Stat Mana;
protected Stat ManaRegen;
public int Experience { get; protected set; }
protected Stat WalkVelocity;
protected Stat RunVelocity;
protected Stat RunDrain;
public long Experience { get; protected set; }
public PlayerState() : base() { }
public PlayerState(int clientHash, string name, int id, int level, float x, float y,
int vitality, int strength, int energy, int dexterity, int experience, eHero herotype,
int vitality, int strength, int energy, int dexterity, long experience, eHero herotype,
IHeroTypeConfig heroconfig, ILevelExperienceConfig expconfig)
: base(name, id, level, 0, x, y)
{
this.ClientHash = clientHash;
Stamina = new Stat(0, 0, 0, true);
Mana = new Stat(0, 0, 0, true);
ManaRegen = new Stat(0, heroconfig.StartingManaRegen, heroconfig.StartingManaRegen, true);
Vitality = new Stat(0, vitality, vitality, true);
Strength = new Stat(0, strength, strength, true);
@ -47,6 +55,10 @@ namespace OpenDiablo2.Common.Models.Mobs
AttackRating = new Stat(0, 0, 0, false);
DefenseRating = new Stat(0, 0, 0, false);
WalkVelocity = new Stat(0, heroconfig.WalkVelocity, 100, false); // TODO: what should max velocity be? (replace the 100)
RunVelocity = new Stat(0, heroconfig.RunVelocity, 100, false); // TODO: what should max velocity be?
RunDrain = new Stat(0, heroconfig.RunDrain, heroconfig.RunDrain, true);
Experience = experience; // how much total exp do they have
HeroType = herotype;
@ -63,11 +75,11 @@ namespace OpenDiablo2.Common.Models.Mobs
}
#region Level and Experience
public int GetExperienceToLevel()
public long GetExperienceToLevel()
{
return GetExperienceTotalToLevel() - Experience;
}
public int GetExperienceTotalToLevel()
public long GetExperienceTotalToLevel()
{
return ExperienceConfig.GetTotalExperienceForLevel(Level + 1);
}
@ -75,7 +87,7 @@ namespace OpenDiablo2.Common.Models.Mobs
{
return ExperienceConfig.GetMaxLevel();
}
public bool AddExperience(int amount)
public bool AddExperience(long amount)
{
// returns true if you level up from this
Experience += amount;
@ -183,6 +195,10 @@ namespace OpenDiablo2.Common.Models.Mobs
{
Mana.AddCurrent(-mana);
}
public int GetManaRegen()
{
return ManaRegen.GetCurrent();
}
#endregion Mana
#region Stamina
@ -204,6 +220,21 @@ namespace OpenDiablo2.Common.Models.Mobs
}
#endregion Stamina
#region Movement
public int GetRunVelocity()
{
return RunVelocity.GetCurrent();
}
public int GetWalkVeloicty()
{
return WalkVelocity.GetCurrent();
}
public int GetRunDrain()
{
return RunDrain.GetCurrent();
}
#endregion Movement
// TODO: when a player equips an item, apply the relevant modifiers to their stats
// TODO: when a player unequips an item, remove the relevant modifiers from their stats
}

View File

@ -56,6 +56,7 @@
<Compile Include="Attributes\MessageFrameAttribute.cs" />
<Compile Include="Attributes\SceneAttribute.cs" />
<Compile Include="AutofacModule.cs" />
<Compile Include="Enums\eItemContainerType.cs" />
<Compile Include="Enums\eAnimationFrame.cs" />
<Compile Include="Enums\eArmorType.cs" />
<Compile Include="Enums\eCompositType.cs" />
@ -77,6 +78,7 @@
<Compile Include="Enums\Mobs\eDamageTypes.cs" />
<Compile Include="Enums\Mobs\eMobFlags.cs" />
<Compile Include="Enums\Mobs\eStatModifierType.cs" />
<Compile Include="Interfaces\IItemManager.cs" />
<Compile Include="Extensions\MobManagerExtensions.cs" />
<Compile Include="Interfaces\IGameServer.cs" />
<Compile Include="Interfaces\MessageBus\ISessionEventProvider.cs" />
@ -87,9 +89,11 @@
<Compile Include="Models\BitMuncher.cs" />
<Compile Include="Models\MPQCOF.cs" />
<Compile Include="Models\MPQDCC.cs" />
<Compile Include="Models\ItemContainerLayout.cs" />
<Compile Include="Models\PlayerInfo.cs" />
<Compile Include="Models\PlayerLocationDetails.cs" />
<Compile Include="Interfaces\UI\IButton.cs" />
<Compile Include="Interfaces\UI\IItemContainer.cs" />
<Compile Include="Interfaces\UI\IPanelFrame.cs" />
<Compile Include="Interfaces\UI\IInventoryPanel.cs" />
<Compile Include="Interfaces\IEngineDataManager.cs" />
@ -122,6 +126,10 @@
<Compile Include="Models\BitStream.cs" />
<Compile Include="Models\ButtonLayout.cs" />
<Compile Include="Models\LevelDetail.cs" />
<Compile Include="Models\Item\Item.cs" />
<Compile Include="Models\Item\Armor.cs" />
<Compile Include="Models\Item\Weapon.cs" />
<Compile Include="Models\Item\Misc.cs" />
<Compile Include="Models\LevelPreset.cs" />
<Compile Include="Models\LevelType.cs" />
<Compile Include="Models\MapCellInfo.cs" />

View File

@ -117,6 +117,13 @@ namespace OpenDiablo2.Common
public static string RunButton = "data\\global\\ui\\PANEL\\runbutton.dc6";
public static string MenuButton = "data\\global\\ui\\PANEL\\menubutton.DC6";
public static string ArmorPlaceholder = "data\\global\\ui\\PANEL\\inv_armor.DC6";
public static string BeltPlaceholder = "data\\global\\ui\\PANEL\\inv_belt.DC6";
public static string BootsPlaceholder = "data\\global\\ui\\PANEL\\inv_boots.DC6";
public static string HelmGlovePlaceholder = "data\\global\\ui\\PANEL\\inv_helm_glove.DC6";
public static string RingAmuletPlaceholder = "data\\global\\ui\\PANEL\\inv_ring_amulet.DC6";
public static string WeaponsPlaceholder = "data\\global\\ui\\PANEL\\inv_weapons.DC6";
// --- Data ---
// TODO: Doesn't sound right :)
public static string EnglishTable = "data\\local\\lng\\eng\\English.txt";
@ -130,6 +137,18 @@ namespace OpenDiablo2.Common
public static string AnimationData = "data\\global\\animdata.d2";
public static string PlayerAnimationBase = "data\\global\\CHARS";
// --- Inventory Data ---
public static string Weapons = "data\\global\\excel\\weapons.txt";
public static string Armor = "data\\global\\excel\\armor.txt";
public static string Misc = "data\\global\\excel\\misc.txt";
// --- Character Data ---
public static string Experience = "data\\global\\excel\\experience.txt";
public static string CharStats = "data\\global\\excel\\charstats.txt";
public static string GeneratePathForItem(string spriteName)
{
return $"data\\global\\items\\{spriteName}.dc6";
}
}
}

View File

@ -17,6 +17,7 @@ namespace OpenDiablo2.Core
builder.RegisterType<Button>().As<IButton>().InstancePerDependency();
builder.RegisterType<EngineDataManager>().As<IEngineDataManager>().SingleInstance();
builder.RegisterType<ItemManager>().As<IItemManager>().SingleInstance();
builder.RegisterType<GameEngine>().AsImplementedInterfaces().SingleInstance();
builder.RegisterType<GameState>().As<IGameState>().SingleInstance();
builder.RegisterType<MapEngine>().As<IMapEngine>().SingleInstance();
@ -24,6 +25,7 @@ namespace OpenDiablo2.Core
builder.RegisterType<PanelFrame>().As<IPanelFrame>().InstancePerDependency();
builder.RegisterType<CharacterPanel>().As<ICharacterPanel>().InstancePerDependency();
builder.RegisterType<InventoryPanel>().As<IInventoryPanel>().InstancePerDependency();
builder.RegisterType<ItemContainer>().As<IItemContainer>().InstancePerDependency();
builder.RegisterType<MPQProvider>().As<IMPQProvider>().SingleInstance();
builder.RegisterType<ResourceManager>().As<IResourceManager>().SingleInstance();
builder.RegisterType<TextDictionary>().As<ITextDictionary>().SingleInstance();

View File

@ -4,8 +4,11 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenDiablo2.Common;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.Common.Interfaces.Mobs;
using OpenDiablo2.Common.Models;
using OpenDiablo2.Common.Models.Mobs;
namespace OpenDiablo2.Core
{
@ -18,6 +21,9 @@ namespace OpenDiablo2.Core
public List<LevelPreset> LevelPresets { get; internal set; }
public List<LevelType> LevelTypes { get; internal set; }
public List<LevelDetail> LevelDetails { get; internal set; }
public List<Item> Items { get; internal set; } = new List<Item>();
public Dictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; internal set; } = new Dictionary<eHero, ILevelExperienceConfig>();
public Dictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; internal set; } = new Dictionary<eHero, IHeroTypeConfig>();
public EngineDataManager(IMPQProvider mpqProvider)
{
@ -26,6 +32,10 @@ namespace OpenDiablo2.Core
LoadLevelPresets();
LoadLevelTypes();
LoadLevelDetails();
LoadItemData();
LoadCharacterData();
}
private void LoadLevelTypes()
@ -72,5 +82,91 @@ namespace OpenDiablo2.Core
LevelDetails = new List<LevelDetail>(data);
}
private void LoadItemData()
{
var weaponData = LoadWeaponData();
var armorData = LoadArmorData();
var miscData = LoadMiscData();
Items.AddRange(weaponData);
Items.AddRange(armorData);
Items.AddRange(miscData);
}
private IEnumerable<Weapon> LoadWeaponData()
{
var data = mpqProvider
.GetTextFile(ResourcePaths.Weapons)
.Skip(1)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Select(x => x.Split('\t'))
//.Where(x => !String.IsNullOrWhiteSpace(x[27]))
.ToArray()
.Select(x => x.ToWeapon());
return data;
;
}
private IEnumerable<Armor> LoadArmorData()
{
var data = mpqProvider
.GetTextFile(ResourcePaths.Armor)
.Skip(1)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Select(x => x.Split('\t'))
//.Where(x => !String.IsNullOrWhiteSpace(x[27]))
.ToArray()
.Select(x => x.ToArmor());
return data;
}
private IEnumerable<Misc> LoadMiscData()
{
var data = mpqProvider
.GetTextFile(ResourcePaths.Misc)
.Skip(1)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Select(x => x.Split('\t'))
//.Where(x => !String.IsNullOrWhiteSpace(x[27]))
.ToArray()
.Select(x => x.ToMisc());
return data;
}
private void LoadCharacterData()
{
LoadExperienceConfig();
LoadHeroTypeConfig();
}
private void LoadExperienceConfig()
{
var data = mpqProvider
.GetTextFile(ResourcePaths.Experience)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Select(x => x.Split('\t'))
.ToArray()
.ToLevelExperienceConfigs();
ExperienceConfigs = data;
}
private void LoadHeroTypeConfig()
{
var data = mpqProvider
.GetTextFile(ResourcePaths.CharStats)
.Skip(1)
.Where(x => !String.IsNullOrWhiteSpace(x))
.Select(x => x.Split('\t'))
.Where(x => x[0] != "Expansion")
.ToArray()
.ToDictionary(x => (eHero)Enum.Parse(typeof(eHero),x[0]), x => x.ToHeroTypeConfig());
HeroTypeConfigs = data;
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenDiablo2.Common;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.Common.Models;
@ -34,8 +35,11 @@ namespace OpenDiablo2.Core.GameState_
public bool ShowInventoryPanel { get; set; } = false;
public bool ShowCharacterPanel { get; set; } = false;
readonly private IMouseCursor originalMouseCursor;
public int Seed { get; internal set; }
public Item SelectedItem { get; internal set; }
public object ThreadLocker { get; } = new object();
IEnumerable<PlayerInfo> IGameState.PlayerInfos => PlayerInfos;
@ -60,6 +64,8 @@ namespace OpenDiablo2.Core.GameState_
this.engineDataManager = engineDataManager;
this.renderWindow = renderWindow;
this.originalMouseCursor = renderWindow.MouseCursor;
}
public void Initialize(string characterName, eHero hero, eSessionType sessionType)
@ -244,6 +250,20 @@ namespace OpenDiablo2.Core.GameState_
return ShowCharacterPanel;
}
public void SelectItem(Item item)
{
if(item == null)
{
renderWindow.MouseCursor = this.originalMouseCursor;
} else {
var cursorsprite = renderWindow.LoadSprite(ResourcePaths.GeneratePathForItem(item.InvFile), Palettes.Units);
renderWindow.MouseCursor = renderWindow.LoadCursor(cursorsprite, 0, new Point(cursorsprite.FrameSize.Width / 2, cursorsprite.FrameSize.Height / 2));
}
this.SelectedItem = item;
}
private MapCellInfo GetMapCellInfo(MapInfo map, int cellX, int cellY, MPQDS1TileProps props, eRenderCellType cellType, MPQDS1WallOrientationTileProps wallOrientations = null)
{
if (!map.CellInfo.ContainsKey(cellType))

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenDiablo2.Common;
using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.Common.Models;
namespace OpenDiablo2.Core
{
public sealed class ItemManager : IItemManager
{
private IEngineDataManager engineDataManager;
public ItemManager(IEngineDataManager engineDataManager)
{
this.engineDataManager = engineDataManager;
}
public Item getItem(string code)
{
Item item = engineDataManager.Items.Where(x => x.Code == code).FirstOrDefault();
return item;
}
}
}

View File

@ -56,6 +56,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AutofacModule.cs" />
<Compile Include="ItemManager.cs" />
<Compile Include="EngineDataManager.cs" />
<Compile Include="GameEngine.cs" />
<Compile Include="GameState\GameState.cs" />
@ -67,21 +68,22 @@
<Compile Include="ResourceManager.cs" />
<Compile Include="TextDictionary.cs" />
<Compile Include="UI\Button.cs" />
<Compile Include="UI\ItemContainer.cs" />
<Compile Include="UI\PanelFrame.cs" />
<Compile Include="UI\InventoryPanel.cs" />
<Compile Include="UI\TextBox.cs" />
<Compile Include="UI\MiniPanel.cs" />
<Compile Include="UI\CharacterPanel.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenDiablo2.Common\OpenDiablo2.Common.csproj">
<Project>{b743160e-a0bb-45dc-9998-967a85e50562}</Project>
<Name>OpenDiablo2.Common</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -6,32 +6,111 @@ using OpenDiablo2.Common.Interfaces;
namespace OpenDiablo2.Core.UI
{
/**
* TODO: Check positioning, it's probably not exact
* TODO: Add logic so it can be used as an element in inventory grid
**/
public sealed class InventoryPanel : IInventoryPanel
{
private readonly IRenderWindow renderWindow;
private ISprite sprite;
private IPanelFrame panelFrame;
private Point location;
public Point Location { get; set; }
public Point Location {
get => location;
set {
previouslyContainedItem = location;
location = value;
}
}
public InventoryPanel(Func<ePanelFrameType, IPanelFrame> createPanelFrame, IRenderWindow renderWindow)
// Test vars
public IItemContainer helmContainer, armorContainer, weaponLeftContainer, weaponRightContainer, beltContainer, gloveContainer, bootsContainer;
private Point previouslyContainedItem;
private IItemContainer ringtLeftContainer;
private IItemContainer ringtRightContainer;
private IItemContainer amuletContainer;
public InventoryPanel(Func<ePanelFrameType, IPanelFrame> createPanelFrame, IRenderWindow renderWindow, IItemManager itemManager, Func<eItemContainerType, IItemContainer> createItemContainer)
{
this.renderWindow = renderWindow;
this.panelFrame = createPanelFrame(ePanelFrameType.Right);
sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Units, new Point(402,61));
Location = new Point(400, 0);
this.helmContainer = createItemContainer(eItemContainerType.Helm);
this.helmContainer.Location = new Point(Location.X + 138, Location.Y + 68);
this.helmContainer.SetContainedItem(itemManager.getItem("cap"));
this.amuletContainer = createItemContainer(eItemContainerType.Amulet);
this.amuletContainer.Location = new Point(Location.X + 211, Location.Y + 92);
this.amuletContainer.SetContainedItem(itemManager.getItem("vip"));
this.armorContainer = createItemContainer(eItemContainerType.Armor);
this.armorContainer.Location = new Point(Location.X + 138, Location.Y + 138);
this.armorContainer.SetContainedItem(itemManager.getItem("hla"));
this.weaponLeftContainer = createItemContainer(eItemContainerType.Weapon);
this.weaponLeftContainer.Location = new Point(Location.X + 22, Location.Y + 108);
this.weaponLeftContainer.SetContainedItem(itemManager.getItem("ame"));
this.weaponRightContainer = createItemContainer(eItemContainerType.Weapon);
this.weaponRightContainer.Location = new Point(Location.X + 255, Location.Y + 108);
this.weaponRightContainer.SetContainedItem(itemManager.getItem("paf"));
this.beltContainer = createItemContainer(eItemContainerType.Belt);
this.beltContainer.Location = new Point(Location.X + 138, Location.Y + 238);
this.beltContainer.SetContainedItem(itemManager.getItem("vbl"));
this.ringtLeftContainer = createItemContainer(eItemContainerType.Ring);
this.ringtLeftContainer.Location = new Point(Location.X + 97, Location.Y + 238);
this.ringtLeftContainer.SetContainedItem(itemManager.getItem("rin"));
this.ringtRightContainer = createItemContainer(eItemContainerType.Ring);
this.ringtRightContainer.Location = new Point(Location.X + 211, Location.Y + 238);
this.ringtRightContainer.SetContainedItem(itemManager.getItem("rin"));
this.gloveContainer = createItemContainer(eItemContainerType.Glove);
this.gloveContainer.Location = new Point(Location.X + 22, Location.Y + 238);
this.gloveContainer.SetContainedItem(itemManager.getItem("tgl"));
this.bootsContainer = createItemContainer(eItemContainerType.Boots);
this.bootsContainer.Location = new Point(Location.X + 255, Location.Y + 238);
this.bootsContainer.SetContainedItem(itemManager.getItem("lbt"));
}
public void Update()
{
helmContainer.Update();
amuletContainer.Update();
armorContainer.Update();
weaponLeftContainer.Update();
weaponRightContainer.Update();
beltContainer.Update();
ringtLeftContainer.Update();
ringtRightContainer.Update();
gloveContainer.Update();
bootsContainer.Update();
}
public void Render()
{
panelFrame.Render();
renderWindow.Draw(sprite, 2, 2, 1);
helmContainer.Render();
amuletContainer.Render();
armorContainer.Render();
weaponLeftContainer.Render();
weaponRightContainer.Render();
beltContainer.Render();
ringtLeftContainer.Render();
ringtRightContainer.Render();
gloveContainer.Render();
bootsContainer.Render();
}
public void Dispose()

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using OpenDiablo2.Common;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.Common.Models;
namespace OpenDiablo2.Core.UI
{
// TODO: Self-align when side panels are open
public sealed class ItemContainer : IItemContainer
{
private readonly IRenderWindow renderWindow;
private readonly IGameState gameState;
private ISprite sprite;
private ItemContainerLayout itemContainerLayout;
private IMouseInfoProvider mouseInfoProvider;
public Item ContainedItem { get; internal set; }
private Dictionary<eItemContainerType, ISprite> sprites = new Dictionary<eItemContainerType, ISprite>();
private Point location = new Point();
public Point Location
{
get => location;
set
{
if (location == value)
return;
location = value;
placeholderSprite.Location = new Point(value.X, value.Y + placeholderSprite.LocalFrameSize.Height);
}
}
private ISprite placeholderSprite;
public Size Size { get; internal set; }
public ItemContainer(IRenderWindow renderWindow, IGameState gameState, ItemContainerLayout itemContainerLayout, IMouseInfoProvider mouseInfoProvider)
{
this.renderWindow = renderWindow;
this.gameState = gameState;
this.itemContainerLayout = itemContainerLayout;
this.mouseInfoProvider = mouseInfoProvider;
placeholderSprite = renderWindow.LoadSprite(itemContainerLayout.ResourceName, itemContainerLayout.PaletteName);
placeholderSprite.Location = new Point(location.X, location.Y + placeholderSprite.LocalFrameSize.Height);
this.Size = placeholderSprite.FrameSize; // For all but generic size is equal to the placeholder size. Source: me.
}
public void SetContainedItem(Item containedItem)
{
ContainedItem = containedItem;
if (ContainedItem != null)
{
sprite = renderWindow.LoadSprite(ResourcePaths.GeneratePathForItem(this.ContainedItem.InvFile), Palettes.Units);
sprite.Location = new Point(location.X, location.Y + sprite.LocalFrameSize.Height);
}
}
public void Update()
{
var hovered = (mouseInfoProvider.MouseX >= location.X && mouseInfoProvider.MouseX < (location.X + this.Size.Width))
&& (mouseInfoProvider.MouseY >= location.Y && mouseInfoProvider.MouseY < (location.Y + this.Size.Height));
if (hovered && mouseInfoProvider.LeftMousePressed)
{
// If there is an item contained, remove from container and send to mouse
if (this.ContainedItem != null)
{
if (this.gameState.SelectedItem != null)
{
var switchItem = this.gameState.SelectedItem;
this.gameState.SelectItem(this.ContainedItem);
this.SetContainedItem(switchItem);
} else
{
this.gameState.SelectItem(this.ContainedItem);
this.SetContainedItem(null);
}
}
else if (this.gameState.SelectedItem != null)
{
this.SetContainedItem(this.gameState.SelectedItem);
this.gameState.SelectItem(null);
}
}
}
public void Render()
{
if (this.ContainedItem == null)
{
renderWindow.Draw(placeholderSprite, this.itemContainerLayout.BaseFrame);
}
else
{
renderWindow.Draw(sprite);
}
}
public void Dispose()
{
sprite.Dispose();
}
}
}

View File

@ -12,15 +12,17 @@ namespace OpenDiablo2.GameServer_
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly IMobManager mobManager;
private readonly IEngineDataManager engineDataManager;
public int Seed { get; private set; }
public IEnumerable<PlayerState> Players => mobManager.Players;
const double Deg2Rad = Math.PI / 180.0;
public GameServer(IMobManager mobManager)
public GameServer(IMobManager mobManager, IEngineDataManager engineDataManager)
{
this.mobManager = mobManager;
this.engineDataManager = engineDataManager;
}
public void InitializeNewGame()
@ -31,8 +33,35 @@ namespace OpenDiablo2.GameServer_
public int SpawnNewPlayer(int clientHash, string playerName, eHero heroType)
{
ILevelExperienceConfig expConfig = null;
IHeroTypeConfig heroConfig = null;
if (engineDataManager.ExperienceConfigs.ContainsKey(heroType))
{
expConfig = engineDataManager.ExperienceConfigs[heroType];
}
else
{
log.Error("Error: Experience Config not loaded for '" + heroType.ToString() + "'.");
expConfig = new LevelExperienceConfig(new List<long>() { 100 });
// TODO: should we have a more robust default experience config?
// or should we just fail in some way here?
}
if (engineDataManager.HeroTypeConfigs.ContainsKey(heroType))
{
heroConfig = engineDataManager.HeroTypeConfigs[heroType];
}
else
{
log.Error("Error: Hero Config not loaded for '" + heroType.ToString() + "'.");
heroConfig = new HeroTypeConfig(10, 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 9,
1, 10, 10, 10, 10, 10, 10, 0, "hth", new List<string>(), new List<string>(), new List<int>());
// TODO: should we have a more robust default hero config?
// or should we just fail in some way here?
// ... we should probably just fail here
}
var newPlayer = new PlayerState(clientHash, playerName, mobManager.GetNextAvailableMobId(), 1, 20.0f, 20.0f, 10, 10, 10, 10, 0, heroType,
new HeroTypeConfig(10, 10, 10, 50, 50, 50, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), new LevelExperienceConfig(new List<int>() { 100 }));
heroConfig, expConfig);
mobManager.AddPlayer(newPlayer);
return newPlayer.Id;

View File

@ -20,6 +20,7 @@ namespace OpenDiablo2.SDL2_
public int MouseX { get; internal set; } = 0;
public int MouseY { get; internal set; } = 0;
public bool LeftMouseDown { get; internal set; } = false;
public bool LeftMousePressed { get; internal set; } = false;
public bool RightMouseDown { get; internal set; } = false;
public bool ReserveMouse { get; set; } = false;
@ -141,6 +142,8 @@ namespace OpenDiablo2.SDL2_
public unsafe void Update()
{
LeftMousePressed = false;
while (SDL.SDL_PollEvent(out SDL.SDL_Event evt) != 0)
{
if (evt.type == SDL.SDL_EventType.SDL_MOUSEMOTION)
@ -155,6 +158,7 @@ namespace OpenDiablo2.SDL2_
switch ((uint)evt.button.button)
{
case SDL.SDL_BUTTON_LEFT:
LeftMousePressed = true; // Cannot find a better to handle a single press
LeftMouseDown = true;
break;
case SDL.SDL_BUTTON_RIGHT:
@ -439,8 +443,8 @@ namespace OpenDiablo2.SDL2_
var multiple = globalConfig.HardwareMouseScale;
var spr = sprite as SDL2Sprite;
var surface = SDL.SDL_CreateRGBSurface(0, spr.LocalFrameSize.Width * multiple, spr.LocalFrameSize.Height * multiple, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000);
var yOffset = (spr.FrameSize.Height - spr.LocalFrameSize.Height);
var XOffset = (spr.FrameSize.Width - spr.LocalFrameSize.Width);
var yOffset = 0; //(spr.FrameSize.Height - spr.LocalFrameSize.Height);
var XOffset = 0; //(spr.FrameSize.Width - spr.LocalFrameSize.Width);
var pixels = (UInt32*)((SDL.SDL_Surface*)surface)->pixels;
for (var y = 0; y < (spr.LocalFrameSize.Height * multiple) - 1; y++)
for (var x = 0; x < (spr.LocalFrameSize.Width * multiple) - 1; x++)

View File

@ -43,6 +43,7 @@ namespace OpenDiablo2.Scenes
IGameState gameState,
IMouseInfoProvider mouseInfoProvider,
IKeyboardInfoProvider keyboardInfoProvider,
IItemManager itemManager,
ISessionManager sessionManager,
Func<eButtonType, IButton> createButton,
Func<IMiniPanel> createMiniPanel,
@ -77,6 +78,11 @@ namespace OpenDiablo2.Scenes
menuButton = createButton(eButtonType.Menu);
menuButton.Location = new Point(393, 561);
menuButton.OnToggle = OnMenuToggle;
/*var item = itemManager.getItem("hdm");
var cursorsprite = renderWindow.LoadSprite(ResourcePaths.GeneratePathForItem(item.InvFile), Palettes.Units);
renderWindow.MouseCursor = renderWindow.LoadCursor(cursorsprite, 0, new Point(cursorsprite.FrameSize.Width/2, cursorsprite.FrameSize.Height / 2));*/
}
private void OnMenuToggle(bool isToggled)
@ -148,7 +154,15 @@ namespace OpenDiablo2.Scenes
minipanel.Update();
}
characterpanel.Update();
if (gameState.ShowInventoryPanel)
{
inventorypanel.Update();
}
if (gameState.ShowCharacterPanel)
{
characterpanel.Update();
}
runButton.Update();
menuButton.Update();
@ -202,4 +216,4 @@ namespace OpenDiablo2.Scenes
}
}
}
}

View File

@ -12,6 +12,7 @@
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@ -24,7 +25,6 @@
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>

View File

@ -85,6 +85,12 @@ namespace OpenDiablo2
return (panelFrameType) => componentContext.Resolve<IPanelFrame>(new NamedParameter("panelFrameType", panelFrameType));
});
containerBuilder.Register<Func<eItemContainerType, IItemContainer>>(c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (itemContainerType) => componentContext.Resolve<IItemContainer>(new NamedParameter("itemContainerLayout", ItemContainerLayout.Values[itemContainerType]));
});
/* Uncomment the below if we support multiple textbox types
containerBuilder.Register<Func<TextBox>>(c =>
{