commit
2007fb7edc
200 files changed
+27710
No files matched your search
+229
@@ -0,0 +1,229 @@
|
||||
#pragma once
|
||||
|
||||
#include "fighter.h"
|
||||
#include "protocol.h"
|
||||
|
||||
struct Game;
|
||||
|
||||
constexpr int BEST_OF_MAX = 9;
|
||||
constexpr int PLAYERS_MAX = 4;
|
||||
constexpr int PLAYERS_MIN = 2;
|
||||
constexpr int TIMER_MAX = 10;
|
||||
// A queued game's area: room per player, a margin each end, its height, how finely the ground's checked for one, and
|
||||
// how far below its floor feet still count as in it.
|
||||
constexpr float QUEUE_SLOT_WIDTH = 24;
|
||||
constexpr float QUEUE_MARGIN = 6;
|
||||
constexpr float QUEUE_HEIGHT = 40;
|
||||
constexpr float QUEUE_PROBE_STEP = 4;
|
||||
constexpr float QUEUE_FEET_SLACK = 3;
|
||||
constexpr int QUEUE_START_TICKS = 60;
|
||||
constexpr int BASE_HEALTH_MAX = 10000;
|
||||
constexpr int BASE_HEALTH_MIN = 10;
|
||||
constexpr int PERIOD_MAX = 10;
|
||||
constexpr int PERIOD_MIN = 2;
|
||||
constexpr float MULTIPLIER_MAX = 5;
|
||||
constexpr float COUNTDOWN_TIME = 1;
|
||||
constexpr float READY_TIME = 15;
|
||||
constexpr float CHOICE_SLOT_TIME = 5;
|
||||
|
||||
enum MatchMode
|
||||
{
|
||||
MODE_DEATHMATCH,
|
||||
MODE_RACE
|
||||
};
|
||||
|
||||
enum MatchState
|
||||
{
|
||||
MATCH_PRACTICE,
|
||||
MATCH_COUNTDOWN,
|
||||
MATCH_FIGHT,
|
||||
MATCH_ROUND_OVER,
|
||||
MATCH_OVER
|
||||
};
|
||||
|
||||
// When a match hands out items: once at its start, every round, or every period rounds.
|
||||
enum PickTiming
|
||||
{
|
||||
PICK_FIRST_ROUND,
|
||||
PICK_EVERY_ROUND,
|
||||
PICK_PERIOD
|
||||
};
|
||||
|
||||
// How a match hands out one kind of item: how many slots, dealt at random or chosen in the menu, on which rounds, the
|
||||
// level they start at (1 to 3), whether they gain one each round, whether every fighter mirrors one loadout, whether
|
||||
// a loadout can hold the same item more than once (copies always stack; see Fighter).
|
||||
struct ItemRules
|
||||
{
|
||||
int period = 2;
|
||||
int slots = SLOTS_DEFAULT;
|
||||
int startLevel = 1;
|
||||
int timing = PICK_FIRST_ROUND;
|
||||
bool isChoice = true;
|
||||
bool isDuplicates = false;
|
||||
bool isLevelUp = true;
|
||||
bool isMirror = false;
|
||||
|
||||
bool operator==(const ItemRules&) const = default;
|
||||
};
|
||||
|
||||
// A match's settings, picked in the menu's Play tab. A deathmatch is best of an odd number of rounds, won by taking
|
||||
// more than half of them. Health is the first round's, multiplied by the multiplier for each round after. Timer is a
|
||||
// round's limit in minutes (0 for none). Single player fills every other slot with bots, and bot fill only decides it
|
||||
// in multiplayer.
|
||||
struct Rules
|
||||
{
|
||||
ItemRules trinkets;
|
||||
ItemRules weapons;
|
||||
float health = 250;
|
||||
float healthMultiplier = 2;
|
||||
int bestOf = 3;
|
||||
int mode = MODE_DEATHMATCH;
|
||||
int players = PLAYERS_MIN;
|
||||
int timer = 0;
|
||||
bool isBotFill = false;
|
||||
|
||||
bool operator==(const Rules&) const = default;
|
||||
int wins_get() const
|
||||
{
|
||||
return bestOf / 2 + 1;
|
||||
}
|
||||
};
|
||||
|
||||
// A change a player makes to their own fighter from the menu, sent through its controls so that every machine applies
|
||||
// it on the same tick (and rollback replays it). Item puts an item (or EDIT_EMPTY) in a slot, and is the only kind a
|
||||
// match takes, as a Choice pick; the rest are the sandbox's: one copy's level, an item's level (with every copy of it
|
||||
// equipped), the slot counts (index weapons, value trinkets), PvP on or off, and online, the colour (if no one else has
|
||||
// it).
|
||||
enum EditType
|
||||
{
|
||||
EDIT_ITEM,
|
||||
EDIT_SLOT_LEVEL,
|
||||
EDIT_ITEM_LEVEL,
|
||||
EDIT_SLOTS,
|
||||
EDIT_PVP,
|
||||
EDIT_COLOR,
|
||||
// Online, leaving a queued game (forfeiting it if it's still on).
|
||||
EDIT_LEAVE
|
||||
};
|
||||
|
||||
struct Edit
|
||||
{
|
||||
int type = EDIT_ITEM;
|
||||
bool isTrinket = false;
|
||||
int index = 0;
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
constexpr int EDIT_EMPTY = 31;
|
||||
constexpr int EDIT_FIELD_BITS = 5;
|
||||
constexpr int EDIT_FIELD_MASK = (1 << EDIT_FIELD_BITS) - 1;
|
||||
constexpr int EDIT_KIND_SHIFT = EDIT_FIELD_BITS * 2;
|
||||
constexpr int EDIT_TYPE_SHIFT = EDIT_KIND_SHIFT + 1;
|
||||
|
||||
// An edit packed into one number for a fighter's controls (-1 is none).
|
||||
inline int edit_encode(Edit edit)
|
||||
{
|
||||
return (edit.value & EDIT_FIELD_MASK) | (edit.index & EDIT_FIELD_MASK) << EDIT_FIELD_BITS |
|
||||
edit.isTrinket << EDIT_KIND_SHIFT | edit.type << EDIT_TYPE_SHIFT;
|
||||
}
|
||||
|
||||
inline Edit edit_decode(int code)
|
||||
{
|
||||
return {.type = code >> EDIT_TYPE_SHIFT,
|
||||
.isTrinket = (code >> EDIT_KIND_SHIFT & 1) != 0,
|
||||
.index = code >> EDIT_FIELD_BITS & EDIT_FIELD_MASK,
|
||||
.value = code & EDIT_FIELD_MASK};
|
||||
}
|
||||
|
||||
// Putting an item in a slot (or emptying it, for an item below 0).
|
||||
inline int pick_encode(bool isTrinket, int slot, int item)
|
||||
{
|
||||
return edit_encode(
|
||||
{.type = EDIT_ITEM, .isTrinket = isTrinket, .index = slot, .value = item < 0 ? EDIT_EMPTY : item});
|
||||
}
|
||||
|
||||
// The default rules for a mode: a best-of-three deathmatch for two, or a three minute race for four.
|
||||
Rules rules_get(int mode);
|
||||
Rules rules_clean(Rules rules);
|
||||
|
||||
// Online, a game queued in the lobby's sandbox by one of its fighters: its rules, and the area on the ground where
|
||||
// whoever wants to play it gathers (the queuer standing at its left).
|
||||
struct Queue
|
||||
{
|
||||
Rules rules;
|
||||
Rect area;
|
||||
// How many ticks it's been ready to start for (it starts after QUEUE_START_TICKS).
|
||||
int readyTicks = 0;
|
||||
bool isActive = false;
|
||||
};
|
||||
|
||||
// Best-of-three deathmatch, or a single race, played by the rules. Practice is the sandbox with the dummy and the menu.
|
||||
// Each round opens with a long countdown to ready up in (cut short once every fighter is ready), at the round's level
|
||||
// and health. Countdown is how long it ran from: longer on rounds where fighters choose items. On the rounds items are
|
||||
// handed out, they're dealt at random, or chosen in the menu during the countdown with any slots left empty dealt at
|
||||
// random when it ends. A deathmatch round goes to the last fighter standing, or when the timer runs out to whoever has
|
||||
// the most health left. A drawn round is replayed. A race is won by the first over the finish line (finishers leave the
|
||||
// course), ending once everyone is over, a while after the winner, or when the timer runs out (then the one furthest
|
||||
// along wins if nobody finished). Forfeiting, or Escape after a match, goes back to the sandbox with the loadout and
|
||||
// levels from before it. Enter after a match plays again.
|
||||
class Match
|
||||
{
|
||||
public:
|
||||
Rules rules = rules_get(MODE_DEATHMATCH);
|
||||
MatchState state = MATCH_PRACTICE;
|
||||
float clock = 0;
|
||||
float countdown = READY_TIME;
|
||||
float finishTimes[MAX_FIGHTERS] = {};
|
||||
float timer = 0;
|
||||
int round = 0;
|
||||
int winner = -1;
|
||||
int wins[MAX_FIGHTERS] = {};
|
||||
int colors[MAX_FIGHTERS] = {0, 1, 2, 3};
|
||||
// Online, which lobby member plays each fighter (-1 for none) and their name, kept with the game so every machine
|
||||
// (and a player joining) agrees who's who as fighters come and go.
|
||||
int owners[MAX_FIGHTERS] = {-1, -1, -1, -1};
|
||||
char names[MAX_FIGHTERS][PLAYER_NAME_MAX + 1] = {};
|
||||
bool isReady[MAX_FIGHTERS] = {};
|
||||
// Online, in the lobby's sandbox: each fighter's queued game, which queue's area it's standing in (-1 for none),
|
||||
// whether it's readied up there, and whether it's away playing a queued game (faded, and left alone meanwhile).
|
||||
// In a queued game, whether each fighter has left it (out for good), and whether that was before it was over.
|
||||
Queue queues[MAX_FIGHTERS];
|
||||
int queuedIn[MAX_FIGHTERS] = {-1, -1, -1, -1};
|
||||
bool isQueueReady[MAX_FIGHTERS] = {};
|
||||
bool isAway[MAX_FIGHTERS] = {};
|
||||
bool isGone[MAX_FIGHTERS] = {};
|
||||
bool isForfeited[MAX_FIGHTERS] = {};
|
||||
// After a queued game, how many ticks everyone's been set to play it again for (see Session).
|
||||
int againTicks = 0;
|
||||
bool isTrinketPick = false;
|
||||
bool isWeaponPick = false;
|
||||
Fighter sandbox;
|
||||
|
||||
void update(Game& game);
|
||||
void start(Game& game);
|
||||
void colors_assign(Game& game);
|
||||
void sandbox_return(Game& game);
|
||||
void sandbox_join(Game& game, int device);
|
||||
void sandbox_leave(Game& game, int fighter);
|
||||
bool is_racing();
|
||||
float health_get();
|
||||
bool is_final_round(Game& game);
|
||||
float time_limit_get();
|
||||
void queue_open(Game& game, int fighter, const Rules& rules);
|
||||
int queue_members_get(Game& game, int queuer, int* members);
|
||||
bool is_queue_full(Game& game, int queuer);
|
||||
int queue_startable_get(Game& game);
|
||||
bool is_queue_set(Game& game, int queuer);
|
||||
void queue_slots_shift(int from, int count);
|
||||
int humans_left_get(Game& game);
|
||||
|
||||
private:
|
||||
void round_start(Game& game, bool isFirst);
|
||||
void fight_start(Game& game);
|
||||
void edit_take(Game& game, Fighter& fighter);
|
||||
void mirror_copy(Game& game, bool isTrinket);
|
||||
void deathmatch_update(Game& game);
|
||||
void race_update(Game& game);
|
||||
void queues_update(Game& game);
|
||||
void leaves_take(Game& game);
|
||||
};
|
||||
Reference in new issue
Block a user