Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build/
.vscode/
.vscode/
config.txt
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ make
* `unitHp` - starting hit points of every new unit [default: 100]
* `unitDamage` - how much damage do units deal on every attack [default: 10]
* `allowedNameCharacters` - string of characters that can be used in player names [default: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_]
* `maxResourceSpawn` - amount of times server will try to spawn a resource in one game tick / maximum amount of resources that can spawn in one tick [default: 1]
* `resourceChance` - chance of resource spawning in one attempt [default: 0.1]

### Example:

Expand All @@ -54,6 +56,8 @@ boardY 5
resourceHp 20
unitHp 20
unitDamage 5
maxResourceSpawn 2
resourceChance 0.2
```

Pair can appear in any order. If pair not listed default value will be used.
Expand All @@ -70,26 +74,26 @@ Some messages consist of only type character others contain more data.
- `n` `<name>` `\n` - set name or rename self
- `j` - request join (player will be sent to game room or queue)
- `q` - request quit (player will be removed from game room or queue, can still rejoin with `j`)
- `m` `<x1>` ` ` `<y1>` ` ` `<x2>` ` ` `<y2>` `\n` - request unit to move (`<x1><y1>` are coordinates of the unit, `<x2><y2>` designate destination)
- `a` `<x1>` ` ` `<y1>` ` ` `<x2>` ` ` `<y2>` `\n` - request unit to attack another unit (`<x1><y1>` are coordinates of the unit, `<x2><y2>` coordinates of the target unit) (possible to attack own units)
- `d` `<x1>` ` ` `<y1>` `\n` - request unit to mine the resource (`<x1><y1>` are coordinates of the unit) (unit can only mine resource that it is standing on)
- `m` `<id>` ` ` `<x2>` ` ` `<y2>` `\n` - request unit of id `<id>` to move to field of coordinates: `<x2><y2>`
- `a` `<id1>` ` ` `<id1>` `\n` - request unit to attack another unit (`<id1>` is id of the controlled unit, `<id2>` id id of the target unit) (possible to attack own units)
- `d` `<id>` `\n` - request unit to mine the resource (`<id>` is an id of the controlled unit) (unit can only mine resource that it is standing on)

### From server

- `c` `<millis>` ` ` `<maxPlayers>` ` ` `<boardX>` ` ` `<boardY>` ` ` `<unitsToWin>` ` ` `<startResources>` ` ` `<resourceHp>` ` ` `<unitHp>` ` ` `<unitDamage>` ` ` `<allowedNameCharacters>` `\n` - whole server configuration sent to newly joined clients
- `j` `<player name>` `\n` - new player has joined the game room
- `l` `<player name>` `\n` - player `<player name>` has either left or lost the game
- `m` `<id>` ` ` `<x>` ` ` `<y>` `\n` - unit of id `<id>` has moved to `<x>;<y>`
- `a` `<id1>` ` ` `<id2>` `\n` - unit of id `<id1>` attacked unit of id `<id2>`
- `d` `<id>` `\n` - unit of id `<id>` mined a resource
- `a` `<id1>` ` ` `<id2>` ` ` `<hp>` `\n` - unit of id `<id1>` attacked unit of id `<id2>` and target unit has now `<hp>` hp left
- `d` `<id>` ` ` `<hp>` `\n` - unit of id `<id>` mined a resource and resource has now `<hp>` hp left
- `u` `<player name>` ` ` `<id>` ` ` `<x>` ` ` `<y>` - player `<player name>` has aquired unit of id `<id>` on field `<x>;<y>`
- `f` `<x>` ` ` `<y>` ` ` `<hp>` `\n` - new resource spawned on field `<x>;<y>`
- `t` `\n` - sent to all players in game room in regular time intervals, marks the and of each tick and a start of the next one
- `q` `\n` - player was sent to queue (in response to: `j`)
- `y` `\n` - client request accepted (in response to: `n`)
- `n` `\n` - client request denied (in response to: `j` or `n`)
- `L` `\n` - client lost the game (and was moved out of game room)
- `W` `\n` - client won the game (and was moved out of game room)
- `L` `<name>` `\n` - client lost the game (and was moved out of game room), `<name>` is the name of the player who won
- `W` `<name>` `\n` - client won the game (and was moved out of game room), `<name>` is the name of the player who won

### Board state message

Expand Down Expand Up @@ -130,4 +134,5 @@ Numbers are represented as strings of characters (97 ---> "97" not 'a').
**6:** client can send multiple: `m` `a` `d` messages
**6:** if client sends `q` => go to step **4**
**6:** if server sends `W` or `L` => go to step **4**
**6:** if server sends `l` with clients name => go to step **4**
**7:** server sends `t` => go to step **6**
8 changes: 0 additions & 8 deletions config.txt

This file was deleted.

7 changes: 6 additions & 1 deletion src/msg/addressUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ rts::unit* message::addressUnitByCoordinates::getUnit(const rts::game* g) const{

message::addressUnitById::addressUnitById(
unsigned int id
) : addressUnit(), unitId(id) {}
) : addressUnit(), unitId(id) {}

rts::unit* message::addressUnitById::getUnit(const rts::game* g) const{
if (g->unitsById.find(unitId) == g->unitsById.end()) return nullptr;
return g->unitsById.at(unitId);
}
5 changes: 3 additions & 2 deletions src/msg/addressUnit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ namespace rts {

namespace message {

class addressUnit : public base {
class addressUnit {
public:
virtual rts::unit* getUnit(const rts::game* g) const = 0;
virtual ~addressUnit() = default;
};

class addressUnitByCoordinates : public addressUnit {
Expand All @@ -27,6 +28,6 @@ namespace message {
const unsigned int unitId;

addressUnitById(unsigned int id);
// rts::unit* getUnit(const rts::game* g) const override; ... TO DO ...
rts::unit* getUnit(const rts::game* g) const override;
};
}
49 changes: 24 additions & 25 deletions src/msg/handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,42 +104,41 @@ void message::handler::init(){
};

messageProcessors['m'] = [](message::handler* mh){
int sx, sy, dx, dy;
int a, b, c;
auto it = mh->buffer.begin();
bool success = mh->tryGetInt(sx, it, ' ');
if (success) success &= mh->tryGetInt(sy, it, ' ');
if (success) success &= mh->tryGetInt(dx, it, ' ');
if (success) success &= mh->tryGetInt(dy, it, '\n');
if (success) {
message::move msg(dx, dy, sx, sy);
mh->onNewMessage(&msg);
mh->buffer.erase(mh->buffer.begin(), it);
mh->msgType = '?';

if (mh->tryGetInt(a, it, ' ')){
if (mh->tryGetInt(b, it, ' ')){
if (mh->tryGetInt(c, it, '\n')) {
message::move msg(a, b, c);
mh->onNewMessage(&msg);
mh->buffer.erase(mh->buffer.begin(), it);
mh->msgType = '?';
}
}
}
};

messageProcessors['a'] = [](message::handler* mh){
int sx, sy, dx, dy;
int a, b;
auto it = mh->buffer.begin();
bool success = mh->tryGetInt(sx, it, ' ');
if (success) success &= mh->tryGetInt(sy, it, ' ');
if (success) success &= mh->tryGetInt(dx, it, ' ');
if (success) success &= mh->tryGetInt(dy, it, '\n');
if (success) {
message::attack msg(dx, dy, sx, sy);
mh->onNewMessage(&msg);
mh->buffer.erase(mh->buffer.begin(), it);
mh->msgType = '?';

if (mh->tryGetInt(a, it, ' ')){
if (mh->tryGetInt(b, it, '\n')){
message::attack msg(a, b);
mh->onNewMessage(&msg);
mh->buffer.erase(mh->buffer.begin(), it);
mh->msgType = '?';
}
}
};

messageProcessors['d'] = [](message::handler* mh){
int sx, sy;
int a;
auto it = mh->buffer.begin();
bool success = mh->tryGetInt(sx, it, ' ');
if (success) success &= mh->tryGetInt(sy, it, '\n');
if (success) {
message::mine msg(sx, sy);

if (mh->tryGetInt(a, it, '\n')){
message::mine msg(a);
mh->onNewMessage(&msg);
mh->buffer.erase(mh->buffer.begin(), it);
mh->msgType = '?';
Expand Down
63 changes: 63 additions & 0 deletions src/msg/unitCommands.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <msg/unitCommands.hpp>
#include <rts/field.hpp>
#include <rts/game.hpp>
#include <rts/unit.hpp>

rts::unit* message::command::getUnit(rts::game* game) const{
return source->getUnit(game);
}

message::command::command(
unsigned int sourceId
) : source(new addressUnitById(sourceId)) {}

message::command::command(
unsigned int sourceX, unsigned int sourceY
) : source(new addressUnitByCoordinates(sourceX, sourceY)) {}

message::command::~command() {
delete source;
}


rts::field* message::move::getDestinationField(rts::game* game) const {
return game->_board.getField(destX, destY);
}

message::move::move(
unsigned int sx, unsigned int sy,
unsigned int dx, unsigned int dy
) : command(sx, sy), destX(dx), destY(dy) {}

message::move::move(
unsigned int si,
unsigned int dx, unsigned int dy
) : command(si), destX(dx), destY(dy) {}


rts::unit* message::attack::getTarget(rts::game* game) const {
return target->getUnit(game);
}

message::attack::attack(
unsigned int sx, unsigned int sy,
unsigned int tx, unsigned int ty
) : command(sx, sy), target(new addressUnitByCoordinates(tx, ty)) {}

message::attack::attack(
unsigned int si,
unsigned int ti
) : command(si), target(new addressUnitById(ti)) {}

message::attack::~attack(){
delete target;
}


message::mine::mine(
unsigned int sx, unsigned int sy
) : command(sx, sy) {}

message::mine::mine(
unsigned int si
) : command(si) {}
58 changes: 46 additions & 12 deletions src/msg/unitCommands.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,68 @@

#include <msg/addressUnit.hpp>

namespace rts {
class field;
}

namespace message {
class move : public addressUnitByCoordinates {
class command : public base {
addressUnit* source;
public:
rts::unit* getUnit(rts::game* game) const;

command(unsigned int sourceId);
command(unsigned int sourceX, unsigned int sourceY);

~command();
};

class move : public command {
const unsigned int destX;
const unsigned int destY;

public:
rts::field* getDestinationField(rts::game* game) const;

move(
unsigned int dx, unsigned int dy,
unsigned int sx, unsigned int sy
) : addressUnitByCoordinates(sx, sy), destX(dx), destY(dy) {}
unsigned int sx, unsigned int sy,
unsigned int dx, unsigned int dy
);

move(
unsigned int si,
unsigned int dx, unsigned int dy
);
};

class attack : public addressUnitByCoordinates {
class attack : public command {
addressUnit* target;

public:
const unsigned int destX;
const unsigned int destY;
rts::unit* getTarget(rts::game* game) const;

attack(
unsigned int dx, unsigned int dy,
unsigned int sx, unsigned int sy
) : addressUnitByCoordinates(sx, sy), destX(dx), destY(dy) {}
unsigned int sx, unsigned int sy,
unsigned int tx, unsigned int ty
);

attack(
unsigned int si,
unsigned int ti
);

~attack();
};

class mine : public addressUnitByCoordinates {
class mine : public command {
public:

mine(
unsigned int sx, unsigned int sy
) : addressUnitByCoordinates(sx, sy) {}
);

mine(
unsigned int si
);
};
}
2 changes: 1 addition & 1 deletion src/rts/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace rts {
class board {
std::vector<std::vector<field>> fields;

std::mt19937 gen; // mersenne_twister_engine seeded with rd()
std::mt19937 gen;

public:
board(unsigned int x = 256, unsigned int y = 256);
Expand Down
29 changes: 20 additions & 9 deletions src/rts/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ std::unordered_map<std::string, std::function<void(rts::game*, std::ifstream&)>>
{"resourceHp", [](rts::game* g, std::ifstream& f){ f >> g->resourceHp; }},
{"unitHp", [](rts::game* g, std::ifstream& f){ f >> g->unitHp; }},
{"unitDamage", [](rts::game* g, std::ifstream& f){ f >> g->unitDamage; }},
{"allowedNameCharacters", [](rts::game* g, std::ifstream& f){ f >> g->allowedNameCharacters; }}
{"allowedNameCharacters", [](rts::game* g, std::ifstream& f){ f >> g->allowedNameCharacters; }},
{"maxResourceSpawn", [](rts::game* g, std::ifstream& f){ f >> g->maxResourceSpawn; }},
{"resourceChance", [](rts::game* g, std::ifstream& f){ f >> g->resourceChance; }}
}; // i wish there was reflection system in c++

rts::game::game(const char *port, const char* configFile) : _server(port) {
rts::game::game(const char *port, const char* configFile) : _server(port), gen(std::random_device()()) {
_server.onNewClient = std::bind(&rts::game::handleNewClient, this, std::placeholders::_1);

if (configFile != nullptr) {
Expand Down Expand Up @@ -121,17 +123,21 @@ void rts::game::handleNewClient(client* client_) {

void rts::game::loopLogic(){
// spawn resource and inform players
if (rand() % 10 == 0) {
field* f = _board.spawnResource(resourceHp);
if (f) {
sendToPlayers(activePlayers, newResourceMessage(f));
std::uniform_real_distribution<double> distrib(0.0, 1.0);
for (unsigned int i = 0; i < maxResourceSpawn; ++i){
if (distrib(gen) < resourceChance){
field* f = _board.spawnResource(resourceHp);
if (f) {
sendToPlayers(activePlayers, newResourceMessage(f));
}
}
}

// allow units to move again
for (player* p : activePlayers) {
for (unit* u : p->units){
u->movedThisRound = false;
u->lastField = u->f;
}
}

Expand Down Expand Up @@ -236,15 +242,20 @@ void rts::game::deletePlayer(player* pl){
void rts::game::playerLostAllUnits(player* pl) {
assert(pl);
assert(activePlayers.find(pl) != activePlayers.end());
pl->getClient()->sendToClient({'L','\n'});
std::vector<char> buff = {'l'};
message::appendStringWDelim(buff, pl->getName(), '\n');
pl->getClient()->sendToClient(buff);
removePlayerFromRoomOrQueue(pl);
}

void rts::game::tryWin(player* pl){
if (pl->units.size() >= unitsToWin) {
pl->getClient()->sendToClient({'W','\n'});
std::vector<char> buff = {'W'};
message::appendStringWDelim(buff, pl->getName(), '\n');
pl->getClient()->sendToClient(buff);
buff[0] = 'L';
for (player* p : activePlayers){
if (p != pl) p->getClient()->sendToClient({'L','\n'});
if (p != pl) p->getClient()->sendToClient(buff);
}

clearRoom();
Expand Down
Loading