beta heart system
This commit is contained in:
parent
b8c29cad9d
commit
c5f08c8bcc
@ -8,6 +8,7 @@ players:
|
|||||||
startXPosition: 50
|
startXPosition: 50
|
||||||
fireCooldown: 10
|
fireCooldown: 10
|
||||||
speed: 20
|
speed: 20
|
||||||
|
lives: 3
|
||||||
user1:
|
user1:
|
||||||
color: red
|
color: red
|
||||||
keys:
|
keys:
|
||||||
|
@ -20,6 +20,7 @@ struct ConfigData {
|
|||||||
unsigned playersSpeed;
|
unsigned playersSpeed;
|
||||||
unsigned playersWidth;
|
unsigned playersWidth;
|
||||||
unsigned playersFireCooldown;
|
unsigned playersFireCooldown;
|
||||||
|
unsigned playersLives;
|
||||||
vector<PlayerDef> playerDefs;
|
vector<PlayerDef> playerDefs;
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ private:
|
|||||||
bool direction = true;
|
bool direction = true;
|
||||||
|
|
||||||
vector<missile> missiles;
|
vector<missile> missiles;
|
||||||
vector<torpedo> torpedos;
|
vector<Torpedo> torpedos;
|
||||||
|
|
||||||
PlayMode playMode;
|
PlayMode playMode;
|
||||||
vector<Player> players;
|
vector<Player> players;
|
||||||
@ -37,6 +37,7 @@ private:
|
|||||||
unsigned fireCooldown=120;
|
unsigned fireCooldown=120;
|
||||||
|
|
||||||
// basic methods
|
// basic methods
|
||||||
|
void initGame();
|
||||||
bool updateColumns();
|
bool updateColumns();
|
||||||
void handleScoreSaving();
|
void handleScoreSaving();
|
||||||
Position invIndexToPos(unsigned x, unsigned y) const;
|
Position invIndexToPos(unsigned x, unsigned y) const;
|
||||||
@ -69,7 +70,7 @@ public:
|
|||||||
// in case someone wants to mess with the code, here's a minimal API, costs nothing to us
|
// in case someone wants to mess with the code, here's a minimal API, costs nothing to us
|
||||||
Game();
|
Game();
|
||||||
void managedGames();
|
void managedGames();
|
||||||
WinValue playGame();
|
WinValue enterGameLoop();
|
||||||
|
|
||||||
bool reloadConfig();
|
bool reloadConfig();
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,6 @@ enum class PlayMode {
|
|||||||
NONE,
|
NONE,
|
||||||
SINGLE,
|
SINGLE,
|
||||||
TWO_LOCAL,
|
TWO_LOCAL,
|
||||||
TWO_TCPIP,
|
|
||||||
EXIT,
|
EXIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,7 +11,10 @@ struct Player{
|
|||||||
unsigned fireCooldown=0;
|
unsigned fireCooldown=0;
|
||||||
|
|
||||||
// TODO remove ?
|
// TODO remove ?
|
||||||
bool isEliminated();
|
bool hasDeathAnimation() const;
|
||||||
|
bool isEliminated() const;
|
||||||
|
bool isPlaying() const;
|
||||||
|
void damage();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
typedef Position missile;
|
typedef Position missile;
|
||||||
|
|
||||||
class torpedo : public Position {
|
class Torpedo : public Position {
|
||||||
public:
|
public:
|
||||||
playerID owner;
|
playerID owner;
|
||||||
torpedo(int x, int y, playerID owner);
|
Torpedo(int x, int y, playerID owner);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#ifndef GUARD_SCORESMANAGER_H
|
#ifndef GUARD_SCORESMANAGER_H
|
||||||
#define GUARD_SCORESMANAGER_H
|
#define GUARD_SCORESMANAGER_H
|
||||||
|
|
||||||
#include <utility>
|
#include<utility>
|
||||||
#include <vector>
|
#include<vector>
|
||||||
#include <string>
|
#include<string>
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
struct ScoreLink{
|
struct ScoreLink{
|
||||||
string name;
|
string name;
|
||||||
unsigned score;
|
unsigned score;
|
||||||
ScoreLink() = default;
|
|
||||||
ScoreLink(const string& name, unsigned score);
|
ScoreLink(const string& name, unsigned score);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
#define PROJ_LENGTH_FACTOR 2
|
#define PROJ_LENGTH_FACTOR 2
|
||||||
// TODO utiliser ca de partout
|
// TODO utiliser ca de partout
|
||||||
|
|
||||||
|
/* Copy constructuor and assignement are disabled in most of
|
||||||
|
* our classes so we're sure we can't accidentally copy players
|
||||||
|
* (We need to explicitly specify the default constructor)*/
|
||||||
#define INV_GET_POS(i) confData.invadersSize*(i)+confData.invadersDistance*(i)
|
#define INV_GET_POS(i) confData.invadersSize*(i)+confData.invadersDistance*(i)
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,6 +169,7 @@ void ConfigBuilder::readConfig() {
|
|||||||
collectedData.startXPosition = getInt("players.startXPosition");
|
collectedData.startXPosition = getInt("players.startXPosition");
|
||||||
collectedData.playersSpeed = getInt("players.speed");
|
collectedData.playersSpeed = getInt("players.speed");
|
||||||
collectedData.playersFireCooldown = getInt("players.fireCooldown");
|
collectedData.playersFireCooldown = getInt("players.fireCooldown");
|
||||||
|
collectedData.playersLives = getInt("players.lives");
|
||||||
|
|
||||||
// the scalability behind the vector of players is only an illusion, because we force player count to be 1 or 2
|
// the scalability behind the vector of players is only an illusion, because we force player count to be 1 or 2
|
||||||
// It was done so the 2+ players implementation could be easier in the future, if wanted
|
// It was done so the 2+ players implementation could be easier in the future, if wanted
|
||||||
@ -272,6 +273,6 @@ bool Game::reloadConfig() {
|
|||||||
cerr << "(The old configuration was kept in memory)" << endl;
|
cerr << "(The old configuration was kept in memory)" << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
confData = builder.collectedData;
|
confData = move(builder.collectedData);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ void Game::displayAll(unsigned fps) const {
|
|||||||
for(const missile& miss : missiles){
|
for(const missile& miss : missiles){
|
||||||
pm.drawMissile(miss, confData.missilesWidth, confData.missilesColor);
|
pm.drawMissile(miss, confData.missilesWidth, confData.missilesColor);
|
||||||
}
|
}
|
||||||
for(const torpedo& tor : torpedos){
|
for(const Torpedo& tor : torpedos){
|
||||||
pm.drawTorpedo(tor, confData.torpedosWidth, confData.torpedosColor);
|
pm.drawTorpedo(tor, confData.torpedosWidth, confData.torpedosColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,17 +30,16 @@ void Game::displayAll(unsigned fps) const {
|
|||||||
|
|
||||||
|
|
||||||
for(size_t i=0;i<players.size();++i){
|
for(size_t i=0;i<players.size();++i){
|
||||||
|
if(players[i].deathAnimCounter%2==0){
|
||||||
pm.drawPlayer(players[i].x, confData.playersWidth, confData.playerDefs[i].color);
|
pm.drawPlayer(players[i].x, confData.playersWidth, confData.playerDefs[i].color);
|
||||||
}
|
}
|
||||||
|
displayHearts(i);
|
||||||
// As said before, the player loop is an illusion, 2 players max
|
|
||||||
for(unsigned i=0;i<players[0].lives;++i){
|
|
||||||
|
|
||||||
}
|
}
|
||||||
pm.drawHeart(Position(0, 70));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::displayHearts(playerID pID) const {
|
void Game::displayHearts(playerID pID) const {
|
||||||
|
|
||||||
|
// As said before, the player loop is an illusion, 2 players max
|
||||||
unsigned x;
|
unsigned x;
|
||||||
if(pID==PLAYER1)x = 0;
|
if(pID==PLAYER1)x = 0;
|
||||||
else x = pm.getScreenWidth()-HEART_LENGTH;
|
else x = pm.getScreenWidth()-HEART_LENGTH;
|
||||||
@ -50,14 +49,14 @@ void Game::displayHearts(playerID pID) const {
|
|||||||
pm.drawHeart(Position(x, y));
|
pm.drawHeart(Position(x, y));
|
||||||
y+=HEART_LENGTH+5;
|
y+=HEART_LENGTH+5;
|
||||||
}
|
}
|
||||||
if(players[pID].deathAnimCounter>0){
|
if(players[pID].hasDeathAnimation()){
|
||||||
|
pm.drawHeart(Position(x, y+players[pID].deathAnimCounter*5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::displayInvader(const Position& pos, InvaderType type) const {
|
void Game::displayInvader(const Position& pos, InvaderType type) const {
|
||||||
if(type==InvaderType::NONE)return;
|
if(type==InvaderType::NONE)return;
|
||||||
InvaderTypeDef invDef = confData.invadersDef.at(type);
|
const InvaderTypeDef& invDef = confData.invadersDef.at(type);
|
||||||
switch(type){
|
switch(type){
|
||||||
case InvaderType::TYPEA:{
|
case InvaderType::TYPEA:{
|
||||||
pm.drawInvaderA(pos, confData.invadersSize, invDef.color);
|
pm.drawInvaderA(pos, confData.invadersSize, invDef.color);
|
||||||
@ -74,7 +73,6 @@ void Game::displayInvader(const Position& pos, InvaderType type) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void applyBezier(Position& pos, const Position& point, const double percent) {
|
void applyBezier(Position& pos, const Position& point, const double percent) {
|
||||||
pos += (point-pos)*percent;
|
pos += (point-pos)*percent;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,8 @@ void Game::managedGames() {
|
|||||||
if(playMode==PlayMode::NONE){
|
if(playMode==PlayMode::NONE){
|
||||||
playMode = pm.showInitialMenu();
|
playMode = pm.showInitialMenu();
|
||||||
}else{
|
}else{
|
||||||
playGame(); // will read the playMode
|
initGame();
|
||||||
|
enterGameLoop(); // will read the playMode
|
||||||
handleScoreSaving();
|
handleScoreSaving();
|
||||||
cout << "END OF GAME" << endl;
|
cout << "END OF GAME" << endl;
|
||||||
break; // TODO remove
|
break; // TODO remove
|
||||||
@ -66,19 +67,13 @@ void Game::managedGames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO maybe directly call theses from pm and do not use getters ?
|
// we assume the game has been played before, and so we need to clean used members
|
||||||
|
void Game::initGame(){
|
||||||
/**
|
|
||||||
* Plays the game, and returns once the game is finished
|
|
||||||
*
|
|
||||||
* @return @WinValue::PLAYERS if the players won, @WinValue::INVADERS is the invaders won, WinValue::NOBODY else (also in case of error)
|
|
||||||
*/
|
|
||||||
WinValue Game::playGame(){ // returns when game is finished
|
|
||||||
// INIT
|
|
||||||
// we assume the game has been played before, and so we need to clean used members
|
|
||||||
grid = confData.grid; // will copy the grid
|
grid = confData.grid; // will copy the grid
|
||||||
updateColumns(); // Would have liked to to that in the "config grid", but.. I'm lazy
|
updateColumns(); // Would have liked to to that in the "config grid", but.. I'm lazy
|
||||||
|
|
||||||
|
// we re-construct players objects, we don't have to clear all members and can rely on the construction value (set in .h file)
|
||||||
|
players.clear();
|
||||||
|
|
||||||
if(playMode==PlayMode::SINGLE){
|
if(playMode==PlayMode::SINGLE){
|
||||||
players.resize(1);
|
players.resize(1);
|
||||||
@ -89,9 +84,21 @@ WinValue Game::playGame(){ // returns when game is finished
|
|||||||
}
|
}
|
||||||
players[0].x = confData.startXPosition;
|
players[0].x = confData.startXPosition;
|
||||||
|
|
||||||
basePos = Position(200, 0);
|
for(unsigned i=0;i<players.size();++i){
|
||||||
// GAMELOOP
|
players[i].id = i;
|
||||||
|
players[i].lives = confData.playersLives;
|
||||||
|
}
|
||||||
|
|
||||||
|
basePos = Position(200, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays the game, and returns once the game is finished
|
||||||
|
*
|
||||||
|
* @return @WinValue::PLAYERS if the players won, @WinValue::INVADERS is the invaders won, WinValue::NOBODY else (also in case of error)
|
||||||
|
*/
|
||||||
|
WinValue Game::enterGameLoop(){ // returns when game is finished
|
||||||
// computed in advance for performance reasons
|
// computed in advance for performance reasons
|
||||||
chrono::milliseconds maxFrameTime = chrono::milliseconds(1000/confData.maxFPS);
|
chrono::milliseconds maxFrameTime = chrono::milliseconds(1000/confData.maxFPS);
|
||||||
|
|
||||||
|
@ -2,39 +2,33 @@
|
|||||||
|
|
||||||
#define ISPRESSED(ID, X) window.isPressed({confData.playerDefs[ID].keys.X, false})
|
#define ISPRESSED(ID, X) window.isPressed({confData.playerDefs[ID].keys.X, false})
|
||||||
void Game::manageOnePlayer(playerID pID){
|
void Game::manageOnePlayer(playerID pID){
|
||||||
// manage death
|
Player& p = players[pID];
|
||||||
|
|
||||||
// we do not use isEliminated here because we can handle it better with if/else
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* lives = 0 && counter == 0 -> elim
|
|
||||||
* lives = 1 && counter == 0 -> play
|
|
||||||
* lives = 0 && counter == 1 -> anim
|
|
||||||
* lives = 1 && counter == 1 -> anim
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(players[pID].deathAnimCounter==0){
|
|
||||||
if(players[pID].lives==0)return;
|
|
||||||
}else{
|
|
||||||
++players[pID].deathAnimCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (ISPRESSED(pID, left)){
|
if (ISPRESSED(pID, left)){
|
||||||
if(players[pID].x < confData.playersSpeed) players[pID].x = 0;
|
if(p.x < confData.playersSpeed) p.x = 0;
|
||||||
else players[pID].x -= confData.playersSpeed;
|
else p.x -= confData.playersSpeed;
|
||||||
}
|
}
|
||||||
if (ISPRESSED(pID, right)){
|
if (ISPRESSED(pID, right)){
|
||||||
if(players[pID].x + confData.playersWidth + confData.playersSpeed >= pm.getScreenWidth()) players[pID].x = pm.getScreenWidth() - confData.playersWidth - 1;
|
if(p.x + confData.playersWidth + confData.playersSpeed >= pm.getScreenWidth()) p.x = pm.getScreenWidth() - confData.playersWidth - 1;
|
||||||
else players[pID].x += confData.playersSpeed;
|
else p.x += confData.playersSpeed;
|
||||||
}
|
}
|
||||||
if(players[pID].fireCooldown==0) {
|
|
||||||
|
|
||||||
|
if(p.hasDeathAnimation()) {
|
||||||
|
++p.deathAnimCounter;
|
||||||
|
if (p.deathAnimCounter == 100) {
|
||||||
|
p.deathAnimCounter = 0;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(p.isEliminated())return;
|
||||||
|
|
||||||
|
if(p.fireCooldown==0) {
|
||||||
if (ISPRESSED(pID, shoot)) {
|
if (ISPRESSED(pID, shoot)) {
|
||||||
torpedos.emplace_back(players[pID].x + confData.playersWidth / 2, pm.getScreenHeight() - PLAYER_HEIGHT, pID);
|
torpedos.emplace_back(p.x + confData.playersWidth / 2, pm.getScreenHeight() - PLAYER_HEIGHT, pID);
|
||||||
players[pID].fireCooldown = confData.playersFireCooldown;
|
p.fireCooldown = confData.playersFireCooldown;
|
||||||
|
}
|
||||||
|
}else --p.fireCooldown;
|
||||||
}
|
}
|
||||||
}else --players[pID].fireCooldown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Makes the players play once
|
/** Makes the players play once
|
||||||
@ -48,7 +42,7 @@ void Game::managePlayers(){
|
|||||||
* @return true if the invaders went down from one line (and we should check lower boundary), else false
|
* @return true if the invaders went down from one line (and we should check lower boundary), else false
|
||||||
*/
|
*/
|
||||||
bool Game::manageInvaders(){
|
bool Game::manageInvaders(){
|
||||||
if(grid.size()==0)return false; // If there are no more invaders we don't need to manage them
|
if(grid.empty())return false; // If there are no more invaders we don't need to manage them
|
||||||
// shoot
|
// shoot
|
||||||
if(fireCooldown==0) {
|
if(fireCooldown==0) {
|
||||||
fireCooldown = confData.invadersFireCooldown + rand() % 60;
|
fireCooldown = confData.invadersFireCooldown + rand() % 60;
|
||||||
@ -152,15 +146,17 @@ bool Game::checkMissilesAndPlayers() {
|
|||||||
if(miss_ite->getY()>=pm.getScreenHeight()-PLAYER_HEIGHT){ // check collision on Y
|
if(miss_ite->getY()>=pm.getScreenHeight()-PLAYER_HEIGHT){ // check collision on Y
|
||||||
// now check collision on X (with both players)
|
// now check collision on X (with both players)
|
||||||
for(Player& p : players){
|
for(Player& p : players){
|
||||||
|
if(p.isPlaying()){
|
||||||
if(areLinesColliding(
|
if(areLinesColliding(
|
||||||
miss_ite->getX(), miss_ite->getX() + confData.missilesWidth,
|
miss_ite->getX(), miss_ite->getX() + confData.missilesWidth,
|
||||||
p.x, p.x + confData.playersWidth)){
|
p.x, p.x + confData.playersWidth)){
|
||||||
wasColliding = true;
|
wasColliding = true;
|
||||||
if(p.deathAnimCounter)p.deathAnimCounter = 1;
|
p.damage();
|
||||||
// do not break, the second player also deserves to be hit
|
// do not break, the second player also deserves to be hit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if(wasColliding)missiles.erase(miss_ite);
|
if(wasColliding)missiles.erase(miss_ite);
|
||||||
else ++miss_ite;
|
else ++miss_ite;
|
||||||
}
|
}
|
||||||
@ -190,7 +186,7 @@ bool Game::checkTorpedosAndInvaders() {
|
|||||||
|
|
||||||
|
|
||||||
InvaderType invType = grid[i][grid[i].size()];
|
InvaderType invType = grid[i][grid[i].size()];
|
||||||
players[tor_ite->owner].score += confData.invadersDef[invType].points;
|
players[tor_ite->owner].score += confData.invadersDef.at(invType).points;
|
||||||
torpedos.erase(tor_ite);
|
torpedos.erase(tor_ite);
|
||||||
|
|
||||||
grid[i][alienIndex] = InvaderType::NONE;
|
grid[i][alienIndex] = InvaderType::NONE;
|
||||||
|
@ -69,6 +69,10 @@ bool Game::manageGod() {
|
|||||||
playerID target;
|
playerID target;
|
||||||
if (players.size() == 1)target = PLAYER1; // don't want to use random if not needed
|
if (players.size() == 1)target = PLAYER1; // don't want to use random if not needed
|
||||||
else target = rand() % players.size();
|
else target = rand() % players.size();
|
||||||
|
/*
|
||||||
|
* Let's just pretend god is drunk and can fire at a player that have a death animation, because
|
||||||
|
* honestly at this point I want to re-code the whole game engine to allow a better handling of cases like this...
|
||||||
|
*/
|
||||||
|
|
||||||
Position playerMiddlePos(players[target].x + confData.playersWidth / 2,
|
Position playerMiddlePos(players[target].x + confData.playersWidth / 2,
|
||||||
pm.getScreenHeight() - PLAYER_HEIGHT / 2);
|
pm.getScreenHeight() - PLAYER_HEIGHT / 2);
|
||||||
@ -96,16 +100,18 @@ bool Game::manageGod() {
|
|||||||
// check player collision
|
// check player collision
|
||||||
} else if (invaderPos.getY() + confData.invadersSize >= pm.getScreenHeight() - PLAYER_HEIGHT) {
|
} else if (invaderPos.getY() + confData.invadersSize >= pm.getScreenHeight() - PLAYER_HEIGHT) {
|
||||||
for (Player &p: players) {
|
for (Player &p: players) {
|
||||||
|
if(p.isPlaying()){
|
||||||
if (areLinesColliding(
|
if (areLinesColliding(
|
||||||
p.x, p.x + confData.playersWidth,
|
p.x, p.x + confData.playersWidth,
|
||||||
invaderPos.getX(), invaderPos.getX() + confData.invadersSize
|
invaderPos.getX(), invaderPos.getX() + confData.invadersSize
|
||||||
)) {
|
)) {
|
||||||
// TODO manage player death
|
p.damage();
|
||||||
touched = true;
|
touched = true;
|
||||||
// do not break, the other player also deserves to be hit
|
// do not break, the other player also deserves to be hit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (touched) {
|
if (touched) {
|
||||||
god.state = GodState::WAIT;
|
god.state = GodState::WAIT;
|
||||||
god.counter = 0;
|
god.counter = 0;
|
||||||
|
@ -1,5 +1,18 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
|
||||||
bool Player::isEliminated() {
|
bool Player::isPlaying() const {
|
||||||
return lives == 0 && deathAnimCounter == 0;
|
return !isEliminated() && !hasDeathAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Player::hasDeathAnimation() const {
|
||||||
|
return deathAnimCounter!=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Player::isEliminated() const {
|
||||||
|
return lives == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::damage() {
|
||||||
|
--lives;
|
||||||
|
deathAnimCounter = 1;
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#include "projectiles.h"
|
#include "projectiles.h"
|
||||||
|
|
||||||
torpedo::torpedo(int x, int y, playerID owner) : Position(x, y) {
|
Torpedo::Torpedo(int x, int y, playerID owner) : Position(x, y) {
|
||||||
this->owner = owner;
|
this->owner = owner;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ void ScoresManager::inputScore(const string& name, unsigned score) {
|
|||||||
++ite;
|
++ite;
|
||||||
}
|
}
|
||||||
if(ite==scores.end())scores.emplace(ite, name, score);
|
if(ite==scores.end())scores.emplace(ite, name, score);
|
||||||
if(scores.size()==6)scores.resize(5);
|
if(scores.size()==6)scores.pop_back();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user