test: cover testEquipment
This commit is contained in:
1 parent
0863a2a595
commit
1677d11150
1 file changed
+220
@@ -157,3 +157,223 @@ VF_TEST(theHeldToolDecidesAttackDamageSpeedAndReach) {
|
|||||||
CHECK_NEAR(stats.attackReach, unarmedAttackReach + 0.5f, 0.0001f);
|
CHECK_NEAR(stats.attackReach, unarmedAttackReach + 0.5f, 0.0001f);
|
||||||
CHECK_NEAR(modifierTotal(stats, AttributeModifier::Attribute::AttackDamage), 6.0f, 0.0001f);
|
CHECK_NEAR(modifierTotal(stats, AttributeModifier::Attribute::AttackDamage), 6.0f, 0.0001f);
|
||||||
|
|
||||||
|
CombatStats combat;
|
||||||
|
stats.applyTo(combat);
|
||||||
|
CHECK_NEAR(combat.baseAttackDamage, 7.0f, 0.0001f);
|
||||||
|
CHECK_NEAR(combat.attackSpeed, 1.6f, 0.0001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(sharpnessReachesCombatThroughTheEnchantSetAndNotThroughAttackDamage) {
|
||||||
|
Equipment plain;
|
||||||
|
plain.equip(EquipSlot::MainHand, makeTool(ItemId::DiamondSword));
|
||||||
|
|
||||||
|
Equipment sharp;
|
||||||
|
sharp.equip(EquipSlot::MainHand,
|
||||||
|
makeEnchantedTool(ItemId::DiamondSword, withEnchant(EnchantKind::Sharpness, 5)));
|
||||||
|
|
||||||
|
// The item value is identical; only the enchantment set differs.
|
||||||
|
CHECK_NEAR(plain.stats().attackDamage, sharp.stats().attackDamage, 0.0001f);
|
||||||
|
CHECK(plain.stats().weaponEnchants.empty());
|
||||||
|
CHECK_EQ(sharp.stats().weaponEnchants.levelOf(EnchantKind::Sharpness), 5);
|
||||||
|
|
||||||
|
EffectSet none;
|
||||||
|
CombatStats attacker = readyToSwing();
|
||||||
|
float plainSwing = equippedMeleeDamage(plain, attacker, none, false, false, false);
|
||||||
|
float sharpSwing = equippedMeleeDamage(sharp, attacker, none, false, false, false);
|
||||||
|
CHECK(sharpSwing > plainSwing);
|
||||||
|
CHECK_NEAR(sharpSwing - plainSwing, 3.0f, 0.05f);
|
||||||
|
|
||||||
|
Equipment unarmed;
|
||||||
|
CHECK(equippedMeleeDamage(unarmed, attacker, none, false, false, false) < plainSwing);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(efficiencyRaisesMiningSpeedWhileTheCombatNumbersStayPut) {
|
||||||
|
Equipment plain;
|
||||||
|
plain.equip(EquipSlot::MainHand, makeTool(ItemId::DiamondPickaxe));
|
||||||
|
|
||||||
|
Equipment quick;
|
||||||
|
quick.equip(EquipSlot::MainHand,
|
||||||
|
makeEnchantedTool(ItemId::DiamondPickaxe, withEnchant(EnchantKind::Efficiency, 4)));
|
||||||
|
|
||||||
|
EquipmentStats plainStats = plain.stats();
|
||||||
|
EquipmentStats quickStats = quick.stats();
|
||||||
|
|
||||||
|
CHECK_NEAR(plainStats.miningSpeed, toolTierSpeedMultiplier(ToolTier::Diamond), 0.0001f);
|
||||||
|
CHECK_NEAR(quickStats.miningSpeed, plainStats.miningSpeed + 17.0f, 0.0001f);
|
||||||
|
CHECK_NEAR(quickStats.attackDamage, plainStats.attackDamage, 0.0001f);
|
||||||
|
CHECK(modifierTotal(quickStats, AttributeModifier::Attribute::MiningSpeed) >
|
||||||
|
modifierTotal(plainStats, AttributeModifier::Attribute::MiningSpeed));
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(armorWeightCostsMovementSpeedInProportionToItsPoints) {
|
||||||
|
Equipment bare;
|
||||||
|
CHECK_NEAR(bare.stats().movementSpeed, 1.0f, 0.0001f);
|
||||||
|
|
||||||
|
Equipment leather;
|
||||||
|
leather.equipArmor(makeArmor(Armor::Material::Leather, Armor::Slot::Helmet));
|
||||||
|
Equipment diamond = fullDiamond();
|
||||||
|
|
||||||
|
CHECK(leather.stats().movementSpeed < 1.0f);
|
||||||
|
CHECK(diamond.stats().movementSpeed < leather.stats().movementSpeed);
|
||||||
|
CHECK_NEAR(diamond.stats().movementSpeed, 1.0f - 0.20f, 0.0001f);
|
||||||
|
CHECK_NEAR(modifierTotal(diamond.stats(), AttributeModifier::Attribute::MovementSpeed), -0.20f,
|
||||||
|
0.0001f);
|
||||||
|
CHECK_NEAR(armorWeightPenalty(0), 0.0f, 0.0001f);
|
||||||
|
CHECK_NEAR(armorWeightPenalty(100), 0.35f, 0.0001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(armorWearsDownWhenHitsLandAndAPieceVanishesAtZero) {
|
||||||
|
Equipment gear;
|
||||||
|
Armor helmet = makeArmor(Armor::Material::Leather, Armor::Slot::Helmet);
|
||||||
|
gear.equipArmor(helmet);
|
||||||
|
int startingDurability = gear.armorPiece(EquipSlot::Head).durability;
|
||||||
|
CHECK(startingDurability > 0);
|
||||||
|
|
||||||
|
uint32_t rng = 8u;
|
||||||
|
int spent = gear.wearFromHit(8.0f, rng);
|
||||||
|
CHECK(spent > 0);
|
||||||
|
CHECK_EQ(gear.armorPiece(EquipSlot::Head).durability, startingDurability - spent);
|
||||||
|
|
||||||
|
int guard = 0;
|
||||||
|
while (gear.wornPieces() > 0 && guard < 5000) {
|
||||||
|
gear.wearFromHit(20.0f, rng);
|
||||||
|
++guard;
|
||||||
|
}
|
||||||
|
CHECK(guard < 5000);
|
||||||
|
CHECK_EQ(gear.wornPieces(), 0);
|
||||||
|
CHECK(gear.armorPiece(EquipSlot::Head).material == Armor::Material::None);
|
||||||
|
CHECK_EQ(gear.stats().armorPoints, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(unbreakingArmorSurvivesNoticeablyMoreHits) {
|
||||||
|
uint32_t plainRng = 31u;
|
||||||
|
Equipment plain;
|
||||||
|
plain.equipArmor(makeArmor(Armor::Material::Iron, Armor::Slot::Chestplate));
|
||||||
|
int plainHits = 0;
|
||||||
|
while (plain.wornPieces() > 0 && plainHits < 20000) {
|
||||||
|
plain.wearFromHit(4.0f, plainRng);
|
||||||
|
++plainHits;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t toughRng = 31u;
|
||||||
|
Equipment tough;
|
||||||
|
Armor reinforced = makeArmor(Armor::Material::Iron, Armor::Slot::Chestplate);
|
||||||
|
addEnchant(reinforced.enchants, EnchantKind::Unbreaking, 3);
|
||||||
|
tough.equipArmor(reinforced);
|
||||||
|
int toughHits = 0;
|
||||||
|
while (tough.wornPieces() > 0 && toughHits < 20000) {
|
||||||
|
tough.wearFromHit(4.0f, toughRng);
|
||||||
|
++toughHits;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(plainHits > 0);
|
||||||
|
CHECK(toughHits > plainHits * 2);
|
||||||
|
CHECK(toughHits < 20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(theHeldToolBreaksAtZeroUnlessItIsUnbreakable) {
|
||||||
|
uint32_t rng = 17u;
|
||||||
|
Equipment gear;
|
||||||
|
gear.equip(EquipSlot::MainHand, makeTool(ItemId::WoodShovel));
|
||||||
|
int max = gear.mainHand().meta.durability.max;
|
||||||
|
|
||||||
|
for (int hit = 1; hit < max; ++hit) {
|
||||||
|
CHECK(gear.useHeld(EquipSlot::MainHand, 1, rng) == WearResult::Damaged);
|
||||||
|
}
|
||||||
|
CHECK(gear.useHeld(EquipSlot::MainHand, 1, rng) == WearResult::Broke);
|
||||||
|
CHECK(gear.mainHand().empty());
|
||||||
|
|
||||||
|
MetaStack indestructible = makeTool(ItemId::WoodShovel);
|
||||||
|
indestructible.meta.unbreakable = true;
|
||||||
|
gear.equip(EquipSlot::OffHand, indestructible);
|
||||||
|
CHECK(gear.useHeld(EquipSlot::OffHand, 5000, rng) == WearResult::Absorbed);
|
||||||
|
CHECK(!gear.offHand().empty());
|
||||||
|
CHECK(gear.useHeld(EquipSlot::Head, 1, rng) == WearResult::NotDamageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(experiencePickedUpRepairsMendingGearBeforeTheHeldTool) {
|
||||||
|
Equipment gear;
|
||||||
|
Armor boots = makeArmor(Armor::Material::Iron, Armor::Slot::Boots);
|
||||||
|
addEnchant(boots.enchants, EnchantKind::Mending, 1);
|
||||||
|
boots.durability = boots.maxDurability - 30;
|
||||||
|
gear.equipArmor(boots);
|
||||||
|
|
||||||
|
MetaStack pickaxe = makeEnchantedTool(ItemId::IronPickaxe, withEnchant(EnchantKind::Mending, 1));
|
||||||
|
pickaxe.meta.durability.used = 100;
|
||||||
|
gear.equip(EquipSlot::MainHand, pickaxe);
|
||||||
|
|
||||||
|
int repaired = gear.absorbExperience(10);
|
||||||
|
CHECK_EQ(repaired, 20);
|
||||||
|
CHECK_EQ(gear.armorPiece(EquipSlot::Feet).durability, boots.maxDurability - 10);
|
||||||
|
CHECK_EQ(gear.mainHand().meta.durability.used, 100);
|
||||||
|
|
||||||
|
int spilled = gear.absorbExperience(100);
|
||||||
|
CHECK_EQ(gear.armorPiece(EquipSlot::Feet).durability, boots.maxDurability);
|
||||||
|
CHECK(gear.mainHand().meta.durability.used < 100);
|
||||||
|
CHECK(spilled > 10);
|
||||||
|
|
||||||
|
Equipment plain;
|
||||||
|
plain.equipArmor(makeArmor(Armor::Material::Iron, Armor::Slot::Boots));
|
||||||
|
CHECK_EQ(plain.absorbExperience(50), 0);
|
||||||
|
CHECK_EQ(plain.absorbExperience(0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(theHandsRoundTripThroughAnOpenMenu) {
|
||||||
|
ContainerMenu menu(MenuKind::PlayerInventory, &sharedRegistry());
|
||||||
|
const MenuLayout& layout = menu.layout();
|
||||||
|
|
||||||
|
MetaStack sword = makeEnchantedTool(ItemId::IronSword, withEnchant(EnchantKind::FireAspect, 2));
|
||||||
|
sword.meta.customName = "Emberfang";
|
||||||
|
menu.slot(layout.hotbarFirst + 4).cell.stack = sword;
|
||||||
|
menu.slot(layout.offHandSlot).cell.stack = makeStack(ItemId::Bread, 5);
|
||||||
|
|
||||||
|
Equipment gear;
|
||||||
|
loadHandsFromMenu(gear, menu, 4);
|
||||||
|
CHECK(stacksIdentical(gear.mainHand(), sword));
|
||||||
|
CHECK_EQ(gear.offHand().count, 5);
|
||||||
|
CHECK_EQ(gear.stats().weaponEnchants.levelOf(EnchantKind::FireAspect), 2);
|
||||||
|
|
||||||
|
uint32_t rng = 4u;
|
||||||
|
gear.useHeld(EquipSlot::MainHand, 3, rng);
|
||||||
|
storeHandsIntoMenu(gear, menu, 4);
|
||||||
|
CHECK_EQ(menu.stackAt(layout.hotbarFirst + 4).meta.durability.used, 3);
|
||||||
|
CHECK(menu.stackAt(layout.hotbarFirst + 4).meta.customName == std::string("Emberfang"));
|
||||||
|
|
||||||
|
// A chest screen has no off-hand slot, and loading from it leaves that hand
|
||||||
|
// exactly as it was.
|
||||||
|
ContainerMenu chest(MenuKind::Chest, &sharedRegistry());
|
||||||
|
chest.slot(chest.layout().hotbarFirst).cell.stack = makeStack(ItemId::Stone, 2);
|
||||||
|
loadHandsFromMenu(gear, chest, 0);
|
||||||
|
CHECK(gear.mainHand().item == ItemId::Stone);
|
||||||
|
CHECK_EQ(gear.offHand().count, 5);
|
||||||
|
|
||||||
|
loadHandsFromMenu(gear, chest, 99);
|
||||||
|
CHECK(gear.mainHand().item == ItemId::Stone);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(theModifierListAddsUpToTheStatsItIsDescribing) {
|
||||||
|
Equipment gear = fullDiamond();
|
||||||
|
gear.equip(EquipSlot::MainHand,
|
||||||
|
makeEnchantedTool(ItemId::IronAxe, withEnchant(EnchantKind::Efficiency, 2)));
|
||||||
|
EquipmentStats stats = gear.stats();
|
||||||
|
|
||||||
|
CHECK_NEAR(unarmedAttackDamage +
|
||||||
|
modifierTotal(stats, AttributeModifier::Attribute::AttackDamage),
|
||||||
|
stats.attackDamage, 0.0001f);
|
||||||
|
CHECK_NEAR(unarmedAttackSpeed + modifierTotal(stats, AttributeModifier::Attribute::AttackSpeed),
|
||||||
|
stats.attackSpeed, 0.0001f);
|
||||||
|
CHECK_NEAR(unarmedAttackReach + modifierTotal(stats, AttributeModifier::Attribute::AttackReach),
|
||||||
|
stats.attackReach, 0.0001f);
|
||||||
|
CHECK_NEAR(1.0f + modifierTotal(stats, AttributeModifier::Attribute::MiningSpeed),
|
||||||
|
stats.miningSpeed, 0.0001f);
|
||||||
|
CHECK_NEAR(1.0f + modifierTotal(stats, AttributeModifier::Attribute::MovementSpeed),
|
||||||
|
stats.movementSpeed, 0.0001f);
|
||||||
|
CHECK_NEAR(modifierTotal(stats, AttributeModifier::Attribute::ArmorPoints),
|
||||||
|
static_cast<float>(stats.armorPoints), 0.0001f);
|
||||||
|
|
||||||
|
int handModifiers = 0;
|
||||||
|
for (const AttributeModifier& modifier : stats.modifiers) {
|
||||||
|
if (modifier.slot == EquipSlot::MainHand) ++handModifiers;
|
||||||
|
}
|
||||||
|
CHECK(handModifiers >= 4);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user