readme
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
#ifndef COMBAT_CLASS
|
||||
#define COMBAT_CLASS
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "StatusEffect.h"
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Animation;
|
||||
class CharacterBody;
|
||||
|
||||
// One swing in a combo. Timings are frames of its animation, which has lastFrame of them.
|
||||
struct AttackMove {
|
||||
Animation* animation = nullptr;
|
||||
float duration = 0.5f; // real seconds for the whole move, recovery and all. 0 plays the animation at its own speed.
|
||||
float lastFrame = 120.0f;
|
||||
float hitStartFrame = 40.0f; // the fist can connect from here
|
||||
float hitEndFrame = 60.0f; // to here
|
||||
float recoveryFrame = 60.0f; // from here it's just getting back to normal, and the next swing can cut in
|
||||
float damage = 8.0f;
|
||||
glm::vec3 hitboxSize = glm::vec3(0.9f, 1.2f, 1.0f); // meters across, tall and deep
|
||||
glm::vec3 hitboxOffset = glm::vec3(0.0f, 0.3f, 0.85f); // its middle from the attacker's: right, up and forward. Starts at its front.
|
||||
float knockback = 2.0f; // m/s away from the attacker
|
||||
float knockbackUp = 0.0f; // m/s upward, enough of it and they leave the ground
|
||||
float stun = 0.0f; // real seconds whoever it hits can't do anything
|
||||
bool hitsKnockedDown = false; // can hit characters that are knocked down
|
||||
float moveSpeedMultiplier = 0.0f; // of walking speed while it's going, recovery and all. 0 stands still.
|
||||
float forwardVelocity = 4.0f; // m/s added along where it faces as the swing starts
|
||||
};
|
||||
|
||||
// A move on a number key, like shooting. It plays on the action layer like a swing and goes off partway through,
|
||||
// then can't be used again until its cooldown is up. Timings are frames of its animation, which has lastFrame of them,
|
||||
// or with lastFrame 0, frames at 60 a second.
|
||||
struct Ability {
|
||||
enum class Effect {
|
||||
Shot, // a long thin hitbox from the gun toward where it was aimed, out for the frame it fires
|
||||
Stab, // a short hitbox in front of it the frame it fires. A hit leaves its prop stuck in them, bleeding them.
|
||||
Sweep // a wide hitbox in front of it the frame it fires, catching everyone in it
|
||||
};
|
||||
|
||||
std::string name;
|
||||
std::string description; // what it does, shown hovering over it in the moves list
|
||||
Effect effect = Effect::Shot;
|
||||
Animation* animation = nullptr;
|
||||
float duration = 0.0f; // real seconds for the whole move. 0 plays the animation at its own speed.
|
||||
float lastFrame = 40.0f;
|
||||
float fireFrame = 4.0f; // when it goes off
|
||||
float hitExitFrame = 0.0f; // when it lands, it's over this far in rather than at lastFrame. 0 plays it all.
|
||||
float missExitFrame = 0.0f; // when it doesn't land, it's over this far in. 0 plays it all.
|
||||
float cooldown = 0.5f; // real seconds from it finishing until it can be used again
|
||||
float moveSpeedMultiplier = 0.5f; // of walking speed while it's going
|
||||
bool pivots = false; // keeps turning to face where the player looks while it's going, so it can be aimed
|
||||
float pivotEndFrame = 0.0f; // stops pivoting here, 0 pivots all the way through
|
||||
std::string sound; // played where it goes off, as it does. Empty plays nothing.
|
||||
float screenshake = 0.0f; // how hard the camera shakes as it goes off, when it's the player's
|
||||
|
||||
float damage = 12.0f;
|
||||
float range = 100.0f; // meters, how long the shot's hitbox reaches
|
||||
glm::vec2 hitboxSize = glm::vec2(0.3f, 0.3f); // meters across and tall, around the line of the shot
|
||||
float knockback = 1.0f; // m/s away from the shooter
|
||||
float stun = 0.0f; // real seconds whoever it hits can't do anything
|
||||
float knockdownTime = 0.0f; // real seconds whoever it hits is knocked down for, 0 doesn't
|
||||
// Played on whoever it kills, instead of them just dropping. If it has a bone called Camera and the player is
|
||||
// either of them, the camera follows that bone until it's over.
|
||||
Animation* killAnimation = nullptr;
|
||||
struct KillSound {
|
||||
float frame = 0.0f; // into killAnimation, at 60 a second
|
||||
std::string file;
|
||||
};
|
||||
std::vector<KillSound> killSounds; // played over the kill animation, heard when the camera's following it
|
||||
bool hitsKnockedDown = false; // can hit characters that are knocked down
|
||||
|
||||
// A model shown on one of the animation's own bones while it's going, like a knife. Empty shows nothing.
|
||||
std::string prop;
|
||||
std::string propBone;
|
||||
glm::vec3 propTurn = glm::vec3(0.0f); // degrees around x, y and z on top of the bone's rotation
|
||||
|
||||
// Stab only: how long the prop stays stuck in whoever it hits, hurting them bleedDamage a second meanwhile
|
||||
float bleedTime = 0.0f; // real seconds
|
||||
float bleedDamage = 0.0f;
|
||||
|
||||
// Carries it forward lungeDistance meters, at a steady pace from lungeStartFrame to lungeEndFrame. 0 stays put.
|
||||
float lungeDistance = 0.0f;
|
||||
float lungeStartFrame = 0.0f;
|
||||
float lungeEndFrame = 0.0f;
|
||||
|
||||
// Whoever it hits gets status for statusTime real seconds, at statusFrame if it's still going then,
|
||||
// or as they're hit with statusFrame 0
|
||||
bool appliesStatus = false;
|
||||
StatusEffect::Type status = StatusEffect::Type::HeavyGravity;
|
||||
float statusTime = 0.0f;
|
||||
float statusFrame = 0.0f;
|
||||
};
|
||||
|
||||
// An ability that's just gone off, for the game to carry out
|
||||
struct AbilityFired {
|
||||
int index = -1; // into abilities
|
||||
glm::vec3 aimPoint = glm::vec3(0.0f); // world space, what it was aimed at
|
||||
bool status = false; // its statusFrame came rather than its fireFrame: whoever it hit gets its status now
|
||||
};
|
||||
|
||||
// A character's attacks: a combo that goes through its moves in order, each click starting the next one
|
||||
// while the last is recovering. Waiting out a recovery starts the combo over, so does finishing it.
|
||||
// Abilities sit beside it, one per number key.
|
||||
class CharacterCombat {
|
||||
public:
|
||||
std::vector<AttackMove> combo;
|
||||
std::string comboName; // what the moves list calls the combo
|
||||
std::vector<Ability> abilities; // abilities[0] is on 1, abilities[1] on 2 and so on
|
||||
|
||||
// Asks for the next swing, which starts as soon as the one going lets it
|
||||
void QueueAttack() { queued = true; }
|
||||
|
||||
// Uses abilities[index] aimed at aimPoint, as soon as whatever's going lets it. Nothing while it's cooling down.
|
||||
void UseAbility(int index, const glm::vec3& aimPoint);
|
||||
|
||||
// Stops whatever swing or ability is going, and starts the combo over. Cooldowns carry on.
|
||||
void Reset();
|
||||
|
||||
// Once a frame, dt in game time. Starts queued swings on the body's action layer.
|
||||
void Step(CharacterBody& body, float dt);
|
||||
|
||||
// The swing going now, nullptr between swings
|
||||
const AttackMove* GetCurrentMove() const;
|
||||
int GetCurrentIndex() const { return current; }
|
||||
|
||||
// The ability going now, nullptr if none is
|
||||
const Ability* GetCurrentAbility() const;
|
||||
|
||||
// Different every time an ability starts, for telling one use from the next
|
||||
unsigned int GetAbilityUse() const { return abilityUse; }
|
||||
|
||||
// The ability going now landed, so it ends early if it has a hitExitFrame
|
||||
void AbilityLanded() { abilityLanded = ability >= 0; }
|
||||
bool HasAbilityLanded() const { return abilityLanded; }
|
||||
|
||||
// Whether the ability it's in is lunging it forward right now, and if so how fast, in m/s of game time
|
||||
bool GetAbilityLunge(float& speed) const;
|
||||
|
||||
// Whether the ability it's in turns it to face where it's aimed right now
|
||||
bool IsAbilityPivoting() const;
|
||||
|
||||
// Whether abilities[index] can be used now, and how much of its cooldown is left, 1 just used to 0 ready
|
||||
bool IsAbilityReady(int index) const;
|
||||
float GetCooldownFraction(int index) const;
|
||||
|
||||
// Abilities that went off since the last call, emptied by it
|
||||
std::vector<AbilityFired> TakeFired();
|
||||
|
||||
// Whether the current swing can connect right now, so its hitbox is out
|
||||
bool IsHitting() const;
|
||||
|
||||
// Different for every swing anyone throws, so its hitbox only hits each character once
|
||||
unsigned int GetSwingId() const { return swingId; }
|
||||
|
||||
// A swing id nothing else has, for anything else that puts out hitboxes
|
||||
static unsigned int NewSwingId();
|
||||
|
||||
private:
|
||||
float MoveTime(const AttackMove& move) const; // game seconds the whole move takes
|
||||
float FrameTime(const AttackMove& move, float frame) const; // game seconds into the move
|
||||
void Start(CharacterBody& body, int index);
|
||||
void StartAbility(CharacterBody& body, int index);
|
||||
void StepAbility(CharacterBody& body, float dt);
|
||||
|
||||
int current = -1; // index into combo, -1 between swings
|
||||
int next = 0;
|
||||
float time = 0.0f; // seconds into the current swing
|
||||
bool queued = false;
|
||||
unsigned int swingId = 0;
|
||||
|
||||
int ability = -1; // index into abilities going now, -1 if none
|
||||
float abilityTime = 0.0f; // game seconds into it
|
||||
bool abilityFired = false;
|
||||
bool abilityStatusFired = false;
|
||||
bool abilityLanded = false;
|
||||
unsigned int abilityUse = 0;
|
||||
int queuedAbility = -1;
|
||||
glm::vec3 queuedAim = glm::vec3(0.0f);
|
||||
glm::vec3 abilityAim = glm::vec3(0.0f);
|
||||
std::vector<float> cooldowns; // game seconds left, by ability
|
||||
std::vector<AbilityFired> fired;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user