Beispiel #1
0
// update players damage stats.
void updateMultiStatsDamage(UDWORD attacker, UDWORD defender, UDWORD inflicted)
{
	PLAYERSTATS st;

	if (Cheated)
	{
		return;
	}
	// FIXME: Why in the world are we using two different structs for stats when we can use only one?
	// Host controls self + AI, so update the scores for them as well.
	if (attacker < MAX_PLAYERS)
	{
		if (myResponsibility(attacker) && NetPlay.bComms)
		{
			st = getMultiStats(attacker);	// get stats
			if (NetPlay.bComms)
			{
				st.scoreToAdd += (2 * inflicted);
			}
			else
			{
				st.recentScore += (2 * inflicted);
			}
			setMultiStats(attacker, st, true);
		}
		else
		{
			ingame.skScores[attacker][0] += (2 * inflicted);	// increment skirmish players rough score.
		}
	}

	// FIXME: Why in the world are we using two different structs for stats when we can use only one?
	// Host controls self + AI, so update the scores for them as well.
	if (defender < MAX_PLAYERS)
	{
		if (myResponsibility(defender) && NetPlay.bComms)
		{
			st = getMultiStats(defender);	// get stats
			if (NetPlay.bComms)
			{
				st.scoreToAdd  -= inflicted;
			}
			else
			{
				st.recentScore  -= inflicted;
			}
			setMultiStats(defender, st, true);
		}
		else
		{
			ingame.skScores[defender][0] -= inflicted;	// increment skirmish players rough score.
		}
	}
}
Beispiel #2
0
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Score
// We use setMultiStats() to broadcast the score when needed.
bool sendScoreCheck(void)
{
	static UDWORD	lastsent = 0;

	if (lastsent > gameTime)
	{
		lastsent= 0;
	}

	if (gameTime - lastsent < SCORE_FREQUENCY)
	{
		return true;
	}

	lastsent = gameTime;

	// Broadcast any changes in other players, but not in FRONTEND!!!
	if (titleMode != MULTIOPTION && titleMode != MULTILIMIT)
	{
		uint8_t			i;

		for (i = 0; i < game.maxPlayers; i++)
		{
			// Host controls AI's scores + his own...
			if (myResponsibility(i))
			{
				// Send score to everyone else
				setMultiStats(i, getMultiStats(i), false);
			}
		}
	}

	return true;
}
Beispiel #3
0
void recvMultiStats(NETQUEUE queue)
{
	uint32_t playerIndex;

	NETbeginDecode(queue, NET_PLAYER_STATS);
		// Retrieve the ID number of the player for which we need to
		// update the stats
		NETuint32_t(&playerIndex);

		if (playerIndex >= MAX_PLAYERS)
		{
			return;
		}

		// we don't what to update ourselves, we already know our score (FIXME: rewrite setMultiStats())
		if (!myResponsibility(playerIndex))
		{
			// Retrieve the actual stats
			NETuint32_t(&playerStats[playerIndex].played);
			NETuint32_t(&playerStats[playerIndex].wins);
			NETuint32_t(&playerStats[playerIndex].losses);
			NETuint32_t(&playerStats[playerIndex].totalKills);
			NETuint32_t(&playerStats[playerIndex].totalScore);
			NETuint32_t(&playerStats[playerIndex].recentKills);
			NETuint32_t(&playerStats[playerIndex].recentScore);
			NETuint32_t(&playerStats[playerIndex].killsToAdd);
			NETuint32_t(&playerStats[playerIndex].scoreToAdd);
		}
	NETend();
}
Beispiel #4
0
// ////////////////////////////////////////////////////////////////////////////
// Send a new Droid to the other players
bool SendDroid(DROID_TEMPLATE *pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrdersP)
{
	if (!bMultiMessages)
	{
		return true;
	}

	ASSERT_OR_RETURN(false, x != 0 && y != 0, "SendDroid: Invalid droid coordinates");
	ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "invalid player %u", player);

	// Dont send other droids during campaign setup
	if (ingame.localJoiningInProgress)
	{
		return true;
	}

	// Only send the droid if we are responsible
	if (!myResponsibility(player))
	{
		// Don't build if we are not responsible
		return false;
	}

	debug(LOG_SYNC, "Droid sent with id of %u", id);
	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DEBUG_ADD_DROID);
	{
		Position pos(x, y, 0);
		bool haveInitialOrders = initialOrdersP != NULL;
		int32_t droidType = pTemplate->droidType;

		NETuint8_t(&player);
		NETuint32_t(&id);
		NETPosition(&pos);
		NETqstring(pTemplate->name);
		NETint32_t(&droidType);
		NETuint8_t(&pTemplate->asParts[COMP_BODY]);
		NETuint8_t(&pTemplate->asParts[COMP_BRAIN]);
		NETuint8_t(&pTemplate->asParts[COMP_PROPULSION]);
		NETuint8_t(&pTemplate->asParts[COMP_REPAIRUNIT]);
		NETuint8_t(&pTemplate->asParts[COMP_ECM]);
		NETuint8_t(&pTemplate->asParts[COMP_SENSOR]);
		NETuint8_t(&pTemplate->asParts[COMP_CONSTRUCT]);
		NETint8_t(&pTemplate->numWeaps);
		for (int i = 0; i < pTemplate->numWeaps; i++)
		{
			NETuint8_t(&pTemplate->asWeaps[i]);
		}
		NETbool(&haveInitialOrders);
		if (haveInitialOrders)
		{
			INITIAL_DROID_ORDERS initialOrders = *initialOrdersP;
			NETuint32_t(&initialOrders.secondaryOrder);
			NETint32_t(&initialOrders.moveToX);
			NETint32_t(&initialOrders.moveToY);
			NETuint32_t(&initialOrders.factoryId);  // For making scripts happy.
		}
	}
	debug(LOG_LIFE, "===> sending Droid from %u id of %u ", player, id);
	return NETend();
}
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// New research stuff, so you can see what others are up to!
// inform others that I'm researching this.
bool sendResearchStatus(STRUCTURE *psBuilding, uint32_t index, uint8_t player, bool bStart)
{
	if (!myResponsibility(player) || gameTime < 5)
	{
		return true;
	}

	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_RESEARCHSTATUS);
		NETuint8_t(&player);
		NETbool(&bStart);

		// If we know the building researching it then send its ID
		if (psBuilding)
		{
			NETuint32_t(&psBuilding->id);
		}
		else
		{
			uint32_t zero = 0;
			NETuint32_t(&zero);
		}

		// Finally the topic in question
		NETuint32_t(&index);
	NETend();

	// Tell UI to remove from the list of available research.
	MakeResearchStartedPending(&asPlayerResList[player][index]);

	return true;
}
Beispiel #6
0
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Power Checking. Send a power level check every now and again.
static BOOL sendPowerCheck()
{
	uint8_t         player;

	if (powerCheckLastSent > gameTime)
	{
		powerCheckLastSent = 0;
	}

	// Only send if not done recently
	if (gameTime - powerCheckLastSent < POWER_PERIOD)
	{
		return true;
	}

	powerCheckLastSent = gameTime;
	for (player = 0; player < MAX_PLAYERS; ++player)
	{
		powerCheckLastPower[player] = getPrecisePower(player);
		if (myResponsibility(player))
		{
			if (!isInSync())  // Don't really send anything, unless out of synch.
			{
				NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_POWER);
					NETuint8_t(&player);
					NETuint32_t(&gameTime);
					NETint64_t(&powerCheckLastPower[player]);
				NETend();
			}
		}
	}
	return true;
}
Beispiel #7
0
// update kills
void updateMultiStatsKills(BASE_OBJECT *psKilled,UDWORD player)
{
	PLAYERSTATS	st;

	if (Cheated)
	{
		return;
	}
	// FIXME: Why in the world are we using two different structs for stats when we can use only one?
	// Host controls self + AI, so update the scores for them as well.
	if(myResponsibility(player) && NetPlay.bComms)
	{
		st  = getMultiStats(player);

		if(NetPlay.bComms)
		{
			st.killsToAdd++;		// increase kill count;
		}
		else
		{
			st.recentKills++;
		}
		setMultiStats(player, st, true);
	}
	else
	{
		ingame.skScores[player][1]++;
	}
}
//AI multiplayer message, send from a certain player index to another player index
bool sendAIMessage(char *pStr, UDWORD player, UDWORD to)
{
	UDWORD	sendPlayer;

	//check if this is one of the local players, don't need net send then
	if (to == selectedPlayer || myResponsibility(to))	//(the only) human on this machine or AI on this machine
	{
		triggerEventChat(player, to, pStr);

		//Just show "him" the message
		displayAIMessage(pStr, player, to);

		//Received a console message from a player callback
		//store and call later
		//-------------------------------------------------
		if (!msgStackPush(CALL_AI_MSG,player,to,pStr,-1,-1,NULL))
		{
			debug(LOG_ERROR, "sendAIMessage() - msgStackPush - stack failed");
			return false;
		}
	}
	else		//not a local player (use multiplayer mode)
	{
		if (!ingame.localOptionsReceived)
		{
			return true;
		}

		//find machine that is hosting this human or AI
		sendPlayer = whosResponsible(to);

		if (sendPlayer >= MAX_PLAYERS)
		{
			debug(LOG_ERROR, "sendAIMessage() - sendPlayer >= MAX_PLAYERS");
			return false;
		}

		if (!isHumanPlayer(sendPlayer))		//NETsend can't send to non-humans
		{
			debug(LOG_ERROR, "sendAIMessage() - player is not human.");
			return false;
		}

		//send to the player who is hosting 'to' player (might be himself if human and not AI)
		NETbeginEncode(NETnetQueue(sendPlayer), NET_AITEXTMSG);
			NETuint32_t(&player);			//save the actual sender
			//save the actual player that is to get this msg on the source machine (source can host many AIs)
			NETuint32_t(&to);				//save the actual receiver (might not be the same as the one we are actually sending to, in case of AIs)
			NETstring(pStr, MAX_CONSOLE_STRING_LENGTH);		// copy message in.
		NETend();
	}

	return true;
}
Beispiel #9
0
// ////////////////////////////////////////////////////////////////////////////
// Droid update information
void sendDroidInfo(DROID *psDroid, DroidOrder const &order, bool add)
{
	if (!myResponsibility(psDroid->player))
	{
		return;
	}

	QueuedDroidInfo info;
	memset(&info, 0x00, sizeof(info));  // Suppress uninitialised warnings. (The uninitialised values in the queue would be ignored when reading the queue.)

	info.player = psDroid->player;
	info.droidId = psDroid->id;
	info.subType = order.psObj != NULL? ObjOrder : LocOrder;
	info.order = order.type;
	if (info.subType == ObjOrder)
	{
		info.destId = order.psObj->id;
		info.destType = order.psObj->type;
	}
	else
	{
		info.pos = order.pos;
	}
	if (order.type == DORDER_BUILD || order.type == DORDER_LINEBUILD)
	{
		info.structRef = order.psStats->ref;
		info.direction = order.direction;
		if (!isConstructionDroid(psDroid))
		{
			return;  // No point ordering things to build if they can't build anything.
		}
	}
	if (order.type == DORDER_LINEBUILD)
	{
		info.pos2 = order.pos2;
	}
	if (order.type == DORDER_BUILDMODULE)
	{
		info.index = order.index;
	}

	info.add = add;

	// Send later, grouped by order, so multiple droids with the same order can be encoded to much less data.
	queuedOrders.push_back(info);

	// Update pending orders, so the UI knows it happened.
	DROID_ORDER_DATA sOrder = infoToOrderData(info, order.psStats);
	if (!add)
	{
		psDroid->listPendingBegin = psDroid->asOrderList.size();
	}
	orderDroidAddPending(psDroid, &sOrder);
}
Beispiel #10
0
void recvMultiStats(NETQUEUE queue)
{
	uint32_t playerIndex;

	NETbeginDecode(queue, NET_PLAYER_STATS);
	// Retrieve the ID number of the player for which we need to
	// update the stats
	NETuint32_t(&playerIndex);

	if (playerIndex >= MAX_PLAYERS)
	{
		NETend();
		return;
	}


	if (playerIndex != queue.index && queue.index != NET_HOST_ONLY)
	{
		HandleBadParam("NET_PLAYER_STATS given incorrect params.", playerIndex, queue.index);
		NETend();
		return;
	}

	// we don't what to update ourselves, we already know our score (FIXME: rewrite setMultiStats())
	if (!myResponsibility(playerIndex))
	{
		// Retrieve the actual stats
		NETuint32_t(&playerStats[playerIndex].played);
		NETuint32_t(&playerStats[playerIndex].wins);
		NETuint32_t(&playerStats[playerIndex].losses);
		NETuint32_t(&playerStats[playerIndex].totalKills);
		NETuint32_t(&playerStats[playerIndex].totalScore);
		NETuint32_t(&playerStats[playerIndex].recentKills);
		NETuint32_t(&playerStats[playerIndex].recentScore);
		EcKey::Key identity;
		NETbytes(&identity);
		EcKey::Key prevIdentity;
		if (!playerStats[playerIndex].identity.empty())
		{
			prevIdentity = playerStats[playerIndex].identity.toBytes(EcKey::Public);
		}
		playerStats[playerIndex].identity.clear();
		if (!identity.empty())
		{
			playerStats[playerIndex].identity.fromBytes(identity, EcKey::Public);
		}
		if (identity != prevIdentity)
		{
			ingame.PingTimes[playerIndex] = PING_LIMIT;
		}
	}
	NETend();
}
Beispiel #11
0
// ////////////////////////////////////////////////////////////////////////////
// add an artifact on destruction if required.
void  technologyGiveAway(const STRUCTURE *pS)
{
	int				i;
	uint8_t			count = 1;
	uint32_t		x, y;
	FEATURE			*pF = NULL;
	FEATURE_TYPE	type = FEAT_GEN_ARTE;

	// If a fully built factory (or with modules under construction) which is our responsibility got destroyed
	if (pS->pStructureType->type == REF_FACTORY && (pS->status == SS_BUILT || pS->currentBuildPts >= pS->body)
	 && myResponsibility(pS->player))
	{
		x = map_coord(pS->pos.x);
		y = map_coord(pS->pos.y);

		// Pick a tile to place the artifact
		if (!pickATileGen(&x, &y, LOOK_FOR_EMPTY_TILE, zonedPAT))
		{
			ASSERT(false, "technologyGiveAway: Unable to find a free location");
		}

		// Get the feature offset
		for(i = 0; i < numFeatureStats && asFeatureStats[i].subType != FEAT_GEN_ARTE; i++);

		// 'Build' the artifact
		pF = buildFeature((asFeatureStats + i), world_coord(x), world_coord(y), false);
		if (pF)
		{
			pF->player = pS->player;
		}

		NETbeginEncode(NET_ARTIFACTS, NET_ALL_PLAYERS);
		{
			/* Make sure that we don't have to violate the constness of pS.
			 * Since the nettype functions aren't const correct when sending
			 */
			uint8_t player = pS->player;

			NETuint8_t(&count);
			NETenum(&type);
			NETuint32_t(&x);
			NETuint32_t(&y);
			NETuint32_t(&pF->id);
			NETuint8_t(&player);
		}
		NETend();
	}

	return;
}
Beispiel #12
0
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Score
// We use setMultiStats() to broadcast the score when needed.
BOOL sendScoreCheck(void)
{
	static UDWORD	lastsent = 0;

	if (lastsent > gameTime)
	{
		lastsent= 0;
	}

	if (gameTime - lastsent < SCORE_FREQUENCY)
	{
		return true;
	}

	lastsent = gameTime;

	// Broadcast any changes in other players, but not in FRONTEND!!!
	if (titleMode != MULTIOPTION && titleMode != MULTILIMIT)
	{
		uint8_t			i;

		for (i = 0; i < MAX_PLAYERS; i++)
		{
			PLAYERSTATS		stats;

			// Host controls AI's scores + his own...
			if (myResponsibility(i))
			{
				// Update score
				stats = getMultiStats(i);

				// Add recently scored points
				stats.recentKills += stats.killsToAdd;
				stats.totalKills  += stats.killsToAdd;
				stats.recentScore += stats.scoreToAdd;
				stats.totalScore  += stats.scoreToAdd;

				// Zero them out
				stats.killsToAdd = stats.scoreToAdd = 0;

				// Send score to everyone else
				setMultiStats(i, stats, false);
			}
		}
	}

	return true;
}
Beispiel #13
0
// ////////////////////////////////////////////////////////////////////////////
// Send a new Droid to the other players
BOOL SendDroid(const DROID_TEMPLATE* pTemplate, uint32_t x, uint32_t y, uint8_t player, uint32_t id, const INITIAL_DROID_ORDERS *initialOrdersP)
{
	if (!bMultiMessages)
		return true;

	ASSERT(x != 0 && y != 0, "SendDroid: Invalid droid coordinates");
	ASSERT( player < MAX_PLAYERS, "invalid player %u", player);

	// Dont send other droids during campaign setup
	if (ingame.localJoiningInProgress)
	{
		return true;
	}

	// Only send the droid if we are responsible
	if (!myResponsibility(player))
	{
		// Don't build if we are not responsible
		return false;
	}

	debug(LOG_SYNC, "Droid sent with id of %u", id);
	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROID);
	{
		Position pos = { x, y, 0 };
		uint32_t templateID = pTemplate->multiPlayerID;
		BOOL haveInitialOrders = initialOrdersP != NULL;

		NETuint8_t(&player);
		NETuint32_t(&id);
		NETPosition(&pos);
		NETuint32_t(&templateID);
		NETbool(&haveInitialOrders);
		if (haveInitialOrders)
		{
			INITIAL_DROID_ORDERS initialOrders = *initialOrdersP;
			NETuint32_t(&initialOrders.secondaryOrder);
			NETint32_t(&initialOrders.moveToX);
			NETint32_t(&initialOrders.moveToY);
			NETuint32_t(&initialOrders.factoryId);  // For making scripts happy.
		}
	}
	debug(LOG_LIFE, "===> sending Droid from %u id of %u ",player,id);
	return NETend();
}
Beispiel #14
0
// ////////////////////////////////////////////////////////////////////////////
// Droid update information
BOOL SendDroidInfo(const DROID* psDroid, DROID_ORDER order, uint32_t x, uint32_t y, const BASE_OBJECT* psObj, const BASE_STATS *psStats, uint32_t x2, uint32_t y2, uint16_t direction)
{
	if (!bMultiMessages)
		return true;

	if (!myResponsibility(psDroid->player))
	{
		return true;
	}

	QueuedDroidInfo info;
	memset(&info, 0x00, sizeof(info));  // Suppress uninitialised warnings. (The uninitialised values in the queue would be ignored when reading the queue.)

	info.player = psDroid->player;
	info.droidId = psDroid->id;
	info.order = order;
	info.subType = psObj != NULL;
	if (info.subType)
	{
		info.destId = psObj->id;
		info.destType = psObj->type;
	}
	else
	{
		info.x = x;
		info.y = y;
	}
	if (order == DORDER_BUILD || order == DORDER_LINEBUILD)
	{
		info.structRef = psStats->ref;
		info.direction = direction;
	}
	if (order == DORDER_LINEBUILD)
	{
		info.x2 = x2;
		info.y2 = y2;
	}

	// Send later, grouped by order, so multiple droids with the same order can be encoded to much less data.
	queuedOrders.push_back(info);

	return true;
}
Beispiel #15
0
// ////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////
// Score
// We use setMultiStats() to broadcast the score when needed.
bool sendScoreCheck(void)
{
	// Broadcast any changes in other players, but not in FRONTEND!!!
	if (titleMode != MULTIOPTION && titleMode != MULTILIMIT)
	{
		uint8_t			i;

		for (i = 0; i < game.maxPlayers; i++)
		{
			// Host controls AI's scores + his own...
			if (myResponsibility(i))
			{
				// Send score to everyone else
				setMultiStats(i, getMultiStats(i), false);
			}
		}
	}

	return true;
}
Beispiel #16
0
void sendPlayerGameTime()
{
	unsigned player;
	uint32_t latencyTicks = discreteChosenLatency / GAME_TICKS_PER_UPDATE;
	uint32_t checkTime = gameTime;
	uint32_t checkCrc = nextDebugSync();

	for (player = 0; player < game.maxPlayers; ++player)
	{
		if (!myResponsibility(player) && whosResponsible(player) != realSelectedPlayer)
		{
			continue;
		}

		NETbeginEncode(NETgameQueue(player), GAME_GAME_TIME);
			NETuint32_t(&latencyTicks);
			NETuint32_t(&checkTime);
			NETuint32_tLarge(&checkCrc);
			NETuint16_t(&wantedLatency);
		NETend();
	}
}
Beispiel #17
0
// ////////////////////////////////////////////////////////////////////////////
// add an artifact on destruction if required.
void  technologyGiveAway(const STRUCTURE *pS)
{
	uint8_t			count = 1;
	FEATURE_TYPE	type = FEAT_GEN_ARTE;

	// If a fully built factory (or with modules under construction) which is our responsibility got destroyed
	if (pS->pStructureType->type == REF_FACTORY && (pS->status == SS_BUILT || pS->currentBuildPts >= pS->body)
	 && myResponsibility(pS->player))
	{
		uint32_t x = map_coord(pS->pos.x);
		uint32_t y = map_coord(pS->pos.y);
		uint32_t id = generateNewObjectId();

		// Pick a tile to place the artifact
		if (!pickATileGen(&x, &y, LOOK_FOR_EMPTY_TILE, zonedPAT))
		{
			ASSERT(false, "technologyGiveAway: Unable to find a free location");
		}

		NETbeginEncode(NETgameQueue(selectedPlayer), GAME_ARTIFACTS);
		{
			/* Make sure that we don't have to violate the constness of pS.
			 * Since the nettype functions aren't const correct when sending
			 */
			uint8_t player = pS->player;

			NETuint8_t(&count);
			NETenum(&type);
			NETuint32_t(&x);
			NETuint32_t(&y);
			NETuint32_t(&id);
			NETuint8_t(&player);
		}
		NETend();
	}

	return;
}
void recvMultiStats(NETQUEUE queue)
{
	uint32_t playerIndex;

	NETbeginDecode(queue, NET_PLAYER_STATS);
		// Retrieve the ID number of the player for which we need to
		// update the stats
		NETuint32_t(&playerIndex);

		if (playerIndex >= MAX_PLAYERS)
		{
			NETend();
			return;
		}


		if (playerIndex != queue.index && queue.index != NET_HOST_ONLY)
		{
			HandleBadParam("NET_PLAYER_STATS given incorrect params.", playerIndex, queue.index);
			NETend();
			return;
		}

		// we don't what to update ourselves, we already know our score (FIXME: rewrite setMultiStats())
		if (!myResponsibility(playerIndex))
		{
			// Retrieve the actual stats
			NETuint32_t(&playerStats[playerIndex].played);
			NETuint32_t(&playerStats[playerIndex].wins);
			NETuint32_t(&playerStats[playerIndex].losses);
			NETuint32_t(&playerStats[playerIndex].totalKills);
			NETuint32_t(&playerStats[playerIndex].totalScore);
			NETuint32_t(&playerStats[playerIndex].recentKills);
			NETuint32_t(&playerStats[playerIndex].recentScore);
		}
	NETend();
}
Beispiel #19
0
// ///////////////////////////////////////////////////////////////////////////
// send a droid info packet.
static BOOL sendDroidCheck(void)
{
	DROID			*pD, **ppD;
	uint8_t			i, count;
	static UDWORD	lastSent = 0;		// Last time a struct was sent.
	UDWORD			toSend = 12;

	if (lastSent > gameTime)
	{
		lastSent= 0;
	}

	// Only send a struct send if not done recently
	if (gameTime - lastSent < DROID_PERIOD)
	{
		return true;
	}

	lastSent = gameTime;


	if (!isInSync())  // Don't really send anything, unless out of synch.
	{
		NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_DROID);
	}

		// Allocate space for the list of droids to send
		ppD = alloca(sizeof(DROID *) * toSend);

		// Get the list of droids to sent
		for (i = 0, count = 0; i < toSend; i++)
		{
			pD = pickADroid();

			if (pD == NULL || (pD->gameCheckDroid != NULL && ((PACKAGED_CHECK *)pD->gameCheckDroid)->gameTime > gameTime))
			{
				continue;  // Didn't find a droid, or droid was synched recently.
			}

			// If the droid is ours add it to the list
			if (myResponsibility(pD->player))
			{
				ppD[count++] = pD;
			}
			free(pD->gameCheckDroid);
			pD->gameCheckDroid = (PACKAGED_CHECK *)malloc(sizeof(PACKAGED_CHECK));
			*(PACKAGED_CHECK *)pD->gameCheckDroid = packageCheck(pD);
		}

		if (!isInSync())  // Don't really send anything, unless out of synch.
		{
			// Send the number of droids to expect
			NETuint8_t(&count);
			NETuint32_t(&gameTime);  // Send game time.

			// Add the droids to the packet
			for (i = 0; i < count; i++)
			{
				NETPACKAGED_CHECK((PACKAGED_CHECK *)ppD[i]->gameCheckDroid);
			}
		}

	if (!isInSync())  // Don't really send anything, unless out of synch.
	{
		return NETend();
	}

	return true;
}
Beispiel #20
0
static void displayMultiPlayer(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, PIELIGHT *pColours)
{
	char			str[128];
	UDWORD			x					= xOffset+psWidget->x;
	UDWORD			y					= yOffset+psWidget->y;
	UDWORD			player = psWidget->UserData; //get the in game player number.
	Position		position;
	Vector3i 		rotation;

	if( responsibleFor(player,0) )
	{
		displayExtraGubbins(widgGetFromID(psWScreen,MULTIMENU_FORM)->height);
	}

	iV_SetFont(font_regular);											// font
	iV_SetTextColour(WZCOL_TEXT_BRIGHT);

	if(isHumanPlayer(player) || (game.type == SKIRMISH && player<game.maxPlayers) )
	{
		ssprintf(str, "%d: %s", NetPlay.players[player].position, getPlayerName(player));
		if (isHumanPlayer(player))
		{
			SetPlayerTextColor(alliances[selectedPlayer][player], player);
		}
		else
		{
			SetPlayerTextColor(alliances[selectedPlayer][player], player);
		}

		while(iV_GetTextWidth(str) >= (MULTIMENU_C0-MULTIMENU_C2-10) )
		{
			str[strlen(str)-1]='\0';
		}
		iV_DrawText(str, x+MULTIMENU_C2, y+MULTIMENU_FONT_OSET);

		//c3-7 alliance
		//manage buttons by showing or hiding them. gifts only in campaign,
		{
			if(game.alliance != NO_ALLIANCES)
			{
				if(alliances[selectedPlayer][player] == ALLIANCE_FORMED)
				{
					if(player != selectedPlayer &&  !giftsUp[player] )
					{
						if (game.alliance != ALLIANCES_TEAMS)
						{
							widgReveal(psWScreen,MULTIMENU_GIFT_RAD+ player);
							widgReveal(psWScreen,MULTIMENU_GIFT_RES+ player);
						}
						widgReveal(psWScreen,MULTIMENU_GIFT_DRO+ player);
						widgReveal(psWScreen,MULTIMENU_GIFT_POW+ player);
						giftsUp[player] = true;
					}
				}
				else
				{
					if(player != selectedPlayer && giftsUp[player])
					{
						if (game.alliance != ALLIANCES_TEAMS)
						{
							widgHide(psWScreen,MULTIMENU_GIFT_RAD+ player);
							widgHide(psWScreen,MULTIMENU_GIFT_RES+ player);
						}
						widgHide(psWScreen,MULTIMENU_GIFT_DRO+ player);
						widgHide(psWScreen,MULTIMENU_GIFT_POW+ player);
						giftsUp[player] = false;
					}
				}
			}
		}
	}
	if(isHumanPlayer(player))
	{
		SetPlayerTextColor(alliances[selectedPlayer][player], player);

		// Let's use the real score for MP games
		if (NetPlay.bComms)
		{
			//c8:score,
			if (Cheated)
			{
				sprintf(str,"(cheated)");
			}
			else
			{
				sprintf(str,"%d",getMultiStats(player).recentScore);
			}
			iV_DrawText(str, x+MULTIMENU_C8, y+MULTIMENU_FONT_OSET);

			//c9:kills,
			sprintf(str,"%d",getMultiStats(player).recentKills);
			iV_DrawText(str, x+MULTIMENU_C9, y+MULTIMENU_FONT_OSET);
		}
		else
		{
			// estimate of score for skirmish games
			sprintf(str,"%d",ingame.skScores[player][0]);
			iV_DrawText(str, x+MULTIMENU_C8, y+MULTIMENU_FONT_OSET);
			// estimated kills
			sprintf(str,"%d",ingame.skScores[player][1]);
			iV_DrawText(str, x+MULTIMENU_C9, y+MULTIMENU_FONT_OSET);
		}

		if(!getDebugMappingStatus())
		{
			//only show player's units, and nobody elses.
			//c10:units
			if (myResponsibility(player))
			{
				SetPlayerTextColor(alliances[selectedPlayer][player], player);
				sprintf(str, "%d", getNumDroids(player) + getNumTransporterDroids(player));
				iV_DrawText(str, x+MULTIMENU_C10, y+MULTIMENU_FONT_OSET);
			}

			if (runningMultiplayer())
			{
				//c11:ping
				if (player != selectedPlayer)
				{
					if (ingame.PingTimes[player] >= 2000)
					{
						sprintf(str,"???");
					}
					else
					{
						sprintf(str, "%d", ingame.PingTimes[player]);
					}
					iV_DrawText(str, x+MULTIMENU_C11, y+MULTIMENU_FONT_OSET);
				}
			}
			else
			{
				int num;
				STRUCTURE *temp;
				// NOTE, This tallys up *all* the structures you have. Test out via 'start with no base'.
				for (num = 0, temp = apsStructLists[player]; temp != NULL;num++,temp = temp->psNext);
				//c11: Structures
				sprintf(str, "%d", num);
				iV_DrawText(str, x+MULTIMENU_C11, y+MULTIMENU_FONT_OSET);
			}
		}
	}
	else
	{
		SetPlayerTextColor(alliances[selectedPlayer][player], player);

		// Let's use the real score for MP games
		if (NetPlay.bComms)
		{
			//c8:score,
			if (Cheated)
			{
				sprintf(str,"(cheated)");
			}
			else
			{
				sprintf(str,"%d",getMultiStats(player).recentScore);
			}
			iV_DrawText(str, x+MULTIMENU_C8, y+MULTIMENU_FONT_OSET);

			//c9:kills,
			sprintf(str,"%d",getMultiStats(player).recentKills);
			iV_DrawText(str, x+MULTIMENU_C9, y+MULTIMENU_FONT_OSET);
		}
		else
		{
			// estimate of score for skirmish games
			sprintf(str,"%d",ingame.skScores[player][0]);
			iV_DrawText(str, x+MULTIMENU_C8, y+MULTIMENU_FONT_OSET);
			// estimated kills
			sprintf(str,"%d",ingame.skScores[player][1]);
			iV_DrawText(str, x+MULTIMENU_C9, y+MULTIMENU_FONT_OSET);
		}
	}

	/* Display player power instead of number of played games
	  * and number of units instead of ping when in debug mode
	  */
	if(getDebugMappingStatus())			//Won't pass this when in both release and multiplayer modes
	{
		//c10: Total number of player units in possession
		sprintf(str,"%d",getNumDroids(player) + getNumTransporterDroids(player));
		iV_DrawText(str, x+MULTIMENU_C10, y+MULTIMENU_FONT_OSET);

		//c11: Player power
		sprintf(str, "%u", (int)getPower(player));
		iV_DrawText(str, MULTIMENU_FORM_X+MULTIMENU_C11, y+MULTIMENU_FONT_OSET);
	}

	// a droid of theirs.
	if(apsDroidLists[player])
	{
		pie_SetGeometricOffset( MULTIMENU_FORM_X+MULTIMENU_C1 ,y+MULTIMENU_PLAYER_H);
		rotation.x = -15;
		rotation.y = 45;
		rotation.z = 0;
		position.x = 0;
		position.y = 0;
		position.z = 2000;		//scale them!

		displayComponentButtonObject(apsDroidLists[player],&rotation,&position,false, 100);
	}

	// clean up widgets if player leaves while menu is up.
	if(!isHumanPlayer(player) && !(game.type == SKIRMISH && player<game.maxPlayers))
	{
		if(widgGetFromID(psWScreen,MULTIMENU_CHANNEL+player))
		{
			widgDelete(psWScreen,MULTIMENU_CHANNEL+ player);
		}

		if(widgGetFromID(psWScreen,MULTIMENU_ALLIANCE_BASE+player) )
		{
			widgDelete(psWScreen,MULTIMENU_ALLIANCE_BASE+ player);
			widgDelete(psWScreen,MULTIMENU_GIFT_RAD+ player);
			widgDelete(psWScreen,MULTIMENU_GIFT_RES+ player);
			widgDelete(psWScreen,MULTIMENU_GIFT_DRO+ player);
			widgDelete(psWScreen,MULTIMENU_GIFT_POW+ player);
			giftsUp[player] = false;
		}
	}
}
Beispiel #21
0
// ////////////////////////////////////////////////////////////////////////
// Send structure information.
static BOOL sendStructureCheck(void)
{
	uint8_t         player;

	if (structureCheckLastSent > gameTime)
	{
		structureCheckLastSent = 0;
	}
	// Only send a struct send if not done recently
	if (gameTime - structureCheckLastSent < STRUCT_PERIOD)
	{
		return true;
	}

	structureCheckLastSent = gameTime;

	for (player = 0; player < MAX_PLAYERS; ++player)
	{
		STRUCTURE       *pS = pickAStructure(player);
		bool            hasCapacity = true;
		uint8_t         capacity;

		// Only send info about complete buildings
		if (pS == NULL || pS->status != SS_BUILT)
		{
			structureCheckLastId[player] = 0;
			continue;
		}

		switch (pS->pStructureType->type)
		{
			case REF_RESEARCH:
				capacity = pS->pFunctionality->researchFacility.capacity;
				break;
			case REF_FACTORY:
			case REF_VTOL_FACTORY:
				capacity = pS->pFunctionality->factory.capacity;
				break;
			case REF_POWER_GEN:
				capacity = pS->pFunctionality->powerGenerator.capacity;
			default:
				hasCapacity = false;
				break;
		}
		structureCheckLastId[player] = pS->id;
		structureCheckLastBody[player] = pS->body;
		structureCheckLastDirection[player] = pS->rot;
		structureCheckLastType[player] = pS->pStructureType->type;

		if (myResponsibility(player))
		{
			if (!isInSync())  // Don't really send anything, unless out of synch.
			{
				NETbeginEncode(NETgameQueue(selectedPlayer), GAME_CHECK_STRUCT);
					NETuint8_t(&player);
					NETuint32_t(&gameTime);
					NETuint32_t(&pS->id);
					NETuint32_t(&pS->body);
					NETuint32_t(&pS->pStructureType->type);
					NETRotation(&pS->rot);
					if (hasCapacity)
					{
						NETuint8_t(&capacity);
					}
				NETend();
			}
		}
	}

	return true;
}
Beispiel #22
0
bool stageTwoInitialise(void)
{
	int i;

	debug(LOG_WZ, "== stageTwoInitalise ==");

	// make sure we clear on loading; this a bad hack to fix a bug when
	// loading a savegame where we are building a lassat
	for (i = 0; i < MAX_PLAYERS; i++)
	{
		setLasSatExists(false, i);
	}

	if(bMultiPlayer)
	{
		if (!multiTemplateSetup())
		{
			return false;
		}
	}

	if (!dispInitialise())		/* Initialise the display system */
	{
		return false;
	}

	if(!initMiscImds())			/* Set up the explosions */
	{
		iV_ShutDown();
		debug( LOG_FATAL, "Can't find all the explosions graphics?" );
		abort();
		return false;
	}

	if (!cmdDroidInit())
	{
		return false;
	}

   	/* Shift the interface initialisation here temporarily so that it
   		can pick up the stats after they have been loaded */

	if (!intInitialise())
	{
		return false;
	}

	if (!initMessage())			/* Initialise the message heaps */
	{
		return false;
	}

	if (!gwInitialise())
	{
		return false;
	}

	// keymappings
	keyClearMappings();
	keyInitMappings(false);

	// Set the default uncoloured cursor here, since it looks slightly
	// better for menus and such.
	wzSetCursor(CURSOR_DEFAULT);

	SetFormAudioIDs(ID_SOUND_WINDOWOPEN,ID_SOUND_WINDOWCLOSE);

	// Setup game queues.
	// Don't ask why this doesn't go in stage three. In fact, don't even ask me what stage one/two/three is supposed to mean, it seems about as descriptive as stage doStuff, stage doMoreStuff and stage doEvenMoreStuff...
	debug(LOG_MAIN, "Init game queues, I am %d.", selectedPlayer);
	sendQueuedDroidInfo();  // Discard any pending orders which could later get flushed into the game queue.
	for (i = 0; i < MAX_PLAYERS; ++i)
	{
		NETinitQueue(NETgameQueue(i));

		if (!myResponsibility(i))
		{
			NETsetNoSendOverNetwork(NETgameQueue(i));
		}
	}

	debug(LOG_MAIN, "stageTwoInitialise: done");

	return true;
}
Beispiel #23
0
/* Do the AI for a droid */
void aiUpdateDroid(DROID *psDroid)
{
	BASE_OBJECT	*psTarget;
	BOOL		lookForTarget,updateTarget;

	ASSERT(psDroid != NULL, "Invalid droid pointer");
	if (!psDroid || isDead((BASE_OBJECT *)psDroid))
	{
		return;
	}

	// HACK: we always want to update orders when NOT running a MP game,
	// and we don't want to update when the droid belongs to another human player
	if (!myResponsibility(psDroid->player) && bMultiPlayer
		  && isHumanPlayer(psDroid->player))
	{
		return;		// we should not order this droid around
	}
	
	lookForTarget = false;
	updateTarget = false;
	
	// look for a target if doing nothing
	if (orderState(psDroid, DORDER_NONE) ||
		orderState(psDroid, DORDER_GUARD) ||
		orderState(psDroid, DORDER_TEMP_HOLD))
	{
		lookForTarget = true;
	}
	// but do not choose another target if doing anything while guarding
	if (orderState(psDroid, DORDER_GUARD) &&
		(psDroid->action != DACTION_NONE))
	{
		lookForTarget = false;
	}
	// except when self-repairing
	if (psDroid->action == DACTION_DROIDREPAIR &&
	    psDroid->psActionTarget[0] == (BASE_OBJECT *)psDroid)
	{
		lookForTarget = true;
	}
	// don't look for a target if sulking
	if (psDroid->action == DACTION_SULK)
	{
		lookForTarget = false;
	}

	/* Only try to update target if already have some target */
	if (psDroid->action == DACTION_ATTACK ||
		psDroid->action == DACTION_MOVEFIRE ||
		psDroid->action == DACTION_MOVETOATTACK ||
		psDroid->action == DACTION_ROTATETOATTACK)
	{
		updateTarget = true;
	}
	if ((orderState(psDroid, DORDER_OBSERVE) || orderState(psDroid, DORDER_ATTACKTARGET)) &&
	    psDroid->psTarget && aiObjectIsProbablyDoomed(psDroid->psTarget))
	{
		lookForTarget = true;
		updateTarget = false;
	}

	/* Don't update target if we are sent to attack and reached
		attack destination (attacking our target) */
	if (orderState(psDroid, DORDER_ATTACK) && psDroid->psActionTarget[0] == psDroid->psTarget)
	{
		updateTarget = false;
	}

	// don't look for a target if there are any queued orders
	if (psDroid->listSize > 0)
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// horrible check to stop droids looking for a target if
	// they would switch to the guard order in the order update loop
	if ((psDroid->order == DORDER_NONE) &&
		(psDroid->player == selectedPlayer) &&
		!isVtolDroid(psDroid) &&
		secondaryGetState(psDroid, DSO_HALTTYPE) == DSS_HALT_GUARD)
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// don't allow units to start attacking if they will switch to guarding the commander
	if(hasCommander(psDroid))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	if(bMultiPlayer && isVtolDroid(psDroid) && isHumanPlayer(psDroid->player))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// do not look for a target if droid is currently under direct control.
	if(driveModeActive() && (psDroid == driveGetDriven())) {
		lookForTarget = false;
		updateTarget = false;
	}

	// CB and VTOL CB droids can't autotarget.
	if (psDroid->droidType == DROID_SENSOR && !standardSensorDroid(psDroid))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// do not attack if the attack level is wrong
	if (secondaryGetState(psDroid, DSO_ATTACK_LEVEL) != DSS_ALEV_ALWAYS)
	{
		lookForTarget = false;
	}

	/* For commanders and non-assigned non-commanders:
	 look for a better target once in a while */
	if(!lookForTarget && updateTarget)
	{
		if((psDroid->numWeaps > 0) && !hasCommander(psDroid))	//not assigned to commander
		{
			if((psDroid->id + gameTime)/TARGET_UPD_SKIP_FRAMES != (psDroid->id + gameTime - deltaGameTime)/TARGET_UPD_SKIP_FRAMES)
			{
				unsigned int i;

				(void)updateAttackTarget((BASE_OBJECT*)psDroid, 0); // this function always has to be called on weapon-slot 0 (even if ->numWeaps == 0)

				//updates all targets
				for (i = 1; i < psDroid->numWeaps; ++i)
				{
					(void)updateAttackTarget((BASE_OBJECT*)psDroid, i);
				}
			}
		}
	}

	/* Null target - see if there is an enemy to attack */

	if (lookForTarget && !updateTarget)
	{
		if (psDroid->droidType == DROID_SENSOR)
		{
			if (aiChooseSensorTarget((BASE_OBJECT *)psDroid, &psTarget))
			{
				orderDroidObj(psDroid, DORDER_OBSERVE, psTarget);
			}
		}
		else
		{
			if (aiChooseTarget((BASE_OBJECT *)psDroid, &psTarget, 0, true, NULL))
			{
				orderDroidObj(psDroid, DORDER_ATTACKTARGET, psTarget);
			}
		}
	}
}