Skip to content

Commit 5afc59c

Browse files
committed
Merge branch 'development'
2 parents d72d6ff + 873ebc6 commit 5afc59c

File tree

15 files changed

+359
-41
lines changed

15 files changed

+359
-41
lines changed

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
NWN_VERSION=8193.34
2-
NWNX_VERSION=d15bc22
2+
NWNX_VERSION=6a552d9

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,28 @@ All notable changes to this project will be documented in this file.
33

44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

6+
## 8193.34.6
7+
https://github.com/nwn-dotnet/Anvil/compare/v8193.34.5...v8193.34.6
8+
9+
### Added
10+
- Added `Color` equality members `Equals` and operators `==` `!=`
11+
- `NwGameTables`: Added `ExpTable`
12+
- `NwGameTables`: Added `SkillItemCostTable`
13+
14+
### Package Updates
15+
- Paket.Core 7.0.2 -> 7.1.4
16+
- NWNX d15bc22 -> 6a552d9
17+
18+
### Fixed
19+
- Fixed an issue that prevented .NET 6 plugins from being loaded with Paket.
20+
621
## 8193.34.5
722
https://github.com/nwn-dotnet/Anvil/compare/v8193.34.4...v8193.34.5
823

924
### Added
1025
- `NwCreature.Encounter`: Gets the encounter that spawned the creature.
26+
- `NwAreaOfEffect.Spell`: Gets the spell that created the area of effect.
27+
- `NwAreaOfEffect.RemainingDuration`: Gets the remaining duration on the area of effect.
1128

1229
## 8193.34.4
1330
https://github.com/nwn-dotnet/Anvil/compare/v8193.34.3...v8193.34.4

NWN.Anvil.Tests/src/main/API/ColorTests.cs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,6 @@ namespace Anvil.Tests.API
88
[TestFixture(Category = "API")]
99
public sealed class ColorTests
1010
{
11-
[Test]
12-
[Description("Converts a color into a color token, then checks the resulting string for control characters.")]
13-
[TestCaseSource(nameof(ColorTestCases))]
14-
public void CreateColorTokenContainsNoNullTerminators(Color color)
15-
{
16-
string colorToken = color.ToColorToken();
17-
Assert.That(colorToken, Does.Not.Contain('\0'), "color token contains a null character");
18-
}
19-
2011
[Test]
2112
[Description("Converting a color structure to a packed rgba value retains the correct color values.")]
2213
[TestCaseSource(nameof(ColorTestCases))]
@@ -40,13 +31,32 @@ public void ConvertColorToUnsignedRgbaRetainsValue(Color color)
4031
}
4132

4233
[Test]
43-
[Description("Converting a packed rgba value returns the correct color.")]
44-
[TestCase(0xFF0000FFu, 0xFF, 0, 0, 0xFF)]
45-
[TestCase(0x6E7882FFu, 0x6E, 0x78, 0x82, 0xFF)]
46-
[TestCase(0x6E141E10u, 0x6E, 0x14, 0x1E, 0x10)]
47-
public void ParseRGBAReturnsCorrectColor(uint packedColor, byte expectedRed, byte expectedGreen, byte expectedBlue, byte expectedAlpha)
34+
[Description("Converts a color into a color token, then checks the resulting string for control characters.")]
35+
[TestCaseSource(nameof(ColorTestCases))]
36+
public void CreateColorTokenContainsNoNullTerminators(Color color)
4837
{
49-
Assert.That(Color.FromRGBA(packedColor), Is.EqualTo(new Color(expectedRed, expectedGreen, expectedBlue, expectedAlpha)));
38+
string colorToken = color.ToColorToken();
39+
Assert.That(colorToken, Does.Not.Contain('\0'), "color token contains a null character");
40+
}
41+
42+
[Test]
43+
[Description("Deserializing a NUI color json structure creates the correct color.")]
44+
[TestCase(@"{""r"":255,""g"":0,""b"":0,""a"":0}", 255, 0, 0, 0)]
45+
[TestCase(@"{""r"":255,""g"":100,""b"":0,""a"":0}", 255, 100, 0, 0)]
46+
[TestCase(@"{""r"":255,""g"":100,""b"":10,""a"":30}", 255, 100, 10, 30)]
47+
public void DeserializeColorCreatesCorrectColor(string json, byte expectedRed, byte expectedGreen, byte expectedBlue, byte expectedAlpha)
48+
{
49+
Color color = JsonConvert.DeserializeObject<Color>(json);
50+
Assert.That(color, Is.EqualTo(new Color(expectedRed, expectedGreen, expectedBlue, expectedAlpha)));
51+
}
52+
53+
[Test]
54+
[Description("Identical colors are considered equal.")]
55+
[TestCaseSource(nameof(ColorTestCases))]
56+
public void IdenticalColorsAreEqual(Color color)
57+
{
58+
Color color2 = new Color(color.Red, color.Green, color.Blue, color.Alpha);
59+
Assert.AreEqual(color, color2);
5060
}
5161

5262
[Test]
@@ -72,14 +82,13 @@ public void ParseRGBAHexStringReturnsCorrectColor(string hexString, byte expecte
7282
}
7383

7484
[Test]
75-
[Description("Deserializing a NUI color json structure creates the correct color.")]
76-
[TestCase(@"{""r"":255,""g"":0,""b"":0,""a"":0}", 255, 0, 0, 0)]
77-
[TestCase(@"{""r"":255,""g"":100,""b"":0,""a"":0}", 255, 100, 0, 0)]
78-
[TestCase(@"{""r"":255,""g"":100,""b"":10,""a"":30}", 255, 100, 10, 30)]
79-
public void DeserializeColorCreatesCorrectColor(string json, byte expectedRed, byte expectedGreen, byte expectedBlue, byte expectedAlpha)
85+
[Description("Converting a packed rgba value returns the correct color.")]
86+
[TestCase(0xFF0000FFu, 0xFF, 0, 0, 0xFF)]
87+
[TestCase(0x6E7882FFu, 0x6E, 0x78, 0x82, 0xFF)]
88+
[TestCase(0x6E141E10u, 0x6E, 0x14, 0x1E, 0x10)]
89+
public void ParseRGBAReturnsCorrectColor(uint packedColor, byte expectedRed, byte expectedGreen, byte expectedBlue, byte expectedAlpha)
8090
{
81-
Color color = JsonConvert.DeserializeObject<Color>(json);
82-
Assert.That(color, Is.EqualTo(new Color(expectedRed, expectedGreen, expectedBlue, expectedAlpha)));
91+
Assert.That(Color.FromRGBA(packedColor), Is.EqualTo(new Color(expectedRed, expectedGreen, expectedBlue, expectedAlpha)));
8392
}
8493

8594
[Test]

NWN.Anvil.Tests/src/main/API/TwoDimArray/NwGameTableTests.cs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ public void ProgrammedEffectTableReturnsValidData()
369369
Assert.That(lightRow.GetParamString(8), Is.EqualTo(null));
370370
}
371371

372+
[Test(Description = "Damage level table entries return valid data")]
372373
[TestCase(0, "UNINJURED", 6409)]
373374
[TestCase(1, "BARELY_INJURED", 6410)]
374375
[TestCase(2, "INJURED", 6411)]
@@ -379,8 +380,130 @@ public void DamageLevelTableReturnsValidData(int rowIndex, string label, int? st
379380
TwoDimArray<DamageLevelEntry> table = NwGameTables.DamageLevelTable;
380381
DamageLevelEntry row = table.GetRow(rowIndex);
381382

383+
Assert.That(row.RowIndex, Is.EqualTo(rowIndex));
382384
Assert.That(row.Label, Is.EqualTo(label));
383385
Assert.That(row.StrRef?.Id, Is.EqualTo(strRef));
384386
}
387+
388+
[Test(Description = "XP table entries return valid data")]
389+
[TestCase(0, 1, 0u)]
390+
[TestCase(1, 2, 1000u)]
391+
[TestCase(2, 3, 3000u)]
392+
[TestCase(3, 4, 6000u)]
393+
[TestCase(4, 5, 10000u)]
394+
[TestCase(5, 6, 15000u)]
395+
[TestCase(6, 7, 21000u)]
396+
[TestCase(7, 8, 28000u)]
397+
[TestCase(8, 9, 36000u)]
398+
[TestCase(9, 10, 45000u)]
399+
[TestCase(10, 11, 55000u)]
400+
[TestCase(11, 12, 66000u)]
401+
[TestCase(12, 13, 78000u)]
402+
[TestCase(13, 14, 91000u)]
403+
[TestCase(14, 15, 105000u)]
404+
[TestCase(15, 16, 120000u)]
405+
[TestCase(16, 17, 136000u)]
406+
[TestCase(17, 18, 153000u)]
407+
[TestCase(18, 19, 171000u)]
408+
[TestCase(19, 20, 190000u)]
409+
[TestCase(20, 21, 210000u)]
410+
[TestCase(21, 22, 231000u)]
411+
[TestCase(22, 23, 253000u)]
412+
[TestCase(23, 24, 276000u)]
413+
[TestCase(24, 25, 300000u)]
414+
[TestCase(25, 26, 325000u)]
415+
[TestCase(26, 27, 351000u)]
416+
[TestCase(27, 28, 378000u)]
417+
[TestCase(28, 29, 406000u)]
418+
[TestCase(29, 30, 435000u)]
419+
[TestCase(30, 31, 465000u)]
420+
[TestCase(31, 32, 496000u)]
421+
[TestCase(32, 33, 528000u)]
422+
[TestCase(33, 34, 561000u)]
423+
[TestCase(34, 35, 595000u)]
424+
[TestCase(35, 36, 630000u)]
425+
[TestCase(36, 37, 666000u)]
426+
[TestCase(37, 38, 703000u)]
427+
[TestCase(38, 39, 741000u)]
428+
[TestCase(39, 40, 780000u)]
429+
[TestCase(40, 41, 0xFFFFFFFFu)]
430+
public void ExpTableReturnsValidData(int rowIndex, int? level, uint? xp)
431+
{
432+
TwoDimArray<ExpTableEntry> table = NwGameTables.ExpTable;
433+
ExpTableEntry row = table.GetRow(rowIndex);
434+
435+
Assert.That(row.RowIndex, Is.EqualTo(rowIndex));
436+
Assert.That(row.Level, Is.EqualTo(level));
437+
Assert.That(row.XP, Is.EqualTo(xp));
438+
}
439+
440+
[Test(Description = "Skill item cost entries return valid data")]
441+
[TestCase(0, 5, 1, 5, 10)]
442+
[TestCase(1, 10, 1, 5, 10)]
443+
[TestCase(2, 50, 1, 5, 10)]
444+
[TestCase(3, 100, 1, 5, 10)]
445+
[TestCase(4, 150, 1, 5, 10)]
446+
[TestCase(5, 200, 1, 5, 10)]
447+
[TestCase(6, 300, 1, 5, 10)]
448+
[TestCase(7, 400, 1, 5, 10)]
449+
[TestCase(8, 500, 1, 5, 10)]
450+
[TestCase(9, 1000, 1, 5, 10)]
451+
[TestCase(10, 2500, 5, 10, 15)]
452+
[TestCase(11, 3750, 5, 10, 15)]
453+
[TestCase(12, 4800, 5, 10, 15)]
454+
[TestCase(13, 6500, 10, 15, 20)]
455+
[TestCase(14, 9500, 10, 15, 20)]
456+
[TestCase(15, 13000, 10, 15, 20)]
457+
[TestCase(16, 17000, 10, 15, 20)]
458+
[TestCase(17, 20000, 10, 15, 20)]
459+
[TestCase(18, 30000, 15, 20, 25)]
460+
[TestCase(19, 40000, 15, 20, 25)]
461+
[TestCase(20, 50000, 15, 20, 25)]
462+
[TestCase(21, 60000, 15, 20, 25)]
463+
[TestCase(22, 80000, 15, 20, 25)]
464+
[TestCase(23, 100000, 15, 20, 25)]
465+
[TestCase(24, 150000, 20, 25, 30)]
466+
[TestCase(25, 200000, 20, 25, 30)]
467+
[TestCase(26, 250000, 20, 25, 30)]
468+
[TestCase(27, 300000, 20, 25, 30)]
469+
[TestCase(28, 350000, 25, 30, 35)]
470+
[TestCase(29, 400000, 25, 30, 35)]
471+
[TestCase(30, 500000, 25, 30, 35)]
472+
[TestCase(31, 600000, 25, 30, 35)]
473+
[TestCase(32, 700000, 30, 35, 40)]
474+
[TestCase(33, 800000, 30, 35, 40)]
475+
[TestCase(34, 900000, 30, 35, 40)]
476+
[TestCase(35, 1000000, 30, 35, 40)]
477+
[TestCase(36, 1100000, 35, 40, 45)]
478+
[TestCase(37, 1200000, 35, 40, 45)]
479+
[TestCase(38, 1300000, 35, 40, 45)]
480+
[TestCase(39, 1400000, 35, 40, 45)]
481+
[TestCase(40, 1500000, 40, 45, 50)]
482+
[TestCase(41, 1600000, 40, 45, 50)]
483+
[TestCase(42, 1700000, 40, 45, 50)]
484+
[TestCase(43, 1800000, 40, 45, 50)]
485+
[TestCase(44, 1900000, 45, 50, 55)]
486+
[TestCase(45, 2000000, 45, 50, 55)]
487+
[TestCase(46, 2100000, 45, 50, 55)]
488+
[TestCase(47, 2200000, 45, 50, 55)]
489+
[TestCase(48, 2300000, 50, 55, 60)]
490+
[TestCase(49, 2400000, 50, 55, 60)]
491+
[TestCase(50, 2500000, 50, 55, 60)]
492+
[TestCase(51, 3000000, 55, 60, 65)]
493+
[TestCase(52, 5000000, 60, 65, 70)]
494+
[TestCase(53, 6000000, 70, 75, 80)]
495+
[TestCase(54, 9000000, 80, 85, 90)]
496+
[TestCase(55, 12000000, null, null, null)]
497+
public void SkillItemCostTableReturnsValidData(int rowIndex, int? deviceCostMax, int? skillReqClass, int? skillReqRace, int? skillReqAlign)
498+
{
499+
TwoDimArray<SkillItemCostTableEntry> table = NwGameTables.SkillItemCostTable;
500+
SkillItemCostTableEntry row = table.GetRow(rowIndex);
501+
502+
Assert.That(row.RowIndex, Is.EqualTo(rowIndex));
503+
Assert.That(row.DeviceCostMax, Is.EqualTo(deviceCostMax));
504+
Assert.That(row.ClassSkillRequirement, Is.EqualTo(skillReqClass));
505+
Assert.That(row.RaceSkillRequirement, Is.EqualTo(skillReqRace));
506+
Assert.That(row.AlignmentSkillRequirement, Is.EqualTo(skillReqAlign));
507+
}
385508
}
386509
}

NWN.Anvil/NWN.Anvil.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<!--Build-->
33
<PropertyGroup>
4+
<!--When changing target frameworks, make sure to update Anvil.Internal.Assemblies.TargetFrameworks-->
45
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
56
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
67
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
@@ -58,7 +59,7 @@
5859
<PackageReference Include="LightInject" Version="6.4.1" />
5960
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
6061
<PackageReference Include="NLog" Version="4.7.15" />
61-
<PackageReference Include="Paket.Core" Version="7.0.2" PrivateAssets="all" />
62+
<PackageReference Include="Paket.Core" Version="7.1.4" PrivateAssets="all" />
6263
<PackageReference Include="NWN.Core" Version="8193.34.3" PrivateAssets="compile" />
6364
<PackageReference Include="NWN.Native" Version="8193.34.3" PrivateAssets="compile" />
6465
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />

NWN.Anvil/src/main/API/Color.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Anvil.API
77
/// <summary>
88
/// A 8 bit Color structure.
99
/// </summary>
10-
public readonly struct Color
10+
public readonly struct Color : IEquatable<Color>
1111
{
1212
/// <summary>
1313
/// Gets the alpha value of this color as a byte (0-255).
@@ -120,6 +120,31 @@ public static Color FromRGBA(string rgbaHexString)
120120
return FromRGBA(Convert.ToInt32(rgbaHexString.Trim().TrimStart('#'), 16));
121121
}
122122

123+
public static bool operator ==(Color left, Color right)
124+
{
125+
return left.Equals(right);
126+
}
127+
128+
public static bool operator !=(Color left, Color right)
129+
{
130+
return !left.Equals(right);
131+
}
132+
133+
public bool Equals(Color other)
134+
{
135+
return Alpha == other.Alpha && Blue == other.Blue && Green == other.Green && Red == other.Red;
136+
}
137+
138+
public override bool Equals(object obj)
139+
{
140+
return obj is Color other && Equals(other);
141+
}
142+
143+
public override int GetHashCode()
144+
{
145+
return HashCode.Combine(Alpha, Blue, Green, Red);
146+
}
147+
123148
/// <summary>
124149
/// Returns the 3 character sequence token for this color, used in coloring text.<br/>
125150
/// This is mostly for internal use. Use <see cref="StringExtensions.ColorString"/> for formatting text with a certain color.

NWN.Anvil/src/main/API/Object/NwAreaOfEffect.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ internal NwAreaOfEffect(CNWSAreaOfEffectObject areaOfEffectObject) : base(areaOf
1818
AreaOfEffect = areaOfEffectObject;
1919
}
2020

21+
/// <summary>
22+
/// Gets the spell from which the Area Of Effect was created.
23+
/// </summary>
24+
public NwSpell Spell => NwSpell.FromSpellId((int)AreaOfEffect.m_nSpellId);
25+
26+
/// <summary>
27+
/// Gets the Area Of Effect duration.
28+
/// </summary>
29+
public TimeSpan RemainingDuration => TimeSpan.FromMilliseconds(AreaOfEffect.m_nDuration);
30+
2131
/// <summary>
2232
/// Gets the creator of this Area of Effect.
2333
/// </summary>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace Anvil.API
2+
{
3+
public sealed class ExpTableEntry : ITwoDimArrayEntry
4+
{
5+
/// <summary>
6+
/// Gets the character level.
7+
/// </summary>
8+
public int? Level { get; set; }
9+
10+
public int RowIndex { get; init; }
11+
12+
/// <summary>
13+
/// Gets the XP required to gain <see cref="Level"/>.
14+
/// </summary>
15+
public uint? XP { get; set; }
16+
17+
public void InterpretEntry(TwoDimArrayEntry entry)
18+
{
19+
Level = entry.GetInt("Level");
20+
XP = unchecked((uint?)entry.GetInt("XP"));
21+
}
22+
}
23+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System.Linq;
2+
3+
namespace Anvil.API
4+
{
5+
public static class ExpTableExtensions
6+
{
7+
/// <summary>
8+
/// Gets the current level for a player with the specified XP.
9+
/// </summary>
10+
/// <param name="table">The table to lookup.</param>
11+
/// <param name="xp">The amount of xp.</param>
12+
public static int? GetLevelFromXP(this TwoDimArray<ExpTableEntry> table, int xp)
13+
{
14+
int? level = 1;
15+
foreach (ExpTableEntry entry in table)
16+
{
17+
if (entry.XP > xp)
18+
{
19+
break;
20+
}
21+
22+
level = entry.Level;
23+
}
24+
25+
return level;
26+
}
27+
28+
/// <summary>
29+
/// Gets the amount of XP needed for the specified level.
30+
/// </summary>
31+
/// <param name="table">The table to lookup.</param>
32+
/// <param name="level">The level to lookup.</param>
33+
public static uint? GetXPFromLevel(this TwoDimArray<ExpTableEntry> table, int level)
34+
{
35+
return table.FirstOrDefault(entry => entry.Level == level)?.XP;
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)