~ubuntu-branches/debian/sid/monopd/sid

« back to all changes in this revision

Viewing changes to .pc/01_gcc43_includes.diff/src/game.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Schepler
  • Date: 2011-07-18 22:07:44 UTC
  • Revision ID: james.westby@ubuntu.com-20110718220744-bg6e0yij97p8xxno
Tags: 0.9.3-5
* Orphaning package (see #634499).
* Bump Standards-Version to 3.9.2.
* Update to 3.0 (quilt) source format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2001-2004 Rob Kaper <cap@capsi.com>,
 
2
//               2001 Erik Bourget <ebourg@cs.mcgill.ca>
 
3
//
 
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.
 
7
//
 
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.
 
12
//
 
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.
 
17
 
 
18
#define __USE_XOPEN
 
19
#include <stdarg.h>
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <syslog.h>
 
23
#include <algo.h> // libstdc++ from the gcc 2.95 has no #include <algo> yet :(
 
24
 
 
25
#include <map>
 
26
#include <string>
 
27
#include <iostream>
 
28
#include <fstream>
 
29
 
 
30
#include "auction.h"
 
31
#include "card.h"
 
32
#include "cardgroup.h"
 
33
#include "debt.h"
 
34
#include "estate.h"
 
35
#include "estategroup.h"
 
36
#include "game.h"
 
37
#include "io.h"
 
38
#include "player.h"
 
39
#include "trade.h"
 
40
 
 
41
Game::Game(int id)
 
42
 :      GameObject(id, GGame),
 
43
        m_pWinner( 0 )
 
44
{
 
45
        m_status = Config;
 
46
 
 
47
        m_startMoney = 0;
 
48
        m_houses = 0;
 
49
        m_hotels = 0;
 
50
        m_master = m_pTurn = 0;
 
51
        m_goEstate =  0;
 
52
        m_gameType = m_bgColor = "";
 
53
        m_isValid = m_pausedForDialog = false;
 
54
        m_auction = 0;
 
55
        m_auctionDebt = 0;
 
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);
 
63
        dice[0]=0;
 
64
        dice[1]=0;
 
65
 
 
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 );
 
69
 
 
70
        m_nextCardGroupId = m_nextEstateId = m_nextEstateGroupId = m_nextTradeId = m_nextAuctionId = 0;
 
71
 
 
72
        addBoolConfigOption( "automatetax", "Automate tax decisions", false, true );
 
73
        addBoolConfigOption( "allowspectators", "Allow spectators", false, true );
 
74
}
 
75
 
 
76
Game::~Game()
 
77
{
 
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()); }
 
85
 
 
86
        if (m_auction)
 
87
                delete m_auction;
 
88
}
 
89
 
 
90
void Game::ioWrite(const char *fmt, ...)
 
91
{
 
92
        int n, size = 256;
 
93
        char *buf = new char[size];
 
94
        static std::string ioStr;
 
95
        va_list arg;
 
96
 
 
97
        buf[0] = 0;
 
98
 
 
99
        while (1)
 
100
        {
 
101
                va_start(arg, fmt);
 
102
                n = vsnprintf(buf, size, fmt, arg);
 
103
                va_end(arg);
 
104
 
 
105
                if (n > -1 && n < size)
 
106
                {
 
107
                        ioStr = buf;
 
108
                        delete[] buf;
 
109
                        ioWrite(ioStr);
 
110
                        return;
 
111
                }
 
112
 
 
113
                if (n > -1)
 
114
                        size = n+1;
 
115
                else
 
116
                        size *= 2;
 
117
 
 
118
                delete[] buf;
 
119
                buf = new char[size];
 
120
        }
 
121
}
 
122
 
 
123
void Game::ioWrite(const std::string data)
 
124
{
 
125
        Player *pTmp = 0;
 
126
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
127
                pTmp->ioWrite(data);
 
128
}
 
129
 
 
130
void Game::ioInfo(const char *data, ...)
 
131
{
 
132
        va_list arg;
 
133
        char buf[2048];
 
134
        
 
135
        va_start(arg, data);
 
136
        vsnprintf(buf, sizeof(buf)-1, data, arg);
 
137
        va_end(arg);
 
138
        buf[sizeof(buf)-1] = 0;
 
139
 
 
140
        ioWrite("<monopd><msg type=\"info\" value=\"%s\"/></monopd>\n", buf);
 
141
}
 
142
 
 
143
void Game::ioInfo(const std::string data)
 
144
{
 
145
        ioWrite("<monopd><msg type=\"info\" value=\"" + data + "\"/></monopd>\n");
 
146
}
 
147
 
 
148
void Game::ioError(const std::string data)
 
149
{
 
150
        ioWrite("<monopd><msg type=\"error\" value=\"" + data + "\"/></monopd>\n");
 
151
}
 
152
 
 
153
void Game::loadGameType(const std::string &gameType)
 
154
{
 
155
        if (m_gameType != gameType)
 
156
        {
 
157
                m_gameType = gameType;
 
158
                loadConfig();
 
159
 
 
160
                unsetChildProperties(); // so that the first player joining won't get estateupdates until init
 
161
        }
 
162
}
 
163
 
 
164
void Game::loadConfig()
 
165
{
 
166
        enum ConfigGroup { Board, EstateGroups, Estates, CardGroups, Cards, Other };
 
167
        ConfigGroup configGroup = Other;
 
168
        std::map<Estate *, int> payTargets;
 
169
        EstateGroup *group = 0;
 
170
        Estate *eTmp = 0;
 
171
        CardGroup *cardGroup = 0;
 
172
        Card *card = 0;
 
173
        unsigned int goEstate = 0, nextCardId = 0;
 
174
        int pos = 0;
 
175
 
 
176
        std::string line, key, value;
 
177
        std::string filename = std::string(MONOPD_DATADIR "/games/") + m_gameType + ".conf";
 
178
 
 
179
        std::ifstream infile( filename.c_str() );
 
180
        if ( infile.bad() )
 
181
                return;
 
182
 
 
183
        while ( getline( infile, line, '\n') )
 
184
        {
 
185
                if ( !line.size() || line[0] == '#' ) {}
 
186
                else if ( line[0] == '<' )
 
187
                {
 
188
                        value = line.substr( 1, line.size()-2 );
 
189
                        if ( value == "Board" )
 
190
                                configGroup = 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;
 
197
                        else
 
198
                                configGroup = Other;
 
199
                }
 
200
                else if ( line[0] == '[' )
 
201
                {
 
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 );
 
209
                }
 
210
                else
 
211
                {
 
212
                        pos = line.find( "=" );
 
213
                        if ( pos != std::string::npos )
 
214
                        {
 
215
                                key = line.substr( 0, pos );
 
216
                                value = line.substr( pos+1 );
 
217
 
 
218
                                if (configGroup == Board)
 
219
                                {
 
220
                                        if ( key == "go" )
 
221
                                                goEstate = atoi( value.c_str() );
 
222
                                        else if ( key == "bgcolor" )
 
223
                                                m_bgColor = value;
 
224
                                }
 
225
                                else if (configGroup == EstateGroups)
 
226
                                        parseConfigEntry( group, key, value );
 
227
                                else if (configGroup == Estates)
 
228
                                {
 
229
                                        if ( key == "paytarget" )
 
230
                                                payTargets[eTmp] = atoi( value.c_str() );
 
231
                                        else
 
232
                                                parseConfigEntry( eTmp, key, value );
 
233
                                }
 
234
                                else if (configGroup == CardGroups)
 
235
                                {
 
236
                                        if ( key == "groupname" )
 
237
                                        {
 
238
                                                cardGroup = newCardGroup( value );
 
239
                                                configGroup = Cards;
 
240
                                        }
 
241
                                }
 
242
                                else if (configGroup == Cards)
 
243
                                {
 
244
                                        if ( key == "groupname" )
 
245
                                                cardGroup = newCardGroup( value );
 
246
                                        else
 
247
                                                parseConfigEntry( card, key, value );
 
248
                                }
 
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() );
 
259
                        }
 
260
                }
 
261
        }
 
262
        infile.close();
 
263
 
 
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);
 
271
 
 
272
        // Go estate is required, defaults to first specified
 
273
        if (!(m_goEstate = findEstate(goEstate)))
 
274
                m_goEstate = findEstate(0);
 
275
        if (!m_goEstate)
 
276
                return;
 
277
 
 
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));
 
281
        payTargets.clear();
 
282
 
 
283
        eTmp = 0;
 
284
        for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
 
285
        {
 
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);
 
292
        }
 
293
 
 
294
        m_isValid = true;
 
295
}
 
296
 
 
297
void Game::parseConfigEntry(Estate *es, const std::string &key, const std::string &value)
 
298
{
 
299
        if (!es)
 
300
                return;
 
301
 
 
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"
 
308
                        )
 
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 ) );
 
326
}
 
327
 
 
328
void Game::parseConfigEntry(Card *card, const std::string &key, const std::string &value)
 
329
{
 
330
        if (!card)
 
331
                return;
 
332
 
 
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 );
 
355
}
 
356
 
 
357
void Game::parseConfigEntry(EstateGroup *group, const std::string &key, const std::string &value)
 
358
{
 
359
         if (!group)
 
360
                return;
 
361
 
 
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 );
 
372
}
 
373
 
 
374
void Game::editConfiguration(Player *pInput, char *data)
 
375
{
 
376
        if (pInput != m_master)
 
377
        {
 
378
                pInput->ioError("Only the master can edit the game configuration.");
 
379
                return;
 
380
        }
 
381
 
 
382
        if (m_status != Config)
 
383
        {
 
384
                pInput->ioError("This game has already been started.");
 
385
                return;
 
386
        }
 
387
 
 
388
        if (!strstr(data, ":"))
 
389
        {
 
390
                pInput->ioError("Invalid input for .gc, no seperator after configId");
 
391
                return;
 
392
        }
 
393
        int configId = atoi(strsep(&data, ":"));
 
394
 
 
395
        GameObject *configOption = findConfigOption(configId);
 
396
        if (!configOption)
 
397
        {
 
398
                pInput->ioError("No such configId: %d.", configId);
 
399
                return;
 
400
        }
 
401
 
 
402
        std::string newValue = data;
 
403
 
 
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()) );
 
410
}
 
411
 
 
412
void Game::editConfig(Player *pInput, char *data)
 
413
{
 
414
        if (pInput != m_master)
 
415
        {
 
416
                pInput->ioError("Only the master can edit the game configuration.");
 
417
                return;
 
418
        }
 
419
        if (m_status != Config)
 
420
        {
 
421
                pInput->ioError("This game has already been started.");
 
422
                return;
 
423
        }
 
424
 
 
425
//      (*m_configOptions.begin())->setProperty( "value", "teststringupdated" );
 
426
 
 
427
        switch(data[0])
 
428
        {
 
429
                case 'a':
 
430
                        setAuctionsEnabled(atoi(data+1));
 
431
                        break;
 
432
                case 'f':
 
433
                        setCollectFines(atoi(data+1));
 
434
                        break;
 
435
                case 'l':
 
436
                        setUnlimitedHouses(atoi(data+1));
 
437
                        break;
 
438
                case 'p':
 
439
                        setDoublePassMoney(atoi(data+1));
 
440
                        break;
 
441
                case 'r':
 
442
                        setNoRentInJail(atoi(data+1));
 
443
                        break;
 
444
                case 's':
 
445
                        setAlwaysShuffle(atoi(data+1));
 
446
                        break;
 
447
                case 'S':
 
448
                        setAllowEstateSales(atoi(data+1));
 
449
                        break;
 
450
                default:
 
451
                        pInput->ioError("No such game configuration command.");
 
452
        }
 
453
}
 
454
 
 
455
GameObject *Game::newConfigOption(const std::string &name, const std::string &description, bool editable)
 
456
{
 
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);
 
462
        return config;
 
463
}
 
464
 
 
465
void Game::addConfigOption(const std::string &name, const std::string &description, const std::string &defaultValue, bool editable)
 
466
{
 
467
        GameObject *config = newConfigOption(name, description, editable);
 
468
        config->setProperty("type", "string", this);
 
469
        config->setProperty("value", defaultValue, this);
 
470
}
 
471
 
 
472
void Game::addConfigOption(const std::string &name, const std::string &description, int defaultValue, bool editable)
 
473
{
 
474
        GameObject *config = newConfigOption(name, description, editable);
 
475
        config->setProperty("type", "int", this);
 
476
        config->setProperty("value", defaultValue, this);
 
477
}
 
478
 
 
479
void Game::addBoolConfigOption(const std::string &name, const std::string &description, bool defaultValue, bool editable)
 
480
{
 
481
        GameObject *config = newConfigOption(name, description, editable);
 
482
        config->setProperty("type", "bool", this);
 
483
        config->setBoolProperty("value", defaultValue, this);
 
484
}
 
485
 
 
486
GameObject *Game::findConfigOption(int configId)
 
487
{
 
488
        for(std::vector<GameObject *>::iterator it = m_configOptions.begin(); it != m_configOptions.end() && (*it) ; ++it)
 
489
                if ( (*it)->id() == configId )
 
490
                        return (*it);
 
491
        return 0;
 
492
}
 
493
 
 
494
GameObject *Game::findConfigOption(const std::string &name)
 
495
{
 
496
        for(std::vector<GameObject *>::iterator it = m_configOptions.begin(); it != m_configOptions.end() && (*it) ; ++it)
 
497
                if ( (*it)->getStringProperty("name") == name )
 
498
                        return (*it);
 
499
        return 0;
 
500
}
 
501
 
 
502
void Game::start(Player *pInput)
 
503
{
 
504
        if (pInput != m_master)
 
505
        {
 
506
                pInput->ioError("Only the master can start a game.");
 
507
                return;
 
508
        }
 
509
        if (m_status != Config)
 
510
        {
 
511
                pInput->ioError("This game has already been started.");
 
512
                return;
 
513
        }
 
514
        int minPlayers = getIntProperty("minplayers");
 
515
        if (m_players.size() < minPlayers)
 
516
        {
 
517
                pInput->ioError("This game requires at least %d players to be started.", minPlayers);
 
518
                return;
 
519
        }
 
520
 
 
521
        // Update status.
 
522
        m_status = Init;
 
523
 
 
524
        // Update whether players can join/watch.
 
525
        GameObject *config = findConfigOption( "allowspectators" );
 
526
        if ( config && config->getBoolProperty( "value" ) )
 
527
                setBoolProperty( "canbejoined", true );
 
528
        else
 
529
                setBoolProperty( "canbejoined", false );
 
530
 
 
531
        // Shuffle players
 
532
        random_shuffle(m_players.begin(), m_players.end());
 
533
 
 
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();
 
538
 
 
539
        // Set all players at Go, give them money
 
540
        Player *pTmp = 0;
 
541
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
542
        {
 
543
                pTmp->reset(false);
 
544
                pTmp->setEstate(m_goEstate);
 
545
                pTmp->addMoney(m_startMoney);
 
546
        }
 
547
 
 
548
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
549
                sendFullUpdate(pTmp);
 
550
 
 
551
        // Add notification of game start.
 
552
        m_status = Run;
 
553
        ioWrite("<monopd><gameupdate gameid=\"%d\" status=\"%s\"/></monopd>\n", m_id, statusLabel().c_str());
 
554
 
 
555
        // Turn goes to first player
 
556
        m_pTurn = *m_players.begin();
 
557
        m_pTurn->setTurn(true);
 
558
}
 
559
 
 
560
void Game::setTokenLocation(Player *pInput, unsigned int estateId)
 
561
{
 
562
        if (!clientsMoving() || !pInput || !m_pTurn)
 
563
                return;
 
564
 
 
565
        Estate *estateLoc = findEstate(estateId);
 
566
 
 
567
        if ( !estateLoc || !pInput->tokenLocation() || !m_pTurn->destination() || (pInput->tokenLocation() == estateLoc) )
 
568
                return;
 
569
 
 
570
        bool useNext = false;
 
571
        unsigned int money = 0;
 
572
 
 
573
//      printf("Game::setTokenLocation, P:%d PTL:%d EID:%d\n", pInput->id(), pInput->tokenLocation()->id(), estateId);
 
574
        
 
575
        Estate *estate = 0;
 
576
        for (std::vector<Estate *>::iterator it = m_estates.begin() ;;)
 
577
        {
 
578
                if (it == m_estates.end())
 
579
                {
 
580
//                      printf("Game::setTokenLocation, reloop\n");
 
581
                        it = m_estates.begin();
 
582
                        continue;
 
583
                }
 
584
                if (!(estate = *it))
 
585
                        break;
 
586
 
 
587
                if (useNext)
 
588
                {
 
589
                        if (estate->getIntProperty("passmoney"))
 
590
                        {
 
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);
 
596
                        }
 
597
                        if (estate == m_pTurn->destination())
 
598
                        {
 
599
//                              printf("Game::setTokenLocation, setPTL:0\n");
 
600
                                pInput->setTokenLocation(0); // Player is done moving
 
601
                                break;
 
602
                        }
 
603
                        if (estate == estateLoc)
 
604
                        {
 
605
//                              printf("Game::setTokenLocation, setPTL:%d\n", estateId);
 
606
                                pInput->setTokenLocation(estate); // Player is not done moving
 
607
                                break;
 
608
                        }
 
609
                }
 
610
                else if (estate == pInput->tokenLocation())
 
611
                {
 
612
//                      printf("Game::setTokenLocation, useNext:%d==PTL\n", estate->id());
 
613
                        useNext = true;
 
614
                }
 
615
 
 
616
                ++it;
 
617
        }
 
618
 
 
619
        // Find out if there are still clients busy with movement.
 
620
        if (clientsMoving()) 
 
621
                return;
 
622
 
 
623
        // Land player!
 
624
        bool endTurn = landPlayer(m_pTurn, false);
 
625
 
 
626
        if (clientsMoving())
 
627
        {
 
628
                // Don't do a thing.. just wait until they are done.
 
629
        }
 
630
        else if (m_pTurn->getBoolProperty("can_buyestate"))
 
631
        {
 
632
                // Don't do a thing..
 
633
        }
 
634
        else if (endTurn)
 
635
                m_pTurn->endTurn();
 
636
}
 
637
 
 
638
void Game::tokenMovementTimeout()
 
639
{
 
640
        // Mark all clients as non moving.
 
641
        Player *pTmp = 0;
 
642
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
643
                if (pTmp->tokenLocation())
 
644
                {
 
645
                        if (m_pTurn && m_pTurn->destination())
 
646
                        {
 
647
                                m_pTurn->setProperty("location", m_pTurn->destination()->id(), this);
 
648
                                m_pTurn->setBoolProperty("directmove", true, this);
 
649
                                setTokenLocation(pTmp, m_pTurn->destination()->id());
 
650
                        }
 
651
                }
 
652
}
 
653
 
 
654
unsigned int Game::auctionTimeout()
 
655
{
 
656
        if (!m_auction)
 
657
                return 0;
 
658
 
 
659
        printf("Game::auctionTimeout %d %d\n", m_id, m_players.size());
 
660
 
 
661
        int status = m_auction->status();
 
662
        switch(status)
 
663
        {
 
664
        case Auction::Sold:
 
665
        case Auction::PaymentDue:
 
666
        case Auction::Completed:
 
667
                break;
 
668
        default:
 
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());
 
672
        }
 
673
        status = m_auction->status();
 
674
 
 
675
        if (status == Auction::Sold || status == Auction::PaymentDue)
 
676
        {
 
677
                printf("Game::auctionTimeout sold||paymentdue %d %d\n", m_id, m_players.size());
 
678
                completeAuction();
 
679
        }
 
680
        if (status == Auction::PaymentDue)
 
681
                return 1;
 
682
 
 
683
        if (status == Auction::Completed)
 
684
        {
 
685
                if (m_pTurn && !clientsMoving() )
 
686
                        m_pTurn->endTurn();
 
687
 
 
688
                printf("Game::auctionTimeout delAuction %d %d\n", m_id, m_players.size());
 
689
 
 
690
                delAuction();
 
691
                return 0;
 
692
        }
 
693
        return 4;
 
694
}
 
695
 
 
696
void Game::newDebtToAll(Player *from, int amount)
 
697
{
 
698
        Player *pTmp = 0;
 
699
        for(std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
 
700
                if (pTmp != from)
 
701
                        newDebt(from, pTmp, 0, amount);
 
702
}
 
703
 
 
704
Debt *Game::newDebt(Player *from, Player *toPlayer, Estate *toEstate, int amount)
 
705
{
 
706
        if (from && (from->getBoolProperty("bankrupt") || from->getBoolProperty("spectator")))
 
707
                return 0;
 
708
        if (toPlayer && (toPlayer->getBoolProperty("bankrupt") || toPlayer->getBoolProperty("spectator")))
 
709
                return 0;
 
710
 
 
711
        Debt *d = new Debt(from, toPlayer, toEstate, amount);
 
712
        m_debts.push_back(d);
 
713
 
 
714
        from->setBoolProperty("hasdebt", true);
 
715
 
 
716
        if (amount > from->assets())
 
717
        {
 
718
                setDisplay(0, false, false, "%s is bankrupt!", from->getStringProperty("name").c_str());
 
719
                bankruptPlayer(from);
 
720
                return 0;
 
721
        }
 
722
        return d;
 
723
}
 
724
 
 
725
Debt *Game::findDebt(Player *p)
 
726
{
 
727
        Debt *dTmp = 0;
 
728
        for(std::vector<Debt *>::iterator it = m_debts.begin(); it != m_debts.end() && (dTmp = *it) ; ++it)
 
729
                if (p == dTmp->from())
 
730
                        return dTmp;
 
731
 
 
732
        return 0;
 
733
}
 
734
 
 
735
Debt *Game::findDebtByCreditor(Player *p)
 
736
{
 
737
        Debt *dTmp = 0;
 
738
        for(std::vector<Debt *>::iterator it = m_debts.begin(); it != m_debts.end() && (dTmp = *it) ; ++it)
 
739
                if (p == dTmp->toPlayer())
 
740
                        return dTmp;
 
741
 
 
742
        return 0;
 
743
}
 
744
 
 
745
void Game::delDebt(Debt *debt)
 
746
{
 
747
        for(std::vector<Debt *>::iterator it = m_debts.begin(); it != m_debts.end(); ++it)
 
748
                if (*it == debt)
 
749
                {
 
750
                        m_debts.erase(it);
 
751
                        break;
 
752
                }
 
753
        Player *pFrom = debt->from();
 
754
        if ( !findDebt(pFrom) )
 
755
                pFrom->setBoolProperty("hasdebt", false);
 
756
 
 
757
        delete debt;
 
758
}
 
759
 
 
760
void Game::solveDebts(Player *pInput, const bool &verbose)
 
761
{
 
762
        Debt *debt = findDebt(pInput);
 
763
        if (!debt)
 
764
        {
 
765
                if (verbose)
 
766
                        ioError("You don't have any debts to pay off!");
 
767
                if (!clientsMoving() && !m_auction && !m_pausedForDialog)
 
768
                        pInput->endTurn();
 
769
                return;
 
770
        }
 
771
 
 
772
        while ( debt = findDebt(pInput) )
 
773
        {
 
774
                if ( !solveDebt(debt) )
 
775
                        break;
 
776
        }
 
777
 
 
778
        if (unsigned int debts = m_debts.size())
 
779
                setDisplay(m_pTurn->estate(), false, false, "There are still %d debts, game still paused.", debts);
 
780
        else
 
781
                setDisplay(m_pTurn->estate(), false, false, "All debts are settled, game continues.");
 
782
 
 
783
        if (!clientsMoving() && !m_auction && !m_pausedForDialog)
 
784
                pInput->endTurn();
 
785
}
 
786
 
 
787
bool Game::solveDebt( Debt *debt )
 
788
{       
 
789
        Player *pFrom = debt->from();
 
790
        int payAmount = debt->amount();
 
791
        if ( !(pFrom->payMoney(payAmount)) )
 
792
                return false;
 
793
 
 
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);
 
800
        
 
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)
 
803
        {
 
804
                m_auctionDebt = 0;
 
805
                completeAuction();
 
806
        }
 
807
        delDebt(debt);
 
808
        return true;
 
809
}
 
810
 
 
811
void Game::enforceDebt(Player *pBroke, Debt *debt)
 
812
{
 
813
        // Find creditors
 
814
        Estate *eCreditor = debt ? debt->toEstate() : 0;
 
815
        Player *pCreditor = debt ? debt->toPlayer() : 0;
 
816
 
 
817
        // Give all cards to creditor or card stack
 
818
        while (Card *card = pBroke->findFirstCard())
 
819
                transferCard(card, pCreditor);
 
820
 
 
821
        // Sell all houses on property
 
822
        Estate *eTmp = 0;
 
823
        for(std::vector<Estate *>::iterator it = m_estates.begin() ; it != m_estates.end() && (eTmp = *it) ; ++it)
 
824
        {
 
825
                if (pBroke == eTmp->owner())
 
826
                {
 
827
                        // Sell houses
 
828
                        int eTmpHouses = eTmp->getIntProperty("houses");
 
829
                        if (eTmpHouses)
 
830
                        {
 
831
                                // Get money
 
832
                                int returnValue = eTmpHouses * eTmp->housePrice() / 2;
 
833
                                pBroke->addMoney(returnValue);
 
834
 
 
835
                                if (!getBoolProperty("unlimitedhouses"))
 
836
                                {
 
837
                                        // Make houses available again
 
838
                                        if ( eTmpHouses == 5 )
 
839
                                                m_hotels++;
 
840
                                        else
 
841
                                                m_houses += eTmpHouses;
 
842
                                }
 
843
                                eTmp->setProperty("houses", 0);
 
844
                        }
 
845
 
 
846
                        // Transfer ownership to creditor
 
847
                        if (pCreditor)
 
848
                                transferEstate(eTmp, pCreditor);
 
849
                        else
 
850
                        {
 
851
                                eTmp->setBoolProperty("mortgaged", false);
 
852
 
 
853
                                // TODO: auction all estate when there is no pCreditor
 
854
                                transferEstate(eTmp, pCreditor);
 
855
                        }
 
856
                        // TODO: send estateupdate?
 
857
                }
 
858
        }
 
859
 
 
860
        // Give all money to creditor
 
861
        int payAmount = pBroke->getIntProperty("money");
 
862
        pBroke->payMoney(payAmount);
 
863
 
 
864
        if (pCreditor)
 
865
                pCreditor->addMoney(payAmount);
 
866
        else if (eCreditor && getBoolProperty("collectfines"))
 
867
                eCreditor->addMoney(payAmount);
 
868
 
 
869
        if (debt)
 
870
                delDebt(debt);
 
871
}
 
872
 
 
873
void Game::newAuction(Player *pInput) 
 
874
{
 
875
        if (!getBoolProperty("auctionsenabled") || !totalAssets())
 
876
        {
 
877
                pInput->ioError("Auctions are not enabled.");
 
878
                return;
 
879
        }
 
880
        if (!(pInput->getBoolProperty("canauction")))
 
881
        {
 
882
                pInput->ioError("You cannot auction anything at the moment.");
 
883
                return;
 
884
        }
 
885
 
 
886
        Estate *estate = pInput->estate();
 
887
 
 
888
        m_auction = new Auction();
 
889
        m_auction->setEstate(estate);
 
890
        m_auction->addToScope(this);
 
891
 
 
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());
 
896
}
 
897
 
 
898
Auction *Game::auction()
 
899
{
 
900
        return m_auction;
 
901
}
 
902
 
 
903
void Game::delAuction()
 
904
{
 
905
        delete m_auction;
 
906
        m_auction = 0;
 
907
}
 
908
 
 
909
// Returns 0 on succesful bid, 1 on error.
 
910
int Game::bidInAuction(Player *pInput, char *data)
 
911
{
 
912
        if (!strstr(data, ":"))
 
913
        {
 
914
                pInput->ioError("Invalid input for .ab, no seperator after auctionId");
 
915
                return 1;
 
916
        }
 
917
        int auctionId = atoi(strsep(&data, ":"));
 
918
        int bid = atoi(data);
 
919
 
 
920
        if ( !m_auction || m_auction->id() != auctionId )
 
921
        {
 
922
                pInput->ioError("No such auctionId: %d.", auctionId);
 
923
                return 1;
 
924
        }
 
925
 
 
926
        switch( m_auction->getIntProperty("status") )
 
927
        {
 
928
        case Auction::Sold:
 
929
        case Auction::PaymentDue:
 
930
        case Auction::Completed:
 
931
                pInput->ioError( "You can no longer bid in auction %d.", auctionId );
 
932
                return 1;
 
933
        default:;
 
934
        }
 
935
 
 
936
        if (bid > pInput->assets())
 
937
        {
 
938
                pInput->ioError("You don't have %d.", bid);
 
939
                return 1;
 
940
        }
 
941
        
 
942
        int highestBid = m_auction->getIntProperty("highbid");
 
943
        if (bid <= highestBid)
 
944
        {
 
945
                pInput->ioError("Minimum bid is %d.", highestBid+1);
 
946
                return 1;
 
947
        }
 
948
 
 
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());
 
951
        return 0;
 
952
}
 
953
 
 
954
void Game::newTrade(Player *pInput, unsigned int playerId)
 
955
{
 
956
        Player *player = findPlayer(playerId);
 
957
        if (!player)
 
958
        {
 
959
                pInput->ioError("No such playerId: %ld.", playerId);
 
960
                return;
 
961
        }
 
962
        else if (player == pInput)
 
963
        {
 
964
                pInput->ioError("Trading with yourself?");
 
965
                return;
 
966
        }
 
967
 
 
968
        // Create a new trade between us and player
 
969
        Trade *t = new Trade(pInput, player, m_nextTradeId++);
 
970
        m_trades.push_back(t);
 
971
}
 
972
 
 
973
Trade *Game::findTrade(Player *_p)
 
974
{
 
975
        Trade *tTmp = 0;
 
976
        for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (tTmp = *it) ; ++it)
 
977
                if (tTmp->hasPlayer(_p))
 
978
                        return tTmp;
 
979
 
 
980
        return 0;
 
981
}
 
982
 
 
983
Trade *Game::findTrade(unsigned int tradeId)
 
984
{
 
985
        Trade *tTmp = 0;
 
986
        for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (tTmp = *it) ; ++it)
 
987
                if (tradeId == tTmp->id()) return tTmp;
 
988
        
 
989
        return 0;
 
990
}
 
991
 
 
992
void Game::delTrade(Trade *trade)
 
993
{
 
994
        for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end(); ++it)
 
995
                if (*it == trade)
 
996
                {
 
997
                        delete trade;
 
998
                        m_trades.erase(it);
 
999
                        break;
 
1000
                }
 
1001
}
 
1002
 
 
1003
void Game::acceptTrade(Player *pInput, char *data)
 
1004
{
 
1005
        bool ignoreRevision = false;
 
1006
        int tradeId = 0, revision = 0;
 
1007
        // data looks like "1:1", tradeid, revision
 
1008
        if (!strstr(data, ":"))
 
1009
        {
 
1010
//              ioError("Invalid input for .Ta, no seperator after tradeId");
 
1011
//              return;
 
1012
                ignoreRevision = true; // backwards compatibility
 
1013
                tradeId = atoi(data);
 
1014
        }
 
1015
        else
 
1016
        {
 
1017
                tradeId = atoi(strsep(&data, ":"));
 
1018
                revision = atoi(data);
 
1019
        }
 
1020
 
 
1021
        Trade *trade = findTrade(tradeId);
 
1022
        if (!trade)
 
1023
        {
 
1024
                pInput->ioError("No such tradeId: %ld.", tradeId);
 
1025
                return;
 
1026
        }
 
1027
        if ( !(trade->hasPlayer(pInput)) )
 
1028
        {
 
1029
                pInput->ioError("You are not part of trade %ld.", tradeId);
 
1030
                return;
 
1031
        }
 
1032
        if (!ignoreRevision && revision != trade->getIntProperty("revision"))
 
1033
        {
 
1034
                pInput->ioError("Ignored accept for trade %ld because it was changed.", tradeId);
 
1035
                return;
 
1036
        }
 
1037
 
 
1038
        trade->setPlayerAccept(pInput, true);
 
1039
 
 
1040
        if (trade->allAccept())
 
1041
        {
 
1042
                // Complete trade
 
1043
                completeTrade(trade);
 
1044
                delTrade(trade);
 
1045
                if (!clientsMoving() && !m_auction && !m_pausedForDialog)
 
1046
                        m_pTurn->endTurn();
 
1047
        }
 
1048
}
 
1049
 
 
1050
void Game::rejectTrade(Player *pInput, unsigned int tradeId)
 
1051
{
 
1052
        Trade *trade = findTrade(tradeId);
 
1053
        if (!trade)
 
1054
        {
 
1055
                pInput->ioError("No such tradeId: %d.", tradeId);
 
1056
                return;
 
1057
        }
 
1058
 
 
1059
        if ( !(trade->hasPlayer(pInput)) )
 
1060
        {
 
1061
                pInput->ioError("You are not part of trade %d.", tradeId);
 
1062
                return;
 
1063
        }
 
1064
 
 
1065
        ioWrite("<monopd><tradeupdate type=\"rejected\" tradeid=\"%d\" actor=\"%d\"/></monopd>\n", trade->id(), pInput->id());
 
1066
        delTrade(trade);
 
1067
}
 
1068
 
 
1069
void Game::completeTrade(Trade *trade)
 
1070
{
 
1071
        ioWrite("<monopd><tradeupdate tradeid=\"%d\" type=\"accepted\"/></monopd>\n", trade->id());
 
1072
 
 
1073
        Player *pFrom, *pTo;
 
1074
        GameObject *object;
 
1075
        while((pTo = trade->firstTarget()))
 
1076
        {
 
1077
                pFrom = trade->firstFrom();
 
1078
                object = trade->takeFirstObject();
 
1079
                switch(object->type())
 
1080
                {
 
1081
                case GameObject::Money:
 
1082
                        unsigned int money;
 
1083
                        money = object->id();
 
1084
                        delete object; // was temporarily created to serve as trade object
 
1085
                        if (!pFrom->payMoney(money))
 
1086
                        {
 
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);
 
1089
                        }
 
1090
                        else
 
1091
                                pTo->addMoney(money);
 
1092
 
 
1093
                        setDisplay(m_pTurn->estate(), false, false, "%s gets %d from %s.", pTo->getStringProperty("name").c_str(), money, pFrom->getStringProperty("name").c_str());
 
1094
                        break;
 
1095
                default:
 
1096
                        transferObject(object->type(), object->id(), pTo, true);
 
1097
                }
 
1098
        }
 
1099
 
 
1100
        // Write "completed" to all players
 
1101
        ioWrite("<monopd><tradeupdate tradeid=\"%d\" type=\"completed\"/></monopd>\n", trade->id());
 
1102
 
 
1103
        // Solve debts for trade players
 
1104
        Player *player = 0;
 
1105
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
1106
                if (trade->hasPlayer(player))
 
1107
                        solveDebts(player);
 
1108
}
 
1109
 
 
1110
void Game::completeAuction()
 
1111
{
 
1112
        if (!m_auction)
 
1113
                return;
 
1114
 
 
1115
        printf("Game::completeAuction()\n");
 
1116
 
 
1117
        Player *pBid = m_auction->highBidder();
 
1118
        if (!pBid)
 
1119
                return;
 
1120
 
 
1121
        int bid = m_auction->getIntProperty("highbid");
 
1122
 
 
1123
        if (m_auction->status() == Auction::Sold)
 
1124
        {
 
1125
                if (!pBid->payMoney(bid))
 
1126
                {
 
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);
 
1130
                        return;
 
1131
                }
 
1132
        }
 
1133
        else if (m_auction->status() == Auction::PaymentDue && m_auctionDebt)
 
1134
                        return;
 
1135
 
 
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);
 
1140
 
 
1141
        if (m_pTurn->getBoolProperty("canrollagain"))
 
1142
        {
 
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());
 
1146
        }
 
1147
        else 
 
1148
                updateTurn();
 
1149
}
 
1150
 
 
1151
void Game::setDisplay(Estate *estate, bool clearText, bool clearButtons, const char *data, ...)
 
1152
{
 
1153
        va_list arg;
 
1154
        char buf[2048];
 
1155
        
 
1156
        va_start(arg, data);
 
1157
        vsnprintf(buf, sizeof(buf)-1, data, arg);
 
1158
        va_end(arg);
 
1159
        buf[sizeof(buf)-1] = 0;
 
1160
 
 
1161
        Player *player = 0;
 
1162
        for (std::vector<Player *>::iterator pit = m_players.begin(); pit != m_players.end() && (player = *pit) ; ++pit)
 
1163
        {
 
1164
                player->setDisplay(estate, std::string(buf));
 
1165
                player->setDisplayClearText(clearText);
 
1166
                player->setDisplayClearButtons(clearButtons);
 
1167
                player->sendDisplayMsg();
 
1168
        }
 
1169
}
 
1170
 
 
1171
void Game::sendMsgEstateUpdate(Estate *e) 
 
1172
{
 
1173
        Estate *eTmp = 0;
 
1174
        Player *pTmp = 0;
 
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));
 
1179
                }
 
1180
        }
 
1181
}
 
1182
 
 
1183
EstateGroup *Game::newGroup(const std::string &name)
 
1184
{
 
1185
        EstateGroup *group = new EstateGroup(m_nextEstateGroupId++, this, name);
 
1186
        m_estateGroups.push_back(group);
 
1187
        return group;
 
1188
}
 
1189
 
 
1190
EstateGroup *Game::findGroup(const std::string &name)
 
1191
{
 
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)
 
1195
                        return group;
 
1196
 
 
1197
        return 0;
 
1198
}
 
1199
 
 
1200
unsigned int Game::estateGroupSize(EstateGroup *estateGroup)
 
1201
{
 
1202
        unsigned int size = 0;
 
1203
 
 
1204
        Estate *eTmp = 0;
 
1205
        for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end() && (eTmp = *it) ; ++it)
 
1206
                if (estateGroup == eTmp->group())
 
1207
                        size++;
 
1208
 
 
1209
        return size;
 
1210
}
 
1211
 
 
1212
Estate *Game::newEstate(const std::string &name)
 
1213
{
 
1214
        Estate *es = new Estate(m_nextEstateId++, &m_estates);
 
1215
        m_estates.push_back(es);
 
1216
 
 
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);
 
1222
 
 
1223
        return es;
 
1224
}
 
1225
 
 
1226
Estate *Game::findEstate(int id)
 
1227
{
 
1228
        if (id >= 0 && id < (int)m_estates.size())
 
1229
                return m_estates[id];
 
1230
        else
 
1231
                return NULL;
 
1232
}
 
1233
 
 
1234
Estate *Game::findNextEstate(EstateGroup *group, Estate *startEstate)
 
1235
{
 
1236
        bool useNext = true;
 
1237
        if (startEstate)
 
1238
                useNext = false;
 
1239
 
 
1240
        Estate *eTmp = 0, *eFirst = 0;
 
1241
        for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
 
1242
        {
 
1243
                if (startEstate && startEstate == eTmp)
 
1244
                        useNext = true;
 
1245
                if (eTmp->group() == group)
 
1246
                {
 
1247
                        if (useNext==true)
 
1248
                                return eTmp;
 
1249
                        else if (!eFirst)
 
1250
                                eFirst = eTmp;
 
1251
                }
 
1252
        }
 
1253
        return eFirst;
 
1254
}
 
1255
 
 
1256
Estate *Game::findNextJailEstate(Estate *startEstate)
 
1257
{
 
1258
        bool useNext = true;
 
1259
        if (startEstate)
 
1260
                useNext = false;
 
1261
 
 
1262
        Estate *eTmp = 0, *eFirst = 0;
 
1263
        for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
 
1264
        {
 
1265
                if (startEstate && startEstate == eTmp)
 
1266
                        useNext = true;
 
1267
                if (eTmp->getBoolProperty("jail"))
 
1268
                {
 
1269
                        if (useNext==true)
 
1270
                                return eTmp;
 
1271
                        else if (!eFirst)
 
1272
                                eFirst = eTmp;
 
1273
                }
 
1274
        }
 
1275
        return eFirst;
 
1276
}
 
1277
 
 
1278
void Game::delEstate(Estate *_e)
 
1279
{
 
1280
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it); ++it)
 
1281
                (*it)->setDisplay(0);
 
1282
 
 
1283
        for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end(); ++it)
 
1284
                if (*it == _e)
 
1285
                {
 
1286
                        m_estates.erase(it);
 
1287
                        break;
 
1288
                }
 
1289
        delete _e;
 
1290
}
 
1291
 
 
1292
void Game::transferEstate(Estate *estate, Player *player, const bool verbose)
 
1293
{
 
1294
        if (estate->owner())
 
1295
        {
 
1296
                Trade *trade = 0;
 
1297
                for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (trade = *it) ; ++it)
 
1298
                        trade->delComponent(estate->type(), estate->id());
 
1299
        }
 
1300
 
 
1301
        estate->setOwner(player);
 
1302
        sendMsgEstateUpdate(estate);
 
1303
 
 
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());
 
1306
}
 
1307
 
 
1308
void Game::transferObject(const enum GameObject::Type type, unsigned int id, Player *player, const bool verbose)
 
1309
{
 
1310
        switch(type)
 
1311
        {
 
1312
        case GameObject::GCard:
 
1313
                transferCard(findCard(id), player, verbose);
 
1314
                break;
 
1315
        case GameObject::GEstate:
 
1316
                transferEstate(findEstate(id), player, verbose);
 
1317
                break;
 
1318
        default:;
 
1319
        }
 
1320
}
 
1321
 
 
1322
void Game::setPausedForDialog(const bool paused)
 
1323
{
 
1324
        m_pausedForDialog = paused;
 
1325
}
 
1326
 
 
1327
const bool Game::pausedForDialog()
 
1328
{
 
1329
        return m_pausedForDialog;
 
1330
}
 
1331
 
 
1332
void Game::transferCard(Card *card, Player *player, const bool verbose)
 
1333
{
 
1334
        Player *owner = card->owner();
 
1335
        if (owner)
 
1336
        {
 
1337
                owner->takeCard(card);
 
1338
                card->setOwner(0);
 
1339
                Trade *trade = 0;
 
1340
                for(std::vector<Trade *>::iterator it = m_trades.begin(); it != m_trades.end() && (trade = *it) ; ++it)
 
1341
                        trade->delComponent(card->type(), card->id());
 
1342
        }
 
1343
        else
 
1344
                card->group()->popCard();
 
1345
 
 
1346
        if (player)
 
1347
        {
 
1348
                player->addCard(card);
 
1349
                card->setOwner(player);
 
1350
        }
 
1351
        else
 
1352
                card->group()->pushCard(card);
 
1353
 
 
1354
        ioWrite("<monopd><cardupdate cardid=\"%d\" owner=\"%d\"/></monopd>\n", card->id(), card->owner() ? card->owner()->id() : -1);
 
1355
        if (verbose)
 
1356
                setDisplay(m_pTurn->estate(), false, false, "%s is now the owner of card %d.", player->getStringProperty("name").c_str(), card->id());
 
1357
}
 
1358
 
 
1359
CardGroup *Game::newCardGroup(const std::string name)
 
1360
{
 
1361
        CardGroup *cardGroup = new CardGroup(m_nextCardGroupId++, this, name);
 
1362
        m_cardGroups.push_back(cardGroup);
 
1363
        return cardGroup;
 
1364
}
 
1365
 
 
1366
CardGroup *Game::findCardGroup(const std::string name)
 
1367
{
 
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)
 
1371
                        return cardGroup;
 
1372
 
 
1373
        return 0;
 
1374
}
 
1375
 
 
1376
Card *Game::findCard(unsigned int id)
 
1377
{
 
1378
        Card *card = 0;
 
1379
 
 
1380
        CardGroup *cardGroup = 0;
 
1381
        for(std::vector<CardGroup *>::iterator it = m_cardGroups.begin(); it != m_cardGroups.end() && (cardGroup = *it) ; ++it)
 
1382
        {
 
1383
                card = cardGroup->findCard(id);
 
1384
                if (card)
 
1385
                        return card;
 
1386
        }
 
1387
 
 
1388
        Player *player = 0;
 
1389
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (player = *it) ; ++it)
 
1390
        {
 
1391
                card = player->findCard(id);
 
1392
                if (card)
 
1393
                        return card;
 
1394
        }
 
1395
 
 
1396
        return 0;
 
1397
}
 
1398
 
 
1399
Player *Game::addPlayer(Player *p, const bool &isMaster, const bool &isSpectator)
 
1400
{
 
1401
        m_players.push_back(p);
 
1402
        setProperty( "players", m_players.size() );
 
1403
 
 
1404
        if ( m_players.size() == getBoolProperty("maxplayers") )
 
1405
                setBoolProperty("canbejoined", false);
 
1406
 
 
1407
        p->setGame(this);
 
1408
        addToScope(p);
 
1409
 
 
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
 
1417
 
 
1418
        if (isMaster)
 
1419
        {
 
1420
                m_master = p;
 
1421
                setProperty( "master", p->id() );
 
1422
        }
 
1423
 
 
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);
 
1433
 
 
1434
 
 
1435
        // Temporarily set status at init for joining player
 
1436
        if (m_status == Run)
 
1437
        {
 
1438
                m_status = Init;
 
1439
                sendFullUpdate(p);
 
1440
                m_status = Run;
 
1441
        }
 
1442
        else
 
1443
                sendFullUpdate(p);
 
1444
 
 
1445
        if (p->getBoolProperty("spectator"))
 
1446
                sendStatus(p);
 
1447
 
 
1448
        return p;
 
1449
}
 
1450
 
 
1451
Player *Game::findPlayer(int playerId)
 
1452
{
 
1453
        Player *pTmp = 0;
 
1454
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
1455
                if (playerId == pTmp->id())
 
1456
                        return pTmp;
 
1457
        
 
1458
        return 0;
 
1459
}
 
1460
 
 
1461
void Game::removePlayer(Player *p)
 
1462
{
 
1463
        if (p->getBoolProperty("hasturn"))
 
1464
                updateTurn();
 
1465
 
 
1466
        // Find player and erase from std::vector
 
1467
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end(); ++it)
 
1468
                if (*it == p)
 
1469
                {
 
1470
                        m_players.erase(it);
 
1471
                        break;
 
1472
                }
 
1473
        setProperty( "players", m_players.size() );
 
1474
 
 
1475
        // Do bankrupt after player is removed from list, player doesn't need the resulting messages
 
1476
        if (m_status != Config)
 
1477
                bankruptPlayer(p);
 
1478
 
 
1479
        // If not in Config, canbejoined might become true again
 
1480
        else if ( m_players.size() < getBoolProperty("maxplayers") )
 
1481
                        setBoolProperty("canbejoined", true);
 
1482
 
 
1483
        p->setGame(0);
 
1484
        removeFromScope(p);
 
1485
 
 
1486
        if (p == m_master && m_players.size() > 0)
 
1487
        {
 
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
 
1492
 
 
1493
                if (m_status == Config)
 
1494
                        sendConfiguration(m_master);
 
1495
        }
 
1496
}
 
1497
 
 
1498
Player *Game::kickPlayer(Player *pInput, int playerId)
 
1499
{
 
1500
        if ( pInput != m_master )
 
1501
        {
 
1502
                pInput->ioError("Only the master can kick players.");
 
1503
                return 0;
 
1504
        }
 
1505
 
 
1506
        if ( m_status != Config )
 
1507
        {
 
1508
                pInput->ioError("You can only kick players during game configuration.");
 
1509
                return 0;
 
1510
        }
 
1511
 
 
1512
        Player *player = findPlayer(playerId);
 
1513
        if (!player)
 
1514
        {
 
1515
                pInput->ioError("No such playerId: %ld.", playerId);
 
1516
                return 0;
 
1517
        }
 
1518
 
 
1519
        return player;
 
1520
}
 
1521
 
 
1522
void Game::upgradePlayer(Player *pInput, int playerId)
 
1523
{
 
1524
        if ( pInput != m_master )
 
1525
        {
 
1526
                pInput->ioError("Only the master can upgrade spectators.");
 
1527
                return;
 
1528
        }
 
1529
 
 
1530
        if ( m_status != Run )
 
1531
        {
 
1532
                pInput->ioError("You can only upgrade spectators during a game in progress.");
 
1533
                return;
 
1534
        }
 
1535
 
 
1536
        Player *player = findPlayer(playerId);
 
1537
        if (!player)
 
1538
        {
 
1539
                pInput->ioError("No such playerId: %ld.", playerId);
 
1540
                return;
 
1541
        }
 
1542
 
 
1543
        if ( !player->getBoolProperty("spectator") )
 
1544
        {
 
1545
                pInput->ioError( "%s is not a spectator in this game.", player->name().c_str() );
 
1546
                return;
 
1547
        }
 
1548
 
 
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);
 
1554
 
 
1555
        ioInfo( "%s upgrades %s to a participating player.", pInput->name().c_str(), player->name().c_str() );
 
1556
}
 
1557
 
 
1558
unsigned int Game::playerAssets(Player *player)
 
1559
{
 
1560
        unsigned int assets = player->getIntProperty("money");
 
1561
        Estate *estate = 0;
 
1562
        for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end() && (estate = *it) ; ++it)
 
1563
        {
 
1564
                if ( player == estate->owner() )
 
1565
                {
 
1566
                        if (!estate->getBoolProperty("mortgaged"))
 
1567
                        {
 
1568
                                assets += estate->getIntProperty("mortgageprice");
 
1569
                                assets += ( estate->getIntProperty("houses") * estate->getIntProperty("sellhouseprice"));
 
1570
                        }
 
1571
                }
 
1572
        }
 
1573
        return assets;
 
1574
}
 
1575
 
 
1576
void Game::updateTurn()
 
1577
{
 
1578
        Player *pOldTurn = m_pTurn;
 
1579
        // Disable turn, roll and buy.
 
1580
        pOldTurn->setTurn(false);
 
1581
 
 
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)
 
1585
        {
 
1586
                if (!pFirst && !player->getBoolProperty("bankrupt"))
 
1587
                        pFirst = player;
 
1588
                        
 
1589
                if (player == pOldTurn)
 
1590
                        useNext = true;
 
1591
                else if (useNext && !player->getBoolProperty("bankrupt") && !player->getBoolProperty("spectator"))
 
1592
                {
 
1593
                        m_pTurn = player;
 
1594
                        useNext = false;
 
1595
                        break;
 
1596
                }
 
1597
        }
 
1598
        if (useNext && pFirst)
 
1599
                m_pTurn = pFirst;
 
1600
 
 
1601
        // Set turn.
 
1602
        setDisplay(pOldTurn->estate(), false, false, "Turn goes to %s.", m_pTurn->getStringProperty("name").c_str());
 
1603
        m_pTurn->setTurn(true);
 
1604
}
 
1605
 
 
1606
bool Game::landPlayer(Player *pTurn, const bool directMove, const std::string &rentMath)
 
1607
{
 
1608
        Estate *destination = pTurn->destination();
 
1609
 
 
1610
        if (destination)
 
1611
        {
 
1612
                bool useNext = false;
 
1613
                unsigned int money = 0;
 
1614
                Estate *estate = 0;
 
1615
                for (std::vector<Estate *>::iterator it = m_estates.begin() ;;)
 
1616
                {
 
1617
                        if (it == m_estates.end())
 
1618
                        {
 
1619
                                it = m_estates.begin();
 
1620
                                continue;
 
1621
                        }
 
1622
 
 
1623
                        if (!(estate = *it))
 
1624
                                break;
 
1625
 
 
1626
                        if (useNext)
 
1627
                        {
 
1628
                                if (estate->getIntProperty("passmoney"))
 
1629
                                {
 
1630
                                        money += estate->getIntProperty("passmoney");
 
1631
                                        // Write incremental message for direct moves, token
 
1632
                                        // confirmation or timeout didn't do it yet.
 
1633
                                        if (directMove)
 
1634
                                                setDisplay(estate, false, false, "%s passes %s and gets %d.", pTurn->getStringProperty("name").c_str(), estate->getStringProperty("name").c_str(), estate->getIntProperty("passmoney"));
 
1635
                                }
 
1636
                                if (estate == destination)
 
1637
                                        break;
 
1638
                        }
 
1639
                        else if (estate == pTurn->estate())
 
1640
                                useNext = true;
 
1641
 
 
1642
                        ++it;
 
1643
                }
 
1644
                pTurn->setEstate(destination);
 
1645
                pTurn->setDestination(0);
 
1646
 
 
1647
                // Store and write final data.
 
1648
                pTurn->addMoney(money);
 
1649
        }
 
1650
        
 
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
 
1653
        // sent earlier.
 
1654
 
 
1655
        // What properties does the estate we are landing on have?
 
1656
        bool endTurn = true;
 
1657
        Player *pOwner = 0;
 
1658
        Estate *es = pTurn->estate();
 
1659
 
 
1660
        if (getBoolProperty("doublepassmoney") && es->getIntProperty("passmoney"))
 
1661
        {
 
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"));
 
1664
        }
 
1665
        else
 
1666
                setDisplay(es, false, false, "%s lands on %s.", pTurn->getStringProperty("name").c_str(), es->getStringProperty("name").c_str());
 
1667
 
 
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"))
 
1672
        {
 
1673
                if ( Estate *eTmp = findNextJailEstate(es) )
 
1674
                        pTurn->toJail(eTmp);
 
1675
                else
 
1676
                        ioError("This gameboard does not have a jail estate.");
 
1677
 
 
1678
                updateTurn();
 
1679
                return true;
 
1680
        }
 
1681
 
 
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
 
1684
        // properties.
 
1685
        if ( int estateMoney = es->getIntProperty("money") )
 
1686
        {
 
1687
                if ( estateMoney > 0)
 
1688
                {
 
1689
                        // Good for you!
 
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);
 
1693
                }
 
1694
                else
 
1695
                {
 
1696
                        // Pay up!
 
1697
                        Estate * const ePayTarget = es->payTarget();
 
1698
                        if (!pTurn->payMoney(estateMoney))
 
1699
                        {
 
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);
 
1705
                                return true;
 
1706
                        }
 
1707
                        else if (ePayTarget && getBoolProperty("collectfines"))
 
1708
                                ePayTarget->addMoney(estateMoney);
 
1709
 
 
1710
                        setDisplay(es, false, false, "%s pays %d.", pTurn->getStringProperty("name").c_str(), estateMoney);
 
1711
                }
 
1712
        }
 
1713
 
 
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");
 
1717
 
 
1718
        if (tax || taxPercentage)
 
1719
        {
 
1720
                int payAmount = 0;
 
1721
                if ( tax && taxPercentage )
 
1722
                {
 
1723
                        GameObject *config = findConfigOption("automatetax");
 
1724
                        if (config && config->getBoolProperty("value") )
 
1725
                        {
 
1726
                                payAmount = tax;
 
1727
                                tax = (taxPercentage * pTurn->assets() / 100);
 
1728
                                if (tax < payAmount)
 
1729
                                                payAmount = tax;
 
1730
                        }
 
1731
                        else
 
1732
                        {
 
1733
                                Player *pTmp = 0;
 
1734
                                for (std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
 
1735
                                        if (pTmp != pTurn)
 
1736
                                        {
 
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();
 
1739
                                        }
 
1740
 
 
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);
 
1744
 
 
1745
                                pTurn->sendDisplayMsg();
 
1746
 
 
1747
                                // TODO: port this into a blocking bool in Display which we can check, will be more generic
 
1748
                                m_pausedForDialog = true;
 
1749
                                return false;
 
1750
                        }
 
1751
                }
 
1752
                else
 
1753
                        payAmount = ( tax ? tax : (int)(taxPercentage * pTurn->assets() / 100 ) );
 
1754
 
 
1755
                Estate * const ePayTarget = es->payTarget();
 
1756
                                
 
1757
                if (!pTurn->payMoney(payAmount))
 
1758
                {
 
1759
                        // TODO: If we go into debt here, we'll never enter rent
 
1760
                        // calculation. So, estates with tax shouldn't be ownable
 
1761
                        // ever.
 
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);
 
1764
                        return true;
 
1765
                }
 
1766
                else if (ePayTarget && getBoolProperty("collectfines"))
 
1767
                        ePayTarget->addMoney(payAmount);
 
1768
                setDisplay(es, false, false, "%s pays %d.", pTurn->getStringProperty("name").c_str(), payAmount);
 
1769
        }
 
1770
 
 
1771
        // Some estates have cards. Handle them before we do rent and purchasing.
 
1772
        if ( CardGroup *cardGroup = es->takeCardGroup() )
 
1773
        {
 
1774
                if (getBoolProperty("alwaysshuffle"))
 
1775
                        cardGroup->shuffleCards();
 
1776
 
 
1777
                endTurn = giveCard(pTurn, es, cardGroup->nextCard());
 
1778
        }
 
1779
 
 
1780
        // Calculate rent for owned estates or offer them for sale.
 
1781
        if ( es->canBeOwned() )
 
1782
        {
 
1783
                if ((pOwner = es->owner()))
 
1784
                {
 
1785
                        // Owned.
 
1786
                        
 
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());
 
1793
                        else
 
1794
                        {
 
1795
                                // Pay payAmount owed.
 
1796
                                int payAmount = es->rent(pTurn, rentMath);
 
1797
 
 
1798
                                if (!pTurn->payMoney(payAmount))
 
1799
                                {
 
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);
 
1802
                                        return true;
 
1803
                                }
 
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);
 
1806
                        }
 
1807
                }
 
1808
                else
 
1809
                {
 
1810
                        // Unowned, thus for sale.
 
1811
                        Player *pTmp = 0;
 
1812
                        for (std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
 
1813
                                if (pTmp != pTurn)
 
1814
                                {
 
1815
                                        pTmp->setDisplay(es, "For sale.");
 
1816
                                        pTmp->sendDisplayMsg();
 
1817
                                }
 
1818
 
 
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();
 
1824
 
 
1825
                        pTurn->setBoolProperty("can_roll", false);
 
1826
                        pTurn->setBoolProperty("can_buyestate", true);
 
1827
                        pTurn->setBoolProperty("canauction", (getBoolProperty("auctionsenabled") && totalAssets()));
 
1828
 
 
1829
                        return false;
 
1830
                }
 
1831
        }
 
1832
        return endTurn;
 
1833
}
 
1834
bool Game::giveCard(Player *pTurn, Estate *estate, Card *card)
 
1835
{
 
1836
        if (!card)
 
1837
        {
 
1838
                ioError(pTurn->name() + " should get a card, but there doesn't seem to be any available!");
 
1839
                return true;
 
1840
        }
 
1841
        setDisplay(estate, false, false, "%s", card->getStringProperty("name").c_str());
 
1842
 
 
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);
 
1847
 
 
1848
        // Actions
 
1849
        if (card->toJail())
 
1850
        {
 
1851
                if ( Estate *eTmp = findNextJailEstate(pTurn->estate()) )
 
1852
                        pTurn->toJail(eTmp);
 
1853
                else
 
1854
                        ioError("This gameboard does not have a jail estate.");
 
1855
 
 
1856
                updateTurn();
 
1857
        }
 
1858
        else if (card->pay())
 
1859
        {
 
1860
                int payAmount = card->pay();
 
1861
                Estate * const ePayTarget = pTurn->estate()->payTarget();
 
1862
                if (payAmount > 0)
 
1863
                {
 
1864
                        if (!pTurn->payMoney(payAmount))
 
1865
                        {
 
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);
 
1868
                                return false;
 
1869
                        }
 
1870
                        else if (ePayTarget && getBoolProperty("collectfines"))
 
1871
                                ePayTarget->addMoney(payAmount);
 
1872
                }
 
1873
                else if (payAmount < 0)
 
1874
                        pTurn->addMoney(-payAmount);
 
1875
        }
 
1876
        else if (card->payEach())
 
1877
        {
 
1878
                Player *pTmp = 0;
 
1879
                int payAmount = 0;
 
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();
 
1883
 
 
1884
                if (payAmount > 0)
 
1885
                {
 
1886
                        if (!pTurn->payMoney(payAmount))
 
1887
                        {
 
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());
 
1890
                        }
 
1891
                        else
 
1892
                        {
 
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());
 
1896
                        }
 
1897
                }
 
1898
                else
 
1899
                {
 
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"))
 
1903
                                {
 
1904
                                        if (!pTmp->payMoney(payAmount))
 
1905
                                        {
 
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);
 
1908
                                        }
 
1909
                                        else
 
1910
                                                pTurn->addMoney(payAmount);
 
1911
                                }
 
1912
                        }
 
1913
        }
 
1914
        else if (card->payHouse() && card->payHotel())
 
1915
        {
 
1916
                int payAmount = 0;
 
1917
 
 
1918
                Estate *eTmp = 0;
 
1919
                for (std::vector<Estate *>::iterator eIt = m_estates.begin() ; eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
 
1920
                {
 
1921
                        if (pTurn == eTmp->owner())
 
1922
                        {
 
1923
                                if (eTmp->getIntProperty("houses") == 5)
 
1924
                                        payAmount += card->payHotel();
 
1925
                                else if (eTmp->getIntProperty("houses"))
 
1926
                                        payAmount += (eTmp->getIntProperty("houses") * card->payHouse());
 
1927
                        }
 
1928
                }
 
1929
 
 
1930
                if (payAmount > 0)
 
1931
                {
 
1932
                        Estate * const ePayTarget = pTurn->estate()->payTarget();
 
1933
                        if (!pTurn->payMoney(payAmount))
 
1934
                        {
 
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);
 
1937
                                return false;
 
1938
                        }
 
1939
                        else if (ePayTarget && getBoolProperty("collectfines"))
 
1940
                                ePayTarget->addMoney(payAmount);
 
1941
                }
 
1942
                else if (payAmount < 0)
 
1943
                        pTurn->addMoney(-payAmount);
 
1944
        }
 
1945
        else if (card->advance() || card->advanceTo()!=-1 || card->advanceToNextOf())
 
1946
        {
 
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())
 
1953
                {
 
1954
                        if (Estate *eTmp = findNextEstate(group, pTurn->estate()))
 
1955
                                pTurn->advanceTo(eTmp->id(), true);
 
1956
                        else
 
1957
                                ioError("Could not find next estate on gameboard.");
 
1958
                }
 
1959
                return landPlayer(pTurn, true, card->rentMath());
 
1960
        }
 
1961
        return true;
 
1962
}
 
1963
 
 
1964
void Game::declareBankrupt(Player *pInput)
 
1965
{
 
1966
        setDisplay(pInput->estate(), false, false, "%s declares bankruptcy!", pInput->getStringProperty("name").c_str());
 
1967
        bankruptPlayer(pInput);
 
1968
}
 
1969
 
 
1970
void Game::bankruptPlayer(Player *pBroke)
 
1971
{
 
1972
        if (pBroke->getBoolProperty("bankrupt") || pBroke->getBoolProperty("spectator"))
 
1973
                return;
 
1974
 
 
1975
        // Set bankrupt flag
 
1976
        pBroke->setBoolProperty("bankrupt", true);
 
1977
 
 
1978
        Debt *debt = 0;
 
1979
        bool debtsWereSolved = false;
 
1980
 
 
1981
        // Find debts we are creditor in and remove them
 
1982
        while ((debt = findDebtByCreditor(pBroke)))
 
1983
        {
 
1984
                delDebt(debt);
 
1985
                debtsWereSolved = true;
 
1986
        }
 
1987
 
 
1988
        // Find debts we are debitor in and pay them off
 
1989
        while ((debt = findDebt(pBroke)))
 
1990
        {
 
1991
                enforceDebt(pBroke, debt);
 
1992
                debtsWereSolved = true;
 
1993
        }
 
1994
 
 
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);
 
1999
 
 
2000
        // Count active (non-bankrupt) players
 
2001
        int activePlayers = 0;
 
2002
        Player *pTmp = 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"))
 
2005
                {
 
2006
                        activePlayers++;
 
2007
                        m_pWinner = pTmp;
 
2008
                }
 
2009
 
 
2010
        if (activePlayers == 1)
 
2011
        {
 
2012
                m_status = End;
 
2013
                syslog(LOG_INFO, "game %d ended: %s wins with a fortune of %d.", m_id, m_pWinner->name().c_str(), m_pWinner->assets());
 
2014
 
 
2015
                pTmp = 0;
 
2016
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2017
                        if (pTmp)
 
2018
                        {
 
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();
 
2022
                                sendStatus(pTmp);
 
2023
                        }
 
2024
        }
 
2025
        else
 
2026
        {
 
2027
                m_pWinner = 0;
 
2028
 
 
2029
                if (activePlayers && !m_debts.size())
 
2030
                {
 
2031
                        if (debtsWereSolved)
 
2032
                                setDisplay(m_pTurn->estate(), false, false, "All debts are settled, game continues.");
 
2033
 
 
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.
 
2037
 
 
2038
                        if (pBroke == m_pTurn)
 
2039
                                updateTurn();
 
2040
                }
 
2041
        }
 
2042
}
 
2043
 
 
2044
int Game::lowestFreeId()
 
2045
{
 
2046
        int lowest = 0;
 
2047
 
 
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;
 
2052
 
 
2053
        return lowest;
 
2054
}
 
2055
 
 
2056
int Game::totalAssets()
 
2057
{
 
2058
        int assets = 0;
 
2059
 
 
2060
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (*it) ; ++it)
 
2061
                assets += (*it)->assets();
 
2062
 
 
2063
        return assets;
 
2064
}
 
2065
 
 
2066
void Game::rollDice()
 
2067
{
 
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 ));
 
2071
}
 
2072
 
 
2073
unsigned int Game::players()
 
2074
{
 
2075
        return m_players.size();
 
2076
}
 
2077
 
 
2078
unsigned int Game::connectedPlayers()
 
2079
{
 
2080
        unsigned int count = 0;
 
2081
        Player *pTmp = 0;
 
2082
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2083
                if (pTmp->socket())
 
2084
                        count++;
 
2085
        return count;
 
2086
}
 
2087
 
 
2088
int Game::debts()
 
2089
{
 
2090
        return m_debts.size();
 
2091
}
 
2092
 
 
2093
unsigned int Game::clientsMoving()
 
2094
{
 
2095
        unsigned int moving = 0;
 
2096
        Player *pTmp = 0;
 
2097
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it) 
 
2098
                if (pTmp->tokenLocation())
 
2099
                        moving++;
 
2100
        return moving;
 
2101
}
 
2102
 
 
2103
void Game::setAllClientsMoving(Estate *estate)
 
2104
{
 
2105
        Player *pTmp = 0;
 
2106
        for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2107
        if (pTmp->socket())
 
2108
                pTmp->setTokenLocation(estate);
 
2109
}
 
2110
 
 
2111
void Game::sendStatus(Player *p)
 
2112
{
 
2113
        p->ioWrite("<monopd><gameupdate gameid=\"%d\" status=\"%s\"/></monopd>\n", m_id, statusLabel().c_str());
 
2114
}
 
2115
 
 
2116
void Game::sendEstateList(Player *p)
 
2117
{
 
2118
        Estate *eTmp = 0;
 
2119
        for(std::vector<Estate *>::iterator eIt = m_estates.begin(); eIt != m_estates.end() && (eTmp = *eIt) ; eIt++)
 
2120
        {
 
2121
                std::string bgColor = eTmp->getStringProperty("bgcolor");
 
2122
                if (!bgColor.size())
 
2123
                {
 
2124
                        EstateGroup *estateGroup = eTmp->group();
 
2125
                        if (estateGroup)
 
2126
                                bgColor = estateGroup->getStringProperty("bgcolor");
 
2127
 
 
2128
                        if (!bgColor.size())
 
2129
                                bgColor = m_bgColor;
 
2130
                }
 
2131
 
 
2132
                std::string color = eTmp->getStringProperty("color");
 
2133
                if (!color.size())
 
2134
                {
 
2135
                        EstateGroup *estateGroup = eTmp->group();
 
2136
                        if (estateGroup)
 
2137
                                color = estateGroup->getStringProperty("color");
 
2138
                }
 
2139
 
 
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));
 
2142
        }
 
2143
}
 
2144
 
 
2145
void Game::sendEstateGroupList(Player *p)
 
2146
{
 
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());
 
2150
}
 
2151
 
 
2152
void Game::sendPlayerList(Player *pOut, bool includeCards)
 
2153
{
 
2154
        Player *pTmp = 0;
 
2155
        for(std::vector<Player *>::iterator it = m_players.begin() ; it != m_players.end() && (pTmp = *it) ; ++it)
 
2156
        {
 
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));
 
2159
 
 
2160
                if (includeCards)
 
2161
                        pTmp->sendCardList(pOut);
 
2162
        }
 
2163
}
 
2164
 
 
2165
void Game::sendFullUpdate(Player *p, const bool userRequest)
 
2166
{
 
2167
        if (p->requestedUpdate())
 
2168
        {
 
2169
                // Last request was also a full update, so the full update XML
 
2170
                // itself triggers the request. Return here to avoid race condition.
 
2171
                return;
 
2172
        }
 
2173
        if (userRequest)
 
2174
                p->setRequestedUpdate(true);
 
2175
 
 
2176
        sendStatus(p);
 
2177
 
 
2178
        if (m_status == Config)
 
2179
                sendConfiguration(p);
 
2180
        else if (m_status == Init || m_status == Run)
 
2181
        {
 
2182
                p->ioWrite("<monopd>");
 
2183
                sendPlayerList(p, true); // includeCards
 
2184
                sendEstateGroupList(p);
 
2185
                sendEstateList(p);
 
2186
                p->ioWrite("</monopd>\n");
 
2187
                p->sendDisplayMsg();
 
2188
        }
 
2189
}
 
2190
 
 
2191
void Game::sendConfiguration(Player *p)
 
2192
{
 
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);
 
2196
 
 
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");
 
2200
}
 
2201
 
 
2202
void Game::setCollectFines(const bool collectFines)
 
2203
{
 
2204
        if (getBoolProperty("collectfines") != collectFines)
 
2205
        {
 
2206
                setBoolProperty("collectfines", collectFines);
 
2207
 
 
2208
                Player *pTmp = 0;
 
2209
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2210
                        sendConfiguration(pTmp);
 
2211
        }
 
2212
}
 
2213
 
 
2214
void Game::setAuctionsEnabled(const bool auctionsEnabled)
 
2215
{
 
2216
        if (getBoolProperty("auctionsenabled") != auctionsEnabled)
 
2217
        {
 
2218
                setBoolProperty("auctionsenabled", auctionsEnabled);
 
2219
 
 
2220
                Player *pTmp = 0;
 
2221
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2222
                        sendConfiguration(pTmp);
 
2223
        }
 
2224
}
 
2225
 
 
2226
void Game::setDoublePassMoney(bool doublePassMoney)
 
2227
{
 
2228
        if (getBoolProperty("doublepassmoney") != doublePassMoney)
 
2229
        {
 
2230
                setBoolProperty("doublepassmoney", doublePassMoney);
 
2231
 
 
2232
                Player *pTmp = 0;
 
2233
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2234
                        sendConfiguration(pTmp);
 
2235
        }
 
2236
}
 
2237
 
 
2238
void Game::setAlwaysShuffle(const bool alwaysShuffle)
 
2239
{
 
2240
        if (getBoolProperty("alwaysshuffle") != alwaysShuffle)
 
2241
        {
 
2242
                setBoolProperty("alwaysshuffle", alwaysShuffle);
 
2243
 
 
2244
                Player *pTmp = 0;
 
2245
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2246
                        sendConfiguration(pTmp);
 
2247
        }
 
2248
}
 
2249
 
 
2250
void Game::setUnlimitedHouses(bool unlimitedHouses)
 
2251
{
 
2252
        if (getBoolProperty("unlimitedhouses") != unlimitedHouses)
 
2253
        {
 
2254
                setBoolProperty("unlimitedhouses", unlimitedHouses);
 
2255
 
 
2256
                Player *pTmp = 0;
 
2257
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2258
                        sendConfiguration(pTmp);
 
2259
        }
 
2260
}
 
2261
 
 
2262
void Game::setNoRentInJail(bool noRentInJail)
 
2263
{
 
2264
        if (getBoolProperty("norentinjail") != noRentInJail)
 
2265
        {
 
2266
                setBoolProperty("norentinjail", noRentInJail);
 
2267
 
 
2268
                Player *pTmp = 0;
 
2269
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2270
                        sendConfiguration(pTmp);
 
2271
        }
 
2272
}
 
2273
 
 
2274
void Game::setAllowEstateSales(bool allowEstateSales)
 
2275
{
 
2276
        if (getBoolProperty("allowestatesales") != allowEstateSales)
 
2277
        {
 
2278
                setBoolProperty("allowestatesales", allowEstateSales);
 
2279
 
 
2280
                Player *pTmp = 0;
 
2281
                for(std::vector<Player *>::iterator it = m_players.begin(); it != m_players.end() && (pTmp = *it) ; ++it)
 
2282
                        sendConfiguration(pTmp);
 
2283
        }
 
2284
}
 
2285
 
 
2286
const std::string Game::statusLabel()
 
2287
{
 
2288
        switch(m_status)
 
2289
        {
 
2290
        case Config:
 
2291
                return "config";
 
2292
        case Init:
 
2293
                return "init";
 
2294
        case Run:
 
2295
                return "run";
 
2296
        case End:
 
2297
                return "end";
 
2298
        default:
 
2299
                return "default";
 
2300
        }
 
2301
}
 
2302
 
 
2303
bool Game::sendChildXMLUpdate(Player *pOutput, bool updateEmpty)
 
2304
{
 
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)
 
2308
        {
 
2309
                // .. but only when changed (and in property scope)
 
2310
                std::string updateXML = configOption->oldXMLUpdate(pOutput);
 
2311
                if (updateXML.size())
 
2312
                {
 
2313
                        if (updateEmpty)
 
2314
                        {
 
2315
                                pOutput->ioWrite("<monopd> ");
 
2316
                                updateEmpty = false;
 
2317
                        }
 
2318
                        pOutput->ioWrite("%s", updateXML.c_str());
 
2319
                }
 
2320
        }
 
2321
 
 
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)
 
2325
        {
 
2326
                // .. but only when changed (and in property scope)
 
2327
                std::string updateXML = eUpdate->oldXMLUpdate(pOutput);
 
2328
                if (updateXML.size())
 
2329
                {
 
2330
                        if (updateEmpty)
 
2331
                        {
 
2332
                                pOutput->ioWrite("<monopd> ");
 
2333
                                updateEmpty = false;
 
2334
                        }
 
2335
                        pOutput->ioWrite("%s", updateXML.c_str());
 
2336
                }
 
2337
        }
 
2338
        return updateEmpty;
 
2339
}
 
2340
 
 
2341
void Game::unsetChildProperties()
 
2342
{
 
2343
        // Reset config options ..
 
2344
        for(std::vector<GameObject *>::iterator it = m_configOptions.begin(); it != m_configOptions.end() && (*it) ; ++it)
 
2345
                (*it)->unsetPropertiesChanged();
 
2346
 
 
2347
        // Reset estates ..
 
2348
        for(std::vector<Estate *>::iterator it = m_estates.begin(); it != m_estates.end() && (*it) ; ++it)
 
2349
                (*it)->unsetPropertiesChanged();
 
2350
}