feat(vf): add EffectInstance and EffectModifier
This commit is contained in:
1 parent
5a458b1bf0
commit
c6de2c445f
1 file changed
+106
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace vf {
|
||||
|
||||
constexpr int ticksPerSecond = 20;
|
||||
|
||||
enum class EffectKind : uint8_t {
|
||||
Speed, Slowness, Haste, MiningFatigue, Strength, InstantHealth, InstantDamage,
|
||||
JumpBoost, Nausea, Regeneration, Resistance, FireResistance, WaterBreathing,
|
||||
Invisibility, Weakness, Poison, Wither, HealthBoost, Absorption, Saturation,
|
||||
Levitation, NightVision,
|
||||
Count
|
||||
};
|
||||
|
||||
// Instant effects resolve on the first tick after application and never linger.
|
||||
bool isInstantEffect(EffectKind kind);
|
||||
bool isHarmfulEffect(EffectKind kind);
|
||||
|
||||
// Fermented spider eye corruption. Returns EffectKind::Count for effects that
|
||||
// have no counterpart.
|
||||
EffectKind invertedEffect(EffectKind kind);
|
||||
|
||||
struct EffectInstance {
|
||||
EffectKind kind = EffectKind::Speed;
|
||||
int amplifier = 0;
|
||||
int durationTicks = 0;
|
||||
// Scales instant heal/damage magnitude; splash potions land at less than
|
||||
// one on anything not standing on the impact point.
|
||||
float potency = 1.0f;
|
||||
bool ambient = false;
|
||||
|
||||
int level() const { return amplifier + 1; }
|
||||
bool expired() const { return durationTicks <= 0; }
|
||||
};
|
||||
|
||||
EffectInstance makeEffect(EffectKind kind, int level, int durationTicks);
|
||||
|
||||
// Ticks between two firings of a periodic effect. Higher levels fire faster
|
||||
// until the interval bottoms out at a single tick.
|
||||
int periodicIntervalTicks(EffectKind kind, int amplifier);
|
||||
|
||||
// Attribute deltas contributed by a whole EffectSet, resolved once per tick
|
||||
// instead of being queried effect by effect.
|
||||
struct EffectModifier {
|
||||
float moveSpeedMultiplier = 1.0f;
|
||||
float miningSpeedMultiplier = 1.0f;
|
||||
float attackDamageBonus = 0.0f;
|
||||
float incomingDamageMultiplier = 1.0f;
|
||||
float jumpVelocityBonus = 0.0f;
|
||||
float maxHealthBonus = 0.0f;
|
||||
float absorptionHearts = 0.0f;
|
||||
float levitationSpeed = 0.0f;
|
||||
float nauseaIntensity = 0.0f;
|
||||
bool fireImmune = false;
|
||||
bool waterBreathing = false;
|
||||
bool invisible = false;
|
||||
bool nightVision = false;
|
||||
};
|
||||
|
||||
struct EffectSet {
|
||||
// Health and food work produced by one tick, kept separate per source so a
|
||||
// caller can honour the rule that poison stops at half a heart while wither
|
||||
// does not.
|
||||
struct Pending {
|
||||
float regenerationHeal = 0.0f;
|
||||
float instantHeal = 0.0f;
|
||||
float poisonDamage = 0.0f;
|
||||
float witherDamage = 0.0f;
|
||||
float instantDamage = 0.0f;
|
||||
float saturationGain = 0.0f;
|
||||
int expiredCount = 0;
|
||||
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
std::vector<EffectInstance> active;
|
||||
};
|
||||
|
||||
const EffectInstance* findEffect(const EffectSet& set, EffectKind kind);
|
||||
bool hasEffect(const EffectSet& set, EffectKind kind);
|
||||
int effectLevel(const EffectSet& set, EffectKind kind);
|
||||
int effectDuration(const EffectSet& set, EffectKind kind);
|
||||
|
||||
// Applies an effect using the vanilla precedence: a stronger amplifier always
|
||||
// replaces, an equal amplifier replaces only when it lasts longer, a weaker one
|
||||
// is dropped. Instant effects stack as separate entries and are consumed by the
|
||||
// next tickEffects call. Returns true when the set actually changed.
|
||||
bool applyEffect(EffectSet& set, const EffectInstance& effect);
|
||||
|
||||
bool removeEffect(EffectSet& set, EffectKind kind);
|
||||
void clearEffects(EffectSet& set);
|
||||
|
||||
EffectModifier effectModifiers(const EffectSet& set);
|
||||
|
||||
// Advances every effect by one tick, dropping expired ones and reporting the
|
||||
// periodic and instant work owed to the entity this tick.
|
||||
EffectSet::Pending tickEffects(EffectSet& set);
|
||||
|
||||
// Applies one tick of pending health work. Poison never takes the last half
|
||||
// heart; wither and instant damage can kill. Returns the signed health change.
|
||||
float applyEffectTick(const EffectSet::Pending& pending, float& health, float maxHealth);
|
||||
|
||||
} // namespace vf
|
||||
Reference in new issue
Block a user