Beispiel #1
0
/** Receive droid and transporter loading information
 *
 *  \sa sendDroidEmbark(),sendDroidDisEmbark(),recvDroidDisEmbark()
 */
BOOL recvDroidEmbark(NETQUEUE queue)
{
	DROID* psDroid;
	DROID* psTransporterDroid;
	BOOL bDroidRemoved;

	NETbeginDecode(queue, GAME_DROIDEMBARK);
	{
		uint8_t player;
		uint32_t droidID;
		uint32_t transporterID;

		NETuint8_t(&player);
		NETuint32_t(&droidID);
		NETuint32_t(&transporterID);

		// we have to find the droid on our (local) list first.
		if (!IdToDroid(droidID, player, &psDroid))
		{
			NETend();
			// Possible it already died? (sync error?)
			debug(LOG_WARNING, "player's %d droid %d wasn't found?", player,droidID);
			return false;
		}
		if (!IdToDroid(transporterID, player, &psTransporterDroid))
		{
			NETend();
			// Possible it already died? (sync error?)
			debug(LOG_WARNING, "player's %d transport droid %d wasn't found?", player,transporterID);
			return false;
		}

		if (psDroid == NULL)
		{
			// how can this happen?
			return true;
		}

		// Take it out of the world without destroying it (just removes it from the droid list)
		bDroidRemoved = droidRemove(psDroid, apsDroidLists);

		// Init the order for when disembark
		psDroid->order = DORDER_NONE;
		setDroidTarget(psDroid, NULL);
		psDroid->psTarStats = NULL;

		if (bDroidRemoved)
		{
			// and now we need to add it to their transporter group!
			grpJoin(psTransporterDroid->psGroup, psDroid);
		}
		else
		{
			// possible sync error?
			debug(LOG_WARNING, "Eh? Where did unit %d go? Couldn't load droid onto transporter.", droidID);
		}
	}
	NETend();
	return true;
}
Beispiel #2
0
// recv
BOOL recvDroidSecondary(NETQUEUE queue)
{
	DROID*          psDroid;
	SECONDARY_ORDER sec = DSO_ATTACK_RANGE;
	SECONDARY_STATE state = DSS_NONE;

	NETbeginDecode(queue, GAME_SECONDARY);
	{
		uint8_t player;
		uint32_t droid;

		NETuint8_t(&player);
		NETuint32_t(&droid);
		NETenum(&sec);
		NETenum(&state);

		// If we can not find the droid should we not ask for it?
		if (!IdToDroid(droid, player, &psDroid))
		{
			NETend();
			return false;
		}
	}
	NETend();

	// Set the droids secondary order
	turnOffMultiMsg(true);
	secondarySetState(psDroid, sec, state);
	turnOffMultiMsg(false);

	return true;
}
Beispiel #3
0
// accept and process incoming ping messages.
bool recvPing(NETQUEUE queue)
{
	bool	isNew = false;
	uint8_t	sender, us = selectedPlayer;
	uint8_t challenge[sizeof(pingChallenge)];
	EcKey::Sig challengeResponse;

	NETbeginDecode(queue, NET_PING);
	NETuint8_t(&sender);
	NETbool(&isNew);
	if (isNew)
	{
		NETbin(challenge, sizeof(pingChallenge));
	}
	else
	{
		NETbytes(&challengeResponse);
	}
	NETend();

	if (sender >= MAX_PLAYERS)
	{
		debug(LOG_ERROR, "Bad NET_PING packet, sender is %d", (int)sender);
		return false;
	}

	// If this is a new ping, respond to it
	if (isNew)
	{
		challengeResponse = getMultiStats(us).identity.sign(&challenge, sizeof(pingChallenge));

		NETbeginEncode(NETnetQueue(sender), NET_PING);
		// We are responding to a new ping
		isNew = false;

		NETuint8_t(&us);
		NETbool(&isNew);
		NETbytes(&challengeResponse);
		NETend();
	}
	// They are responding to one of our pings
	else
	{
		if (!getMultiStats(sender).identity.empty() && !getMultiStats(sender).identity.verify(challengeResponse, pingChallenge, sizeof(pingChallenge)))
		{
			// Either bad signature, or we sent more than one ping packet and this response is to an older one than the latest.
			debug(LOG_NEVER, "Bad and/or old NET_PING packet, alleged sender is %d", (int)sender);
			return false;
		}

		// Work out how long it took them to respond
		ingame.PingTimes[sender] = (realTime - PingSend[sender]) / 2;

		// Note that we have received it
		PingSend[sender] = 0;
	}

	return true;
}
// ////////////////////////////////////////////////////////////////////////////
// Network File packet processor.
bool recvMapFileRequested(NETQUEUE queue)
{
	//char mapStr[256],mapName[256],fixedname[256];
	uint32_t player;

	PHYSFS_sint64 fileSize_64;
	PHYSFS_file	*pFileHandle;

	if(!NetPlay.isHost)				// only host should act
	{
		ASSERT(false, "Host only routine detected for client!");
		return false;
	}

	//	Check to see who wants the file
	NETbeginDecode(queue, NET_FILE_REQUESTED);
	NETuint32_t(&player);
	NETend();

	if (!NetPlay.players[player].wzFile.isSending)
	{
		NetPlay.players[player].needFile = true;
		NetPlay.players[player].wzFile.isCancelled = false;
		NetPlay.players[player].wzFile.isSending = true;

		LEVEL_DATASET *mapData = levFindDataSet(game.map, &game.hash);

		addConsoleMessage("Map was requested: SENDING MAP!",DEFAULT_JUSTIFY, SYSTEM_MESSAGE);

		char *mapStr = mapData->realFileName;
		debug(LOG_NET, "Map was requested. Looking for %s", mapStr);

		// Checking to see if file is available...
		pFileHandle = PHYSFS_openRead(mapStr);
		if (pFileHandle == NULL)
		{
			debug(LOG_ERROR, "Failed to open %s for reading: %s", mapStr, PHYSFS_getLastError());
			debug(LOG_FATAL, "You have a map (%s) that can't be located.\n\nMake sure it is in the correct directory and or format! (No map packs!)", mapStr);
			// NOTE: if we get here, then the game is basically over, The host can't send the file for whatever reason...
			// Which also means, that we can't continue.
			debug(LOG_NET, "***Host has a file issue, and is being forced to quit!***");
			NETbeginEncode(NETbroadcastQueue(), NET_HOST_DROPPED);
			NETend();
			abort();
		}

		// get the file's size.
		fileSize_64 = PHYSFS_fileLength(pFileHandle);
		debug(LOG_NET, "File is valid, sending [directory: %s] %s to client %u", PHYSFS_getRealDir(mapStr), mapStr, player);

		NetPlay.players[player].wzFile.pFileHandle = pFileHandle;
		NetPlay.players[player].wzFile.fileSize_32 = (int32_t) fileSize_64;		//we don't support 64bit int nettypes.
		NetPlay.players[player].wzFile.currPos = 0;

		NETsendFile(game.map, game.hash, player);
	}
	return true;
}
Beispiel #5
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();
}
// process a destroy feature msg.
bool recvDestroyFeature(NETQUEUE queue)
{
	FEATURE *pF;
	uint32_t	id;

	NETbeginDecode(queue, GAME_DEBUG_REMOVE_FEATURE);
		NETuint32_t(&id);
	NETend();

	if (!getDebugMappingStatus() && bMultiPlayer)
	{
		debug(LOG_WARNING, "Failed to remove feature for player %u.", NetPlay.players[queue.index].position);
		return false;
	}

	pF = IdToFeature(id,ANYPLAYER);
	if (pF == NULL)
	{
		debug(LOG_FEATURE, "feature id %d not found (probably already destroyed)", id);
		return false;
	}

	debug(LOG_FEATURE, "p%d feature id %d destroyed (%s)", pF->player, pF->id, pF->psStats->pName);
	// Remove the feature locally
	turnOffMultiMsg(true);
	destroyFeature(pF, gameTime - deltaGameTime + 1);  // deltaGameTime is actually 0 here, since we're between updates. However, the value of gameTime - deltaGameTime + 1 will not change when we start the next tick.
	turnOffMultiMsg(false);

	return true;
}
BOOL recvAlliance(BOOL allowAudio)
{
	uint8_t to, from, state;
	int32_t value;

	NETbeginDecode(NET_ALLIANCE);
		NETuint8_t(&from);
		NETuint8_t(&to);
		NETuint8_t(&state);
		NETint32_t(&value);
	NETend();

	switch (state)
	{
		case ALLIANCE_NULL:
			break;
		case ALLIANCE_REQUESTED:
			requestAlliance(from, to, false, allowAudio);
			break;
		case ALLIANCE_FORMED:
			formAlliance(from, to, false, allowAudio, true);
			break;
		case ALLIANCE_BROKEN:
			breakAlliance(from, to, false, allowAudio);
			break;
		default:
			debug(LOG_ERROR, "Unknown alliance state recvd.");
			return false;
			break;
	}

	return true;
}
Beispiel #8
0
void recvPlayerGameTime(NETQUEUE queue)
{
	uint32_t latencyTicks = 0;
	uint32_t checkTime = 0;
	uint32_t checkCrc = 0;

	NETbeginDecode(queue, GAME_GAME_TIME);
		NETuint32_t(&latencyTicks);
		NETuint32_t(&checkTime);
		NETuint32_tLarge(&checkCrc);
		NETuint16_t(&wantedLatencies[queue.index]);
	NETend();

	gameQueueTime[queue.index] = checkTime + latencyTicks * GAME_TICKS_PER_UPDATE;  // gameTime when future messages shall be processed.

	gameQueueCheckTime[queue.index] = checkTime;
	gameQueueCheckCrc[queue.index] = checkCrc;
	if (!checkDebugSync(checkTime, checkCrc))
	{
		crcError = true;
		if (NetPlay.players[queue.index].allocated)
		{
			NETsetPlayerConnectionStatus(CONNECTIONSTATUS_DESYNC, queue.index);
		}
	}

	if (updateReadyTime == 0 && checkPlayerGameTime(NET_ALL_PLAYERS))
	{
		updateReadyTime = wzGetTicks();  // This is the time we were able to tick.
	}
}
Beispiel #9
0
// ////////////////////////////////////////////////////////////////////////////
// Set Player's stats
// send stats to all players when bLocal is false
BOOL setMultiStats(SDWORD player, PLAYERSTATS plStats, BOOL bLocal)
{
	uint32_t playerIndex = (uint32_t)player;

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

	// First copy over the data into our local array
	memcpy(&playerStats[playerIndex], &plStats, sizeof(plStats));

	if (!bLocal)
	{
		// Now send it to all other players
		NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_STATS);
			// Send the ID of the player's stats we're updating
			NETuint32_t(&playerIndex);

			// Send over 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();
	}

	return true;
}
Beispiel #10
0
void recvMultiPlayerFeature(NETQUEUE queue)
{
	FEATURE_TYPE subType = FEAT_TREE;  // Dummy initialisation.
	uint32_t     x, y, id;
	unsigned int i;

	NETbeginDecode(queue, GAME_FEATURES);
	{
		NETenum(&subType);
		NETuint32_t(&x);
		NETuint32_t(&y);
		NETuint32_t(&id);
	}
	NETend();

	// Find the feature stats list that contains the feature type we want to build
	for (i = 0; i < numFeatureStats; ++i)
	{
		// If we found the correct feature type
		if (asFeatureStats[i].subType == subType)
		{
			// Create a feature of the specified type at the given location
			FEATURE *result = buildFeature(&asFeatureStats[i], x, y, false);
			result->id = id;
			break;
		}
	}
}
Beispiel #11
0
// recv lassat info on the receiving end.
BOOL recvLasSat(NETQUEUE queue)
{
	BASE_OBJECT	*psObj;
	UBYTE		player,targetplayer;
	STRUCTURE	*psStruct;
	uint32_t	id,targetid;

	// TODO Add some kind of checking, so that things don't get lasatted by bunkers.
	NETbeginDecode(queue, GAME_LASSAT);
		NETuint8_t(&player);
		NETuint32_t(&id);
		NETuint32_t(&targetid);
		NETuint8_t(&targetplayer);
	NETend();

	psStruct = IdToStruct (id, player);
	psObj	 = IdToPointer(targetid, targetplayer);

	if (psStruct && psObj)
	{
		// Give enemy no quarter, unleash the lasat
		proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0);
		psStruct->asWeaps[0].lastFired = gameTime;

		// Play 5 second countdown message
		audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z);
	}

	return true;
}
Beispiel #12
0
// ////////////////////////////////////////////////////////////////////////////
// give radar information
void giftRadar(uint8_t from, uint8_t to, bool send)
{
	uint32_t dummy = 0;

	if (send)
	{
		uint8_t subType = RADAR_GIFT;

		NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT);
		NETuint8_t(&subType);
		NETuint8_t(&from);
		NETuint8_t(&to);
		NETuint32_t(&dummy);
		NETend();
	}
	// If we are recieving the gift
	else
	{
		hqReward(from, to);
		if (to == selectedPlayer)
		{
			CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives You A Visibility Report"), getPlayerName(from)));
		}
	}
}
Beispiel #13
0
static void giftAutoGame(uint8_t from, uint8_t to, bool send)
{
	uint32_t dummy = 0;

	if (send)
	{
		uint8_t subType = AUTOGAME_GIFT;

		NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT);
		NETuint8_t(&subType);
		NETuint8_t(&from);
		NETuint8_t(&to);
		NETuint32_t(&dummy);
		NETend();
		debug(LOG_SYNC, "We (%d) are telling %d we want to enable/disable a autogame", from, to);
	}
	// If we are recieving the "gift"
	else
	{
		if (to == selectedPlayer)
		{
			NetPlay.players[from].autoGame = !NetPlay.players[from].autoGame ;
			CONPRINTF(ConsoleString, (ConsoleString, "%s has %s the autoGame command", getPlayerName(from), NetPlay.players[from].autoGame ? "Enabled" : "Disabled"));
			debug(LOG_SYNC, "We (%d) are being told that %d has %s autogame", selectedPlayer, from, NetPlay.players[from].autoGame ? "Enabled" : "Disabled");
		}
	}
}
Beispiel #14
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();

	if (!canGiveOrdersFor(queue.index, from))
	{
		debug(LOG_WARNING, "Gift (%d) from %d, to %d, queue.index %d", (int)type, (int)from, (int)to, (int)queue.index);
		syncDebug("Wrong player.");
		return false;
	}

	// 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 STRUCTURE_GIFT:
		audioTrack = ID_GIFT;
		recvGiftStruct(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;
	case AUTOGAME_GIFT:
		audioTrack = ID_SOUND_NEXUS_SYNAPTIC_LINK;
		giftAutoGame(from, to, false);
		break;
	default:
		debug(LOG_ERROR, "recvGift: Unknown Gift recvd");
		return false;
		break;
	}

	// If we are on the receiving end play an audio alert.
	if (bMultiPlayer && to == selectedPlayer)
	{
		audio_QueueTrack(audioTrack);
	}
	return true;
}
// recv lassat info on the receiving end.
BOOL recvLasSat()
{
    BASE_OBJECT	*psObj;
    UBYTE		player,targetplayer;
    STRUCTURE	*psStruct;
    uint32_t	id,targetid;

    NETbeginDecode(NET_LASSAT);
    NETuint8_t(&player);
    NETuint32_t(&id);
    NETuint32_t(&targetid);
    NETuint8_t(&targetplayer);
    NETend();

    psStruct = IdToStruct (id, player);
    psObj	 = IdToPointer(targetid, targetplayer);

    if (psStruct && psObj)
    {
        // Give enemy no quarter, unleash the lasat
        proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos, psObj, true, 0);

        // Play 5 second countdown message
        audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y, psObj->pos.z);
    }

    return true;
}
Beispiel #16
0
// send complete game info set!
void sendOptions()
{
	bool dummy = true;
	unsigned int i;

	if (!NetPlay.isHost || !bHosted)  // Only host should act, and only if the game hasn't started yet.
	{
		ASSERT(false, "Host only routine detected for client or not hosting yet!");
		return;
	}

	NETbeginEncode(NETbroadcastQueue(), NET_OPTIONS);

	// First send information about the game
	NETuint8_t(&game.type);
	NETstring(game.map, 128);
	NETuint8_t(&game.maxPlayers);
	NETstring(game.name, 128);
	NETbool(&dummy);
	NETuint32_t(&game.power);
	NETuint8_t(&game.base);
	NETuint8_t(&game.alliance);
	NETbool(&game.scavengers);

	for (i = 0; i < MAX_PLAYERS; i++)
	{
		NETuint8_t(&game.skDiff[i]);
	}

	// Send the list of who is still joining
	for (i = 0; i < MAX_PLAYERS; i++)
	{
		NETbool(&ingame.JoiningInProgress[i]);
	}

	// Same goes for the alliances
	for (i = 0; i < MAX_PLAYERS; i++)
	{
		unsigned int j;

		for (j = 0; j < MAX_PLAYERS; j++)
		{
			NETuint8_t(&alliances[i][j]);
		}
	}

	// Send the number of structure limits to expect
	NETuint32_t(&ingame.numStructureLimits);
	debug(LOG_NET, "(Host) Structure limits to process on client is %u", ingame.numStructureLimits);
	// Send the structures changed
	for (i = 0; i < ingame.numStructureLimits; i++)
	{
		NETuint32_t(&ingame.pStructureLimits[i].id);
		NETuint32_t(&ingame.pStructureLimits[i].limit);
	}
	updateLimitFlags();
	NETuint8_t(&ingame.flags);

	NETend();
}
// ////////////////////////////////////////////////////////////////////////////
// Set Player's stats
// send stats to all players when bLocal is false
bool setMultiStats(uint32_t playerIndex, PLAYERSTATS plStats, bool bLocal)
{
	if (playerIndex >= MAX_PLAYERS)
	{
		return true;
	}

	// First copy over the data into our local array
	playerStats[playerIndex] = plStats;

	if (!bLocal)
	{
		// Now send it to all other players
		NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_STATS);
			// Send the ID of the player's stats we're updating
			NETuint32_t(&playerIndex);

			// Send over 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();
	}

	return true;
}
// ////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////
// 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 #19
0
BOOL recvDemolishFinished(NETQUEUE queue)
{
	STRUCTURE	*psStruct;
	DROID		*psDroid;
	uint32_t	structID, droidID;

	NETbeginDecode(queue, GAME_DEMOLISH);
		NETuint32_t(&structID);
		NETuint32_t(&droidID);
	NETend();

	psStruct = IdToStruct(structID, ANYPLAYER);
	if (!IdToDroid(droidID, ANYPLAYER, &psDroid))
	{
		debug(LOG_ERROR, "recvDemolishFinished: Packet with bad droid ID received. Discarding!");
		return false;
	}

	if (psStruct)
	{
		// Demolish it
		// Should never get here, if in synch.
		removeStruct(psStruct, true);
		if (psDroid && psDroid->psTarStats)
		{
			// Update droid if reqd
			psDroid->psTarStats = NULL;
		}
	}

	return true;
}
Beispiel #20
0
// ////////////////////////////////////////////////////////////////////////////
// Accept a droid which was destroyed on another machine
BOOL recvDestroyDroid(NETQUEUE queue)
{
	DROID* psDroid;

	NETbeginDecode(queue, GAME_DROIDDEST);
	{
		uint32_t id;

		// Retrieve the droid
		NETuint32_t(&id);
		if (!IdToDroid(id, ANYPLAYER, &psDroid))
		{
			debug(LOG_DEATH, "droid %d on request from player %d can't be found? Must be dead already?",
					id, queue.index );
			return false;
		}
	}
	NETend();

	// If the droid has not died on our machine yet, destroy it
	if(!psDroid->died)
	{
		turnOffMultiMsg(true);
		debug(LOG_DEATH, "Killing droid %d on request from player %d - huh?", psDroid->id, queue.index);
		destroyDroid(psDroid);
		turnOffMultiMsg(false);
	}
	else
	{
		debug(LOG_DEATH, "droid %d is confirmed dead by player %d.", psDroid->id, queue.index);
	}

	return true;
}
Beispiel #21
0
// ////////////////////////////////////////////////////////////////////////////
// give technologies.
static void giftResearch(uint8_t from, uint8_t to, bool send)
{
	int		i;
	uint32_t	dummy = 0;

	if (send)
	{
		uint8_t giftType = RESEARCH_GIFT;

		NETbeginEncode(NETgameQueue(selectedPlayer), GAME_GIFT);
		NETuint8_t(&giftType);
		NETuint8_t(&from);
		NETuint8_t(&to);
		NETuint32_t(&dummy);
		NETend();
	}
	else if (alliancesCanGiveResearchAndRadar(game.alliance))
	{
		if (to == selectedPlayer)
		{
			CONPRINTF(ConsoleString, (ConsoleString, _("%s Gives You Technology Documents"), getPlayerName(from)));
		}
		// For each topic
		for (i = 0; i < asResearch.size(); i++)
		{
			// If they have it and we don't research it
			if (IsResearchCompleted(&asPlayerResList[from][i])
			    && !IsResearchCompleted(&asPlayerResList[to][i]))
			{
				MakeResearchCompleted(&asPlayerResList[to][i]);
				researchResult(i, to, false, NULL, true);
			}
		}
	}
}
Beispiel #22
0
// ////////////////////////////////////////////////////////////////////////////
// acknowledge the destruction of a structure, from another player.
bool recvDestroyStructure(NETQUEUE queue)
{
	uint32_t structID;
	STRUCTURE *psStruct;

	NETbeginDecode(queue, GAME_DEBUG_REMOVE_STRUCTURE);
	NETuint32_t(&structID);
	NETend();

	if (!getDebugMappingStatus() && bMultiPlayer)
	{
		debug(LOG_WARNING, "Failed to remove structure for player %u.", NetPlay.players[queue.index].position);
		return false;
	}

	// Struct to destory
	psStruct = IdToStruct(structID, ANYPLAYER);

	if (psStruct)
	{
		turnOffMultiMsg(true);
		// Remove the struct from remote players machine
		destroyStruct(psStruct, gameTime - deltaGameTime + 1);  // deltaGameTime is actually 0 here, since we're between updates. However, the value of gameTime - deltaGameTime + 1 will not change when we start the next tick.
		turnOffMultiMsg(false);
		// NOTE: I do not think this should be here!
		technologyGiveAway(psStruct);
	}

	return true;
}
Beispiel #23
0
// Actually send the droid info.
void sendQueuedDroidInfo()
{
	// Sort queued orders, to group the same order to multiple droids.
	std::sort(queuedOrders.begin(), queuedOrders.end());

	std::vector<QueuedDroidInfo>::iterator eqBegin, eqEnd;
	for (eqBegin = queuedOrders.begin(); eqBegin != queuedOrders.end(); eqBegin = eqEnd)
	{
		// Find end of range of orders which differ only by the droid ID.
		for (eqEnd = eqBegin + 1; eqEnd != queuedOrders.end() && eqEnd->orderCompare(*eqBegin) == 0; ++eqEnd)
		{}

		NETbeginEncode(NETgameQueue(selectedPlayer), GAME_DROIDINFO);
			NETQueuedDroidInfo(&*eqBegin);

			uint32_t num = eqEnd - eqBegin;
			NETuint32_t(&num);

			uint32_t prevDroidId = 0;
			for (unsigned n = 0; n < num; ++n)
			{
				uint32_t droidId = (eqBegin + n)->droidId;

				// Encode deltas between droid IDs, since the deltas are smaller than the actual droid IDs, and will encode to less bytes on average.
				uint32_t deltaDroidId = droidId - prevDroidId;
				NETuint32_t(&deltaDroidId);

				prevDroidId = droidId;
			}
		NETend();
	}

	// Sent the orders. Don't send them again.
	queuedOrders.clear();
}
Beispiel #24
0
void recvMultiPlayerFeature(NETQUEUE queue)
{
	uint32_t ref = 0xff, x = 0, y = 0, id = 0;
	unsigned int i;

	NETbeginDecode(queue, GAME_DEBUG_ADD_FEATURE);
	{
		NETuint32_t(&ref);
		NETuint32_t(&x);
		NETuint32_t(&y);
		NETuint32_t(&id);
	}
	NETend();

	if (!getDebugMappingStatus() && bMultiPlayer)
	{
		debug(LOG_WARNING, "Failed to add feature for player %u.", NetPlay.players[queue.index].position);
		return;
	}

	// Find the feature stats list that contains the feature type we want to build
	for (i = 0; i < numFeatureStats; ++i)
	{
		// If we found the correct feature type
		if (asFeatureStats[i].ref == ref)
		{
			// Create a feature of the specified type at the given location
			FEATURE *result = buildFeature(&asFeatureStats[i], x, y, false);
			result->id = id;
			break;
		}
	}
}
Beispiel #25
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;
}
//
// At this time, we do NOT support messages for beacons
//
bool sendBeacon(int32_t locX, int32_t locY, int32_t forPlayer, int32_t sender, const char* pStr)
{
	int sendPlayer;
	//debug(LOG_WZ, "sendBeacon: '%s'",pStr);

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

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

	// I assume this is correct, looks like it sends it to ONLY that person, and the routine
	// kf_AddHelpBlip() iterates for each player it needs.
	NETbeginEncode(NETnetQueue(sendPlayer), NET_BEACONMSG);    // send to the player who is hosting 'to' player (might be himself if human and not AI)
		NETint32_t(&sender);                                // save the actual sender

		// save the actual player that is to get this msg on the source machine (source can host many AIs)
		NETint32_t(&forPlayer);                             // save the actual receiver (might not be the same as the one we are actually sending to, in case of AIs)
		NETint32_t(&locX);                                  // save location
		NETint32_t(&locY);

		// const_cast: need to cast away constness because of the const-incorrectness of NETstring (const-incorrect when sending/encoding a packet)
		NETstring((char*)pStr, MAX_CONSOLE_STRING_LENGTH);  // copy message in.
	NETend();

	return true;
}
Beispiel #27
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();
}
// send a newly created template to other players
bool sendTemplate(uint32_t player, DROID_TEMPLATE *pTempl)
{
	NETbeginEncode(NETgameQueue(selectedPlayer), GAME_TEMPLATE);
		NETuint32_t(&player);
		NETtemplate(pTempl);
	return NETend();
}
Beispiel #29
0
void recvProcessDebugMappings(NETQUEUE queue)
{
	bool val = false;
	NETbeginDecode(queue, GAME_DEBUG_MODE);
		NETbool(&val);
	NETend();

	bool oldDebugMode = getDebugMappingStatus();
	processDebugMappings(queue.index, val);
	bool newDebugMode = getDebugMappingStatus();

	char const *cmsg;
	if (val)
	{
		sasprintf((char**)&cmsg, _("%s wants to enable debug mode. Enabled: %s, Disabled: %s."), getPlayerName(queue.index), getWantedDebugMappingStatuses(true).c_str(), getWantedDebugMappingStatuses(false).c_str());
	}
	else
	{
		sasprintf((char**)&cmsg, _("%s wants to disable debug mode. Enabled: %s, Disabled: %s."), getPlayerName(queue.index), getWantedDebugMappingStatuses(true).c_str(), getWantedDebugMappingStatuses(false).c_str());
	}
	addConsoleMessage(cmsg, DEFAULT_JUSTIFY,  SYSTEM_MESSAGE);

	if (!oldDebugMode && newDebugMode)
	{
		addConsoleMessage(_("Debug mode now enabled!"), DEFAULT_JUSTIFY,  SYSTEM_MESSAGE);
	}
	else if (oldDebugMode && !newDebugMode)
	{
		addConsoleMessage(_("Debug mode now disabled!"), DEFAULT_JUSTIFY,  SYSTEM_MESSAGE);
	}
}
Beispiel #30
0
// ////////////////////////////////////////////////////////////////////////////
// give Power
void giftPower(uint8_t from, uint8_t to, BOOL send)
{
	UDWORD gifval;
	uint32_t dummy = 0;

	if (from == ANYPLAYER)
	{
		gifval = OILDRUM_POWER;
	}
	else
	{
		// Give 1/3 of our power away
		gifval = getPower(from) / 3;
		usePower(from, gifval);
	}

	addPower(to, gifval);

	if (send)
	{
		uint8_t giftType = POWER_GIFT;

		NETbeginEncode(NET_GIFT, NET_ALL_PLAYERS);
			NETuint8_t(&giftType);
			NETuint8_t(&from);
			NETuint8_t(&to);
			NETuint32_t(&dummy);
		NETend();
	}
	else if (to == selectedPlayer)
	{
		CONPRINTF(ConsoleString,(ConsoleString,_("%s Gives You %u Power"),getPlayerName(from),gifval));
	}
}