feat: add weaponAttackDamage and weaponAttackSpeed to Equipment

This commit is contained in:
dualfroz committed 2026-09-07 19:30:32 +02:00
1 parent f21ca33cdc
commit c38bf7b07a
1 file changed
+159
+159
View File
@@ -151,3 +151,162 @@ const char* attributeName(AttributeModifier::Attribute attribute) {
return "unknown"; return "unknown";
} }
float weaponAttackDamage(ItemId item) {
if (!isTool(item)) return unarmedAttackDamage;
const ItemInfo& info = itemInfo(item);
switch (info.toolType) {
case ToolType::Sword: return swordDamage(info.toolTier);
case ToolType::Axe: return axeDamage(info.toolTier);
case ToolType::Pickaxe: return pickaxeDamage(info.toolTier);
case ToolType::Shovel: return pickaxeDamage(info.toolTier) + 0.5f;
case ToolType::Hoe: return unarmedAttackDamage;
case ToolType::None: break;
}
return unarmedAttackDamage;
}
float weaponAttackSpeed(ItemId item) {
if (!isTool(item)) return unarmedAttackSpeed;
const ItemInfo& info = itemInfo(item);
switch (info.toolType) {
case ToolType::Sword: return 1.6f;
case ToolType::Axe: return axeSpeed(info.toolTier);
case ToolType::Pickaxe: return 1.2f;
case ToolType::Shovel: return 1.0f;
case ToolType::Hoe: return hoeSpeed(info.toolTier);
case ToolType::None: break;
}
return unarmedAttackSpeed;
}
float weaponAttackReach(ItemId item) {
if (!isTool(item)) return unarmedAttackReach;
switch (itemInfo(item).toolType) {
case ToolType::Sword: return unarmedAttackReach + 0.5f;
case ToolType::Axe:
case ToolType::Hoe: return unarmedAttackReach + 0.25f;
case ToolType::Pickaxe:
case ToolType::Shovel:
case ToolType::None: break;
}
return unarmedAttackReach;
}
float armorWeightPenalty(int armorPoints) {
if (armorPoints <= 0) return 0.0f;
float penalty = 0.01f * static_cast<float>(armorPoints);
return penalty > 0.35f ? 0.35f : penalty;
}
void EquipmentStats::applyTo(CombatStats& stats) const {
stats.armor = armor;
stats.baseAttackDamage = attackDamage;
stats.attackSpeed = attackSpeed;
}
bool Equipment::accepts(EquipSlot slot, const MetaStack& stack) const {
if (stack.empty()) return false;
if (!isHandSlot(slot)) return false;
return true;
}
bool Equipment::equip(EquipSlot slot, const MetaStack& stack) {
if (!accepts(slot, stack)) return false;
hands[static_cast<std::size_t>(handIndex(slot))] = stack;
return true;
}
bool Equipment::equipArmor(const Armor& piece) {
return equipArmorAt(equipSlotFor(piece.slot), piece);
}
bool Equipment::equipArmorAt(EquipSlot slot, const Armor& piece) {
if (!isArmorSlot(slot)) return false;
if (piece.material == Armor::Material::None) return false;
if (armorSlotFor(slot) != piece.slot) return false;
worn.at(piece.slot) = piece;
return true;
}
MetaStack Equipment::unequip(EquipSlot slot) {
if (!isHandSlot(slot)) return MetaStack{};
MetaStack removed = hands[static_cast<std::size_t>(handIndex(slot))];
hands[static_cast<std::size_t>(handIndex(slot))].clear();
return removed;
}
Armor Equipment::unequipArmor(EquipSlot slot) {
if (!isArmorSlot(slot)) return Armor{};
Armor& piece = worn.at(armorSlotFor(slot));
Armor removed = piece;
piece = Armor{};
return removed;
}
const MetaStack& Equipment::hand(EquipSlot slot) const {
if (!isHandSlot(slot)) return noStack();
return hands[static_cast<std::size_t>(handIndex(slot))];
}
const Armor& Equipment::armorPiece(EquipSlot slot) const {
Armor::Slot mapped = armorSlotFor(slot);
if (mapped == Armor::Slot::Count) return noArmor();
return worn.at(mapped);
}
EquipmentStats Equipment::stats() const {
EquipmentStats stats;
stats.armor = worn;
stats.armorPoints = worn.totalPoints();
stats.armorToughness = worn.totalToughness();
for (int i = 0; i < static_cast<int>(Armor::Slot::Count); ++i) {
Armor::Slot armorSlot = static_cast<Armor::Slot>(i);
const Armor& piece = worn.at(armorSlot);
if (!piece.worn()) continue;
EquipSlot slot = equipSlotFor(armorSlot);
addModifier(stats, AttributeModifier::Attribute::ArmorPoints,
AttributeModifier::Operation::Add, static_cast<float>(armorPoints(piece)), slot);
addModifier(stats, AttributeModifier::Attribute::ArmorToughness,
AttributeModifier::Operation::Add, armorToughness(piece), slot);
}
float weight = armorWeightPenalty(stats.armorPoints);
stats.movementSpeed = 1.0f - weight;
addModifier(stats, AttributeModifier::Attribute::MovementSpeed,
AttributeModifier::Operation::MultiplyTotal, -weight, EquipSlot::Chest);
const MetaStack& weapon = hands[0];
if (!weapon.empty()) {
stats.weaponEnchants = weapon.meta.enchants;
stats.attackDamage = weaponAttackDamage(weapon.item);
stats.attackSpeed = weaponAttackSpeed(weapon.item);
stats.attackReach = weaponAttackReach(weapon.item);
stats.miningSpeed = toolTierSpeedMultiplier(itemInfo(weapon.item).toolTier);
int efficiency = weapon.meta.enchants.levelOf(EnchantKind::Efficiency);
if (efficiency > 0) {
float bonus = static_cast<float>(efficiency * efficiency + 1);
stats.miningSpeed += bonus;
addModifier(stats, AttributeModifier::Attribute::MiningSpeed,
AttributeModifier::Operation::Add, bonus, EquipSlot::MainHand);
}
addModifier(stats, AttributeModifier::Attribute::AttackDamage,
AttributeModifier::Operation::Add, stats.attackDamage - unarmedAttackDamage,
EquipSlot::MainHand);
addModifier(stats, AttributeModifier::Attribute::AttackSpeed,
AttributeModifier::Operation::Add, stats.attackSpeed - unarmedAttackSpeed,
EquipSlot::MainHand);
addModifier(stats, AttributeModifier::Attribute::AttackReach,
AttributeModifier::Operation::Add, stats.attackReach - unarmedAttackReach,
EquipSlot::MainHand);
addModifier(stats, AttributeModifier::Attribute::MiningSpeed,
AttributeModifier::Operation::Add,
toolTierSpeedMultiplier(itemInfo(weapon.item).toolTier) - 1.0f,
EquipSlot::MainHand);
}
return stats;
}