141 lines
5.5 KiB
C++
141 lines
5.5 KiB
C++
#include "World.hpp"
|
|
#include "Connection.hpp"
|
|
|
|
#include <string>
|
|
#include <chrono>
|
|
|
|
|
|
|
|
namespace World {
|
|
void fillSettings(Generic::Settings& settings) {
|
|
if (!settings.has_maxdistanceperturn()) {
|
|
settings.set_maxdistanceperturn(0.02f);
|
|
}
|
|
if (!settings.has_robotsperclient()) {
|
|
settings.set_robotsperclient(50);
|
|
}
|
|
if (!settings.has_maxrobothealth()) {
|
|
settings.set_maxrobothealth(20);
|
|
}
|
|
if (!settings.has_maxrobotdamage()) {
|
|
settings.set_maxrobotdamage(4);
|
|
}
|
|
if (!settings.has_protectcooldown()) {
|
|
settings.set_protectcooldown(50);
|
|
}
|
|
if (!settings.has_healcooldown()) {
|
|
settings.set_healcooldown(20);
|
|
}
|
|
if (!settings.has_healperturn()) {
|
|
settings.set_healperturn(2);
|
|
}
|
|
}
|
|
|
|
boost::asio::awaitable<void> Playfield::reset() {
|
|
robots.clear();
|
|
const std::vector<std::vector<Vector2>> robotsPlacementMap = {
|
|
{{0.5f, 0.5f}},
|
|
{{0.0f, 0.0f}, {1.0f, 1.0f}},
|
|
{{0.0f, 0.0f}, {0.5f, 0.5f}, {1.0f, 1.0f}},
|
|
{{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}}
|
|
};
|
|
const auto& robotsPlacement = robotsPlacementMap.at(room.clients.size());
|
|
for (unsigned client = 0; client != room.clients.size(); client++) {
|
|
const auto genericTeamRobotsPlacement = robotsPlacement[client].toGeneric();
|
|
for (unsigned robot = 0; robot != room.info.settings().robotsperclient(); robot++) {
|
|
// Create robot
|
|
Generic::Robot genericRobot;
|
|
genericRobot.set_id(robot);
|
|
genericRobot.set_client(client);
|
|
genericRobot.set_state(Generic::Robot::Idle);
|
|
genericRobot.set_health(20);
|
|
*genericRobot.mutable_position() = genericTeamRobotsPlacement;
|
|
// Add to list
|
|
robots.push_back({genericRobot});
|
|
}
|
|
}
|
|
// Broadcast new playfield
|
|
auto playfieldSync = getPlayfieldSync();
|
|
for (auto& client : room.clients) {
|
|
Connection::Packet packet;
|
|
packet.op.set_code(Generic::Operation::RobotUpdate);
|
|
packet.data = std::make_unique<Generic::PlayfieldSync>(playfieldSync);
|
|
co_await client->sendPacket(packet);
|
|
}
|
|
}
|
|
|
|
boost::asio::awaitable<void> Playfield::updateRobot(const Connection::Client *sender, Generic::Robot& newRobot) {
|
|
turn++;
|
|
// Get local robot
|
|
auto& localRobot = getLocalRobot(sender, newRobot.id());
|
|
// Get distance travelled
|
|
auto distanceTravelled = getDistanceBetween(*localRobot, newRobot);
|
|
if (distanceTravelled != 0.0f) {
|
|
// Check that robot is able to travel
|
|
if (newRobot.state() != Generic::Robot::Idle) {
|
|
throw Connection::Error("Can't travel right now", Generic::Error::IllegalOperation);
|
|
}
|
|
// Check that robot didn't travel too far
|
|
if (distanceTravelled > room.info.settings().maxdistanceperturn()) {
|
|
throw Connection::Error("Can't travel that far ("+std::to_string(distanceTravelled)+" > "+std::to_string(room.info.settings().maxdistanceperturn())+')', Generic::Error::IllegalOperation);
|
|
}
|
|
}
|
|
// Check for illegal changes
|
|
if (localRobot->health() != newRobot.health()) {
|
|
throw Connection::Error("Can't change value", Generic::Error::IllegalOperation);
|
|
}
|
|
if (newRobot.position().x() > 1.0f || newRobot.position().x() < 0.0f || newRobot.position().y() > 1.0f || newRobot.position().y() < 0.0f) {
|
|
throw Connection::Error("Position is out of range", Generic::Error::OutOfRange);
|
|
}
|
|
// Apply heal
|
|
if (newRobot.state() == Generic::Robot::Heal) {
|
|
newRobot.set_health(localRobot->health() + room.info.settings().healperturn());
|
|
if (newRobot.health() > room.info.settings().maxrobothealth()) {
|
|
newRobot.set_health(room.info.settings().maxrobothealth());
|
|
newRobot.set_state(Generic::Robot::Idle);
|
|
}
|
|
}
|
|
// Check for state change
|
|
if (localRobot->state() != newRobot.state()) {
|
|
// Enforce cooldowns
|
|
if (newRobot.state() == Generic::Robot::Protect && turn - localRobot.stateTimer < room.info.settings().protectcooldown()
|
|
|| newRobot.state() == Generic::Robot::Heal && turn - localRobot.stateTimer < room.info.settings().healcooldown()) {
|
|
throw Connection::Error("Can't change state yet (cooldown still in progress)", Generic::Error::IllegalOperation);
|
|
}
|
|
// Reset timer
|
|
localRobot.stateTimer = turn;
|
|
}
|
|
// Apply changes to local robot
|
|
*localRobot = newRobot;
|
|
// Broadcast new robot
|
|
for (auto& client : room.clients) {
|
|
Connection::Packet packet;
|
|
packet.op.set_code(Generic::Operation::RobotUpdate);
|
|
packet.data = std::make_unique<Generic::Robot>(*localRobot);
|
|
co_await client->sendPacket(packet);
|
|
}
|
|
}
|
|
|
|
LocalRobot& Playfield::getLocalRobot(const Connection::Client *sender, unsigned robot) {
|
|
// Check that new robot is in range
|
|
if (robot >= robots.size()) {
|
|
throw Connection::Error("Robot is out of range ("+std::to_string(robot)+" >= "+std::to_string(robots.size())+')', Generic::Error::OutOfRange);
|
|
}
|
|
// Get local robot
|
|
auto& localRobot = robots[robot];
|
|
// Check that robot belongs to sender
|
|
if (room.clients[localRobot->client()].get() == sender) {
|
|
throw Connection::Error("Robot does not belong to you", Generic::Error::IllegalOperation);
|
|
}
|
|
// Return local robot
|
|
return localRobot;
|
|
}
|
|
|
|
Generic::RoomInfo Room::getFullRoomInfo() const {
|
|
Generic::RoomInfo fres = info;
|
|
for (const auto& client : clients) {
|
|
*fres.add_members() = client->getUserInfo().publicinfo();
|
|
}
|
|
return fres;
|
|
}
|
|
}
|