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