feat(player): port retail augmentation stat chain

This commit is contained in:
Erik 2026-07-31 08:08:23 +02:00
parent 0cb60d98a0
commit 461a1fb7b4
22 changed files with 953 additions and 138 deletions

View file

@ -257,11 +257,56 @@ public sealed class RuntimeCharacterStateTests
Assert.Equal(100, state.MovementSkills.JumpSkill); // untouched
}
[Fact]
public void MovementSkillAugmentations_UseSameRetailChainAsCharacterSheet()
{
using var state = new RuntimeCharacterState();
state.LocalPlayer.OnSkillUpdate(
RuntimeCharacterState.RunSkillId,
ranks: 0u,
status: 3u,
xp: 0u,
init: 0u,
resistance: 0u,
lastUsed: 0d,
formulaBonus: 200u);
state.LocalPlayer.OnSkillUpdate(
RuntimeCharacterState.JumpSkillId,
ranks: 0u,
status: 2u,
xp: 0u,
init: 0u,
resistance: 0u,
lastUsed: 0d,
formulaBonus: 100u);
state.UpdateMovementSkillBase(runSkillBase: 200, jumpSkillBase: 100);
state.UpdateMovementSkillAugmentations(
new PlayerSkillMath.AugmentationBonuses(
AllSkills: 2,
JackOfAllTrades: true,
SkilledSpecialized: 3,
SkilledMelee: false,
SkilledMissile: false,
SkilledMagic: false));
Assert.Equal(213, state.MovementSkills.RunSkill);
Assert.Equal(107, state.MovementSkills.JumpSkill);
}
[Fact]
public void ResetSession_ClearsBurdenStaminaAndSkillBase()
{
using var state = new RuntimeCharacterState();
state.UpdateMovementSkillBase(runSkillBase: 200, jumpSkillBase: 100);
state.UpdateMovementSkillAugmentations(
new PlayerSkillMath.AugmentationBonuses(
AllSkills: 2,
JackOfAllTrades: true,
SkilledSpecialized: 3,
SkilledMelee: false,
SkilledMissile: false,
SkilledMagic: false));
state.MovementSkills.UpdateBurden(1.5f);
state.MovementSkills.UpdateStamina(0);
@ -274,7 +319,7 @@ public sealed class RuntimeCharacterStateTests
Assert.True(state.CaptureOwnership().MovementSkillsAreReset);
// A fresh base push after reset must not still carry the pre-reset
// vitae/enchantment adjustment (spellbook was cleared too).
// augmentation/vitae/enchantment adjustment (spellbook was cleared too).
state.UpdateMovementSkillBase(runSkillBase: 200, jumpSkillBase: 100);
Assert.Equal(200, state.MovementSkills.RunSkill);
}

View file

@ -233,6 +233,58 @@ public sealed class LiveSessionEventRouterTests
router.Dispose();
}
[Fact]
public void ObjectTablePropertyChange_RecomputesMovementSkillAugmentations()
{
using var session = NewSession();
const uint playerGuid = 0x50000001u;
var objects = new ClientObjectTable();
var character = new RuntimeCharacterState();
character.LocalPlayer.OnSkillUpdate(
RuntimeCharacterState.RunSkillId,
ranks: 0u,
status: 3u,
xp: 0u,
init: 0u,
resistance: 0u,
lastUsed: 0d,
formulaBonus: 200u);
character.UpdateMovementSkillBase(
runSkillBase: 200,
jumpSkillBase: -1);
var router = new LiveSessionEventRouter(
session,
NoOpEntitySink(),
NoOpEnvironmentSink(),
new LiveInventorySessionBindings(
objects,
PlayerGuid: () => playerGuid,
OnShortcuts: null,
OnUseDone: null,
ItemMana: new ItemManaState(),
ExternalContainers: new ExternalContainerState()),
new LiveCharacterSessionBindings(
new CombatState(),
character,
ResolveSkillFormulaBonus: null,
OnSkillsUpdated: null,
OnConfirmationRequest: null,
OnConfirmationDone: null,
ClientTime: () => 0d),
NewSocialBindings());
router.Attach();
var properties = new PropertyBundle();
properties.Ints[(uint)PropertyInt.LumAugAllSkills] = 2;
properties.Ints[(uint)PropertyInt.AugmentationJackOfAllTrades] = 1;
properties.Ints[(uint)PropertyInt.LumAugSkilledSpec] = 3;
objects.UpsertProperties(playerGuid, properties);
Assert.Equal(213, character.MovementSkills.RunSkill);
router.Dispose();
}
[Fact]
public void StaminaVitalChange_PushesCurrentStamina()
{