16 if(&potential_ally==&origin)
26 if(potential_ally.
occupant_data!=NULL && origin.occupant_data!=NULL &&
36 const int x_length = x_right - x_left + 1;
37 const int y_height = y_down - y_up + 1;
39 vector<vector<GridCell> > to_return(x_length,vector<GridCell>(y_height));
40 for(
int i=x_left; i<=x_right; i++)
41 for(
int j=y_up; j<=y_down; j++)
43 GridCell& sanitized = to_return[i-x_left][j-y_up];
44 sanitized = worldGrid[i][j];
66 RoboSim::RoboSim(
int initial_robots_per_combatant,
int skill_points,
int length,
int width,
int obstacles) :
70 for(
int i=0; i<length; i++)
71 for(
int j=0; j<width; j++)
81 for(
int i=0; i<initial_robots_per_combatant; i++)
86 x_pos = rand()%length;
92 worldGrid[x_pos][y_pos].occupant_data = &data;
96 vector<uint8_t> creation_message(64);
110 for(
int i=0; i<obstacles; i++)
115 x_pos = rand()%length;
116 y_pos = rand()%width;
152 for(
int i=0;
true; i++)
194 if(power > actingRobot.status.power || power > actingRobot.specs.attack || power < 1)
195 throw RoboSimExecutionException(
"attempted melee attack with illegal power level",actingRobot.player,*actingRobot.assoc_cell);
198 if(!isAdjacent(adjacent_cell))
199 throw RoboSimExecutionException(
"attempted to melee attack nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell);
203 if(adjacent_cell.
x_coord > rsim.worldGrid.size() || adjacent_cell.
y_coord > rsim.worldGrid[0].size() ||
205 throw RoboSimExecutionException(
"passed invalid cell coordinates to meleeAttack()",actingRobot.player,*actingRobot.assoc_cell,adjacent_cell);
214 throw RoboSimExecutionException(
"attempted to attack empty cell",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
216 throw RoboSimExecutionException(
"attempted to attack blocked tile",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
222 throw RoboSimExecutionException(
"attempted to attack energy capsule",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
224 throw RoboSimExecutionException(
"ERROR in RoboSim.RoboAPIImplementor.meleeAttack(). This is probably not the student's fault. Contact Patrick Simmons about this message. (Not the Doobie Brother...)");
229 actingRobot.status.charge-=power;
230 actingRobot.status.power-=power;
233 int raw_attack = actingRobot.specs.attack;
240 int attack = raw_attack + power;
243 return processAttack(attack,cell_to_attack,power);
251 if(power > actingRobot.status.power || power > actingRobot.specs.attack || power < 1)
252 throw RoboSimExecutionException(
"attempted ranged attack with illegal power level",actingRobot.player,*actingRobot.assoc_cell);
256 if(nonadjacent_cell.
x_coord > rsim.worldGrid.size() || nonadjacent_cell.
y_coord > rsim.worldGrid[0].size() ||
258 throw RoboSimExecutionException(
"passed invalid cell coordinates to rangedAttack()",actingRobot.player,*actingRobot.assoc_cell,nonadjacent_cell);
261 if(isAdjacent(nonadjacent_cell))
269 if(!shortest_path.size())
270 throw RoboSimExecutionException(
"attempted to range attack cell with no clear path",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
271 else if(shortest_path.size()>actingRobot.specs.defense)
272 throw RoboSimExecutionException(
"attempted to range attack cell more than (defense) tiles away",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
278 throw RoboSimExecutionException(
"attempted to attack empty cell",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
280 throw RoboSimExecutionException(
"attempted to attack blocked tile",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
286 throw RoboSimExecutionException(
"attempted to attack energy capsule",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
288 throw RoboSimExecutionException(
"ERROR in RoboSim.RoboAPIImplementor.rangedAttack(). This is probably not the student's fault. Contact Patrick Simmons about this message. (Not the Doobie Brother...)");
293 actingRobot.status.charge-=power;
294 actingRobot.status.power-=power;
297 int raw_attack = actingRobot.specs.attack/2;
300 int attack = raw_attack + power;
303 return processAttack(attack,cell_to_attack,power);
312 throw RoboSimExecutionException(
"passed invalid cell coordinates to capsuleAttack()",actingRobot.player,*actingRobot.assoc_cell,cell);
318 auto capsule_it = find(actingRobot.status.capsules.begin(),actingRobot.status.capsules.end(),power_of_capsule);
320 if(capsule_it==actingRobot.status.capsules.end())
321 throw RoboSimExecutionException(
string(
"passed invalid power to capsuleAttack(): doesn't have capsule of power ")+to_string(power_of_capsule),actingRobot.player,*actingRobot.assoc_cell);
324 if(actingRobot.specs.attack + actingRobot.specs.defense < power_of_capsule)
325 throw RoboSimExecutionException(
"attempted to use capsule of greater power than attack+defense",actingRobot.player,*actingRobot.assoc_cell);
330 if(!shortest_path.size())
333 if(shortest_path.size() > power_of_capsule + actingRobot.specs.defense)
340 throw RoboSimExecutionException(
"attempted to attack empty cell",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
342 throw RoboSimExecutionException(
"attempted to attack blocked tile",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
348 throw RoboSimExecutionException(
"attempted to attack energy capsule",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
350 throw RoboSimExecutionException(
"ERROR in RoboSim.RoboAPIImplementor.capsuleAttack(). This is probably not the student's fault. Contact Patrick Simmons about this message. (Not the Doobie Brother...)");
356 actingRobot.status.capsules.erase(capsule_it);
359 return processAttack(actingRobot.specs.attack + power_of_capsule,cell_to_attack,(
int)(ceil(0.1 * power_of_capsule * actingRobot.specs.attack)));
367 int x_coord = actingRobot.assoc_cell->x_coord;
368 const int actor_x = x_coord;
369 int y_coord = actingRobot.assoc_cell->y_coord;
370 const int actor_y = y_coord;
388 if(x_coord < 0 || x_coord > rsim.worldGrid.size() || y_coord < 0 || y_coord > rsim.worldGrid[0].size())
392 if(rsim.worldGrid[x_coord][y_coord].contents!=
EMPTY && rsim.worldGrid[x_coord][y_coord].contents!=
FORT)
393 throw RoboSimExecutionException(
"attempted to move onto illegal cell",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][y_coord]);
396 if(rsim.worldGrid[x_coord][y_coord].contents==
FORT && rsim.worldGrid[x_coord][y_coord].fort_orientation!=way)
397 throw RoboSimExecutionException(
"attempted to move onto a fort from an illegal direction",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][y_coord]);
400 const bool x_left = x_coord<actor_x;
401 const bool y_left = y_coord<actor_y;
404 for(
int i=(x_left ? actor_x-1 : actor_x+1); i!=x_coord; i=(x_left ? i-1 : i+1))
405 if(rsim.worldGrid[i][y_coord].contents!=
EMPTY)
406 throw RoboSimExecutionException(
"attempted to cross illegal cell",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[i][y_coord]);
410 for(
int i=(y_left ? actor_y-1 : actor_y+1); i!=y_coord; i=(y_left ? i-1 : i+1))
411 if(rsim.worldGrid[x_coord][i].contents!=
EMPTY)
412 throw RoboSimExecutionException(
"attempted to cross illegal cell",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][i]);
416 if(steps > actingRobot.status.power)
417 throw RoboSimExecutionException(
"attempted to move too far (not enough power)",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][y_coord]);
420 actingRobot.status.power-=steps;
421 actingRobot.status.charge-=steps;
424 actingRobot.assoc_cell->contents =
EMPTY;
425 actingRobot.assoc_cell->occupant_data = NULL;
426 actingRobot.assoc_cell = &rsim.worldGrid[x_coord][y_coord];
427 actingRobot.assoc_cell->contents =
SELF;
428 actingRobot.assoc_cell->occupant_data = &actingRobot;
436 if(adjacent_cell.
x_coord > rsim.worldGrid.size() || adjacent_cell.
y_coord > rsim.worldGrid[0].size() || adjacent_cell.
x_coord < 0 || adjacent_cell.
y_coord < 0)
437 throw RoboSimExecutionException(
"passed invalid cell coordinates to pick_up_capsule()",actingRobot.player,*actingRobot.assoc_cell,adjacent_cell);
443 if(!isAdjacent(adjacent_cell))
444 throw RoboSimExecutionException(
"attempted to pick up capsule in nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell,gridCell);
447 if(actingRobot.status.power==0)
448 throw RoboSimExecutionException(
"attempted to pick up capsule with no power",actingRobot.player,*actingRobot.assoc_cell,gridCell);
452 throw RoboSimExecutionException(
"attempted to pick up capsule from cell with no capsule",actingRobot.player,*actingRobot.assoc_cell,gridCell);
455 if(actingRobot.status.capsules.size()+1>actingRobot.specs.attack+actingRobot.specs.defense)
456 throw RoboSimExecutionException(
"attempted to pick up too many capsules",actingRobot.player,*actingRobot.assoc_cell,gridCell);
461 actingRobot.status.power--;
464 actingRobot.status.capsules.push_back(gridCell.
capsule_power);
473 if(adjacent_cell.
x_coord > rsim.worldGrid.size() || adjacent_cell.
y_coord > rsim.worldGrid[0].size() || adjacent_cell.
x_coord < 0 || adjacent_cell.
y_coord < 0)
474 throw RoboSimExecutionException(
"passed invalid cell coordinates to pick_up_capsule()",actingRobot.player,*actingRobot.assoc_cell,adjacent_cell);
480 if(!isAdjacent(adjacent_cell))
481 throw RoboSimExecutionException(
"attempted to pick up capsule in nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell,gridCell);
485 throw RoboSimExecutionException(
"attempted to place capsule in nonempty cell",actingRobot.player,*actingRobot.assoc_cell,gridCell);
488 auto it = find(actingRobot.status.capsules.begin(),actingRobot.status.capsules.end(),power_of_capsule);
489 if(it==actingRobot.status.capsules.end())
490 throw RoboSimExecutionException(
string(
"attempted to drop capsule with power ")+to_string(power_of_capsule)+
", having no such capsule",actingRobot.player,*actingRobot.assoc_cell,gridCell);
497 actingRobot.status.capsules.erase(it);
503 if(actingRobot.whatBuilding==
NOTHING)
507 int capsule_power = actingRobot.investedPower/10;
508 switch(actingRobot.whatBuilding)
511 if(actingRobot.investedPower >= 50)
513 actingRobot.invested_assoc_cell->contents =
WALL;
514 actingRobot.invested_assoc_cell->wallforthealth =
WALL_HEALTH;
517 actingRobot.invested_assoc_cell->contents =
EMPTY;
521 if(actingRobot.investedPower >= 75)
523 actingRobot.invested_assoc_cell->contents =
FORT;
524 actingRobot.invested_assoc_cell->wallforthealth =
WALL_HEALTH;
527 actingRobot.invested_assoc_cell->contents =
EMPTY;
533 if(actingRobot.status.capsules.size()+1>actingRobot.specs.attack+actingRobot.specs.defense)
534 throw RoboSimExecutionException(
"attempted to finish building capsule when already at max capsule capacity",actingRobot.player,*actingRobot.assoc_cell);
535 actingRobot.status.capsules.push_back(capsule_power);
540 int skill_points = actingRobot.investedPower/20;
544 if(creation_message.size()!=0 && creation_message.size()!=64)
545 throw RoboSimExecutionException(
"passed incorrect sized creation message to setBuildTarget()",actingRobot.player,*actingRobot.assoc_cell,*actingRobot.invested_assoc_cell);
548 if(!creation_message.size())
550 creation_message.resize(64);
551 creation_message[1] = rsim.turnOrder.size() % 256;
552 creation_message[0] = rsim.turnOrder.size() / 256;
556 actingRobot.invested_assoc_cell->contents =
SELF;
564 throw RoboSimExecutionException(
"something went wrong calling student's constructor", actingRobot.player,*actingRobot.assoc_cell, *actingRobot.invested_assoc_cell);
566 rsim.turnOrder.emplace_back();
567 RobotData& data = *(rsim.turnOrder.rbegin());
569 data.
assoc_cell = actingRobot.invested_assoc_cell;
571 data.
player = actingRobot.player;
576 actingRobot.invested_assoc_cell->contents =
EMPTY;
584 if(actingRobot.whatBuilding!=
NOTHING)
585 finalizeBuilding(message);
590 if(location!=NULL && (location->
x_coord > rsim.worldGrid.size() || location->
y_coord > rsim.worldGrid[0].size() || location->
x_coord < 0 || location->
y_coord < 0))
591 throw RoboSimExecutionException(
"passed invalid cell coordinates to setBuildTarget()",actingRobot.player,*actingRobot.assoc_cell,*location);
597 actingRobot.whatBuilding = status;
598 actingRobot.investedPower = 0;
599 actingRobot.invested_assoc_cell = gridCell;
605 if(actingRobot.whatBuilding!=
NOTHING && actingRobot.whatBuilding!=
CAPSULE)
606 throw RoboSimExecutionException(
"passed null to setBuildTarget() location with non-null and non-capsule build target",actingRobot.player,*actingRobot.assoc_cell);
612 throw RoboSimExecutionException(
"attempted to target capsule or null building on non-null adjacent cell",actingRobot.player,*actingRobot.assoc_cell,*location);
615 if(!isAdjacent(*location))
616 throw RoboSimExecutionException(
"attempted to set build target to nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell,*gridCell);
620 throw RoboSimExecutionException(
"attempted to set build target to nonempty cell",actingRobot.player,*actingRobot.assoc_cell,*gridCell);
RobotData * occupant_data
RoboSim(int initial_robots_per_combatant, int skill_points, int length, int width, int obstacles)
virtual Robot_Specs createRobot(WorldAPI *api, int skill_points, std::vector< std::uint8_t > message)=0
RoboAPIImplementor(RoboSim &rsim_, RobotData &actingRobot_)
#define RBP_CALL_CONSTRUCTOR(x)
AttackResult capsuleAttack(int power_of_capsule, GridCell &cell)
static const int WALL_HEALTH
AttackResult meleeAttack(int power, GridCell &adjacent_cell)
AttackResult rangedAttack(int power, GridCell &nonadjacent_cell)
vector< RobotData > turnOrder
void drop_capsule(GridCell &adjacent_cell, int power_of_capsule)
void move(int steps, Direction way)
static Robot_Specs checkSpecsValid(Robot_Specs proposed, int player, int skill_points)
AttackResult processAttack(int attack, GridCell &cell_to_attack, int power)
bool operator()(const GridCell &potential_ally)
void setBuildTarget(BuildStatus status, GridCell *location)
vector< vector< GridCell > > worldGrid
void pick_up_capsule(GridCell &adjacent_cell)
static std::list< GridCell * > findShortestPath(GridCell &origin, const GridCell &target, std::vector< std::vector< GridCell > > &grid)
vector< vector< GridCell > > getSanitizedSubGrid(int x_left, int y_up, int x_right, int y_down, int player) const
void finalizeBuilding(vector< uint8_t > creation_message)
GridCell * invested_assoc_cell
bool calculateHit(int attack, int defense)