feat(vf): add WitherFightConfig and WitherTarget to Boss
This commit is contained in:
1 parent
76f2be284b
commit
5d7081ff32
1 file changed
+128
@@ -158,3 +158,131 @@ public:
|
|||||||
DragonFight(DragonFight&&) = delete;
|
DragonFight(DragonFight&&) = delete;
|
||||||
DragonFight& operator=(DragonFight&&) = delete;
|
DragonFight& operator=(DragonFight&&) = delete;
|
||||||
|
|
||||||
|
BossTickReport tick(const DragonPlayerInput& input);
|
||||||
|
|
||||||
|
const BossState& state() const { return boss; }
|
||||||
|
const DragonFightConfig& settings() const { return cfg; }
|
||||||
|
const std::vector<CrystalNode>& crystals() const { return pillarCrystals; }
|
||||||
|
int aliveCrystalCount() const;
|
||||||
|
// Taken from the End generator: the fight orbits and perches on the real
|
||||||
|
// exit portal column, not on an invented origin.
|
||||||
|
Vec3 portalCenter() const { return portal; }
|
||||||
|
|
||||||
|
bool exitPortalOpen() const { return portalOpen; }
|
||||||
|
bool dragonEggDropped() const { return eggDropped; }
|
||||||
|
Vec3i eggPosition() const { return eggCell; }
|
||||||
|
|
||||||
|
const BehaviorTree& brain() const { return tree; }
|
||||||
|
const BehaviorContext& context() const { return ctx; }
|
||||||
|
|
||||||
|
// Writes the reward the fight earned: the real End exit portal from
|
||||||
|
// EndGen. Refuses while the dragon still lives.
|
||||||
|
bool placeVictoryStructures(World& world, const EndGenerator& end) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void buildTree();
|
||||||
|
int resolvePlayerShot(const DragonPlayerInput& input);
|
||||||
|
void applyPlayerMelee(const DragonPlayerInput& input);
|
||||||
|
float applyCrystalHealing();
|
||||||
|
|
||||||
|
DragonFightConfig cfg;
|
||||||
|
BossState boss;
|
||||||
|
std::vector<CrystalNode> pillarCrystals;
|
||||||
|
BehaviorTree tree;
|
||||||
|
BehaviorContext ctx;
|
||||||
|
DragonPlayerInput lastInput;
|
||||||
|
Vec3 portal;
|
||||||
|
Vec3i eggCell;
|
||||||
|
bool portalOpen = false;
|
||||||
|
bool eggDropped = false;
|
||||||
|
float damageThisTick = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WitherFightConfig {
|
||||||
|
float maxHealth = 300.0f;
|
||||||
|
int summonTicks = 220;
|
||||||
|
float summonBlastRadius = 8.0f;
|
||||||
|
float summonBlastDamage = 12.0f;
|
||||||
|
float armorThreshold = 0.5f;
|
||||||
|
float projectileDamage = 5.0f;
|
||||||
|
float projectileRange = 32.0f;
|
||||||
|
int projectileCooldownTicks = 20;
|
||||||
|
int minionCooldownTicks = 100;
|
||||||
|
int maxMinions = 3;
|
||||||
|
float minionSpawnRange = 6.0f;
|
||||||
|
float armoredRegenPerTick = 0.06f;
|
||||||
|
float moveStep = 0.35f;
|
||||||
|
float minTargetDistance = 6.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WitherTarget {
|
||||||
|
Vec3 position;
|
||||||
|
float health = 20.0f;
|
||||||
|
bool alive = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BossMinion {
|
||||||
|
Vec3 position;
|
||||||
|
float health = 6.0f;
|
||||||
|
bool alive = true;
|
||||||
|
long long spawnedTick = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WitherHit {
|
||||||
|
float amount = 0.0f;
|
||||||
|
bool projectile = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The block pattern that calls the wither: a soul sand T topped with three
|
||||||
|
// heads, readable along either horizontal axis.
|
||||||
|
Block witherBaseBlock();
|
||||||
|
Block witherHeadBlock();
|
||||||
|
bool witherPatternAt(const World& world, const Vec3i& baseCell, bool alongX);
|
||||||
|
bool findWitherPattern(const World& world, const Vec3i& baseCell, bool& outAlongX);
|
||||||
|
void consumeWitherPattern(World& world, const Vec3i& baseCell, bool alongX);
|
||||||
|
|
||||||
|
// Summons out of a block pattern, blasts everything around it on arrival, then
|
||||||
|
// hunts the nearest living target. Below half health it armours up: projectiles
|
||||||
|
// stop landing entirely and it starts regenerating and calling minions.
|
||||||
|
class WitherFight {
|
||||||
|
public:
|
||||||
|
explicit WitherFight(uint32_t seed, const WitherFightConfig& config = {});
|
||||||
|
|
||||||
|
WitherFight(const WitherFight&) = delete;
|
||||||
|
WitherFight& operator=(const WitherFight&) = delete;
|
||||||
|
WitherFight(WitherFight&&) = delete;
|
||||||
|
WitherFight& operator=(WitherFight&&) = delete;
|
||||||
|
|
||||||
|
void begin(const Vec3& spawnPosition);
|
||||||
|
// Consumes the pattern in the world and starts the fight at its centre.
|
||||||
|
bool summonFromWorld(World& world, const Vec3i& baseCell);
|
||||||
|
|
||||||
|
BossTickReport tick(const std::vector<WitherHit>& incoming,
|
||||||
|
std::vector<WitherTarget>& targets);
|
||||||
|
|
||||||
|
const BossState& state() const { return boss; }
|
||||||
|
const WitherFightConfig& settings() const { return cfg; }
|
||||||
|
const std::vector<BossMinion>& minions() const { return summoned; }
|
||||||
|
bool armored() const { return boss.phase == BossPhase::Armored; }
|
||||||
|
int aliveMinionCount() const;
|
||||||
|
|
||||||
|
const BehaviorTree& brain() const { return tree; }
|
||||||
|
const BehaviorContext& context() const { return ctx; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void buildTree();
|
||||||
|
float applyIncoming(const std::vector<WitherHit>& incoming);
|
||||||
|
int nearestAliveTarget() const;
|
||||||
|
|
||||||
|
WitherFightConfig cfg;
|
||||||
|
BossState boss;
|
||||||
|
std::vector<BossMinion> summoned;
|
||||||
|
BehaviorTree tree;
|
||||||
|
BehaviorContext ctx;
|
||||||
|
std::vector<WitherTarget>* activeTargets = nullptr;
|
||||||
|
float damageThisTick = 0.0f;
|
||||||
|
float healedThisTick = 0.0f;
|
||||||
|
int minionsThisTick = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vf
|
||||||
Reference in new issue
Block a user