#include "World.hpp" #include #include #include 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 Playfield::reset() { robots.clear(); const std::vector> 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(clients.size()); for (unsigned client = 0; client != clients.size(); client++) { const auto genericTeamRobotsPlacement = robotsPlacement[client].toGeneric(); for (unsigned robot = 0; robot != 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 : clients) { Connection::Packet packet; packet.op.set_code(Generic::Operation::RobotUpdate); packet.data = std::make_unique(playfieldSync); co_await client->sendPacket(packet); } } boost::asio::awaitable 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 > settings.maxdistanceperturn()) { throw Connection::Error("Can't travel that far ("+std::to_string(distanceTravelled)+" > "+std::to_string(settings.maxdistanceperturn())+')', Generic::Error::IllegalOperation); } } // Check for illegal changes if (localRobot->health() != newRobot.health()) { throw Connection::Error("Can't change value", Generic::Error::IllegalOperation); } // Apply heal if (newRobot.state() == Generic::Robot::Heal) { newRobot.set_health(localRobot->health() + settings.healperturn()); if (newRobot.health() > settings.maxrobothealth()) { newRobot.set_health(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 < settings.protectcooldown() || newRobot.state() == Generic::Robot::Heal && turn - localRobot.stateTimer < 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 : clients) { Connection::Packet packet; packet.op.set_code(Generic::Operation::RobotUpdate); packet.data = std::make_unique(*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 (clients[localRobot->client()].get() == sender) { throw Connection::Error("Robot does not belong to you", Generic::Error::IllegalOperation); } // Return local robot return localRobot; } }