Api.hxx

00001 /*
00002 ** TowBowlTactics, an adaptation of the tabletop game Blood Bowl.
00003 **
00004 ** Copyright (C) 2006, 2007 The TBT Team.
00005 **
00006 ** This program is free software; you can redistribute it and/or
00007 ** modify it under the terms of the GNU General Public License
00008 ** as published by the Free Software Foundation; either version 2
00009 ** of the License, or (at your option) any later version.
00010 **
00011 ** The complete GNU General Public Licence Notice can be found as the
00012 ** `NOTICE' file in the root directory.
00013 **
00014 ** The TBT Team consists of people listed in the `AUTHORS' file.
00015 */
00016 
00017 #include "Dice.hh"
00018 
00019 #define CHECK_TEAM                              \
00020 {                                               \
00021   if (selected_team_ == NULL)                   \
00022     return BAD_TEAM;                            \
00023 }
00024 
00025 #define CHECK_PLAYER                            \
00026 {                                               \
00027   if (selected_player_ == NULL)                 \
00028     return BAD_PLAYER;                          \
00029 }
00030 
00031 #define CHECK_POS(X, Y)                         \
00032 {                                               \
00033   if (X < 0 || X >= COLS || Y < 0 || Y >= ROWS) \
00034     return BAD_ARGUMENT;                        \
00035 }
00036 
00037 
00038 
00039 inline Api::Api(CRules* rules)
00040   : BaseApi<CRules>(rules),
00041     selected_team_(NULL),
00042     selected_player_(NULL),
00043     skilled_player_(NULL)
00044 {
00045   for (int i = 0; i < DCL_LAST; i++)
00046     possible_declarations_[i] = false;
00047   for (int i = 0; i < ACT_LAST; i++)
00048     possible_actions_[i] = false;
00049 }
00050 
00051 inline Api::~Api()
00052 {
00053 }
00054 
00055 /*
00056 ** Actions
00057 */
00058 
00059 inline void Api::doEndTurn()
00060 {
00061   rules_->sendPacket(MsgEndTurn());
00062 }
00063 
00064 inline void Api::doMoveTurnMarker()
00065 {
00066   rules_->sendPacket(MsgMoveTurnMarker());
00067 }
00068 
00069 inline void Api::doAskIllegalProcedure()
00070 {
00071   rules_->sendPacket(MsgIllegalProc());
00072 }
00073 
00074 inline int Api::doChooseKickoff(bool kickoff)
00075 {
00076   assert(rules_->getState() != GS_WAIT);
00077   if (rules_->getState() != GS_DRAWKICKER)
00078     {
00079       LOG2("You do not have the choice of who will kick off. (%1)", gameStateString());
00080       return INVALID_ACTION;
00081     }
00082 
00083   MsgDrawKicker pkt;
00084   pkt.kickoff = (kickoff ? 1 : 0);
00085   rules_->sendPacket(pkt);
00086   return SUCCESS;
00087 }
00088 
00089 inline int Api::doPlacePlayer(const Point& pos)
00090 {
00091   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00092   CHECK_TEAM;
00093   CHECK_PLAYER;
00094 
00095   if (rules_->getState() != GS_INITKICKOFF)
00096     {
00097       LOG2("It's not the right moment to place player #%1 on the field. (%2)",
00098           selected_player_->getId(), gameStateString());
00099       return INVALID_ACTION;
00100     }
00101 
00102   Position player_pos(pos);
00103   MsgPlayerPos pkt;
00104   pkt.player_id = selected_player_->getId();
00105   pkt.col = player_pos.col;
00106   pkt.row = player_pos.row;
00107   rules_->sendPacket(pkt);
00108 
00109   return SUCCESS;
00110 }
00111 
00112 inline int Api::doEndPlacement()
00113 {
00114   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00115 
00116   if (rules_->getState() != GS_INITKICKOFF)
00117     {
00118       LOG2("It's not the right moment to end team placement. (%1)", gameStateString());
00119       return INVALID_ACTION;
00120     }
00121 
00122   MsgInitKickoff pkt;
00123   pkt.place_team = 1;
00124   rules_->sendPacket(pkt);
00125 
00126   return SUCCESS;
00127 }
00128 
00129 inline int Api::doPlaceBall(const Point& pos)
00130 {
00131   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00132 
00133   if (rules_->getState() != GS_KICKOFF)
00134     {
00135       LOG2("This is not the right moment to kick the ball. (%1)", gameStateString());
00136       return INVALID_ACTION;
00137     }
00138 
00139   Position bpos(pos);
00140   if (!rules_->field_->intoField(bpos))
00141     {
00142       LOG2("Kick-off rejected. Ball is not into the field: %1.", pos);
00143       return INVALID_ACTION;
00144     }
00145   if ((rules_->getCoachId() == 0 && bpos.row < 13)
00146       || (rules_->getCoachId() == 1 && bpos.row > 12))
00147     {
00148       LOG2("Kick-off rejected. Ball is in your part of the field: %1.", pos);
00149       return INVALID_ACTION;
00150     }
00151   MsgBallPos pkt;
00152   pkt.row = bpos.row;
00153   pkt.col = bpos.col;
00154   rules_->sendPacket(pkt);
00155 
00156   return SUCCESS;
00157 }
00158 
00159 inline int Api::doGiveBall(int player_id)
00160 {
00161   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00162 
00163   if (rules_->getState() != GS_TOUCHBACK)
00164     {
00165       LOG2("There is no touchback. (%1)", gameStateString());
00166       return INVALID_ACTION;
00167     }
00168 
00169   const CPlayer* player = getPlayer(player_id);
00170   if (player == NULL)
00171     {
00172       LOG2("Player `%1' does not exist.", player_id);
00173       return BAD_PLAYER;
00174     }
00175 
00176   if (player->getStatus() != STA_STANDING)
00177     {
00178       LOG2("Player `%1' can't carry the ball. (%2)", player_id, player->getStatus());
00179       return INVALID_ACTION;
00180     }
00181   MsgGiveBall pkt;
00182   pkt.player_id = player_id;
00183   rules_->sendPacket(pkt);
00184   return SUCCESS;
00185 }
00186 
00187 inline int Api::doReroll(bool reroll)
00188 {
00189   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00190   if (rules_->getState() != GS_REROLL && rules_->getState() != GS_BLOCK)
00191     {
00192       LOG2("Cannot do reroll nor accept (no dice to reroll). (%1)", gameStateString());
00193       return INVALID_ACTION;
00194     }
00195   if (reroll && !selected_team_->canUseReroll())
00196     {
00197       LOG2("Cannot use reroll (no one left or already use one this turn).");
00198       return INVALID_ACTION;
00199     }
00200 
00201   MsgReroll msg(rules_->our_team_->getTeamId());
00202   msg.reroll = reroll;
00203   rules_->sendPacket(msg);
00204   return SUCCESS;
00205 }
00206 
00207 inline int Api::doUseSkill(enum eSkill skill, bool useIt)
00208 {
00209   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00210 
00211   if (skilled_player_ == NULL)
00212     return BAD_PLAYER;
00213   if (!skilled_player_->hasSkill(skill))
00214     {
00215       LOG2("Player %1 of team %2 doesn't have the skill %3.", skilled_player_->getId(),
00216           skilled_player_->getTeamId(), Player::stringify(skill));
00217       return INVALID_ACTION;
00218     }
00219   if (rules_->getState() != GS_REROLL && rules_->getState() != GS_SKILL)
00220     {
00221       LOG2("Cannot use the skill %1 or not now.", Player::stringify(skill));
00222       return INVALID_ACTION;
00223     }
00224   if (rules_->getState() == GS_REROLL && !useIt)
00225     {
00226       LOG2("Use Api::doReroll(false) in order to accept a roll result.");
00227       return INVALID_ACTION;
00228     }
00229 
00230   MsgSkill msg(rules_->our_team_->getTeamId());
00231   msg.player_id = skilled_player_->getId();
00232   msg.skill = skill;
00233   msg.choice = (useIt ? 1 : 0 );
00234   rules_->sendPacket(msg);
00235   return SUCCESS;
00236 }
00237 
00238 inline int Api::doDeclare(enum eDeclaredAction action)
00239 {
00240   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00241   CHECK_TEAM;
00242   CHECK_PLAYER;
00243 
00244   if (action == DCL_UNASSIGNED)
00245     {
00246       LOG2("You can't declare an empty action for player #%1.", selected_player_->getId());
00247       return INVALID_ACTION;
00248     }
00249   return rules_->our_team_->declareAction(selected_player_, action);
00250 }
00251 
00252 inline int Api::doChooseBlockDice(int n)
00253 {
00254   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00255   if (rules_->getState() != GS_BLOCK && rules_->getState() != GS_REROLL)
00256     {
00257       LOG2("You do not have the choice of which block dice to apply.");
00258       return INVALID_ACTION;
00259     }
00260   if (rules_->getState() == GS_REROLL)
00261     {
00262       MsgReroll msgr;
00263       msgr.reroll = false;
00264       rules_->sendPacket(msgr);
00265     }
00266   MsgBlockDice msg(rules_->our_team_->getTeamId());
00267   msg.dice = n;
00268   rules_->sendPacket(msg);
00269   return SUCCESS;
00270 }
00271 
00272 inline int Api::doBlockPush(int n)
00273 {
00274   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00275   if (rules_->getState() != GS_PUSH)
00276     {
00277       LOG2("You do not have the choice of which square to push in.");
00278       return INVALID_ACTION;
00279     }
00280   MsgBlockPush msg(rules_->our_team_->getTeamId());
00281   msg.square_chosen = n;
00282   rules_->sendPacket(msg);
00283   return SUCCESS;
00284 }
00285 
00286 inline int Api::doFollow(bool follow)
00287 {
00288   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00289   if (rules_->getState() != GS_FOLLOW)
00290     {
00291       LOG2("You do not have the choice to follow or not.");
00292       return INVALID_ACTION;
00293     }
00294   MsgFollow msg(rules_->our_team_->getTeamId());
00295   msg.follow = follow;
00296   rules_->sendPacket(msg);
00297   return SUCCESS;
00298 }
00299 
00300 inline int Api::doStandUpPlayer()
00301 {
00302   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00303   CHECK_TEAM;
00304   CHECK_PLAYER;
00305 
00306   return selected_player_->standUp();
00307 }
00308 
00309 inline int Api::doMovePlayer(const Point& to)
00310 {
00311   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00312   CHECK_TEAM;
00313   CHECK_PLAYER;
00314 
00315   return selected_player_->move(to);
00316 }
00317 
00318 inline int Api::doBlockPlayer(int def_p)
00319 {
00320   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00321   CHECK_TEAM;
00322   CHECK_PLAYER;
00323 
00324   CPlayer* opponent = rules_->other_team_->getPlayer(def_p);
00325   return selected_player_->block(opponent);
00326 }
00327 
00328 inline int Api::doPassPlayer(const Point& to)
00329 {
00330   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00331   CHECK_TEAM;
00332   CHECK_PLAYER;
00333 
00334   return selected_player_->pass(to);
00335 }
00336 
00337 inline void Api::sendChatMessage(const std::string& msg)
00338 {
00339   if (rules_->getState() == GS_WAIT)
00340     return;
00341 
00342   MsgChat pkt;
00343   stringToPacket(pkt.msg, msg, sizeof(pkt.msg));
00344   rules_->sendPacket(pkt);
00345 }
00346 
00347 inline void Api::doCheatDice(int roll)
00348 {
00349   MsgCheatDice pkt;
00350   pkt.next_result = roll;
00351   rules_->sendPacket(pkt);
00352 }
00353 
00354 
00355 /*
00356 ** Accessors, for the game
00357 */
00358 
00359 inline int Api::turn() const
00360 {
00361   return rules_->cur_turn_;
00362 }
00363 
00364 inline int Api::half() const
00365 {
00366   return rules_->cur_half_;
00367 }
00368 
00369 inline int Api::myTeamId() const
00370 {
00371   return rules_->getCoachId();
00372 }
00373 
00374 inline Point Api::ball() const
00375 {
00376   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00377   return rules_->ball_->getPosition();
00378 }
00379 
00380 inline const CPlayer* Api::getBallOwner() const
00381 {
00382   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00383   return rules_->ball_->getOwner();
00384 }
00385 
00386 inline int Api::teamId(const Point& pos)
00387 {
00388   CHECK_POS(pos.x, pos.y);
00389   CPlayer* p = rules_->field_->getPlayer(pos);
00390   if (p != NULL)
00391     return p->getTeamId();
00392   return -1;
00393 }
00394 
00395 inline int Api::playerId(const Point& pos)
00396 {
00397   CHECK_POS(pos.x, pos.y);
00398   CPlayer* p = rules_->field_->getPlayer(pos);
00399   if (p != NULL)
00400     return p->getId();
00401   return -1;
00402 }
00403 
00404 inline void Api::selectTeam(int team_id)
00405 {
00406   selected_team_ = NULL;
00407   selected_player_ = NULL;
00408 
00409   if (rules_->getState() == GS_WAIT)
00410     return;
00411   if (team_id == US || (team_id <= 1 && team_id == rules_->getCoachId()))
00412     selected_team_ = rules_->our_team_;
00413   if (team_id == THEM || ((team_id == 0 || team_id == 1) && team_id != rules_->getCoachId()))
00414     selected_team_ = rules_->other_team_;
00415 }
00416 
00417 inline int Api::selectPlayer(int player_id)
00418 {
00419   CHECK_TEAM;
00420   selected_player_ = selected_team_->getPlayer(player_id);
00421   return selected_player_ == NULL ? BAD_PLAYER : SUCCESS;
00422 }
00423 
00424 inline int Api::selectSkilledPlayer(int player_id)
00425 {
00426   skilled_player_ = rules_->our_team_->getPlayer(player_id);
00427   return skilled_player_ == NULL ? BAD_PLAYER : SUCCESS;
00428 }
00429 
00430 inline int Api::declarationPossibleNumber()
00431 {
00432   CHECK_TEAM;
00433   CHECK_PLAYER;
00434 
00435   if (selected_player_->hasPlayed())
00436     return 0;
00437   if (selected_player_->getAction() != DCL_UNASSIGNED)
00438     return 0;
00439   if (selected_player_->getStatus() != STA_STANDING
00440       && selected_player_->getStatus() != STA_PRONE)
00441     return 0;
00442 
00443   int number = DCL_LAST;
00444   for (int i = 0; i < DCL_LAST; i++)
00445     possible_declarations_[i] = true;
00446 
00447   if (selected_player_->getStatus() == STA_PRONE ||
00448       !(rules_->getField()->hasAdjacentPlayer(
00449           selected_player_->getPosition(),
00450           STA_STANDING,
00451           rules_->other_team_->getTeamId())))
00452     {
00453       number --;
00454       possible_declarations_[DCL_BLOCK] = false;
00455     }
00456   if (selected_team_->hasDoneBlitz())
00457     {
00458       number --;
00459       possible_declarations_[DCL_BLITZ] = false;
00460     }
00461   if (selected_team_->hasDonePass())
00462     {
00463       number --;
00464       possible_declarations_[DCL_PASS] = false;
00465     }
00466   return number;
00467 }
00468 
00469 inline int Api::declarationPossible(int index) const
00470 {
00471   if (index < 0 || DCL_LAST <= index)
00472     return BAD_ARGUMENT;
00473 
00474   int declared_action = DCL_UNASSIGNED;
00475   while (index >= 0)
00476     {
00477       declared_action ++;
00478       if (declared_action >= DCL_LAST)
00479         return BAD_ARGUMENT;
00480       else if (possible_declarations_[declared_action])
00481         index --;
00482     }
00483   return declared_action;
00484 }
00485 
00486 inline int Api::actionPossibleNumber()
00487 {
00488   CHECK_TEAM;
00489   CHECK_PLAYER;
00490 
00491   if (selected_player_->hasPlayed())
00492     return 0;
00493   if (selected_player_->getAction() != DCL_UNASSIGNED)
00494     return 0;
00495   if (selected_player_->getStatus() != STA_STANDING
00496       && selected_player_->getStatus() != STA_PRONE)
00497     return 0;
00498 
00499   int number = 0;
00500   for (int i = 0; i < ACT_LAST; i++)
00501     possible_actions_[i] = false;
00502 
00503   if (selected_player_->getStatus() == STA_PRONE)
00504     {
00505       if (selected_player_->getAction() != DCL_BLOCK)
00506         {
00507           number ++;
00508           possible_actions_[ACT_STANDUP] = true;
00509         }
00510       return number;
00511     }
00512   
00513   if (selected_player_->getAction() != DCL_BLOCK
00514       && rules_->getField()->hasAdjacentEmptySquare(selected_player_->getPosition()))
00515     {
00516       number ++;
00517       possible_actions_[ACT_MOVE] = true;
00518     }
00519   if ((selected_player_->getAction() == DCL_BLOCK
00520         || selected_player_->getAction() == DCL_BLITZ)
00521       && rules_->getField()->hasAdjacentPlayer(
00522         selected_player_->getPosition(),
00523         STA_STANDING,
00524         rules_->other_team_->getTeamId())
00525       && !(selected_player_->hasBlocked()))
00526     {
00527       number ++;
00528       possible_actions_[ACT_BLOCK] = true;
00529     }
00530   if (selected_player_->getAction() == DCL_PASS
00531        && selected_player_ == rules_->ball_->getOwner()
00532        )
00533     {
00534       number ++;
00535       possible_actions_[ACT_THROW] = true;
00536     }
00537   return number;
00538 }
00539 
00540 inline int Api::actionPossible(int index) const
00541 {
00542   if (index < 0 || ACT_LAST <= index)
00543     return BAD_ARGUMENT;
00544 
00545   int action = -1;
00546   while (index >= 0)
00547     {
00548       action ++;
00549       if (action >= ACT_LAST)
00550         return BAD_ARGUMENT;
00551       else if (possible_actions_[action])
00552         index --;
00553     }
00554   return action;
00555 }
00556 
00557 inline int Api::moveLength(const Point& to)
00558 {
00559   CHECK_TEAM;
00560   CHECK_PLAYER;
00561   CHECK_POS(to.x, to.y);
00562 
00563   player_path_ = &rules_->field_->getPath(selected_player_->getPosition(),
00564                                           to,
00565                                           selected_player_);
00566   return player_path_->size();
00567 }
00568 
00569 inline int Api::moveDifficulty(int step)
00570 {
00571   if (player_path_ == NULL || step < 0 || step >= (int)player_path_->size())
00572     return BAD_ARGUMENT;
00573 
00574   Position step_pos((*player_path_)[step]);
00575   int nbt = rules_->field_->getNbTackleZones(selected_team_->getTeamId(), step_pos);
00576   if (nbt == 0)
00577     return 0;
00578   return (7 - std::min(selected_player_->getAg(), 6)) + nbt - 1;
00579 }
00580 
00581 inline Point Api::movePath(int step)
00582 {
00583   if (player_path_ == NULL || step < 0 || step >= (int)player_path_->size())
00584     return Point(-1, -1);
00585 
00586   return (*player_path_)[step];
00587 }
00588 
00589 inline int Api::movePossible(const Point& to)
00590 {
00591   CHECK_TEAM;
00592   CHECK_PLAYER;
00593   CHECK_POS(to.x, to.y);
00594 
00595   // FIXME: do a better implementation.
00596   return rules_->field_->getPath(selected_player_->getPosition(),
00597                                  to,
00598                                  selected_player_).empty() ? 0 : 1;
00599 }
00600 
00601 inline int Api::remainingTime() const
00602 {
00603   int state = rules_->getState();
00604   int tr;
00605 
00606   if (state != GS_COACH1 && state != GS_COACH2)
00607     return -1;
00608   tr = rules_->timer_.getTimeRemaining();
00609   return tr < 0 ? 0 : tr;
00610 }
00611 
00612 
00613 inline const char* Api::gameStateString() const
00614 {
00615   switch (rules_->getState())
00616     {
00617     case GS_INITGAME:
00618       return "GS_INITGAME";
00619     case GS_INITHALF:
00620       return "GS_INITHALF";
00621     case GS_DRAWKICKER:
00622       return "GS_DRAWKICKER";
00623     case GS_INITKICKOFF:
00624       return "GS_INITKICKOFF";
00625     case GS_KICKOFF:
00626       return "GS_KICKOFF";
00627     case GS_COACH1:
00628       return "GS_COACH1";
00629     case GS_COACH2:
00630       return "GS_COACH2";
00631     case GS_TOUCHBACK:
00632       return "GS_TOUCHBACK";
00633     case GS_REROLL:
00634       return "GS_REROLL";
00635     case GS_BLOCK:
00636       return "GS_BLOCK";
00637     case GS_PUSH:
00638       return "GS_PUSH";
00639     case GS_FOLLOW:
00640       return "GS_FOLLOW";
00641     case GS_SKILL:
00642       return "GS_SKILL";
00643     }
00644   return BaseApi<CRules>::getStateString();
00645 }
00646 
00647 inline const CTeam* Api::getTeam() const
00648 {
00649   return selected_team_;
00650 }
00651 
00652 inline const CPlayer* Api::getPlayer() const
00653 {
00654   return selected_player_;
00655 }
00656 
00657 inline const CPlayer* Api::getPlayer(int player_id)
00658 {
00659   if (selected_team_ == NULL)
00660     return NULL;
00661   return selected_team_->getPlayer(player_id);
00662 }
00663 
00664 inline const CPlayer* Api::getPlayer(const Point& pos)
00665 {
00666   return rules_->field_->getPlayer(pos);
00667 }
00668 
00669 inline const Weather* Api::getWeather() const
00670 {
00671   assert(rules_->getState() != GS_WAIT && rules_->getState() != GS_INITGAME);
00672   return rules_->weather_;
00673 }

Generated on Sat Jun 23 16:07:22 2007 for Stechec/TBT by  doxygen 1.4.7