1
// Copyright (c) 2001-2004 Rob Kaper <cap@capsi.com>,
2
// 2001 Erik Bourget <ebourg@cs.mcgill.ca>
4
// This program is free software; you can redistribute it and/or
5
// modify it under the terms of the GNU General Public License
6
// version 2 as published by the Free Software Foundation.
8
// This program is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
// General Public License for more details.
13
// You should have received a copy of the GNU General Public License
14
// along with this program; see the file COPYING. If not, write to
15
// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16
// Boston, MA 02111-1307, USA.
23
#include <algo.h> // libstdc++ from the gcc 2.95 has no #include <algo> yet :(
32
#include "cardgroup.h"
35
#include "estategroup.h"
42
: GameObject(id, GGame),
50
m_master = m_pTurn = 0;
52
m_gameType = m_bgColor = "";
53
m_isValid = m_pausedForDialog = false;
56
setBoolProperty("collectfines", false, this);
57
setBoolProperty("doublepassmoney", false, this);
58
setBoolProperty("alwaysshuffle", false, this);
59
setBoolProperty("unlimitedhouses", false, this);
60
setBoolProperty("norentinjail", false, this);
61
setBoolProperty("allowestatesales", false, this);
62
setBoolProperty("auctionsenabled", true, this);
66
// addConfigOption( "test", "A test config option", "teststring" );
67
// addConfigOption( "test2", "An int test config option", 23 );
68
// addBoolConfigOption( "test3", "A bool test config option", true );
70
m_nextCardGroupId = m_nextEstateId = m_nextEstateGroupId = m_nextTradeId = m_nextAuctionId = 0;
72
addBoolConfigOption( "automatetax", "Automate tax decisions", false, true );
73
addBoolConfigOption( "allowspectators", "Allow spectators", false, true );
78
// We are responsible for the objects allocated
79
while (!m_cardGroups.empty()) { delete *m_cardGroups.begin(); m_cardGroups.erase(m_cardGroups.begin()); }
80
while (!m_debts.empty()) { delete *m_debts.begin(); m_debts.erase(m_debts.begin()); }
81
while (!m_estates.empty()) { delete *m_estates.begin(); m_estates.erase(m_estates.begin()); }
82
while (!m_estateGroups.empty()) { delete *m_estateGroups.begin(); m_estateGroups.erase(m_estateGroups.begin()); }
83
while (!m_trades.empty()) { delete *m_trades.begin(); m_trades.erase(m_trades.begin()); }
84
while (!m_configOptions.empty()) { delete *m_configOptions.begin(); m_configOptions.erase(m_configOptions.begin()); }
90
void Game::ioWrite(const char *fmt, ...)
93
char *buf = new char[size];
94
static std::string ioStr;
102
n = vsnprintf(buf, size, fmt, arg);
105
if (n > -1 && n < size)
119
buf = new char[size];
123
void Game::ioWrite(const std::string data)
126
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
130
void Game::ioInfo(const char *data, ...)
136
vsnprintf(buf, sizeof(buf)-1, data, arg);
138
buf[sizeof(buf)-1] = 0;
140
ioWrite("<monopd><msg type=\"info\" value=\"%s\"/></monopd>\n", buf);
143
void Game::ioInfo(const std::string data)
145
ioWrite("<monopd><msg type=\"info\" value=\"" + data + "\"/></monopd>\n");
148
void Game::ioError(const std::string data)
150
ioWrite("<monopd><msg type=\"error\" value=\"" + data + "\"/></monopd>\n");
153
void Game::loadGameType(const std::string &gameType)
155
if (m_gameType != gameType)
157
m_gameType = gameType;
160
unsetChildProperties(); // so that the first player joining won't get estateupdates until init
164
void Game::loadConfig()
166
enum ConfigGroup { Board, EstateGroups, Estates, CardGroups, Cards, Other };
167
ConfigGroup configGroup = Other;
168
std::map<Estate *, int> payTargets;
169
EstateGroup *group = 0;
171
CardGroup *cardGroup = 0;
173
unsigned int goEstate = 0, nextCardId = 0;
176
std::string line, key, value;
177
std::string filename = std::string(MONOPD_DATADIR "/games/") + m_gameType + ".conf";
179
std::ifstream infile( filename.c_str() );
183
while ( getline( infile, line, '\n') )
185
if ( !line.size() || line[0] == '#' ) {}
186
else if ( line[0] == '<' )
188
value = line.substr( 1, line.size()-2 );
189
if ( value == "Board" )
191
else if ( value == "EstateGroups" )
192
configGroup = EstateGroups;
193
else if ( value == "Estates" )
194
configGroup = Estates;
195
else if ( value == "Cards" )
196
configGroup = CardGroups;
200
else if ( line[0] == '[' )
202
value = line.substr( 1, line.size()-2 );
203
if (configGroup == EstateGroups)
204
group = newGroup( value );
205
else if (configGroup == Estates)
206
eTmp = newEstate( value );
207
else if (configGroup == Cards && cardGroup)
208
card = cardGroup->newCard( nextCardId++, value );
212
pos = line.find( "=" );
213
if ( pos != std::string::npos )
215
key = line.substr( 0, pos );
216
value = line.substr( pos+1 );
218
if (configGroup == Board)
221
goEstate = atoi( value.c_str() );
222
else if ( key == "bgcolor" )
225
else if (configGroup == EstateGroups)
226
parseConfigEntry( group, key, value );
227
else if (configGroup == Estates)
229
if ( key == "paytarget" )
230
payTargets[eTmp] = atoi( value.c_str() );
232
parseConfigEntry( eTmp, key, value );
234
else if (configGroup == CardGroups)
236
if ( key == "groupname" )
238
cardGroup = newCardGroup( value );
242
else if (configGroup == Cards)
244
if ( key == "groupname" )
245
cardGroup = newCardGroup( value );
247
parseConfigEntry( card, key, value );
249
else if ( key == "name" || key == "description")
250
setProperty( key, value );
251
else if ( key == "minplayers" || key == "maxplayers" )
252
setProperty( key, atoi( value.c_str() ) );
253
else if ( key == "houses" )
254
m_houses = atoi( value.c_str() );
255
else if ( key == "hotels" )
256
m_hotels = atoi( value.c_str() );
257
else if ( key == "startmoney" )
258
m_startMoney = atoi( value.c_str() );
264
// Make sure defaults are within reasonable limits
265
if (getIntProperty("minplayers") < 2)
266
setProperty("minplayers", 2);
267
if (getIntProperty("maxplayers") < getIntProperty("minplayers"))
268
setProperty("maxplayers", getIntProperty("minplayers"));
269
else if (getIntProperty("maxplayers") > 32)
270
setProperty("maxplayers", 32);
272
// Go estate is required, defaults to first specified
273
if (!(m_goEstate = findEstate(goEstate)))
274
m_goEstate = findEstate(0);
278
// Fix defaults for estates
279
for (std::map<Estate *, int>::iterator it = payTargets.begin() ; it != payTargets.end() && (eTmp = (*it).first) ; it++)
280
eTmp->setPayTarget(findEstate((*it).second));
284
for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
286
if (!eTmp->hasIntProperty("mortgageprice"))
287
eTmp->setProperty("mortgageprice", (int)(eTmp->price()/2), this);
288
if (!eTmp->hasIntProperty("unmortgageprice"))
289
eTmp->setProperty("unmortgageprice", (int)((eTmp->price()/2)*1.1), this);
290
if (!eTmp->hasIntProperty("sellhouseprice"))
291
eTmp->setProperty("sellhouseprice", (int)(eTmp->housePrice()/2), this);
297
void Game::parseConfigEntry(Estate *es, const std::string &key, const std::string &value)
302
if ( key == "group" )
303
es->setEstateGroup( findGroup( value ) );
304
else if ( key == "color" || key == "bgcolor" || key == "icon" )
305
es->setProperty( key, value, this );
306
else if ( key == "price" || key == "mortgageprice" || key == "unmortgageprice" || key == "houseprice" || key == "sellhouseprice" ||
307
key == "payamount" || key == "passmoney" || key == "tax" || key == "taxpercentage"
309
es->setProperty( key, atoi( value.c_str() ), this );
310
else if ( key == "rent0" )
311
es->setRent(0, atoi( value.c_str() ) );
312
else if ( key == "rent1" )
313
es->setRent(1, atoi( value.c_str() ) );
314
else if ( key == "rent2" )
315
es->setRent(2, atoi( value.c_str() ) );
316
else if ( key == "rent3" )
317
es->setRent(3, atoi( value.c_str() ) );
318
else if ( key == "rent4" )
319
es->setRent(4, atoi( value.c_str() ) );
320
else if ( key == "rent5" )
321
es->setRent(5, atoi( value.c_str() ) );
322
else if ( key == "tojail" || key == "jail" )
323
es->setBoolProperty( key, atoi( value.c_str() ), this );
324
else if ( key == "takecard" )
325
es->setTakeCardGroup( findCardGroup( value ) );
328
void Game::parseConfigEntry(Card *card, const std::string &key, const std::string &value)
333
if ( key == "canbeowned" )
334
card->setCanBeOwned( atoi( value.c_str() ) );
335
else if ( key == "pay" )
336
card->setPay( atoi( value.c_str() ) );
337
else if ( key == "payhouse" )
338
card->setPayHouse( atoi( value.c_str() ) );
339
else if ( key == "payhotel" )
340
card->setPayHotel( atoi( value.c_str() ) );
341
else if ( key == "payeach" )
342
card->setPayEach( atoi( value.c_str() ) );
343
else if ( key == "tojail" )
344
card->setToJail( atoi( value.c_str() ) );
345
else if ( key == "outofjail" )
346
card->setOutOfJail( atoi( value.c_str() ) );
347
else if ( key == "advance" )
348
card->setAdvance( atoi( value.c_str() ) );
349
else if ( key == "advanceto" )
350
card->setAdvanceTo( atoi( value.c_str() ) );
351
else if ( key == "advancetonextof" )
352
card->setAdvanceToNextOf( findGroup( value ) );
353
else if ( key == "rentmath" )
354
card->setRentMath( value );
357
void Game::parseConfigEntry(EstateGroup *group, const std::string &key, const std::string &value)
362
if ( key == "price" )
363
group->setPrice( atoi( value.c_str() ) );
364
else if ( key == "houseprice" )
365
group->setHousePrice( atoi( value.c_str() ) );
366
else if ( key == "color" || key == "bgcolor" )
367
group->setProperty( key, value, this );
368
else if ( key == "rentmath" )
369
group->setRentMath( value );
370
else if ( key == "rentvar" )
371
group->setRentVar( value );
374
void Game::editConfiguration(Player *pInput, char *data)
376
if (pInput != m_master)
378
pInput->ioError("Only the master can edit the game configuration.");
382
if (m_status != Config)
384
pInput->ioError("This game has already been started.");
388
if (!strstr(data, ":"))
390
pInput->ioError("Invalid input for .gc, no seperator after configId");
393
int configId = atoi(strsep(&data, ":"));
395
GameObject *configOption = findConfigOption(configId);
398
pInput->ioError("No such configId: %d.", configId);
402
std::string newValue = data;
404
if ( configOption->getStringProperty("type") == "string" )
405
configOption->setProperty( "value", newValue );
406
else if ( configOption->getStringProperty("type") == "int" )
407
configOption->setProperty( "value", atoi(newValue.c_str()) );
408
else if ( configOption->getStringProperty("type") == "bool" )
409
configOption->setBoolProperty( "value", atoi(newValue.c_str()) );
412
void Game::editConfig(Player *pInput, char *data)
414
if (pInput != m_master)
416
pInput->ioError("Only the master can edit the game configuration.");
419
if (m_status != Config)
421
pInput->ioError("This game has already been started.");
425
// (*m_configOptions.begin())->setProperty( "value", "teststringupdated" );
430
setAuctionsEnabled(atoi(data+1));
433
setCollectFines(atoi(data+1));
436
setUnlimitedHouses(atoi(data+1));
439
setDoublePassMoney(atoi(data+1));
442
setNoRentInJail(atoi(data+1));
445
setAlwaysShuffle(atoi(data+1));
448
setAllowEstateSales(atoi(data+1));
451
pInput->ioError("No such game configuration command.");
455
GameObject *Game::newConfigOption(const std::string &name, const std::string &description, bool editable)
457
GameObject *config = new GameObject( m_configOptions.size()+1 , ConfigOption, this);
458
m_configOptions.push_back(config);
459
config->setProperty("name", name, this);
460
config->setProperty("description", description, this);
461
config->setBoolProperty("edit", editable, this);
465
void Game::addConfigOption(const std::string &name, const std::string &description, const std::string &defaultValue, bool editable)
467
GameObject *config = newConfigOption(name, description, editable);
468
config->setProperty("type", "string", this);
469
config->setProperty("value", defaultValue, this);
472
void Game::addConfigOption(const std::string &name, const std::string &description, int defaultValue, bool editable)
474
GameObject *config = newConfigOption(name, description, editable);
475
config->setProperty("type", "int", this);
476
config->setProperty("value", defaultValue, this);
479
void Game::addBoolConfigOption(const std::string &name, const std::string &description, bool defaultValue, bool editable)
481
GameObject *config = newConfigOption(name, description, editable);
482
config->setProperty("type", "bool", this);
483
config->setBoolProperty("value", defaultValue, this);
486
GameObject *Game::findConfigOption(int configId)
488
for(std::vector<GameObject *>::iterator it = m_configOptions.begin(); it != m_configOptions.end() && (*it) ; ++it)
489
if ( (*it)->id() == configId )
494
GameObject *Game::findConfigOption(const std::string &name)
496
for(std::vector<GameObject *>::iterator it = m_configOptions.begin(); it != m_configOptions.end() && (*it) ; ++it)
497
if ( (*it)->getStringProperty("name") == name )
502
void Game::start(Player *pInput)
504
if (pInput != m_master)
506
pInput->ioError("Only the master can start a game.");
509
if (m_status != Config)
511
pInput->ioError("This game has already been started.");
514
int minPlayers = getIntProperty("minplayers");
515
if (m_players.size() < minPlayers)
517
pInput->ioError("This game requires at least %d players to be started.", minPlayers);
524
// Update whether players can join/watch.
525
GameObject *config = findConfigOption( "allowspectators" );
526
if ( config && config->getBoolProperty( "value" ) )
527
setBoolProperty( "canbejoined", true );
529
setBoolProperty( "canbejoined", false );
532
random_shuffle(m_players.begin(), m_players.end());
534
// Shuffle card decks.
535
CardGroup *cardGroup = 0;
536
for (std::vector<CardGroup *>::iterator it = m_cardGroups.begin() ; it != m_cardGroups.end() && (cardGroup = *it) ; ++it)
537
cardGroup->shuffleCards();
539
// Set all players at Go, give them money
541
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
544
pTmp->setEstate(m_goEstate);
545
pTmp->addMoney(m_startMoney);
548
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
549
sendFullUpdate(pTmp);
551
// Add notification of game start.
553
ioWrite("<monopd><gameupdate gameid=\"%d\" status=\"%s\"/></monopd>\n", m_id, statusLabel().c_str());
555
// Turn goes to first player
556
m_pTurn = *m_players.begin();
557
m_pTurn->setTurn(true);
560
void Game::setTokenLocation(Player *pInput, unsigned int estateId)
562
if (!clientsMoving() || !pInput || !m_pTurn)
565
Estate *estateLoc = findEstate(estateId);
567
if ( !estateLoc || !pInput->tokenLocation() || !m_pTurn->destination() || (pInput->tokenLocation() == estateLoc) )
570
bool useNext = false;
571
unsigned int money = 0;
573
// printf("Game::setTokenLocation, P:%d PTL:%d EID:%d\n", pInput->id(), pInput->tokenLocation()->id(), estateId);
576
for (std::vector<Estate *>::iterator it = m_estates.begin() ;;)
578
if (it == m_estates.end())
580
// printf("Game::setTokenLocation, reloop\n");
581
it = m_estates.begin();
589
if (estate->getIntProperty("passmoney"))
591
// printf("Game::setTokenLocation, pass:%d\n", estate->id());
592
pInput->setDisplay(0, "%s passes %s and gets %d.", m_pTurn->getStringProperty("name").c_str(), estate->getStringProperty("name").c_str(), estate->getIntProperty("passmoney"));
593
pInput->sendDisplayMsg();
594
money += estate->getIntProperty("passmoney");
595
pInput->ioWrite("<monopd><playerupdate playerid=\"%d\" money=\"%d\"/></monopd>\n", m_pTurn->id(), m_pTurn->getIntProperty("money") + money);
597
if (estate == m_pTurn->destination())
599
// printf("Game::setTokenLocation, setPTL:0\n");
600
pInput->setTokenLocation(0); // Player is done moving
603
if (estate == estateLoc)
605
// printf("Game::setTokenLocation, setPTL:%d\n", estateId);
606
pInput->setTokenLocation(estate); // Player is not done moving
610
else if (estate == pInput->tokenLocation())
612
// printf("Game::setTokenLocation, useNext:%d==PTL\n", estate->id());
619
// Find out if there are still clients busy with movement.
624
bool endTurn = landPlayer(m_pTurn, false);
628
// Don't do a thing.. just wait until they are done.
630
else if (m_pTurn->getBoolProperty("can_buyestate"))
632
// Don't do a thing..
638
void Game::tokenMovementTimeout()
640
// Mark all clients as non moving.
642
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
643
if (pTmp->tokenLocation())
645
if (m_pTurn && m_pTurn->destination())
647
m_pTurn->setProperty("location", m_pTurn->destination()->id(), this);
648
m_pTurn->setBoolProperty("directmove", true, this);
649
setTokenLocation(pTmp, m_pTurn->destination()->id());
654
unsigned int Game::auctionTimeout()
659
printf("Game::auctionTimeout %d %d\n", m_id, m_players.size());
661
int status = m_auction->status();
665
case Auction::PaymentDue:
666
case Auction::Completed:
669
m_auction->setStatus(status+1);
670
ioWrite("<monopd><auctionupdate auctionid=\"%d\" status=\"%d\"/></monopd>\n", m_auction->id(), m_auction->status());
671
printf("<monopd><auctionupdate auctionid=\"%d\" status=\"%d\"/></monopd>\n", m_auction->id(), m_auction->status());
673
status = m_auction->status();
675
if (status == Auction::Sold || status == Auction::PaymentDue)
677
printf("Game::auctionTimeout sold||paymentdue %d %d\n", m_id, m_players.size());
680
if (status == Auction::PaymentDue)
683
if (status == Auction::Completed)
685
if (m_pTurn && !clientsMoving() )
688
printf("Game::auctionTimeout delAuction %d %d\n", m_id, m_players.size());
696
void Game::newDebtToAll(Player *from, int amount)
699
for(std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
701
newDebt(from, pTmp, 0, amount);
704
Debt *Game::newDebt(Player *from, Player *toPlayer, Estate *toEstate, int amount)
706
if (from && (from->getBoolProperty("bankrupt") || from->getBoolProperty("spectator")))
708
if (toPlayer && (toPlayer->getBoolProperty("bankrupt") || toPlayer->getBoolProperty("spectator")))
711
Debt *d = new Debt(from, toPlayer, toEstate, amount);
712
m_debts.push_back(d);
714
from->setBoolProperty("hasdebt", true);
716
if (amount > from->assets())
718
setDisplay(0, false, false, "%s is bankrupt!", from->getStringProperty("name").c_str());
719
bankruptPlayer(from);
725
Debt *Game::findDebt(Player *p)
728
for(std::vector<Debt *>::iterator it = m_debts.begin(); it != m_debts.end() && (dTmp = *it) ; ++it)
729
if (p == dTmp->from())
735
Debt *Game::findDebtByCreditor(Player *p)
738
for(std::vector<Debt *>::iterator it = m_debts.begin(); it != m_debts.end() && (dTmp = *it) ; ++it)
739
if (p == dTmp->toPlayer())
745
void Game::delDebt(Debt *debt)
747
for(std::vector<Debt *>::iterator it = m_debts.begin(); it != m_debts.end(); ++it)
753
Player *pFrom = debt->from();
754
if ( !findDebt(pFrom) )
755
pFrom->setBoolProperty("hasdebt", false);
760
void Game::solveDebts(Player *pInput, const bool &verbose)
762
Debt *debt = findDebt(pInput);
766
ioError("You don't have any debts to pay off!");
767
if (!clientsMoving() && !m_auction && !m_pausedForDialog)
772
while ( debt = findDebt(pInput) )
774
if ( !solveDebt(debt) )
778
if (unsigned int debts = m_debts.size())
779
setDisplay(m_pTurn->estate(), false, false, "There are still %d debts, game still paused.", debts);
781
setDisplay(m_pTurn->estate(), false, false, "All debts are settled, game continues.");
783
if (!clientsMoving() && !m_auction && !m_pausedForDialog)
787
bool Game::solveDebt( Debt *debt )
789
Player *pFrom = debt->from();
790
int payAmount = debt->amount();
791
if ( !(pFrom->payMoney(payAmount)) )
794
Player *pCreditor = 0;
795
Estate *eCreditor = 0;
796
if ((pCreditor = debt->toPlayer()))
797
pCreditor->addMoney(payAmount);
798
else if ( ( eCreditor = debt->toEstate() ) && getBoolProperty("collectfines") )
799
eCreditor->addMoney(payAmount);
801
setDisplay(m_pTurn->estate(), false, false, "%s pays off a %d debt to %s.", pFrom->getStringProperty("name").c_str(), debt->amount(), (pCreditor ? pCreditor->getStringProperty("name").c_str() : "Bank"));
802
if (debt == m_auctionDebt)
811
void Game::enforceDebt(Player *pBroke, Debt *debt)
814
Estate *eCreditor = debt ? debt->toEstate() : 0;
815
Player *pCreditor = debt ? debt->toPlayer() : 0;
817
// Give all cards to creditor or card stack
818
while (Card *card = pBroke->findFirstCard())
819
transferCard(card, pCreditor);
821
// Sell all houses on property
823
for(std::vector<Estate *>::iterator it = m_estates.begin() ; it != m_estates.end() && (eTmp = *it) ; ++it)
825
if (pBroke == eTmp->owner())
828
int eTmpHouses = eTmp->getIntProperty("houses");
832
int returnValue = eTmpHouses * eTmp->housePrice() / 2;
833
pBroke->addMoney(returnValue);
835
if (!getBoolProperty("unlimitedhouses"))
837
// Make houses available again
838
if ( eTmpHouses == 5 )
841
m_houses += eTmpHouses;
843
eTmp->setProperty("houses", 0);
846
// Transfer ownership to creditor
848
transferEstate(eTmp, pCreditor);
851
eTmp->setBoolProperty("mortgaged", false);
853
// TODO: auction all estate when there is no pCreditor
854
transferEstate(eTmp, pCreditor);
856
// TODO: send estateupdate?
860
// Give all money to creditor
861
int payAmount = pBroke->getIntProperty("money");
862
pBroke->payMoney(payAmount);
865
pCreditor->addMoney(payAmount);
866
else if (eCreditor && getBoolProperty("collectfines"))
867
eCreditor->addMoney(payAmount);
873
void Game::newAuction(Player *pInput)
875
if (!getBoolProperty("auctionsenabled") || !totalAssets())
877
pInput->ioError("Auctions are not enabled.");
880
if (!(pInput->getBoolProperty("canauction")))
882
pInput->ioError("You cannot auction anything at the moment.");
886
Estate *estate = pInput->estate();
888
m_auction = new Auction();
889
m_auction->setEstate(estate);
890
m_auction->addToScope(this);
892
pInput->setBoolProperty("can_buyestate", false);
893
pInput->setBoolProperty("canauction", false);
894
setDisplay(estate, true, true, "%s chooses to auction %s.", pInput->getStringProperty("name").c_str(), estate->getStringProperty("name").c_str());
895
ioWrite("<monopd><auctionupdate auctionid=\"%d\" actor=\"%d\" estateid=\"%d\" status=\"0\"/></monopd>\n", m_auction->id(), pInput->id(), estate->id());
898
Auction *Game::auction()
903
void Game::delAuction()
909
// Returns 0 on succesful bid, 1 on error.
910
int Game::bidInAuction(Player *pInput, char *data)
912
if (!strstr(data, ":"))
914
pInput->ioError("Invalid input for .ab, no seperator after auctionId");
917
int auctionId = atoi(strsep(&data, ":"));
918
int bid = atoi(data);
920
if ( !m_auction || m_auction->id() != auctionId )
922
pInput->ioError("No such auctionId: %d.", auctionId);
926
switch( m_auction->getIntProperty("status") )
929
case Auction::PaymentDue:
930
case Auction::Completed:
931
pInput->ioError( "You can no longer bid in auction %d.", auctionId );
936
if (bid > pInput->assets())
938
pInput->ioError("You don't have %d.", bid);
942
int highestBid = m_auction->getIntProperty("highbid");
943
if (bid <= highestBid)
945
pInput->ioError("Minimum bid is %d.", highestBid+1);
949
m_auction->setHighBid(pInput, bid);
950
ioWrite("<monopd><auctionupdate auctionid=\"%d\" highbid=\"%d\" highbidder=\"%d\" status=\"%d\"/></monopd>\n", m_auction->id(), bid, pInput->id(), m_auction->status());
954
void Game::newTrade(Player *pInput, unsigned int playerId)
956
Player *player = findPlayer(playerId);
959
pInput->ioError("No such playerId: %ld.", playerId);
962
else if (player == pInput)
964
pInput->ioError("Trading with yourself?");
968
// Create a new trade between us and player
969
Trade *t = new Trade(pInput, player, m_nextTradeId++);
970
m_trades.push_back(t);
973
Trade *Game::findTrade(Player *_p)
976
for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (tTmp = *it) ; ++it)
977
if (tTmp->hasPlayer(_p))
983
Trade *Game::findTrade(unsigned int tradeId)
986
for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (tTmp = *it) ; ++it)
987
if (tradeId == tTmp->id()) return tTmp;
992
void Game::delTrade(Trade *trade)
994
for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end(); ++it)
1003
void Game::acceptTrade(Player *pInput, char *data)
1005
bool ignoreRevision = false;
1006
int tradeId = 0, revision = 0;
1007
// data looks like "1:1", tradeid, revision
1008
if (!strstr(data, ":"))
1010
// ioError("Invalid input for .Ta, no seperator after tradeId");
1012
ignoreRevision = true; // backwards compatibility
1013
tradeId = atoi(data);
1017
tradeId = atoi(strsep(&data, ":"));
1018
revision = atoi(data);
1021
Trade *trade = findTrade(tradeId);
1024
pInput->ioError("No such tradeId: %ld.", tradeId);
1027
if ( !(trade->hasPlayer(pInput)) )
1029
pInput->ioError("You are not part of trade %ld.", tradeId);
1032
if (!ignoreRevision && revision != trade->getIntProperty("revision"))
1034
pInput->ioError("Ignored accept for trade %ld because it was changed.", tradeId);
1038
trade->setPlayerAccept(pInput, true);
1040
if (trade->allAccept())
1043
completeTrade(trade);
1045
if (!clientsMoving() && !m_auction && !m_pausedForDialog)
1050
void Game::rejectTrade(Player *pInput, unsigned int tradeId)
1052
Trade *trade = findTrade(tradeId);
1055
pInput->ioError("No such tradeId: %d.", tradeId);
1059
if ( !(trade->hasPlayer(pInput)) )
1061
pInput->ioError("You are not part of trade %d.", tradeId);
1065
ioWrite("<monopd><tradeupdate type=\"rejected\" tradeid=\"%d\" actor=\"%d\"/></monopd>\n", trade->id(), pInput->id());
1069
void Game::completeTrade(Trade *trade)
1071
ioWrite("<monopd><tradeupdate tradeid=\"%d\" type=\"accepted\"/></monopd>\n", trade->id());
1073
Player *pFrom, *pTo;
1075
while((pTo = trade->firstTarget()))
1077
pFrom = trade->firstFrom();
1078
object = trade->takeFirstObject();
1079
switch(object->type())
1081
case GameObject::Money:
1083
money = object->id();
1084
delete object; // was temporarily created to serve as trade object
1085
if (!pFrom->payMoney(money))
1087
setDisplay(m_pTurn->estate(), false, false, "%s owes %d to %s. Game paused, %s is not solvent. Player needs to raise %d in cash first.", pFrom->getStringProperty("name").c_str(), money, pTo->getStringProperty("name").c_str(), pFrom->getStringProperty("name").c_str(), (money - pFrom->getIntProperty("money")));
1088
newDebt(pFrom, pTo, 0, money);
1091
pTo->addMoney(money);
1093
setDisplay(m_pTurn->estate(), false, false, "%s gets %d from %s.", pTo->getStringProperty("name").c_str(), money, pFrom->getStringProperty("name").c_str());
1096
transferObject(object->type(), object->id(), pTo, true);
1100
// Write "completed" to all players
1101
ioWrite("<monopd><tradeupdate tradeid=\"%d\" type=\"completed\"/></monopd>\n", trade->id());
1103
// Solve debts for trade players
1105
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
1106
if (trade->hasPlayer(player))
1110
void Game::completeAuction()
1115
printf("Game::completeAuction()\n");
1117
Player *pBid = m_auction->highBidder();
1121
int bid = m_auction->getIntProperty("highbid");
1123
if (m_auction->status() == Auction::Sold)
1125
if (!pBid->payMoney(bid))
1127
setDisplay(m_pTurn->estate(), false, false, "%s has to pay %d. Game paused, %s is not solvent. Player needs to raise %d in cash first.", pBid->getStringProperty("name").c_str(), bid, pBid->getStringProperty("name").c_str(), (bid - pBid->getIntProperty("money")));
1128
m_auctionDebt = newDebt(pBid, 0, 0, bid);
1129
m_auction->setStatus(Auction::PaymentDue);
1133
else if (m_auction->status() == Auction::PaymentDue && m_auctionDebt)
1136
m_auction->setStatus(Auction::Completed);
1137
Estate *estate = m_auction->estate();
1138
transferEstate(estate, pBid);
1139
setDisplay(estate, false, false, "Purchased by %s in an auction for %d.", pBid->getStringProperty("name").c_str(), bid);
1141
if (m_pTurn->getBoolProperty("canrollagain"))
1143
m_pTurn->setBoolProperty("canrollagain", false);
1144
m_pTurn->setBoolProperty("can_roll", true);
1145
setDisplay(estate, false, false, "%s may roll again.", m_pTurn->getStringProperty("name").c_str());
1151
void Game::setDisplay(Estate *estate, bool clearText, bool clearButtons, const char *data, ...)
1156
va_start(arg, data);
1157
vsnprintf(buf, sizeof(buf)-1, data, arg);
1159
buf[sizeof(buf)-1] = 0;
1162
for (std::vector<Player *>::iterator pit = m_players.begin(); pit != m_players.end() && (player = *pit) ; ++pit)
1164
player->setDisplay(estate, std::string(buf));
1165
player->setDisplayClearText(clearText);
1166
player->setDisplayClearButtons(clearButtons);
1167
player->sendDisplayMsg();
1171
void Game::sendMsgEstateUpdate(Estate *e)
1175
for (std::vector<Player *>::iterator pit = m_players.begin(); pit != m_players.end() && (pTmp = *pit) ; ++pit) {
1176
for(std::vector<Estate *>::iterator eit = m_estates.begin(); eit != m_estates.end() && (eTmp = *eit) ; ++eit) {
1177
if(eTmp->group() == e->group())
1178
pTmp->ioWrite("<monopd><estateupdate estateid=\"%d\" owner=\"%d\" can_toggle_mortgage=\"%d\" can_buy_houses=\"%d\" can_sell_houses=\"%d\"/></monopd>\n", eTmp->id(), (eTmp->owner() ? eTmp->owner()->id() : -1), eTmp->canToggleMortgage(pTmp), eTmp->canBuyHouses(pTmp), eTmp->canSellHouses(pTmp));
1183
EstateGroup *Game::newGroup(const std::string &name)
1185
EstateGroup *group = new EstateGroup(m_nextEstateGroupId++, this, name);
1186
m_estateGroups.push_back(group);
1190
EstateGroup *Game::findGroup(const std::string &name)
1192
EstateGroup *group = 0;
1193
for(std::vector<EstateGroup *>::iterator it = m_estateGroups.begin(); it != m_estateGroups.end() && (group = *it) ; ++it)
1194
if (group->name() == name)
1200
unsigned int Game::estateGroupSize(EstateGroup *estateGroup)
1202
unsigned int size = 0;
1205
for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end() && (eTmp = *it) ; ++it)
1206
if (estateGroup == eTmp->group())
1212
Estate *Game::newEstate(const std::string &name)
1214
Estate *es = new Estate(m_nextEstateId++, &m_estates);
1215
m_estates.push_back(es);
1217
// Set properties with game-wide scope
1218
es->setProperty("name", name, this);
1219
es->setProperty("houses", 0, this);
1220
es->setProperty("money", 0, this);
1221
es->setBoolProperty("mortgaged", false, this);
1226
Estate *Game::findEstate(int id)
1228
if (id >= 0 && id < (int)m_estates.size())
1229
return m_estates[id];
1234
Estate *Game::findNextEstate(EstateGroup *group, Estate *startEstate)
1236
bool useNext = true;
1240
Estate *eTmp = 0, *eFirst = 0;
1241
for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
1243
if (startEstate && startEstate == eTmp)
1245
if (eTmp->group() == group)
1256
Estate *Game::findNextJailEstate(Estate *startEstate)
1258
bool useNext = true;
1262
Estate *eTmp = 0, *eFirst = 0;
1263
for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
1265
if (startEstate && startEstate == eTmp)
1267
if (eTmp->getBoolProperty("jail"))
1278
void Game::delEstate(Estate *_e)
1280
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it); ++it)
1281
(*it)->setDisplay(0);
1283
for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end(); ++it)
1286
m_estates.erase(it);
1292
void Game::transferEstate(Estate *estate, Player *player, const bool verbose)
1294
if (estate->owner())
1297
for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (trade = *it) ; ++it)
1298
trade->delComponent(estate->type(), estate->id());
1301
estate->setOwner(player);
1302
sendMsgEstateUpdate(estate);
1304
if (player && verbose)
1305
setDisplay(m_pTurn->estate(), false, false, "%s is now the owner of estate %s.", player->getStringProperty("name").c_str(), estate->getStringProperty("name").c_str());
1308
void Game::transferObject(const enum GameObject::Type type, unsigned int id, Player *player, const bool verbose)
1312
case GameObject::GCard:
1313
transferCard(findCard(id), player, verbose);
1315
case GameObject::GEstate:
1316
transferEstate(findEstate(id), player, verbose);
1322
void Game::setPausedForDialog(const bool paused)
1324
m_pausedForDialog = paused;
1327
const bool Game::pausedForDialog()
1329
return m_pausedForDialog;
1332
void Game::transferCard(Card *card, Player *player, const bool verbose)
1334
Player *owner = card->owner();
1337
owner->takeCard(card);
1340
for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (trade = *it) ; ++it)
1341
trade->delComponent(card->type(), card->id());
1344
card->group()->popCard();
1348
player->addCard(card);
1349
card->setOwner(player);
1352
card->group()->pushCard(card);
1354
ioWrite("<monopd><cardupdate cardid=\"%d\" owner=\"%d\"/></monopd>\n", card->id(), card->owner() ? card->owner()->id() : -1);
1356
setDisplay(m_pTurn->estate(), false, false, "%s is now the owner of card %d.", player->getStringProperty("name").c_str(), card->id());
1359
CardGroup *Game::newCardGroup(const std::string name)
1361
CardGroup *cardGroup = new CardGroup(m_nextCardGroupId++, this, name);
1362
m_cardGroups.push_back(cardGroup);
1366
CardGroup *Game::findCardGroup(const std::string name)
1368
CardGroup *cardGroup = 0;
1369
for(std::vector<CardGroup *>::iterator it = m_cardGroups.begin(); it != m_cardGroups.end(); ++it)
1370
if ((cardGroup = *it) && cardGroup->name() == name)
1376
Card *Game::findCard(unsigned int id)
1380
CardGroup *cardGroup = 0;
1381
for(std::vector<CardGroup *>::iterator it = m_cardGroups.begin(); it != m_cardGroups.end() && (cardGroup = *it) ; ++it)
1383
card = cardGroup->findCard(id);
1389
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
1391
card = player->findCard(id);
1399
Player *Game::addPlayer(Player *p, const bool &isMaster, const bool &isSpectator)
1401
m_players.push_back(p);
1402
setProperty( "players", m_players.size() );
1404
if ( m_players.size() == getBoolProperty("maxplayers") )
1405
setBoolProperty("canbejoined", false);
1410
// Properties with game as scope
1411
p->setProperty("money", 0, this);
1412
p->setBoolProperty("bankrupt", false, this);
1413
p->setBoolProperty("jailed", false, this);
1414
p->setBoolProperty("hasturn", 0, this);
1415
p->setBoolProperty("spectator", isSpectator, this);
1416
p->setBoolProperty("master", isMaster, this); // FIXME: DEPRECATED 1.0
1421
setProperty( "master", p->id() );
1424
// Properties with player as scope
1425
p->setProperty("doublecount", 0);
1426
p->setProperty("jailcount", 0);
1427
p->setBoolProperty("can_roll", false);
1428
p->setBoolProperty("canrollagain", false);
1429
p->setBoolProperty("can_buyestate", false);
1430
p->setBoolProperty("canauction", false);
1431
p->setBoolProperty("hasdebt", false);
1432
p->setBoolProperty("canusecard", false);
1435
// Temporarily set status at init for joining player
1436
if (m_status == Run)
1445
if (p->getBoolProperty("spectator"))
1451
Player *Game::findPlayer(int playerId)
1454
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
1455
if (playerId == pTmp->id())
1461
void Game::removePlayer(Player *p)
1463
if (p->getBoolProperty("hasturn"))
1466
// Find player and erase from std::vector
1467
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end(); ++it)
1470
m_players.erase(it);
1473
setProperty( "players", m_players.size() );
1475
// Do bankrupt after player is removed from list, player doesn't need the resulting messages
1476
if (m_status != Config)
1479
// If not in Config, canbejoined might become true again
1480
else if ( m_players.size() < getBoolProperty("maxplayers") )
1481
setBoolProperty("canbejoined", true);
1486
if (p == m_master && m_players.size() > 0)
1488
m_master->setBoolProperty("master", false); // FIXME: DEPRECATED 1.0
1489
m_master = m_players[0];
1490
setProperty( "master", m_master->id() );
1491
m_master->setBoolProperty("master", true); // FIXME: DEPRECATED 1.0
1493
if (m_status == Config)
1494
sendConfiguration(m_master);
1498
Player *Game::kickPlayer(Player *pInput, int playerId)
1500
if ( pInput != m_master )
1502
pInput->ioError("Only the master can kick players.");
1506
if ( m_status != Config )
1508
pInput->ioError("You can only kick players during game configuration.");
1512
Player *player = findPlayer(playerId);
1515
pInput->ioError("No such playerId: %ld.", playerId);
1522
void Game::upgradePlayer(Player *pInput, int playerId)
1524
if ( pInput != m_master )
1526
pInput->ioError("Only the master can upgrade spectators.");
1530
if ( m_status != Run )
1532
pInput->ioError("You can only upgrade spectators during a game in progress.");
1536
Player *player = findPlayer(playerId);
1539
pInput->ioError("No such playerId: %ld.", playerId);
1543
if ( !player->getBoolProperty("spectator") )
1545
pInput->ioError( "%s is not a spectator in this game.", player->name().c_str() );
1549
// Reset player and remove spectator property.
1550
player->reset(false);
1551
player->setEstate(m_goEstate);
1552
player->addMoney(m_startMoney);
1553
player->setBoolProperty("spectator", 0, this);
1555
ioInfo( "%s upgrades %s to a participating player.", pInput->name().c_str(), player->name().c_str() );
1558
unsigned int Game::playerAssets(Player *player)
1560
unsigned int assets = player->getIntProperty("money");
1562
for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end() && (estate = *it) ; ++it)
1564
if ( player == estate->owner() )
1566
if (!estate->getBoolProperty("mortgaged"))
1568
assets += estate->getIntProperty("mortgageprice");
1569
assets += ( estate->getIntProperty("houses") * estate->getIntProperty("sellhouseprice"));
1576
void Game::updateTurn()
1578
Player *pOldTurn = m_pTurn;
1579
// Disable turn, roll and buy.
1580
pOldTurn->setTurn(false);
1582
Player *player = 0, *pFirst = 0;
1583
bool useNext = false;
1584
for(std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (player = *it) ; ++it)
1586
if (!pFirst && !player->getBoolProperty("bankrupt"))
1589
if (player == pOldTurn)
1591
else if (useNext && !player->getBoolProperty("bankrupt") && !player->getBoolProperty("spectator"))
1598
if (useNext && pFirst)
1602
setDisplay(pOldTurn->estate(), false, false, "Turn goes to %s.", m_pTurn->getStringProperty("name").c_str());
1603
m_pTurn->setTurn(true);
1606
bool Game::landPlayer(Player *pTurn, const bool directMove, const std::string &rentMath)
1608
Estate *destination = pTurn->destination();
1612
bool useNext = false;
1613
unsigned int money = 0;
1615
for (std::vector<Estate *>::iterator it = m_estates.begin() ;;)
1617
if (it == m_estates.end())
1619
it = m_estates.begin();
1623
if (!(estate = *it))
1628
if (estate->getIntProperty("passmoney"))
1630
money += estate->getIntProperty("passmoney");
1631
// Write incremental message for direct moves, token
1632
// confirmation or timeout didn't do it yet.
1634
setDisplay(estate, false, false, "%s passes %s and gets %d.", pTurn->getStringProperty("name").c_str(), estate->getStringProperty("name").c_str(), estate->getIntProperty("passmoney"));
1636
if (estate == destination)
1639
else if (estate == pTurn->estate())
1644
pTurn->setEstate(destination);
1645
pTurn->setDestination(0);
1647
// Store and write final data.
1648
pTurn->addMoney(money);
1651
// Hm, we wait for all tokens to have landed, this is exactly what we
1652
// were trying to avoid with async updates! So some of this stuff can be
1655
// What properties does the estate we are landing on have?
1656
bool endTurn = true;
1658
Estate *es = pTurn->estate();
1660
if (getBoolProperty("doublepassmoney") && es->getIntProperty("passmoney"))
1662
setDisplay(es, false, false, "%s lands on %s and gets %d.", pTurn->getStringProperty("name").c_str(), es->getStringProperty("name").c_str(), es->getIntProperty("passmoney"));
1663
pTurn->addMoney(es->getIntProperty("passmoney"));
1666
setDisplay(es, false, false, "%s lands on %s.", pTurn->getStringProperty("name").c_str(), es->getStringProperty("name").c_str());
1668
// toJail is really serious: if an estate has this property, all other
1669
// properties are ignored when landing it. TODO: Don't ignore and allow
1670
// weird combinations?
1671
if (es->getBoolProperty("tojail"))
1673
if ( Estate *eTmp = findNextJailEstate(es) )
1674
pTurn->toJail(eTmp);
1676
ioError("This gameboard does not have a jail estate.");
1682
// Any estate can have a pot of gold. This is handled before all other
1683
// properties except toJail and works in combination with any of those
1685
if ( int estateMoney = es->getIntProperty("money") )
1687
if ( estateMoney > 0)
1690
pTurn->addMoney(estateMoney);
1691
es->setProperty("money", 0);
1692
setDisplay(es, false, false, "%s gets %d from the fine pot.", pTurn->getStringProperty("name").c_str(), estateMoney);
1697
Estate * const ePayTarget = es->payTarget();
1698
if (!pTurn->payMoney(estateMoney))
1700
// TODO: If we go into debt here, we'll never enter rent
1701
// calculation. But we'll need negative getIntProperty("money") piles for
1702
// Estates because that's basically what tax estates are.
1703
setDisplay(es, false, false, "%s has to pay %d but is not solvent. Game paused, %s is not solvent. Player needs to raise %d in cash first.", pTurn->getStringProperty("name").c_str(), estateMoney, pTurn->getStringProperty("name").c_str(), (estateMoney - pTurn->getIntProperty("money")));
1704
newDebt(pTurn, 0, ePayTarget, estateMoney);
1707
else if (ePayTarget && getBoolProperty("collectfines"))
1708
ePayTarget->addMoney(estateMoney);
1710
setDisplay(es, false, false, "%s pays %d.", pTurn->getStringProperty("name").c_str(), estateMoney);
1714
// Any estate can have taxes on them. This is handled before rent and purchase opportunities.
1715
// TODO: Merge with getIntProperty("money") stuff to avoid duplication?
1716
int tax = es->getIntProperty("tax"), taxPercentage = es->getIntProperty("taxpercentage");
1718
if (tax || taxPercentage)
1721
if ( tax && taxPercentage )
1723
GameObject *config = findConfigOption("automatetax");
1724
if (config && config->getBoolProperty("value") )
1727
tax = (taxPercentage * pTurn->assets() / 100);
1728
if (tax < payAmount)
1734
for (std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
1737
pTmp->setDisplay(es, "%s must pay either %d or %d percent of his/her assets.", pTurn->getStringProperty("name").c_str(), tax, taxPercentage);
1738
pTmp->sendDisplayMsg();
1741
pTurn->setDisplay(es, "Pay either %d or %d percent of your assets.", tax, taxPercentage);
1742
pTurn->addDisplayButton(".T$", std::string("Pay ") + itoa(tax), 1);\
1743
pTurn->addDisplayButton(".T%", std::string("Pay ") + itoa(taxPercentage) + " Percent", 1);
1745
pTurn->sendDisplayMsg();
1747
// TODO: port this into a blocking bool in Display which we can check, will be more generic
1748
m_pausedForDialog = true;
1753
payAmount = ( tax ? tax : (int)(taxPercentage * pTurn->assets() / 100 ) );
1755
Estate * const ePayTarget = es->payTarget();
1757
if (!pTurn->payMoney(payAmount))
1759
// TODO: If we go into debt here, we'll never enter rent
1760
// calculation. So, estates with tax shouldn't be ownable
1762
setDisplay(es, false, false, "Game paused, %s owes %d but is not solvent. Player needs to raise %d in cash first.", pTurn->getStringProperty("name").c_str(), payAmount, (payAmount - pTurn->getIntProperty("money")));
1763
newDebt(pTurn, 0, ePayTarget, payAmount);
1766
else if (ePayTarget && getBoolProperty("collectfines"))
1767
ePayTarget->addMoney(payAmount);
1768
setDisplay(es, false, false, "%s pays %d.", pTurn->getStringProperty("name").c_str(), payAmount);
1771
// Some estates have cards. Handle them before we do rent and purchasing.
1772
if ( CardGroup *cardGroup = es->takeCardGroup() )
1774
if (getBoolProperty("alwaysshuffle"))
1775
cardGroup->shuffleCards();
1777
endTurn = giveCard(pTurn, es, cardGroup->nextCard());
1780
// Calculate rent for owned estates or offer them for sale.
1781
if ( es->canBeOwned() )
1783
if ((pOwner = es->owner()))
1787
if (pOwner == pTurn)
1788
setDisplay(es, false, false, "%s already owns it.", pTurn->getStringProperty("name").c_str());
1789
else if (es->getBoolProperty("mortgaged"))
1790
setDisplay(es, false, false, "%s pays no rent because it's mortgaged.", pTurn->getStringProperty("name").c_str());
1791
else if (getBoolProperty("norentinjail") && pOwner->getBoolProperty("jailed"))
1792
setDisplay(es, false, false, "%s pays no rent because owner %s is in jail.", pTurn->getStringProperty("name").c_str(), pOwner->getStringProperty("name").c_str());
1795
// Pay payAmount owed.
1796
int payAmount = es->rent(pTurn, rentMath);
1798
if (!pTurn->payMoney(payAmount))
1800
setDisplay(es, false, false, "Game paused, %s owes %d to %s but is not solvent. Player needs to raise %d in cash first.", pTurn->getStringProperty("name").c_str(), payAmount, pOwner->getStringProperty("name").c_str(), (payAmount - pTurn->getIntProperty("money")));
1801
newDebt(pTurn, pOwner, 0, payAmount);
1804
setDisplay(es, false, false, "%s pays %d rent to %s.", pTurn->getStringProperty("name").c_str(), payAmount, pOwner->getStringProperty("name").c_str());
1805
pOwner->addMoney(payAmount);
1810
// Unowned, thus for sale.
1812
for (std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
1815
pTmp->setDisplay(es, "For sale.");
1816
pTmp->sendDisplayMsg();
1819
pTurn->setDisplay(es, "For sale.");
1820
pTurn->addDisplayButton(".eb", "Buy", 1);
1821
pTurn->addDisplayButton(".ea", "Auction", (getBoolProperty("auctionsenabled") && totalAssets()));
1822
pTurn->addDisplayButton(".E", "End Turn", !getBoolProperty("auctionsenabled"));
1823
pTurn->sendDisplayMsg();
1825
pTurn->setBoolProperty("can_roll", false);
1826
pTurn->setBoolProperty("can_buyestate", true);
1827
pTurn->setBoolProperty("canauction", (getBoolProperty("auctionsenabled") && totalAssets()));
1834
bool Game::giveCard(Player *pTurn, Estate *estate, Card *card)
1838
ioError(pTurn->name() + " should get a card, but there doesn't seem to be any available!");
1841
setDisplay(estate, false, false, "%s", card->getStringProperty("name").c_str());
1843
// If canBeOwned, remove from stack and give to player. Card can still
1844
// have actions afterwards.
1845
if (card->canBeOwned())
1846
transferCard(card, pTurn);
1851
if ( Estate *eTmp = findNextJailEstate(pTurn->estate()) )
1852
pTurn->toJail(eTmp);
1854
ioError("This gameboard does not have a jail estate.");
1858
else if (card->pay())
1860
int payAmount = card->pay();
1861
Estate * const ePayTarget = pTurn->estate()->payTarget();
1864
if (!pTurn->payMoney(payAmount))
1866
setDisplay(estate, false, false, "Game paused, %s owes %d but is not solvent. Player needs to raise %d in cash first.", pTurn->getStringProperty("name").c_str(), payAmount, (payAmount - pTurn->getIntProperty("money")));
1867
newDebt(pTurn, 0, ePayTarget, payAmount);
1870
else if (ePayTarget && getBoolProperty("collectfines"))
1871
ePayTarget->addMoney(payAmount);
1873
else if (payAmount < 0)
1874
pTurn->addMoney(-payAmount);
1876
else if (card->payEach())
1880
for (std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
1881
if (pTmp != pTurn && !pTmp->getBoolProperty("bankrupt") && !pTmp->getBoolProperty("spectator"))
1882
payAmount += card->payEach();
1886
if (!pTurn->payMoney(payAmount))
1888
setDisplay(estate, false, false, "Game paused, %s owes %d but is not solvent. Player needs to raise %d in cash first.", pTurn->getStringProperty("name").c_str(), payAmount, (payAmount - pTurn->getIntProperty("money")));
1889
newDebtToAll(pTurn, card->payEach());
1893
for (std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
1894
if (pTmp != pTurn && !pTmp->getBoolProperty("bankrupt") && !pTmp->getBoolProperty("spectator"))
1895
pTmp->addMoney(card->payEach());
1900
payAmount = -(card->payEach());
1901
for (std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
1902
if (pTurn != pTmp && !pTmp->getBoolProperty("bankrupt") && !pTmp->getBoolProperty("spectator"))
1904
if (!pTmp->payMoney(payAmount))
1906
setDisplay(estate, false, false, "Game paused, %s owes %d but is not solvent. Player needs to raise %d in cash first.", pTmp->getStringProperty("name").c_str(), payAmount, (payAmount - pTmp->getIntProperty("money")));
1907
newDebt(pTmp, pTurn, 0, payAmount);
1910
pTurn->addMoney(payAmount);
1914
else if (card->payHouse() && card->payHotel())
1919
for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
1921
if (pTurn == eTmp->owner())
1923
if (eTmp->getIntProperty("houses") == 5)
1924
payAmount += card->payHotel();
1925
else if (eTmp->getIntProperty("houses"))
1926
payAmount += (eTmp->getIntProperty("houses") * card->payHouse());
1932
Estate * const ePayTarget = pTurn->estate()->payTarget();
1933
if (!pTurn->payMoney(payAmount))
1935
setDisplay(estate, false, false, "Game paused, %s owes %d but is not solvent. Player needs to raise %d in cash first.", pTurn->getStringProperty("name").c_str(), payAmount, (payAmount - pTurn->getIntProperty("money")));
1936
newDebt(pTurn, 0, ePayTarget, payAmount);
1939
else if (ePayTarget && getBoolProperty("collectfines"))
1940
ePayTarget->addMoney(payAmount);
1942
else if (payAmount < 0)
1943
pTurn->addMoney(-payAmount);
1945
else if (card->advance() || card->advanceTo()!=-1 || card->advanceToNextOf())
1947
// Duplicated from cmd_roll. :-(
1948
if (card->advance())
1949
pTurn->advance(card->advance(), true);
1950
else if (card->advanceTo()!=-1)
1951
pTurn->advanceTo(card->advanceTo(), true);
1952
else if (EstateGroup *group = card->advanceToNextOf())
1954
if (Estate *eTmp = findNextEstate(group, pTurn->estate()))
1955
pTurn->advanceTo(eTmp->id(), true);
1957
ioError("Could not find next estate on gameboard.");
1959
return landPlayer(pTurn, true, card->rentMath());
1964
void Game::declareBankrupt(Player *pInput)
1966
setDisplay(pInput->estate(), false, false, "%s declares bankruptcy!", pInput->getStringProperty("name").c_str());
1967
bankruptPlayer(pInput);
1970
void Game::bankruptPlayer(Player *pBroke)
1972
if (pBroke->getBoolProperty("bankrupt") || pBroke->getBoolProperty("spectator"))
1975
// Set bankrupt flag
1976
pBroke->setBoolProperty("bankrupt", true);
1979
bool debtsWereSolved = false;
1981
// Find debts we are creditor in and remove them
1982
while ((debt = findDebtByCreditor(pBroke)))
1985
debtsWereSolved = true;
1988
// Find debts we are debitor in and pay them off
1989
while ((debt = findDebt(pBroke)))
1991
enforceDebt(pBroke, debt);
1992
debtsWereSolved = true;
1995
// Player might still have assets, when he goes bankrupt without debts
1996
// (disconnection timeout), so we'll enforce giving assets to the Bank.
1997
if (pBroke->assets())
1998
enforceDebt(pBroke);
2000
// Count active (non-bankrupt) players
2001
int activePlayers = 0;
2003
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2004
if (pTmp && !pTmp->getBoolProperty("bankrupt") && !pTmp->getBoolProperty("spectator"))
2010
if (activePlayers == 1)
2013
syslog(LOG_INFO, "game %d ended: %s wins with a fortune of %d.", m_id, m_pWinner->name().c_str(), m_pWinner->assets());
2016
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2019
pTmp->setDisplay(m_pWinner->estate(), "The game has ended! %s wins with a fortune of %d!", m_pWinner->getStringProperty("name").c_str(), m_pWinner->assets());
2020
pTmp->addDisplayButton(".gx", "New Game", true);
2021
pTmp->sendDisplayMsg();
2029
if (activePlayers && !m_debts.size())
2031
if (debtsWereSolved)
2032
setDisplay(m_pTurn->estate(), false, false, "All debts are settled, game continues.");
2034
// Update turn. Always when this function is called as command
2035
// and possibly necessary when this function is called for a
2036
// disconnected user.
2038
if (pBroke == m_pTurn)
2044
int Game::lowestFreeId()
2048
// Find lowest free id in std::vector.
2049
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it) ; ++it)
2050
if ( (*it)->id() >= lowest)
2051
lowest = (*it)->id() + 1;
2056
int Game::totalAssets()
2060
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it) ; ++it)
2061
assets += (*it)->assets();
2066
void Game::rollDice()
2068
// TODO: decent dice display
2069
dice[0] = 1 + (int) (6.0 * rand()/(RAND_MAX + 1.0 ));
2070
dice[1] = 1 + (int) (6.0 * rand()/(RAND_MAX + 1.0 ));
2073
unsigned int Game::players()
2075
return m_players.size();
2078
unsigned int Game::connectedPlayers()
2080
unsigned int count = 0;
2082
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2090
return m_debts.size();
2093
unsigned int Game::clientsMoving()
2095
unsigned int moving = 0;
2097
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2098
if (pTmp->tokenLocation())
2103
void Game::setAllClientsMoving(Estate *estate)
2106
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2108
pTmp->setTokenLocation(estate);
2111
void Game::sendStatus(Player *p)
2113
p->ioWrite("<monopd><gameupdate gameid=\"%d\" status=\"%s\"/></monopd>\n", m_id, statusLabel().c_str());
2116
void Game::sendEstateList(Player *p)
2119
for(std::vector<Estate *>::iterator eIt = m_estates.begin(); eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
2121
std::string bgColor = eTmp->getStringProperty("bgcolor");
2122
if (!bgColor.size())
2124
EstateGroup *estateGroup = eTmp->group();
2126
bgColor = estateGroup->getStringProperty("bgcolor");
2128
if (!bgColor.size())
2129
bgColor = m_bgColor;
2132
std::string color = eTmp->getStringProperty("color");
2135
EstateGroup *estateGroup = eTmp->group();
2137
color = estateGroup->getStringProperty("color");
2140
p->ioWrite("<estateupdate estateid=\"%d\" color=\"%s\" bgcolor=\"%s\" owner=\"%d\" houseprice=\"%d\" group=\"%d\" can_be_owned=\"%d\" can_toggle_mortgage=\"%d\" can_buy_houses=\"%d\" can_sell_houses=\"%d\" price=\"%ld\" rent0=\"%d\" rent1=\"%d\" rent2=\"%d\" rent3=\"%d\" rent4=\"%d\" rent5=\"%d\"/>", eTmp->id(), color.c_str(), bgColor.c_str(), (eTmp->owner() ? eTmp->owner()->id() : -1), eTmp->housePrice(), eTmp->group() ? eTmp->group()->id() : -1, eTmp->canBeOwned(), eTmp->canToggleMortgage(p), eTmp->canBuyHouses(p), eTmp->canSellHouses(p), eTmp->price(), eTmp->rentByHouses(0), eTmp->rentByHouses(1), eTmp->rentByHouses(2), eTmp->rentByHouses(3), eTmp->rentByHouses(4), eTmp->rentByHouses(5));
2141
p->ioWrite(eTmp->oldXMLUpdate(p, true));
2145
void Game::sendEstateGroupList(Player *p)
2147
EstateGroup *egTmp = 0;
2148
for(std::vector<EstateGroup *>::iterator it = m_estateGroups.begin(); it != m_estateGroups.end() && (egTmp = *it) ; ++it)
2149
p->ioWrite("<estategroupupdate groupid=\"%d\" name=\"%s\"/>", egTmp->id(), egTmp->name().c_str());
2152
void Game::sendPlayerList(Player *pOut, bool includeCards)
2155
for(std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
2157
pOut->ioWrite("<playerupdate playerid=\"%d\" name=\"%s\" location=\"%d\" jailed=\"%d\" directmove=\"%d\" hasturn=\"%d\" can_roll=\"%d\"/>", pTmp->id(), pTmp->name().c_str(), pTmp->getIntProperty("location"), pTmp->getBoolProperty("jailed"), 1, pTmp->getBoolProperty("hasturn"), pTmp->getBoolProperty("can_roll"));
2158
pOut->ioWrite(pTmp->oldXMLUpdate(pOut, true));
2161
pTmp->sendCardList(pOut);
2165
void Game::sendFullUpdate(Player *p, const bool userRequest)
2167
if (p->requestedUpdate())
2169
// Last request was also a full update, so the full update XML
2170
// itself triggers the request. Return here to avoid race condition.
2174
p->setRequestedUpdate(true);
2178
if (m_status == Config)
2179
sendConfiguration(p);
2180
else if (m_status == Init || m_status == Run)
2182
p->ioWrite("<monopd>");
2183
sendPlayerList(p, true); // includeCards
2184
sendEstateGroupList(p);
2186
p->ioWrite("</monopd>\n");
2187
p->sendDisplayMsg();
2191
void Game::sendConfiguration(Player *p)
2193
bool edit = (p == m_master);
2194
p->ioWrite("<monopd>");
2195
p->ioWrite("<configupdate gameid=\"%d\"><option type=\"bool\" title=\"Free Parking collects fines\" command=\".gef\" value=\"%d\" edit=\"%d\"/><option type=\"bool\" title=\"Always shuffle decks before taking a card\" command=\".ges\" value=\"%d\" edit=\"%d\"/><option type=\"bool\" title=\"Enable auctions\" value=\"%d\" command=\".gea\" edit=\"%d\"/><option type=\"bool\" title=\"Double pass money on exact landings\" command=\".gep\" value=\"%d\" edit=\"%d\"/><option type=\"bool\" title=\"Bank provides unlimited amount of houses/hotels\" command=\".gel\" value=\"%d\" edit=\"%d\"/><option type=\"bool\" title=\"Players in Jail get no rent\" command=\".ger\" value=\"%d\" edit=\"%d\"/><option type=\"bool\" title=\"Allow estates to be sold back to Bank\" command=\".geS\" value=\"%d\" edit=\"%d\"/></configupdate>", m_id, getBoolProperty("collectfines"), edit, getBoolProperty("alwaysshuffle"), edit, getBoolProperty("auctionsenabled"), edit, getBoolProperty("doublepassmoney"), edit, getBoolProperty("unlimitedhouses"), edit, getBoolProperty("norentinjail"), edit, getBoolProperty("allowestatesales"), edit);
2197
for(std::vector<GameObject *>::iterator it = m_configOptions.begin(); it != m_configOptions.end() && (*it) ; ++it)
2198
p->ioWrite( (*it)->oldXMLUpdate(p, true) );
2199
p->ioWrite("</monopd>\n");
2202
void Game::setCollectFines(const bool collectFines)
2204
if (getBoolProperty("collectfines") != collectFines)
2206
setBoolProperty("collectfines", collectFines);
2209
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2210
sendConfiguration(pTmp);
2214
void Game::setAuctionsEnabled(const bool auctionsEnabled)
2216
if (getBoolProperty("auctionsenabled") != auctionsEnabled)
2218
setBoolProperty("auctionsenabled", auctionsEnabled);
2221
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2222
sendConfiguration(pTmp);
2226
void Game::setDoublePassMoney(bool doublePassMoney)
2228
if (getBoolProperty("doublepassmoney") != doublePassMoney)
2230
setBoolProperty("doublepassmoney", doublePassMoney);
2233
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2234
sendConfiguration(pTmp);
2238
void Game::setAlwaysShuffle(const bool alwaysShuffle)
2240
if (getBoolProperty("alwaysshuffle") != alwaysShuffle)
2242
setBoolProperty("alwaysshuffle", alwaysShuffle);
2245
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2246
sendConfiguration(pTmp);
2250
void Game::setUnlimitedHouses(bool unlimitedHouses)
2252
if (getBoolProperty("unlimitedhouses") != unlimitedHouses)
2254
setBoolProperty("unlimitedhouses", unlimitedHouses);
2257
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2258
sendConfiguration(pTmp);
2262
void Game::setNoRentInJail(bool noRentInJail)
2264
if (getBoolProperty("norentinjail") != noRentInJail)
2266
setBoolProperty("norentinjail", noRentInJail);
2269
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2270
sendConfiguration(pTmp);
2274
void Game::setAllowEstateSales(bool allowEstateSales)
2276
if (getBoolProperty("allowestatesales") != allowEstateSales)
2278
setBoolProperty("allowestatesales", allowEstateSales);
2281
for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
2282
sendConfiguration(pTmp);
2286
const std::string Game::statusLabel()
2303
bool Game::sendChildXMLUpdate(Player *pOutput, bool updateEmpty)
2305
// Send updates about all config options
2306
GameObject *configOption = 0;
2307
for(std::vector<GameObject *>::iterator it = m_configOptions.begin() ; it != m_configOptions.end() && (configOption = *it) ; ++it)
2309
// .. but only when changed (and in property scope)
2310
std::string updateXML = configOption->oldXMLUpdate(pOutput);
2311
if (updateXML.size())
2315
pOutput->ioWrite("<monopd> ");
2316
updateEmpty = false;
2318
pOutput->ioWrite("%s", updateXML.c_str());
2322
// Send updates *about* all estates ..
2323
Estate *eUpdate = 0;
2324
for(std::vector<Estate *>::iterator uit = m_estates.begin(); uit != m_estates.end() && (eUpdate = *uit) ; ++uit)
2326
// .. but only when changed (and in property scope)
2327
std::string updateXML = eUpdate->oldXMLUpdate(pOutput);
2328
if (updateXML.size())
2332
pOutput->ioWrite("<monopd> ");
2333
updateEmpty = false;
2335
pOutput->ioWrite("%s", updateXML.c_str());
2341
void Game::unsetChildProperties()
2343
// Reset config options ..
2344
for(std::vector<GameObject *>::iterator it = m_configOptions.begin(); it != m_configOptions.end() && (*it) ; ++it)
2345
(*it)->unsetPropertiesChanged();
2348
for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end() && (*it) ; ++it)
2349
(*it)->unsetPropertiesChanged();