feat: add shiftedInterval and clampZero

This commit is contained in:
dualfroz committed 2026-09-07 15:22:43 +02:00
1 parent e52980886e
commit 098d58e48e
1 file changed
+183
+183
View File
@@ -0,0 +1,183 @@
#include "vf/Effect.h"
#include <algorithm>
#include <cmath>
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<float>(level);
break;
case EffectKind::Slowness:
modifier.moveSpeedMultiplier *=
clampZero(1.0f - 0.15f * static_cast<float>(level));
break;
case EffectKind::Haste:
modifier.miningSpeedMultiplier *= 1.0f + 0.20f * static_cast<float>(level);
break;
case EffectKind::MiningFatigue:
modifier.miningSpeedMultiplier *= std::pow(0.3f, static_cast<float>(level));
break;
case EffectKind::Strength:
modifier.attackDamageBonus += 3.0f * static_cast<float>(level);
break;
case EffectKind::Weakness:
modifier.attackDamageBonus -= 4.0f * static_cast<float>(level);
break;
case EffectKind::Resistance:
modifier.incomingDamageMultiplier *=
clampZero(1.0f - 0.20f * static_cast<float>(level));
break;
case EffectKind::JumpBoost:
modifier.jumpVelocityBonus += 0.10f * static_cast<float>(level);
break;
case EffectKind::HealthBoost:
modifier.maxHealthBonus += 4.0f * static_cast<float>(level);
break;
case EffectKind::Absorption:
modifier.absorptionHearts += 4.0f * static_cast<float>(level);
break;
case EffectKind::Levitation:
modifier.levitationSpeed += 0.9f * static_cast<float>(level);
break;
case EffectKind::Nausea:
modifier.nauseaIntensity += static_cast<float>(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;
}