예제 #1
0
void requestAlliance(uint8_t from, uint8_t to, bool prop, bool allowAudio)
{
	if (prop && bMultiMessages)
	{
		sendAlliance(from, to, ALLIANCE_REQUESTED, false);
		return;  // Wait for our message.
	}

	syncDebug("Request alliance %d %d", from, to);
	alliances[from][to] = ALLIANCE_REQUESTED;	// We've asked
	alliances[to][from] = ALLIANCE_INVITATION;	// They've been invited


	CBallFrom = from;
	CBallTo = to;
	eventFireCallbackTrigger((TRIGGER_TYPE) CALL_ALLIANCEOFFER);
	triggerEventAllianceOffer(from, to);

	if (to == selectedPlayer)
	{
		CONPRINTF(ConsoleString, (ConsoleString, _("%s Requests An Alliance With You"), getPlayerName(from)));

		if (allowAudio)
		{
			audio_QueueTrack(ID_ALLIANCE_OFF);
		}
	}
	else if (from == selectedPlayer)
	{
		CONPRINTF(ConsoleString, (ConsoleString, _("You Invite %s To Form An Alliance"), getPlayerName(to)));
		if (allowAudio)
		{
			audio_QueueTrack(ID_ALLIANCE_OFF);
		}
	}
}
예제 #2
0
// ////////////////////////////////////////////////////////////////////////////
// A Remote Player has joined the game.
bool MultiPlayerJoin(UDWORD playerIndex)
{
	if(widgGetFromID(psWScreen,IDRET_FORM))	// if ingame.
	{
		audio_QueueTrack( ID_CLAN_ENTER );
	}

	if(widgGetFromID(psWScreen,MULTIOP_PLAYERS))	// if in multimenu.
	{
		if (!multiRequestUp && (bHosted || ingame.localJoiningInProgress))
		{
			addPlayerBox(true);	// update the player box.
		}
	}

	if(NetPlay.isHost)		// host responsible for welcoming this player.
	{
		// if we've already received a request from this player don't reallocate.
		if (ingame.JoiningInProgress[playerIndex])
		{
			return true;
		}
		ASSERT(NetPlay.playercount <= MAX_PLAYERS, "Too many players!");

		// setup data for this player, then broadcast it to the other players.
		setupNewPlayer(playerIndex);						// setup all the guff for that player.
		sendOptions();

		// if skirmish and game full, then kick...
		if (NetPlay.playercount > game.maxPlayers)
		{
			kickPlayer(playerIndex, "the game is already full.", ERROR_FULL);
		}
		// send everyone's stats to the new guy
		{
			int i;

			for (i = 0; i < MAX_PLAYERS; i++)
			{
				if (NetPlay.players[i].allocated)
				{
					setMultiStats(i, getMultiStats(i), false);
				}
			}
		}
	}
	return true;
}
예제 #3
0
// ////////////////////////////////////////////////////////////////////////////
// A remote player has left the game
bool MultiPlayerLeave(UDWORD playerIndex)
{
	if (playerIndex >= MAX_PLAYERS)
	{
		ASSERT(false, "Bad player number");
		return false;
	}

	NETlogEntry("Player leaving game", SYNC_FLAG, playerIndex);
	debug(LOG_NET, "** Player %u [%s], has left the game at game time %u.", playerIndex, getPlayerName(playerIndex), gameTime);

	if (ingame.localJoiningInProgress)
	{
		addConsolePlayerLeftMessage(playerIndex);
		clearPlayer(playerIndex, false);
	}
	else if (NetPlay.isHost)  // If hosting, and game has started (not in pre-game lobby screen, that is).
	{
		sendPlayerLeft(playerIndex);
	}
	game.skDiff[playerIndex] = 0;

	if (NetPlay.players[playerIndex].wzFile.isSending)
	{
		char buf[256];

		ssprintf(buf, _("File transfer has been aborted for %d.") , playerIndex);
		addConsoleMessage(buf, DEFAULT_JUSTIFY, SYSTEM_MESSAGE);
		debug(LOG_INFO, "=== File has been aborted for %d ===", playerIndex);
		NetPlay.players[playerIndex].wzFile.isSending = false;
		NetPlay.players[playerIndex].needFile = false;
	}

	if (widgGetFromID(psWScreen, IDRET_FORM))
	{
		audio_QueueTrack(ID_CLAN_EXIT);
	}

	// fire script callback to reassign skirmish players.
	CBPlayerLeft = playerIndex;
	eventFireCallbackTrigger((TRIGGER_TYPE)CALL_PLAYERLEFT);
	triggerEventPlayerLeft(playerIndex);

	netPlayersUpdated = true;
	return true;
}
예제 #4
0
bool recvGift(NETQUEUE queue)
{
	uint8_t	type, from, to;
	int		audioTrack;
	uint32_t droidID;

	NETbeginDecode(queue, GAME_GIFT);
		NETuint8_t(&type);
		NETuint8_t(&from);
		NETuint8_t(&to);
		NETuint32_t(&droidID);
	NETend();

	// Handle the gift depending on what it is
	switch (type)
	{
		case RADAR_GIFT:
			audioTrack = ID_SENSOR_DOWNLOAD;
			giftRadar(from, to, false);
			break;
		case DROID_GIFT:
			audioTrack = ID_UNITS_TRANSFER;
			recvGiftDroids(from, to, droidID);
			break;
		case RESEARCH_GIFT:
			audioTrack = ID_TECHNOLOGY_TRANSFER;
			giftResearch(from, to, false);
			break;
		case POWER_GIFT:
			audioTrack = ID_POWER_TRANSMIT;
			giftPower(from, to, droidID, false);
			break;
		default:
			debug(LOG_ERROR, "recvGift: Unknown Gift recvd");
			return false;
			break;
	}

	// If we are on the recieving end play an audio alert
	if (to == selectedPlayer)
	{
		audio_QueueTrack(audioTrack);
	}
	return true;
}
예제 #5
0
bool sendGift(uint8_t type, uint8_t to)
{
	int audioTrack;

	switch (type)
	{
	case RADAR_GIFT:
		audioTrack = ID_SENSOR_DOWNLOAD;
		giftRadar(selectedPlayer, to, true);
		break;
	case DROID_GIFT:
		audioTrack = ID_UNITS_TRANSFER;
		sendGiftDroids(selectedPlayer, to);
		break;
	case RESEARCH_GIFT:
		audioTrack = ID_TECHNOLOGY_TRANSFER;
		giftResearch(selectedPlayer, to, true);
		break;
	case POWER_GIFT:
		audioTrack = ID_POWER_TRANSMIT;
		giftPower(selectedPlayer, to, 0, true);
		break;
	case AUTOGAME_GIFT:
		giftAutoGame(selectedPlayer, to, true);
		return true;
		break;
	case STRUCTURE_GIFT:
		// not implemented
	default:
		debug(LOG_ERROR, "Unknown Gift sent");
		return false;
		break;
	}

	// Play the appropriate audio track
	audio_QueueTrack(audioTrack);

	return true;
}
예제 #6
0
// ///////////////////////////////////////////////////////////////
void processMultiPlayerArtifacts(void)
{
	static UDWORD lastCall;
	FEATURE	*pF,*pFN;
	UDWORD	x,y,pl;
	Position position;
	BOOL	found=false;

	// only do this every now and again.
	if(lastCall > gameTime)lastCall= 0;
	if ( (gameTime - lastCall) <2000)
	{
		return;
	}
	lastCall = gameTime;

	for(pF = apsFeatureLists[0]; pF ; pF = pFN)
	{
		pFN = pF->psNext;
		// artifacts
		if(pF->psStats->subType == FEAT_GEN_ARTE)
		{
			found = objectInRange((BASE_OBJECT *)apsDroidLists[selectedPlayer], pF->pos.x, pF->pos.y, (TILE_UNITS+(TILE_UNITS/3))  );
			if(found)
			{
				position = pF->pos;				// Add an effect
				addEffect(&position,EFFECT_EXPLOSION,EXPLOSION_TYPE_DISCOVERY,false,NULL,false);

				x = pF->pos.x;
				y = pF->pos.y;
				pl= pF->player;
				removeFeature(pF);			// remove artifact+ send info.
				giftArtifact(pl,x,y);		// reward player.
				pF->player = 0;
				audio_QueueTrack( ID_SOUND_ARTIFACT_RECOVERED );
			}
		}
	}
}
예제 #7
0
// ///////////////////////////////////////////////////////////////
bool pickupArtefact(int toPlayer, int fromPlayer)
{
	if (fromPlayer < MAX_PLAYERS && bMultiPlayer)
	{
		PLAYER_RESEARCH *pR = asPlayerResList[toPlayer];
		PLAYER_RESEARCH *pO = asPlayerResList[fromPlayer];
		int topic;

		for (topic = numResearch - 1; topic >= 0; topic--)
		{
			if (IsResearchCompleted(&pO[topic])
			 && !IsResearchPossible(&pR[topic]))
			{
				// Make sure the topic can be researched
				if (asResearch[topic].researchPower
				 && asResearch[topic].researchPoints)
				{
					MakeResearchPossible(&pR[topic]);
					if (toPlayer == selectedPlayer)
					{
						CONPRINTF(ConsoleString,(ConsoleString,_("You Discover Blueprints For %s"), getName(asResearch[topic].pName)));
					}
					break;
				}
				// Invalid topic
				else
				{
					debug(LOG_WARNING, "%s is a invalid research topic?", getName(asResearch[topic].pName));
				}
			}
		}

		audio_QueueTrack(ID_SOUND_ARTIFACT_RECOVERED);

		return true;
	}

	return false;
}
예제 #8
0
/* process the results of a completed research topic */
void researchResult(UDWORD researchIndex, UBYTE player, bool bDisplay, STRUCTURE *psResearchFacility, bool bTrigger)
{
	RESEARCH                                       *pResearch = &asResearch[researchIndex];
	MESSAGE						*pMessage;
	//the message gets sent to console
	char						consoleMsg[MAX_RESEARCH_MSG_SIZE];

	ASSERT_OR_RETURN(, researchIndex < asResearch.size(), "Invalid research index %u", researchIndex);

	syncDebug("researchResult(%u, %u, …)", researchIndex, player);

	MakeResearchCompleted(&asPlayerResList[player][researchIndex]);

	//check for structures to be made available
	for (unsigned short pStructureResult : pResearch->pStructureResults)
	{
		if (apStructTypeLists[player][pStructureResult] != REDUNDANT)
		{
			apStructTypeLists[player][pStructureResult] = AVAILABLE;
		}
	}

	//check for structures to be made redundant
	for (unsigned short pRedStruct : pResearch->pRedStructs)
	{
		apStructTypeLists[player][pRedStruct] = REDUNDANT;
	}

	//check for component replacement
	if (!pResearch->componentReplacement.empty())
	{
		for (auto &ri : pResearch->componentReplacement)
		{
			COMPONENT_STATS *pOldComp = ri.pOldComponent;
			replaceComponent(ri.pNewComponent, pOldComp, player);
			apCompLists[player][pOldComp->compType][pOldComp->index] = REDUNDANT;
		}
	}

	//check for artefacts to be made available
	for (auto &componentResult : pResearch->componentResults)
	{
		//determine the type of artefact
		COMPONENT_TYPE type = componentResult->compType;
		//set the component state to AVAILABLE
		int compInc = componentResult->index;
		if (apCompLists[player][type][compInc] != REDUNDANT)
		{
			apCompLists[player][type][compInc] = AVAILABLE;
		}
		//check for default sensor
		if (type == COMP_SENSOR && (asSensorStats + compInc)->location == LOC_DEFAULT)
		{
			aDefaultSensor[player] = compInc;
		}
		//check for default ECM
		else if (type == COMP_ECM && (asECMStats + compInc)->location == LOC_DEFAULT)
		{
			aDefaultECM[player] = compInc;
		}
		//check for default Repair
		else if (type == COMP_REPAIRUNIT && (asRepairStats + compInc)->location == LOC_DEFAULT)
		{
			aDefaultRepair[player] = compInc;
			enableSelfRepair(player);
		}
	}

	//check for artefacts to be made redundant
	for (auto &pRedArtefact : pResearch->pRedArtefacts)
	{
		COMPONENT_TYPE type = pRedArtefact->compType;
		apCompLists[player][type][pRedArtefact->index] = REDUNDANT;
	}

	//Add message to player's list if Major Topic
	if ((pResearch->techCode == TC_MAJOR) && bDisplay)
	{
		//only play sound if major topic
		if (player == selectedPlayer)
		{
			audio_QueueTrack(ID_SOUND_MAJOR_RESEARCH);
		}

		//check there is viewdata for the research topic - just don't add message if not!
		if (pResearch->pViewData != nullptr)
		{
			pMessage = addMessage(MSG_RESEARCH, false, player);
			if (pMessage != nullptr)
			{
				pMessage->pViewData = pResearch->pViewData;
				jsDebugMessageUpdate();
			}
		}
	}
	else if (player == selectedPlayer && bDisplay)
	{
		audio_QueueTrack(ID_SOUND_RESEARCH_COMPLETED);
	}

	if (player == selectedPlayer && bDisplay)
	{
		//add console text message
		if (pResearch->pViewData != nullptr)
		{
			snprintf(consoleMsg, MAX_RESEARCH_MSG_SIZE, _("Research completed: %s"), _(pResearch->pViewData->textMsg[0].toUtf8().c_str()));
			addConsoleMessage(consoleMsg, LEFT_JUSTIFY, SYSTEM_MESSAGE);
		}
		else
		{
			addConsoleMessage(_("Research Completed"), LEFT_JUSTIFY, SYSTEM_MESSAGE);
		}
	}

	if (psResearchFacility)
	{
		psResearchFacility->pFunctionality->researchFacility.psSubject = nullptr;		// Make sure topic is cleared
	}
	if ((bMultiPlayer || player == selectedPlayer) && bTrigger)
	{
		psCBLastResearch = pResearch;  // Fun with pointers. Throw them into some random global variable, and get Nexus to absorb them.
		CBResFacilityOwner = player;
		psCBLastResStructure = psResearchFacility;
		eventFireCallbackTrigger((TRIGGER_TYPE)CALL_RESEARCHCOMPLETED);
		psCBLastResStructure = nullptr;
		CBResFacilityOwner = -1;
		psCBLastResearch = nullptr;
	}
	triggerEventResearched(pResearch, psResearchFacility, player);
}
예제 #9
0
void formAlliance(uint8_t p1, uint8_t p2, BOOL prop, BOOL allowAudio, BOOL allowNotification)
{
	DROID	*psDroid;
	char	tm1[128];

	// Don't add message if already allied
	if (bMultiPlayer && alliances[p1][p2] != ALLIANCE_FORMED && allowNotification)
	{
		sstrcpy(tm1, getPlayerName(p1));
		CONPRINTF(ConsoleString,(ConsoleString,_("%s Forms An Alliance With %s"),tm1,getPlayerName(p2)));
	}

	alliances[p1][p2] = ALLIANCE_FORMED;
	alliances[p2][p1] = ALLIANCE_FORMED;
	if (game.alliance == ALLIANCES_TEAMS)	// this is for shared vision only
	{
		alliancebits[p1] |= 1 << p2;
		alliancebits[p2] |= 1 << p1;
	}

	if (allowAudio && (p1 == selectedPlayer || p2== selectedPlayer))
	{
		audio_QueueTrack(ID_ALLIANCE_ACC);
	}

	if (bMultiMessages && prop)
	{
		sendAlliance(p1, p2, ALLIANCE_FORMED, false);
	}

	// Not campaign and alliances are transitive
	if (game.alliance == ALLIANCES_TEAMS)
	{
		giftRadar(p1, p2, false);
		giftRadar(p2, p1, false);
	}

	// Clear out any attacking orders
	turnOffMultiMsg(true);

	for (psDroid = apsDroidLists[p1]; psDroid; psDroid = psDroid->psNext)	// from -> to
	{
		if (psDroid->order == DORDER_ATTACK
		 && psDroid->psTarget
		 && psDroid->psTarget->player == p2)
		{
			orderDroid(psDroid, DORDER_STOP);
		}
	}
	for (psDroid = apsDroidLists[p2]; psDroid; psDroid = psDroid->psNext)	// to -> from
	{
		if (psDroid->order == DORDER_ATTACK
		 && psDroid->psTarget
 		 && psDroid->psTarget->player == p1)
		{
			orderDroid(psDroid,DORDER_STOP);
		}
	}

	turnOffMultiMsg(false);
}