From 098d58e48ef02692f523e90f9d71d5bee3ee2fcf Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 7 Sep 2026 15:22:43 +0200 Subject: [PATCH] feat: add shiftedInterval and clampZero --- core/src/Effect.cpp | 183 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 core/src/Effect.cpp diff --git a/core/src/Effect.cpp b/core/src/Effect.cpp new file mode 100644 index 0000000..87beb2e --- /dev/null +++ b/core/src/Effect.cpp @@ -0,0 +1,183 @@ +#include "vf/Effect.h" + +#include +#include + +namespace vf { + +namespace { + +int shiftedInterval(int base, int amplifier) { + int interval = base >> std::min(amplifier, 30); + return interval < 1 ? 1 : interval; +} + +float clampZero(float value) { return value < 0.0f ? 0.0f : value; } + +} // namespace + +bool isInstantEffect(EffectKind kind) { + return kind == EffectKind::InstantHealth || kind == EffectKind::InstantDamage; +} + +bool isHarmfulEffect(EffectKind kind) { + switch (kind) { + case EffectKind::Slowness: + case EffectKind::MiningFatigue: + case EffectKind::InstantDamage: + case EffectKind::Nausea: + case EffectKind::Weakness: + case EffectKind::Poison: + case EffectKind::Wither: + case EffectKind::Levitation: + return true; + default: + return false; + } +} + +EffectKind invertedEffect(EffectKind kind) { + switch (kind) { + case EffectKind::Speed: return EffectKind::Slowness; + case EffectKind::Slowness: return EffectKind::Speed; + case EffectKind::InstantHealth: return EffectKind::InstantDamage; + case EffectKind::InstantDamage: return EffectKind::InstantHealth; + case EffectKind::Poison: return EffectKind::InstantDamage; + case EffectKind::JumpBoost: return EffectKind::Slowness; + case EffectKind::NightVision: return EffectKind::Invisibility; + case EffectKind::Invisibility: return EffectKind::NightVision; + case EffectKind::Strength: return EffectKind::Weakness; + case EffectKind::Weakness: return EffectKind::Strength; + default: return EffectKind::Count; + } +} + +EffectInstance makeEffect(EffectKind kind, int level, int durationTicks) { + EffectInstance effect; + effect.kind = kind; + effect.amplifier = std::max(0, level - 1); + effect.durationTicks = isInstantEffect(kind) ? 1 : std::max(0, durationTicks); + return effect; +} + +int periodicIntervalTicks(EffectKind kind, int amplifier) { + switch (kind) { + case EffectKind::Regeneration: return shiftedInterval(50, amplifier); + case EffectKind::Poison: return shiftedInterval(25, amplifier); + case EffectKind::Wither: return shiftedInterval(40, amplifier); + case EffectKind::Saturation: return 1; + default: return 0; + } +} + +bool EffectSet::Pending::empty() const { + return regenerationHeal <= 0.0f && instantHeal <= 0.0f && poisonDamage <= 0.0f && + witherDamage <= 0.0f && instantDamage <= 0.0f && saturationGain <= 0.0f && + expiredCount == 0; +} + +const EffectInstance* findEffect(const EffectSet& set, EffectKind kind) { + const EffectInstance* best = nullptr; + for (const EffectInstance& effect : set.active) { + if (effect.kind != kind) continue; + if (!best || effect.amplifier > best->amplifier) best = &effect; + } + return best; +} + +bool hasEffect(const EffectSet& set, EffectKind kind) { return findEffect(set, kind) != nullptr; } + +int effectLevel(const EffectSet& set, EffectKind kind) { + const EffectInstance* effect = findEffect(set, kind); + return effect ? effect->level() : 0; +} + +int effectDuration(const EffectSet& set, EffectKind kind) { + const EffectInstance* effect = findEffect(set, kind); + return effect ? effect->durationTicks : 0; +} + +bool applyEffect(EffectSet& set, const EffectInstance& effect) { + if (effect.durationTicks <= 0 && !isInstantEffect(effect.kind)) return false; + if (isInstantEffect(effect.kind)) { + EffectInstance instant = effect; + instant.durationTicks = 1; + set.active.push_back(instant); + return true; + } + for (EffectInstance& existing : set.active) { + if (existing.kind != effect.kind) continue; + bool stronger = effect.amplifier > existing.amplifier; + bool sameButLonger = + effect.amplifier == existing.amplifier && effect.durationTicks > existing.durationTicks; + if (!stronger && !sameButLonger) return false; + existing = effect; + return true; + } + set.active.push_back(effect); + return true; +} + +bool removeEffect(EffectSet& set, EffectKind kind) { + std::size_t before = set.active.size(); + set.active.erase(std::remove_if(set.active.begin(), set.active.end(), + [kind](const EffectInstance& e) { return e.kind == kind; }), + set.active.end()); + return set.active.size() != before; +} + +void clearEffects(EffectSet& set) { set.active.clear(); } + +EffectModifier effectModifiers(const EffectSet& set) { + EffectModifier modifier; + for (const EffectInstance& effect : set.active) { + int level = effect.level(); + switch (effect.kind) { + case EffectKind::Speed: + modifier.moveSpeedMultiplier *= 1.0f + 0.20f * static_cast(level); + break; + case EffectKind::Slowness: + modifier.moveSpeedMultiplier *= + clampZero(1.0f - 0.15f * static_cast(level)); + break; + case EffectKind::Haste: + modifier.miningSpeedMultiplier *= 1.0f + 0.20f * static_cast(level); + break; + case EffectKind::MiningFatigue: + modifier.miningSpeedMultiplier *= std::pow(0.3f, static_cast(level)); + break; + case EffectKind::Strength: + modifier.attackDamageBonus += 3.0f * static_cast(level); + break; + case EffectKind::Weakness: + modifier.attackDamageBonus -= 4.0f * static_cast(level); + break; + case EffectKind::Resistance: + modifier.incomingDamageMultiplier *= + clampZero(1.0f - 0.20f * static_cast(level)); + break; + case EffectKind::JumpBoost: + modifier.jumpVelocityBonus += 0.10f * static_cast(level); + break; + case EffectKind::HealthBoost: + modifier.maxHealthBonus += 4.0f * static_cast(level); + break; + case EffectKind::Absorption: + modifier.absorptionHearts += 4.0f * static_cast(level); + break; + case EffectKind::Levitation: + modifier.levitationSpeed += 0.9f * static_cast(level); + break; + case EffectKind::Nausea: + modifier.nauseaIntensity += static_cast(level); + break; + case EffectKind::FireResistance: modifier.fireImmune = true; break; + case EffectKind::WaterBreathing: modifier.waterBreathing = true; break; + case EffectKind::Invisibility: modifier.invisible = true; break; + case EffectKind::NightVision: modifier.nightVision = true; break; + default: break; + } + } + return modifier; +} +