예제 #1
0
	virtual void Decide(const DataObject &input, DataObject &output)
	{
		wxASSERT(2 <= input.numItems());

		bool valid = true;

		size_t die1 = input.read<size_t>();
		size_t die2 = input.read<size_t>(1);

		if(7 == (die1 + die2))
		{
			wxInt32 turn = gameData<wxInt32>(shTurn);
			wxInt32 players = numPlayers();

			wxInt32 round = ((turn - 1) / players) + 1;
			wxInt32 rounds = gameData<wxInt32>(shNo7Rounds);

			if(rounds >= round)
			{
				valid = false;
			}
		}

		output = DataObject(valid);
	}
예제 #2
0
	void BuildAttackPlacements(wxInt32 strength, TileCornerSet& placements)
	{
		// Gather up all of the knights that are below this knight in strength.
		// If any exist on the board, they are potential attack victims.
		wxInt32 players = numPlayers();
		for(wxInt32 i = 0; i < players; ++i)
		{
			// Can't attack self.
			if(i == mPlayer)
			{
				continue;
			}

			const PlayerGame::CornerObjectArray& knights =
				playerGame(i).getCornerObjects(shKnights);
			PlayerGame::CornerObjectArray::const_iterator it, 
				itEnd = knights.end();

			for(it = knights.begin(); it != itEnd; ++it)
			{
				const KnightObject* knight = static_cast<KnightObject*>(
					(*it).get());

				if(knight->strength() < strength)
				{
					placements.insert(knight->tile1());
					placements.insert(knight->tile2());
					placements.insert(knight->tile3());
				}
			}
		}
	}
예제 #3
0
	virtual void Decide(const DataObject &, DataObject &output)
	{
		// If any player has a progress card besides this player, the Spy
		// is playable.
		bool canPlay = false;
		wxInt32 curPlayer = current();

		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(i != curPlayer)
			{
				// The player must have any progress card.
				wxInt32 total = 0;
				total += CountCards(shPlayableTradeCards, i);
				total += CountCards(shPlayablePoliticsCards, i);
				total += CountCards(shPlayableScienceCards, i);
				
				if(0 < total)
				{
					canPlay = true;
					break;
				}
			}
		}

		output = DataObject(canPlay);
	}
	virtual void Decide(const DataObject &, DataObject &output)
	{
		// Determine if there are any players with more VPs than this player.
		// If there are not, they cannot play the card.
		wxInt32 points = playerGameData<wxInt32>(shPoints);
		bool canPlay = false;

		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(points < playerGameData<wxInt32>(shPoints, i))
			{
				// The player must also have cards to donate.
				wxInt32 total = 0;
				const Data::IntHash& resources = 
					playerGameData<Data::IntHash>(shResources, i);
				Data::IntHash::const_iterator it, itEnd = resources.end();
				for(it = resources.begin(); it != itEnd; ++it)
				{
					total += it->second;
				}

				if(0 < total)
				{
					canPlay = true;
					break;
				}
			}
		}

		output = DataObject(canPlay);
	}
예제 #5
0
	virtual void Execute(const DataObject &)
	{
		wxString players;

		// Empty all of the players in the game so they can be filled in as 
		// players rejoin.
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(0 != i)
			{
				players += swCommaSpace;
			}
			players += playerGame(i).player().Name();

			playerGame(i).newPlayer(NullPlayer);
		}

		wxLogDebug(wxT("Restarting a network game with %s."), 
			players.c_str());

		gameData<HashString>(shNetworkRestartState) = 
			gameData<HashString>(shState);
		gameData<HashString>(shState) = shNetworkRestart;

		RULE.Execute(shRulePrepareUI, DataObject());
		RULE.Execute(shRuleRestartGame, DataObject());

		// Immediately check to see if the host takes any of the seats
		// in the game.
		RULE.Execute(shNetworkRuleTakeSeat, 
			DataObject(NET.Players().GetThisPlayer()));
	}
예제 #6
0
	virtual void Execute(const DataObject &)
	{
		wxString players;

		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(0 != i)
			{
				players += swCommaSpace;
			}
			players += playerGame(i).player().Name();
		}

		wxLogDebug(wxT("Starting a new network game with %s."), 
			players.c_str());

		// Set the state different than New so anyone joining in the brief 
		// time between when the host will not be able to add themself as a
		// player to the game.
		gameData<HashString>(shState) = shNetworkLaunch;

		// Randomize the players.  This works because every client is using
		// the same pool of random numbers.
		RULE.Execute(shRuleRandomizePlayers, DataObject());

		// Start the game.
		const Map::StringPairArray& rulesets = MAP.rulesets();
		Controller::get().Transmit(shEventLoadRulesets, rulesets);
		Controller::get().Transmit(shEventStartGame, true);

		// Start with the first rule.
		RULE.Execute(shRule0, DataObject());
	}
예제 #7
0
	virtual void Execute(const DataObject &object)
	{
		const Player &player = object.read<Player>();
		const wxBOOL ready = object.read<wxInt32>(2);

		// First, see if this player is already assigned a color, because
		// they might actually be switching colors with someone else if the
		// host is doing it for them.
		DataObject output;
		RULE.Decide(shNetworkLogicPlayerColor, object, output);
		const ColorType color = output.read<ColorType>();

		// Now actually change the color.
		RULE.Execute(shRuleChangeColor, object);

		// Set their ready flag.
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			const Player &thisPlayer = playerGame(i).player();

			if(player == thisPlayer)
			{
				playerGameData<wxInt32>(shReady, i) = ready;
				break;
			}
		}

		//fire the update mechanism
		Controller::get().Transmit(shEventPreGame, GetGame());

		// Update the UI.
		RULE.Execute(shNetworkRuleChangeColorMessage, object);

		// Finally, if they had a previous color, see if someone else is
		// now that color, and if so, update the UI.
		if(CR_SIZE != color)
		{
			for(wxInt32 i = 0; i < numPlayers(); ++i)
			{
				if(playerGame(i).color() == color)
				{
					RULE.Execute(shNetworkRuleChangeColorMessage, 
						DataObject(playerGame(i).player(), color));
				}
			}
		}
	}
예제 #8
0
	virtual void Execute(const DataObject &)
	{
		//initialize player data needed
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			playerGameData<wxInt32>(shReceivedBonus, i) = FALSE;
		}
	}
예제 #9
0
	void BuildHashes()
	{
		// Just like longest road, build a set of blocked corners, and a set
		// of bridge corners.
		// First, build the hash of all side objects for this player.
		PlayerGame::SideObjectArray sides;
		playerGame(mPlayer).getAllSideObjects(sides);

		PlayerGame::SideObjectArray::const_iterator it, itEnd = sides.end();
		for(it = sides.begin(); it != itEnd; ++it)
		{
			// Add each to the hash.
			SideObject::TileSide side = (*it)->tile1();
			wxInt32 id = Utility::encodeSel(side.first, side.second);
			mSegmentHash[id].object = (*it);
			mSegmentHash[id].counted = false;
			
			side = (*it)->tile2();
			id = Utility::encodeSel(side.first, side.second);
			mSegmentHash[id].object = (*it);
			mSegmentHash[id].counted = false;
		}

		// Now build the sets of all bridge and dead end corners.
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			// If this is the current player, they are bridge corners, 
			// otherwise, dead end corners.
			IntSet &set = (i == mPlayer) ? mBridgeCorners : mDeadEndCorners;
			
			PlayerGame::CornerObjectArray objects;
			playerGame(i).getAllCornerObjects(objects);

			PlayerGame::CornerObjectArray::const_iterator it, 
				itEnd = objects.end();

			for(it = objects.begin(); it != itEnd; ++it)
			{
				// Only add them if they are dead ends, or bridges with the
				// bridge flag set.
				const CornerObjectPtr& object = (*it);

				if( (i != mPlayer) ||
					(true == object->bridge()))
				{
					CornerObject::TileCorner corner = object->tile1();
					set.insert(Utility::encodeSel(
						corner.first, corner.second));
					corner = object->tile2();
					set.insert(Utility::encodeSel(
						corner.first, corner.second));
					corner = object->tile3();
					set.insert(Utility::encodeSel(
						corner.first, corner.second));
				}
			}
		}
	}
예제 #10
0
	BehaviorTreeNode* CNormalMode::askQuestionToPlayerSequence(int player, int round) {

		std::string playerCam = (std::string)"player"+data2string(player+1)+(std::string)"cam1";
		BehaviorTreeInternalNode* sequence;
		(sequence = new ParallelNode(FAIL_ON_ONE, SUCCEED_ON_ALL))
				->addChild((new SequentialNode())
						->addChild(new CPlayDialogue(_questions[player+(numPlayers()*round)]->getId()))
						->addChild(new CAnimateAvatarNode(_players[player], "LEGS_NERVOUS", "TORSO_JUMP", "HEAD_HARD_SWINGING"))
						->addChild(new CSetButtonStatus(_bPlayerName[player], CButton::HIGHLIGHTED))
						->addChild(new CCameraNode(playerCam))		// Camara a jugador 1
						->addChild(new CSetQuestionInHud(_questions[player+(numPlayers()*round)]))
						->addChild(new CUiComponentVisibility(_game->questionsGui(), true))	// Muestra interfaz pregunta
						->addChild(new CFadeUiNode(_fQuestionsGui, 0.001f))					// Hacemos un fade para mostrar el interfaz
				)
				//->addChild(new CTimerButtonNode(_bClock, _timePerQuestion))
			;
		return sequence;
	}
	virtual void Execute(const DataObject &)
	{
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			// Initialize space for players to "lose" their metropolises to the
			// volcano.
			playerGameData<IntArray>(shVolcanoMetropolis, i);
			playerGameData<wxInt32>(shMoveMetropolis, i) = FALSE;
		}
	}
예제 #12
0
	virtual void Execute(const DataObject &)
	{
		wxInt32 &player = gameData<wxInt32>(shCurrentPlayer);
		++player;
		
		if(numPlayers() <= player)
		{
			player = 0;
		}
	}
예제 #13
0
	virtual void Execute(const DataObject &)
	{
		wxInt32 &player = gameData<wxInt32>(shCurrentPlayer);
		--player;
		
		if(-1 == player)
		{
			player = (numPlayers() - 1);
		}
	}
예제 #14
0
	virtual void Execute(const DataObject &)
	{
		wxInt32 switchVal;

		//make a pass through and randomize
		for(wxInt32 i = 0; i < numPlayers(); i++)
		{
			//get the random value
			switchVal = RAND.pooled(numPlayers());

			//sanity check
			if(switchVal == i) 
			{
				continue;
			}

			std::swap(playerGames()[i], playerGames()[switchVal]);
		}
	}
예제 #15
0
	virtual void Execute(const DataObject &)
	{
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			playerGameData<wxInt32>(shStockRoads, i) = 
				sRoads;
			playerGameData<wxInt32>(shStockSettlements, i) = 
				sSettlements;
			playerGameData<wxInt32>(shStockCities, i) = 
				sCities;
		}
	}
	virtual void Decide(const DataObject &input, DataObject &output)
	{
		wxASSERT(1 <= input.numItems());

		wxInt32 thisTile = input.read<wxInt32>();
		wxInt32 tileIsland = tile<wxInt32>(shIsland, thisTile);
		wxInt32 playerIsland = playerGameData<wxInt32>(shHomeIsland);

		//if the player has already selected an island, this tile must
		//be on the same island
		if(0 != playerIsland)
		{
			output = DataObject(tileIsland == playerIsland);
			return;
		}

		//total up the number of islands selected by players

		WX_DECLARE_HASH_MAP(wxInt32, wxInt32, wxIntegerHash, wxIntegerEqual, 
			IntHash);
		IntHash hash;

		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			wxInt32 island = playerGameData<wxInt32>(shHomeIsland, i);

			if(0 != island)
			{
				hash[island]++;
			}
		}
		
		//if the player has not yet selected a home island, then this
		//location will be allowed, as long as half of the players or
		//less (round up) are not on the island
		float dif = numPlayers() - hash[tileIsland];
		float half = float(numPlayers()) * 0.5f;

		output = DataObject((dif > half));
	}
예제 #17
0
	virtual void Decide(const DataObject &input, DataObject &output)
	{
		const Player &player = input.read<Player>();
		ColorType color = CR_SIZE;

		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(player == playerGame(i).player())
			{
				color = playerGame(i).color();
				break;
			}
		}

		output = DataObject(color);
	}
	virtual void Execute(const DataObject &object)
	{
		wxLogDebug(wxT("NetworkRuleConnectionLostInGame: Entry."));

		// Execute any extensions that want to handle this.
		ExecuteExtensions(object);

		const Player &player = object.read<Player>();

		// No matter what the case, the player needs to be replaced with the
		// NullPlayer in the current game so their seat becomes open.
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(player == playerGame(i).player())
			{
				// Set them as Null.
				playerGame(i).newPlayer(NullPlayer);

				// Refresh the PlayerUI with the new name.
				Controller::get().Transmit(shEventNewPlayer, 
					DataObject(GetGame(), i));
				break;
			}
		}

		// If we are in the game right now we need to shut everything
		// down and fire up the Network Restart dialog.
		if(shNetworkRestart != gameData<HashString>(shState))
		{
			Controller::get().Transmit(shEventShutdownUI, 0);

			gameData<HashString>(shNetworkRestartState) = 
				gameData<HashString>(shState);
			gameData<HashString>(shState) = shNetworkRestart;
			wxLogDebug(wxT("NetworkRuleConnectionLostInGame: State is now ")
				wxT("NetworkRestart."));

			RULE.Execute(shRuleRestartGame, DataObject());
		}

		// Always update the players in the network restart list.
		Controller::get().Transmit(shEventNetworkRestartPlayers, GetGame());
		Controller::get().Transmit(shEventSpectator, 0);

		wxLogDebug(wxT("NetworkRuleConnectionLostInGame: Exit."));
	}
	virtual void Execute(const DataObject &object)
	{
		// Only do stuff is this is the server and if we are still in the New
		// game state.
		if( (true == NET.Players().IsHost()) &&
			(shNew == gameData<HashString>(shState))
			)
		{
			const Player &player = object.read<Player>();
			const ColorType color = object.read<ColorType>(1);

			// The reason we scan the game like this is that due to network
			// latency, two players may request the same color at the same
			// time before either of them gets updated with who has that color.
			// This rule protects the game by only allowing the request to go
			// through if the color is free.
			bool safe = true;

			for(wxInt32 i = 0; i < numPlayers(); ++i)
			{
				const PlayerGame &playergame = this->playerGame(i);
				const Player &indexPlayer = playergame.player();

				// If we find the color being used or, heaven forbid, the
				// player already in the game, forbid the assignment.
				if( (color == playergame.color()) ||
					(player == indexPlayer))
				{
					safe = false;
					break;
				}
			}

			// If we made it through safely, assign the color.
			if(true == safe)
			{
				// Since we are calling this from within another rule, the
				// RuleEngine isn't going to send it on to the network.
				// Therefore, we have to do it manually.
				wxASSERT(NET.IsConnected());

				NET.SendRule(shNetworkRuleAddPlayer, object);
			}
		}
	}
예제 #20
0
	void BuildInvalidSet(TileSideSet &invalids)
	{
		PlayerGame::SideObjectArray objects;

		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			const PlayerGame &thisGame = playerGame(i);
			thisGame.getAllSideObjects(objects);
		}

		// Build the hash.
		PlayerGame::SideObjectArray::const_iterator it, itEnd = objects.end();

		for(it = objects.begin(); it != itEnd; ++it)
		{
			invalids.insert((*it)->tile1());
			invalids.insert((*it)->tile2());
		}
	}
	virtual void Execute(const DataObject &object)
	{
		const HashString& card = object.read<HashString>();
		
		RULE.Execute(shRulePlayProgressCardStart, DataObject(card, shTrade));

		// Set things up to be able to use the Commercial Harbor throughout
		// the rest of the turn. 
		wxInt32 curPlayer = current();
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(i != curPlayer)
			{
				playerGameData<wxInt32>(shCommercialHarbor, i) = TRUE;
			}
		}

		// Play the sound.
		RULE.Execute(shRulePlaySound, DataObject(SOUND_PLAY_COMMERCIAL_HARBOR_CARD));

		RULE.Execute(shRulePlayProgressCardEnd, DataObject());
	}
예제 #22
0
	BehaviorTreeNode* CNormalMode::roundsSequence(){
		BehaviorTreeInternalNode* sequence = new SequentialNode();
		for(int r=0; r<numRounds(); ++r){
			sequence->addChild(new CCleanHud);
			sequence->addChild(getPlayerHudVisbility(true));
			for(int p=0; p<numPlayers(); ++p) {
				sequence->addChild(new CResetTimeNode((CModeBT*)this));
				sequence->addChild(askQuestionToPlayerSequence(p, r));
				sequence->addChild(answerSequence());
				sequence->addChild(new CSetButtonStatus(_bColorAnswers[0], CButton::NORMAL));		/// Limpio las respuestas
				sequence->addChild(new CSetButtonStatus(_bColorAnswers[1], CButton::NORMAL));
				sequence->addChild(new CSetButtonStatus(_bColorAnswers[2], CButton::NORMAL));
				sequence->addChild(new CSetButtonStatus(_bColorAnswers[3], CButton::NORMAL));
				sequence->addChild(new CRandomIdleNode(1000));
				sequence->addChild(new CAnimateAvatarNode(_players[p], "LEGS_SWINGING", "TORSO_SWINGING", "HEAD_IDLE"));
				sequence->addChild(new CSetButtonStatus(_bPlayerName[p], CButton::NORMAL));
				sequence->addChild(new CNextQuestionNode(this));
				sequence->addChild(new CNextPlayerNode(this));
				//std::cout<<"Jugador: "<<p<<" Pregunta: "<<p+(numPlayers()*r)<<" en ronda: "<<r<<"\n";
			}

			sequence->addChild(new CNextRoundNode(this));

			sequence->addChild((new CConditionNode(new CEndModeCondition))		/// Compruebo si quedan rondas
					->addChild((new SequentialNode())
							->addChild(new CClearCameraQueue)
							->addChild(new COrientAvatarNode(_host,180.0f))
							->addChild(new CChangeStateNode("intro_ganadores"))
							)
					);
			sequence->addChild((new CInvertedConditionNode(new CEndModeCondition))
					->addChild(scoreReviewSequence())
					);
			sequence->addChild(new CClearCameraQueue);
		}

		return sequence;
	}
예제 #23
0
	virtual void Execute(const DataObject &)
	{
		bool cardFound = false;

		wxInt32 players = numPlayers();
		wxInt32 curPlayer = current();

		bool thisPlayerCard = false;
		wxString thisPlayerName;

		// Go through each player, starting with the current player.  If
		// they get a progress card, run the card dialog.
		for(wxInt32 i = 0; i < players; ++i)
		{
			wxInt32 thisPlayer = (i + curPlayer) % players;

			if(TRUE == playerGameData<wxInt32>(shGainProgressCard, thisPlayer))
			{
                // This player is now in a blocking action.
                RULE.Execute(shRuleBeginBlockingAction, DataObject(thisPlayer));

				// They have some.
				cardFound = true;

				// Shut everything down.
				Controller::get().Transmit(shEventBuildUI, 
					DataObject(false, GetGame()));
				Controller::get().Transmit(shEventControlsUI, 
					DataObject(false));

				Controller::get().Transmit(shEventProgressCards, 
					DataObject(thisPlayer, GetGame()));

				thisPlayerName = playerGame(thisPlayer).player().Name();

				// See if this player is spending gold.
				DataObject input(thisPlayer), output;
				RULE.Decide(shLogicIsThisPlayer, input, output);
				if(true == output.read<bool>())
				{
					thisPlayerCard = true;
				}

				// Only do this one at a time.
				break;
			}
		}

		// If all cards have been selected, continue on.
		if(false == cardFound)
		{
			RULE.Execute(shRuleMarkerPostDiceRoll, DataObject());
		}
		// Otherwise, set the text.
		else
		{
			wxString str1;

			if(true == thisPlayerCard)
			{
				str1 = wxString::Format(stSelectAProgressCard.c_str(),
					thisPlayerName.c_str());
			}
			else
			{
				str1 = wxString::Format(stWaitingSelectAProgressCard.c_str(), 
					thisPlayerName.c_str());
			}

			Controller::get().Transmit(shEventMessageUI, DataObject(str1, 
				GetGame()));
		}
	}
예제 #24
0
	virtual void Execute(const DataObject &)
	{
		bool goldFound = false;

		wxInt32 players = numPlayers();
		wxInt32 curPlayer = current();

		bool thisPlayerGold = false;
		wxString thisPlayerName;

		// Go through each player, starting with the current player.  If
		// they have gold, stop and run the gold selection dialog.
		for(wxInt32 i = 0; i < players; ++i)
		{
			wxInt32 thisPlayer = (i + curPlayer) % players;

			const Data::IntHash& resources =
				playerGameData<Data::IntHash>(shResources, thisPlayer);

			// See if they have gold.
			Data::IntHash::const_iterator it = resources.find(shGold);

			if( (resources.end() != it) &&
				(0 < it->second))
			{
				// They have some.
				goldFound = true;

				// This player is now in a blocking action.
				RULE.Execute(shRuleBeginBlockingAction, DataObject(thisPlayer));

				// Shut everything down.
				Controller::get().Transmit(shEventBuildUI, 
					DataObject(false, GetGame()));
				Controller::get().Transmit(shEventControlsUI, 
					DataObject(false));

				Controller::get().Transmit(shEventGold, 
					DataObject(thisPlayer, GetGame()));

				thisPlayerName = playerGame(thisPlayer).player().Name();

				// See if this player is spending gold.
				DataObject input(thisPlayer), output;
				RULE.Decide(shLogicIsThisPlayer, input, output);
				if(true == output.read<bool>())
				{
					thisPlayerGold = true;
				}

				// Only do this one at a time.
				break;
			}
		}

		// If all gold has been spent, continue on.
		if(false == goldFound)
		{
			RULE.Execute(shRuleMarkerPostDiceRoll, DataObject());
		}
		// Otherwise, set the text.
		else
		{
			wxString str1;

			if(true == thisPlayerGold)
			{
				str1 = wxString::Format(stStringSpendYourGold.c_str(),
					thisPlayerName.c_str());
			}
			else
			{
				str1 = wxString::Format(stWaitingSpendGold.c_str(),
					thisPlayerName.c_str());
			}

			Controller::get().Transmit(shEventMessageUI, DataObject(str1, 
				GetGame()));
		}
	}
예제 #25
0
	virtual void Execute(const DataObject &object)
	{
		// Only execute if we're supposed to.
		if(false == object.read<bool>())
		{
			return;
		}

		// So, here's how the Longest Road algorithm works:
		//
		// 1.  If no player currently has Longest Road...
		//     a) and no one has more than 5 connected roads, no one gets
		//        Longest Road.
		//     b) and multiple players have more than 5 connected roads, but
		//        are tied, no one gets Longest Road.
		//     c) and any one player has more than 5 connected roads and is in
		//        the lead, they get Longest Road.
		// 2.  If someone already has Longest Road...
		//     a) and anyone else ties them in length, the original player
		//        retains Longest Road.
		//     b) and multiple players surpass them in length, but are tied,
		//        Longest Road reverts to unclaimed.
		//     c) and any one person surpasses them and everyone else in 
		//        length, they get Longest Road.
		//     d) and the player drops below 5 in road length, loses Longest
		//        Road, with Longest Road going to the appropriate player
		//        based on the previous criteria.
		//

		// With that in mind, run through each player, retrieving their
		// longest chain of roads.
		wxInt32 players = numPlayers();
		wxInt32 current = gameData<wxInt32>(shLongestRoadPlayer);

		std::vector<wxInt32> lengths(numPlayers(), 0);
		std::vector<PlayerGame::SideObjectArray> chains(numPlayers());

		PlayerGame::SideObjectArray longestChain;

		for(wxInt32 i = 0; i < players; ++i)
		{
			DataObject input(i), output;
			RULE.Decide(shLogicRoadLength, input, output);

			lengths[i] = output.read<wxInt32>();
			chains[i] = output.read<PlayerGame::SideObjectArray>(1);

			// While we're going through each player, clear any Longest Road
			// highlighting.
			PlayerGame::SideObjectArray objects;
			playerGame(i).getAllSideObjects(objects);

			PlayerGame::SideObjectArray::const_iterator it, 
				itEnd = objects.end();
			for(it = objects.begin(); it != itEnd; ++it)
			{
				(*it)->longest(false);
			}
		}

		// Now that we have all the lengths, figure out if Longest Road
		// changes.

		wxInt32 longestLength = 0;
		wxInt32 longestPlayer = -1;

		// In the special case where the original player drops below 5 in road
		// length, clear them out first and then apply the normal rules.
		if( (-1 != current) &&
			(5 > lengths[current]))
		{
			RULE.Execute(shRuleLoseLongestRoad, DataObject(current));
			current = -1;
		}

		// No current holder.
		if(-1 == current)
		{
			// With no current holder, see if anyone is over 5 and the clear
			// leader (no ties).
			for(wxInt32 i = 0; i < players; ++i)
			{
				wxInt32 len = lengths[i];

				if(5 <= len)
				{
					// A clear leader.
					if(longestLength < len)
					{
						longestLength = len;
						longestPlayer = i;
					}
					// A tie.
					else if(longestLength == len)
					{
						longestPlayer = -1;
					}
				}
			}
		}
		// Someone already has it.
		else
		{
			// Set the mark that must be beaten.
			longestPlayer = current;
			longestLength = lengths[current];

			for(wxInt32 i = 0; i < players; ++i)
			{
				// Skip the current holder.
				if(i == current)
				{
					continue;
				}

				wxInt32 len = lengths[i];

				// Look for a clear leader.
				if(longestLength < len)
				{
					longestLength = len;
					longestPlayer = i;
				}
				// Here's where it gets interesting.  If they tie the original 
				// player, it counts for nothing.  However, if they tie a new 
				// player who has already surpassed the original player, then 
				// it's a deadlock, and no one is the longest player.
				else if((longestLength == len) &&
						(longestPlayer != current))
				{
					longestPlayer = -1;
				}
			}
		}

		// Always update the highlighting on the longest road.
		if(-1 != longestPlayer)
		{
			PlayerGame::SideObjectArray& chain = chains[longestPlayer];

			// Mark all of the longest chain.
			PlayerGame::SideObjectArray::const_iterator it, 
				itEnd = chain.end();
			for(it = chain.begin(); it != itEnd; ++it)
			{
				(*it)->longest(true);
			}
		}

		// If it has changed hands, take it away from the loser and award it
		// to the winner.
		if(current != longestPlayer)
		{
			// Take it away from the loser.
			if(-1 != current)
			{
				RULE.Execute(shRuleLoseLongestRoad, DataObject(current));
			}

			// Give it to the winner.
			if(-1 != longestPlayer)
			{
				RULE.Execute(shRuleGainLongestRoad, DataObject(longestPlayer));
			}
		}

		// Regardless of what happens, update every player.
		Controller::get().Transmit(shEventPlayerUI, 
			DataObject(GetGame(), -1));
	}
	virtual void Execute(const DataObject &object)
	{
		bool done = true;
		bool first = true;
		bool thisPlayer = false;
		wxString thisName;

		// If there's no data in the object, this is the first time through,
		// so show the dialogs.
		bool showDialog = true;
		wxInt32 player = -1;

		if(1 <= object.numItems())
		{
			// It's possible for a player to have 6 cards, if they get 5 on 
			// their turn, don't use any, then get another on the next roll.
			// In that case, they may have to discard again.
			player = object.read<wxInt32>();
		}

		wxString str;
		wxInt32 curPlayer = current();

		// See if any players need to discard a progress card.
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if( (i != curPlayer) &&
				(4 < FindTotal(i)))
			{
				if( (true == showDialog) ||
					(player == i))
				{
                    // This player is now in a blocking action.
                    RULE.Execute(shRuleBeginBlockingAction, DataObject(curPlayer));

					// Shut everything down.
					Controller::get().Transmit(shEventBuildUI, 
						DataObject(false, GetGame()));
					Controller::get().Transmit(shEventControlsUI, 
						DataObject(false));

					Controller::get().Transmit(shEventDiscardProgressCards, 
						DataObject(i, GetGame()));
				}

				// Add their name to the waiting list.
				if(true == first)
				{
					first = false;
				}
				else
				{
					str += swCommaSpace;
				}

				const wxString& name = playerGame(i).player().Name();
				str += name;

				// See if this player is losing cards.
				DataObject input(i), output;
				RULE.Decide(shLogicIsThisPlayer, input, output);
				if(true == output.read<bool>())
				{
					thisPlayer = true;
					thisName = name;
				}

				done = false;
			}
		}

		if(true == done)
		{
			RULE.Execute(shRuleMarkerPostDiceRoll, DataObject());
		}
		else
		{
			wxString str1;

			if(true == thisPlayer)
			{
				str1 = wxString::Format(stDiscardOneProgressCard.c_str(),
					thisName.c_str());
			}
			else
			{
				str1 = wxString::Format(stWaitingDiscardOneProgressCard.c_str(),
					str.c_str());
			}

			Controller::get().Transmit(shEventMessageUI, DataObject(str1, 
				GetGame()));
		}
	}
예제 #27
0
	virtual void Execute(const DataObject &object)
	{
        // This isn't purely accurate, but the current player is now 100%
        // dependent on the other players finishing and should not have a
        // turn timer.
        RULE.Execute(shRuleEndBlockingAction, DataObject(current()));

		bool done = true;
		bool first = true;
		bool thisPlayer = false;
		wxString thisName;

		// If there's no data in the object, this is the first time through,
		// so show the lose card dialogs.
		bool showDialog = true;

		if(1 <= object.numItems())
		{
			showDialog = object.read<bool>();
		}

		wxString str;

		// See if any players need to lose cards.
		for(wxInt32 i = 0; i < numPlayers(); ++i)
		{
			if(TRUE == playerGameData<wxInt32>(shWedding, i))
			{
				if(true == showDialog)
				{
                    // This player is now in a blocking action.
                    RULE.Execute(shRuleBeginBlockingAction, DataObject(i));

					// Shut everything down.
					Controller::get().Transmit(shEventBuildUI, 
						DataObject(false, GetGame()));
					Controller::get().Transmit(shEventControlsUI, 
						DataObject(false));

					Controller::get().Transmit(shEventWedding, 
						DataObject(i, GetGame()));
				}

				// Add their name to the waiting list.
				if(true == first)
				{
					first = false;
				}
				else
				{
					str += swCommaSpace;
				}

				const wxString& name = playerGame(i).player().Name();
				str += name;

				// See if this player is losing cards.
				DataObject input(i), output;
				RULE.Decide(shLogicIsThisPlayer, input, output);
				if(true == output.read<bool>())
				{
					thisPlayer = true;
					thisName = name;
				}

				done = false;
			}
		}

		if(true == done)
		{
			RULE.Execute(shRulePlayProgressCardEnd, DataObject());
		}
		else
		{
			wxString str1;

			if(true == thisPlayer)
			{
				str1 = wxString::Format(stSelectTwoResourcesOrCommoditiesToGive.c_str(),
					thisName.c_str());
			}
			else
			{
				str1 = wxString::Format(stWaitingSelectTwoResourcesOrCommoditiesToGive.c_str(),
					str.c_str());
			}

			Controller::get().Transmit(shEventMessageUI, DataObject(str1, 
				GetGame()));
		}
	}