feat: add shiftedInterval and clampZero
This commit is contained in:
1 parent
e52980886e
commit
098d58e48e
1 file changed
+183
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user