PF-1: Add basic classes #1

Merged
malmal200 merged 5 commits from PF-1-add-basics into master 2024-06-15 02:05:33 +02:00
15 changed files with 356 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
.idea/
*.user

View File

@ -0,0 +1,47 @@
using System.Collections.Generic;
using NUnit.Framework;
using pflib_net.characters;
using pflib_net.characters.internals.proficiencies;
using pflib_net.characters.internals.stats;
namespace pflib_net.Tests.characters;
[TestFixture]
[TestOf(typeof(PlayerCharacter))]
public class PlayerCharacterTest
{
[Test]
public void DamageReducesHp()
{
var stats = new Stats(0, 0, 0, 0, 0, 0);
var armorValues = new Dictionary<ProficiencyType, ProficiencyValue>
{
{ ProficiencyType.Unarmored, ProficiencyValue.Expert },
{ ProficiencyType.LightArmor, ProficiencyValue.None },
{ ProficiencyType.MediumArmor, ProficiencyValue.None },
{ ProficiencyType.HeavyArmor, ProficiencyValue.None }
};
var armorProficiency = new ArmorProficiency(armorValues);
var creature = new PlayerCharacter(50, stats, 5, armorProficiency);
creature.ResolveAttack(20, 20);
Assert.That(creature.GetHp(), Is.LessThan(50));
}
[Test]
public void AttackFailsOnMiss()
{
var stats = new Stats(0, 0, 0, 0, 0, 0);
var armorValues = new Dictionary<ProficiencyType, ProficiencyValue>
{
{ ProficiencyType.Unarmored, ProficiencyValue.Expert },
{ ProficiencyType.LightArmor, ProficiencyValue.None },
{ ProficiencyType.MediumArmor, ProficiencyValue.None },
{ ProficiencyType.HeavyArmor, ProficiencyValue.None }
};
var armorProficiency = new ArmorProficiency(armorValues);
var creature = new PlayerCharacter(50, stats, 5, armorProficiency);
creature.ResolveAttack(0, 50);
Assert.That(creature.GetHp(), Is.EqualTo(50));
}
}

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using NUnit.Framework;
using pflib_net.characters.internals.proficiencies;
namespace pflib_net.Tests.characters.internals.proficiencies;
[TestFixture]
[TestOf(typeof(ArmorProficiency))]
public class ArmorProficiencyTest
{
private Dictionary<ProficiencyType, int> _values = new()
{
{ ProficiencyType.Unarmored, 0},
{ ProficiencyType.LightArmor, 5 },
{ ProficiencyType.MediumArmor, 7 },
{ ProficiencyType.HeavyArmor, 9 }
};
private Dictionary<ProficiencyType, ProficiencyValue> _proficiencyValues =
new()
{
{ ProficiencyType.Unarmored, ProficiencyValue.None },
{ ProficiencyType.LightArmor, ProficiencyValue.Trained },
{ ProficiencyType.MediumArmor, ProficiencyValue.Expert },
{ ProficiencyType.HeavyArmor, ProficiencyValue.Master }
};
[Test]
[TestCase(ProficiencyType.Unarmored)]
[TestCase(ProficiencyType.LightArmor)]
[TestCase(ProficiencyType.MediumArmor)]
[TestCase(ProficiencyType.HeavyArmor)]
public void GetValueReturnsCorrectAc(ProficiencyType type)
{
var armorProficiency = new ArmorProficiency(_proficiencyValues);
Assert.That(armorProficiency.GetValue(type, 3), Is.EqualTo(_values[type]));
}
}

View File

@ -0,0 +1,40 @@
using System.Collections.Generic;
using NUnit.Framework;
using pflib_net.characters.internals.stats;
namespace pflib_net.Tests.characters.internals.stats;
[TestFixture]
[TestOf(typeof(Stats))]
public class StatsTest
{
private readonly Dictionary<StatType, int> _values = new Dictionary<StatType, int>()
{
{ StatType.Strength, 1 },
{ StatType.Dexterity, 2 },
{ StatType.Constitution, 3 },
{ StatType.Intelligence, 4 },
{ StatType.Wisdom, 5 },
{ StatType.Charisma, 6 }
};
[Test]
[TestCase(StatType.Strength)]
[TestCase(StatType.Dexterity)]
[TestCase(StatType.Constitution)]
[TestCase(StatType.Intelligence)]
[TestCase(StatType.Wisdom)]
[TestCase(StatType.Charisma)]
public void GetStatsGivesCorrectValues(StatType type)
{
var stats = new Stats(
_values[StatType.Strength],
_values[StatType.Dexterity],
_values[StatType.Constitution],
_values[StatType.Intelligence],
_values[StatType.Wisdom],
_values[StatType.Charisma]
);
Assert.That(stats.GetStat(type), Is.EqualTo(_values[type]));
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>pflib_net.Tests</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\pflib-net\pflib-net.csproj" />
</ItemGroup>
</Project>

22
pflib-net.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pflib-net", "pflib-net\pflib-net.csproj", "{67894E72-B960-45B8-BE46-13B887EDE420}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pflib-net.Tests", "pflib-net.Tests\pflib-net.Tests.csproj", "{C27B21AF-82FC-4AED-845E-DE27602063E0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{67894E72-B960-45B8-BE46-13B887EDE420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67894E72-B960-45B8-BE46-13B887EDE420}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67894E72-B960-45B8-BE46-13B887EDE420}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67894E72-B960-45B8-BE46-13B887EDE420}.Release|Any CPU.Build.0 = Release|Any CPU
{C27B21AF-82FC-4AED-845E-DE27602063E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C27B21AF-82FC-4AED-845E-DE27602063E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C27B21AF-82FC-4AED-845E-DE27602063E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C27B21AF-82FC-4AED-845E-DE27602063E0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,17 @@
namespace pflib_net.characters;
public interface ICharacter
{
/// <summary>
/// Resolve an attack against the character's AC and deal damage appropriately
/// </summary>
/// <param name="roll"></param>
/// <param name="damage"></param>
public void ResolveAttack(int roll, int damage);
/// <summary>
/// Return the HP of the character
/// </summary>
/// <returns></returns>
public int GetHp();
}

View File

@ -0,0 +1,37 @@
using System.Collections.Generic;
using pflib_net.characters.internals.proficiencies;
using pflib_net.characters.internals.stats;
namespace pflib_net.characters;
public class PlayerCharacter : ICharacter
{
private int Hp { get; set; }
private Stats Stats { get; set; }
private int Level { get; set; }
private ArmorProficiency ArmorProficiency { get; }
public PlayerCharacter(int hp, Stats stats, int level, ArmorProficiency armorProficiency)
{
Hp = hp;
Stats = stats;
Level = level;
ArmorProficiency = armorProficiency;
}
public void ResolveAttack(int roll, int damage)
{
if (roll < GetAc()) return;
Hp -= damage;
}
private int GetAc()
{
return 10 + Stats.GetStat(StatType.Dexterity) + ArmorProficiency.GetValue(ProficiencyType.Unarmored, Level);
}
public int GetHp()
{
return Hp;
}
}

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace pflib_net.characters.internals.proficiencies;
public class ArmorProficiency : IProficiency
{
private Dictionary<ProficiencyType, ProficiencyValue> Values { get; set; }
public ArmorProficiency(Dictionary<ProficiencyType, ProficiencyValue> values)
{
Values = values;
}
public int GetValue(ProficiencyType type, int level)
{
if (Values[type].Equals(ProficiencyValue.None))
{
return 0;
}
else
{
return level + (int) Values[type];
}
}
}

View File

@ -0,0 +1,6 @@
namespace pflib_net.characters.internals.proficiencies;
public interface IProficiency
{
public int GetValue(ProficiencyType type, int level);
}

View File

@ -0,0 +1,35 @@
namespace pflib_net.characters.internals.proficiencies;
public enum ProficiencyType
{
Unarmored,
LightArmor,
MediumArmor,
HeavyArmor,
Unarmed,
SimpleWeapon,
MartialWeapon,
AdvancedWeapon,
SkillAcrobatics,
SkillArcana,
SkillAthletics,
SkillCrafting,
SkillDeception,
SkillDiplomacy,
SkillIntimidation,
SkillMedicine,
SkillNature,
SkillOccultism,
SkillPerformance,
SkillReligion,
SkillSociety,
SkillStealth,
SkillSurvival,
SkillThievery,
LoreBardic,
LoreLoremaster,
LoreOther
}

View File

@ -0,0 +1,10 @@
namespace pflib_net.characters.internals.proficiencies;
public enum ProficiencyValue: ushort
{
None = 0,
Trained = 2,
Expert = 4,
Master = 6,
Legendary = 8
}

View File

@ -0,0 +1,11 @@
namespace pflib_net.characters.internals.stats;
public enum StatType
{
Strength,
Dexterity,
Constitution,
Intelligence,
Wisdom,
Charisma
}

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace pflib_net.characters.internals.stats;
public class Stats
{
private Dictionary<StatType, int> StatDict { get; } = new();
public Stats(int strength, int dexterity, int constitution, int intelligence, int wisdom, int charisma)
{
StatDict[StatType.Strength] = strength;
StatDict[StatType.Dexterity] = dexterity;
StatDict[StatType.Constitution] = constitution;
StatDict[StatType.Intelligence] = intelligence;
StatDict[StatType.Wisdom] = wisdom;
StatDict[StatType.Charisma] = charisma;
}
public int GetStat(StatType type)
{
return StatDict[type];
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>pflib_net</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Folder Include="conditions\" />
</ItemGroup>
</Project>