LOGIN .R%s rejoin with cookie .n%s join as %s ALWAYS AVAILABLE .n%s set nickname to %s .pi%s set picture to %s AVAILABLE NOT IN GAME .gl .gn%s new game %s .gj%d join game %s .gS%d join game %s as spectator .R%s reconnect with cookie %s ALWAYS AVAILABLE IN GAME .f full update .gx leave game AVAILABLE IN GAME WHICH HAS NOT ENDED excluding spectators and bankrupt players .t%d set token location Trade .T[c%s] updateTradeObject .T[e%s] updateTradeObject .Tm%s updateTradeMoney .Ta%s acceptTrade .Tr%d rejectTrade IN TAX DIALOG .T$ pay tax amount .T% pay tax percentage AT ANY TIME IN A RUNNING GAME Houses .hb%d buy house on %d .hs%d sell house on %d Estates .em%d mortgage estate %d .es%s sell estate %d DURING AN AUCTION .ab%s bid in auction WHEN DEBTS HAVE TO BE SETTLED .D declare bankruptcy .p solve debts WHEN IT'S THE PLAYER'S TURN Can buy estate .eb buy estate .ea auction estate Jailed .jc use card for leaving jail .jp pay for leaving jail .jr roll for probably leaving jail Can roll .r roll dice OTHERS (WITH OWN AVAILABILITY CHECKS) .E end turn .gd%s set game description .gc%s edit game configuration .ge%s edit game config .gk%d kick player %d .gu%d upgrade player %d .gs start game .d close socket without disconnecting void MonopdServer::processCommands(Player *pInput, const std::string data2) { char *data = (char *)data2.c_str(); if (data[0] != 'f') pInput->setRequestedUpdate(false); // The following commands are _always_ available. switch(data[0]) { case 'n': setPlayerName(pInput, std::string(data+1)); return; case 'p': switch(data[1]) { case 'i': pInput->setProperty("image", data+2, this); return; } break; } // Commands available when player is not within a game. Game *game = pInput->game(); if (!game) { switch(data[0]) { case 'g': switch(data[1]) { case 'l': sendGameList(pInput, true); return; case 'n': newGame(pInput, data2.substr(2)); return; case 'j': joinGame(pInput, atol(data2.substr(2).c_str())); return; case 'S': joinGame( pInput, atol(data2.substr(2).c_str()), true ); return; default: pInput->ioNoSuchCmd("you are not within a game"); } break; case 'R': reconnectPlayer(pInput, data2.substr(1)); break; default: pInput->ioNoSuchCmd("you are not within a game"); } // The rest of the commands are only available within a game. return; } // These commands are always available in a running game, no matter what. switch(data[0]) { case 'f': game->sendFullUpdate(pInput, true); return; case 'g': switch(data[1]) { case 'x': exitGame(game, pInput); return; } break; } switch(game->status()) { case Game::End: pInput->ioNoSuchCmd("this game has ended"); // The rest of the commands are only available when the game has not ended. return; default:; } if (game->status() != Game::Config && !pInput->getBoolProperty("bankrupt") && !pInput->getBoolProperty("spectator")) switch(data[0]) { case 'T': switch(data[1]) { case 'c': case 'e': pInput->updateTradeObject(data+1); return; case 'm': pInput->updateTradeMoney(data+2); return; case 'n': game->newTrade(pInput, atol(data2.substr(2).c_str())); return; case 'a': game->acceptTrade(pInput, data+2); return; case 'r': game->rejectTrade(pInput, atol(data2.substr(2).c_str())); return; } break; } switch(data[0]) { case 't': game->setTokenLocation(pInput, atoi(data+1)); if (!game->clientsMoving()) if (Event *event = findEvent(game, Event::TokenMovementTimeout)) delEvent(event); return; } if (pInput->getBoolProperty("spectator") || pInput->getBoolProperty("bankrupt")) { pInput->ioNoSuchCmd("you are only a spectator"); // The rest of the commands are only available for participating players return; } if (game->clientsMoving()) { pInput->ioNoSuchCmd("other clients are still moving"); // The rest of the commands are only available when no clients are moving return; } // If we're in a tax dialog, we don't accept too many commands. if (game->pausedForDialog()) { switch(data[0]) { case 'T': switch(data[1]) { case '$': pInput->payTax(); return; case '%': pInput->payTax(true); return; default: return; } default: // The rest of the commands are not available during a tax dialog return; } } switch(data[0]) { case 't': // client authors find the no such command message annoying. return; break; // From the official rules: "may buy and erect at any time" case 'h': switch(data[1]) { case 'b': pInput->buyHouse(atoi(data+2)); return; case 's': pInput->sellHouse(atoi(data+2)); return; } break; // From official rules: "Unimproved properties can be mortgaged // through the Bank at any time" // Selling estates is not officially supported, but it makes most // sense here. case 'e': switch(data[1]) { case 'm': pInput->mortgageEstate(atoi(data+2)); return; case 's': pInput->sellEstate(atoi(data+2)); return; } } // Auctions restrict movement and stuff. Auction *auction = game->auction(); if (auction && auction->status() != Auction::Completed) { switch(data[0]) { case 'a': switch(data[1]) { case 'b': if (!game->bidInAuction(pInput, data+2)) { Event *event; event = findEvent(game, Event::AuctionTimeout); if (!event) event = newEvent(Event::AuctionTimeout, game); event->setLaunchTime(time(0) + 4); } return; default: pInput->ioNoSuchCmd(); return; } default: pInput->ioNoSuchCmd("An auction is in progress."); return; } } // Declaring bankruptcy is only possible when a player is in debt. if (game->debts()) { if (game->findDebt(pInput)) switch(data[0]) { case 'D': game->declareBankrupt(pInput); break; case 'p': game->solveDebts(pInput, true); break; default: pInput->ioNoSuchCmd("there are debts to be settled"); } else pInput->ioNoSuchCmd("there are debts to be settled"); // The rest of the commands are only available when there // are no debts to be settled. return; } // These are only available when it's the player's turn if(pInput->getBoolProperty("hasturn")) { if(pInput->getBoolProperty("can_buyestate")) { switch(data[0]) { case 'e': switch(data[1]) { case 'b': pInput->buyEstate(); return; case 'a': game->newAuction(pInput); return; default: pInput->ioNoSuchCmd(); return; } break; } } if(pInput->getBoolProperty("jailed")) { switch(data[0]) { case 'j': switch(data[1]) { case 'c': pInput->useJailCard(); return; case 'p': pInput->payJail(); return; case 'r': pInput->rollJail(); return; default: pInput->ioNoSuchCmd(); } break; } } if(pInput->getBoolProperty("can_roll")) { switch(data[0]) { case 'r': pInput->rollDice(); Event *event = newEvent(Event::TokenMovementTimeout, game); event->setLaunchTime(time(0) + 10); return; } } } // The following commands have their own availability checks. switch(data[0]) { case 'E': pInput->endTurn(true); break; case 'g': switch(data[1]) { case 'd': setGameDescription(pInput, data2.substr(2)); return; case 'c': game->editConfiguration( pInput, data+2 ); return; case 'e': game->editConfig(pInput, data+2); return; case 'k': Player *pKick; pKick = game->kickPlayer( pInput, atoi(data+2) ); if (pKick) exitGame(game, pKick); return; case 'u': game->upgradePlayer( pInput, atoi(data+2) ); return; case 'p': // FIXME: DEPRECATED 1.0 return; case 's': game->start(pInput); // FIXME: DEPRECATED 1.0 if (game->status() == Game::Run) ioWrite("id()) + "\"/>\n"); return; default: pInput->ioNoSuchCmd(); } break; case 'd': pInput->closeSocket(); return; default: pInput->ioNoSuchCmd(); } }