예제 #1
0
/**
 * @brief Buy items.
 * @param[in] base Pointer to the base where items are bought.
 * @param[in] item Pointer to the item to buy.
 * @param[in] number Number of items to buy.
 */
qboolean BS_CheckAndDoBuyItem (base_t* base, const objDef_t *item, int number)
{
	int numItems;
	const int price = BS_GetItemBuyingPrice(item);
	const market_t *market = BS_GetMarket();

	assert(base);

	/* you can't buy more items than there are on market */
	numItems = min(number, market->numItems[item->idx]);

	/* you can't buy more items than you have credits for */
	/** @todo Handle items with price 0 better */
	if (price)
		numItems = min(numItems, ccs.credits / price);
	if (numItems <= 0)
		return qfalse;

	/* you can't buy more items than you have room for */
	/** @todo Handle items with size 0 better */
	if (item->size)
		numItems = min(numItems, (base->capacities[CAP_ITEMS].max - base->capacities[CAP_ITEMS].cur) / item->size);
	/* make sure that numItems is > 0 (can be negative because capacities.cur may be greater than
	 * capacities.max if storage is disabled or if alien items have been collected on mission */
	if (numItems <= 0) {
		UI_Popup(_("Not enough storage space"), _("You cannot buy this item.\nNot enough space in storage.\nBuild more storage facilities."));
		return qfalse;
	}

	B_UpdateStorageAndCapacity(base, item, numItems, qfalse, qfalse);
	BS_RemoveItemFromMarket(item, numItems);
	CL_UpdateCredits(ccs.credits - price * numItems);
	return qtrue;
}
예제 #2
0
/**
 * @brief Hires the employee in a base.
 * @param[in] base Which base the employee should be hired in
 * @param[in] employee Which employee to hire
 * @sa E_HireEmployeeByType
 * @sa E_UnhireEmployee
 * @todo handle EMPL_ROBOT capacities here?
 */
qboolean E_HireEmployee (base_t* base, employee_t* employee)
{
	if (base->capacities[CAP_EMPLOYEES].cur >= base->capacities[CAP_EMPLOYEES].max) {
		UI_Popup(_("Not enough quarters"), _("You don't have enough quarters for your employees.\nBuild more quarters."));
		return qfalse;
	}

	if (employee) {
		/* Now uses quarter space. */
		employee->baseHired = base;
		/* Update other capacities */
		switch (employee->type) {
		case EMPL_WORKER:
			base->capacities[CAP_EMPLOYEES].cur++;
			PR_UpdateProductionCap(base);
			break;
		case EMPL_PILOT:
			AIR_AutoAddPilotToAircraft(base, employee);
		case EMPL_SCIENTIST:
		case EMPL_SOLDIER:
			base->capacities[CAP_EMPLOYEES].cur++;
			break;
		case EMPL_ROBOT:
			base->capacities[CAP_ITEMS].cur += UGV_SIZE;
			break;
		case MAX_EMPL:
			break;
		}
		return qtrue;
	}
	return qfalse;
}
예제 #3
0
/**
 * @brief Move item between containers.
 * @param[in] inv Pointer to the list where the item is currently in.
 * @param[in] toContainer Pointer to target container, to place the item in.
 * @param[in] px target x position in the toContainer container.
 * @param[in] py target y position in the toContainer container.
 * @param[in] fromContainer Pointer to source container, the item is in.
 * @param[in] fItem Pointer to item being moved.
 * @note If you set px or py to -1/NONE the item is automatically placed on
 * @note a free spot in the targetContainer
 * @return true if the move was successful.
 */
bool INV_MoveItem (inventory_t* inv, const invDef_t * toContainer, int px, int py,
	const invDef_t * fromContainer, invList_t *fItem, invList_t **tItem)
{
	int moved;

	if (px >= SHAPE_BIG_MAX_WIDTH || py >= SHAPE_BIG_MAX_HEIGHT)
		return false;

	if (!fItem)
		return false;
	if (!INVSH_CheckAddingItemToInventory(inv, fromContainer->id, toContainer->id, fItem->item, GAME_GetChrMaxLoad(GAME_GetSelectedChr()))) {
		UI_Popup(_("Warning"), _("This soldier can not carry anything else."));
		return false;
	}

	/* move the item */
	moved = cls.i.MoveInInventory(&cls.i, inv, fromContainer, fItem, toContainer, px, py, NULL, tItem);

	switch (moved) {
	case IA_MOVE:
	case IA_ARMOUR:
	case IA_RELOAD:
	case IA_RELOAD_SWAP:
		return true;
	default:
		return false;
	}
}
예제 #4
0
/**
 * @brief Console command to load a savegame
 * @sa SAV_GameLoad
 */
static void SAV_GameLoad_f (void)
{
	const char *error = NULL;

	/* get argument */
	if (Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <filename>\n", Cmd_Argv(0));
		return;
	}

	/* Check if savegame exists */
	if (FS_CheckFile("save/%s.%s", Cmd_Argv(1), SAVEGAME_EXTENSION) <= 0) {
		Com_Printf("savegame file '%s' doesn't exist or an empty file\n", Cmd_Argv(1));
		return;
	}

	Com_DPrintf(DEBUG_CLIENT, "load file '%s'\n", Cmd_Argv(1));

	/* load and go to map */
	if (!SAV_GameLoad(Cmd_Argv(1), &error)) {
		Cbuf_Execute(); /* wipe outstanding campaign commands */
		Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error loading game."), error ? error : "");
		UI_Popup(_("Error"), popupText);
		Cmd_ExecuteString("game_exit");
	}
}
예제 #5
0
/**
 * @brief Move item between containers.
 * @param[in] inv Pointer to the inventory we are working on.
 * @param[in] toContainer Pointer to target container, to place the item in.
 * @param[in] toX target x position in the toContainer container.
 * @param[in] toY target y position in the toContainer container.
 * @param[in] fromContainer Pointer to source container, the item is in.
 * @param[in] fItem Pointer to item being moved.
 * @param[out] uponItem The item the moving item is eventually dropped upon.
 * @note If you set toX or toY to -1/NONE the item is automatically placed on
 * @note a free spot in the targetContainer
 * @return true if the move was successful.
 */
bool INV_MoveItem (inventory_t* inv, const invDef_t *toContainer, int toX, int toY,
	const invDef_t *fromContainer, invList_t *fItem, invList_t **uponItem)
{
	int moved;

	if (toX >= SHAPE_BIG_MAX_WIDTH || toY >= SHAPE_BIG_MAX_HEIGHT)
		return false;

	if (!fItem)
		return false;
	if (!inv->canHoldItemWeight(fromContainer->id, toContainer->id, *fItem, GAME_GetChrMaxLoad(GAME_GetSelectedChr()))) {
		UI_Popup(_("Warning"), _("This soldier can not carry anything else."));
		return false;
	}

	/* move the item */
	moved = cls.i.moveInInventory(inv, fromContainer, fItem, toContainer, toX, toY, nullptr, uponItem);

	switch (moved) {
	case IA_MOVE:
	case IA_ARMOUR:
	case IA_RELOAD:
	case IA_RELOAD_SWAP:
		return true;
	default:
		return false;
	}
}
예제 #6
0
/**
 * @brief Console command binding for save function
 * @sa SAV_GameSave
 * @note called via 'game_save' command
 */
static void SAV_GameSave_f (void)
{
	char comment[MAX_VAR] = "";
	char *error = NULL;
	qboolean result;

	/* get argument */
	if (Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <filename> <comment|*cvar>\n", Cmd_Argv(0));
		return;
	}

	if (!CP_IsRunning()) {
		Com_Printf("No running game - no saving...\n");
		return;
	}

	/* get comment */
	if (Cmd_Argc() > 2) {
		const char *arg = Cmd_Argv(2);
		Q_strncpyz(comment, arg, sizeof(comment));
	}

	result = SAV_GameSave(Cmd_Argv(1), comment, &error);
	if (!result) {
		if (error)
			Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error saving game."), error);
		else
			Com_sprintf(popupText, sizeof(popupText), "%s\n", _("Error saving game."));
		UI_Popup(_("Note"), popupText);
	}
}
예제 #7
0
/**
 * @return @c true if are a compatible client and nothing else must be downloaded or no downloads are still running,
 * @c false if the start of the match must get a little bit postponed (running downloads).
 * @note throws ERR_DISCONNECT if we are not compatible to the server
 */
static bool CL_CanMultiplayerStart (void)
{
	const int day = CL_GetConfigStringInteger(CS_LIGHTMAP);
	const char* serverVersion = CL_GetConfigString(CS_VERSION);

	/* checksum doesn't match with the one the server gave us via configstring */
	if (!Q_streq(UFO_VERSION, serverVersion)) {
		Com_sprintf(popupText, sizeof(popupText), _("Local game version (%s) differs from the server version (%s)"), UFO_VERSION, serverVersion);
		UI_Popup(_("Error"), popupText);
		Com_Error(ERR_DISCONNECT, "Local game version (%s) differs from the server version (%s)", UFO_VERSION, serverVersion);
	/* amount of objects from script files doesn't match */
	} else if (csi.numODs != CL_GetConfigStringInteger(CS_OBJECTAMOUNT)) {
		UI_Popup(_("Error"), _("Script files are not the same"));
		Com_Error(ERR_DISCONNECT, "Script files are not the same");
	}

	/* activate the map loading screen for multiplayer, too */
	SCR_BeginLoadingPlaque();

	/* check download */
	if (cls.downloadMaps) { /* confirm map */
		if (CL_DownloadMap(CL_GetConfigString(CS_NAME)))
			return false;
		cls.downloadMaps = false;
	}

	/* map might still be downloading? */
	if (CL_PendingHTTPDownloads())
		return false;

	if (Com_GetScriptChecksum() != CL_GetConfigStringInteger(CS_UFOCHECKSUM))
		Com_Printf("You are using modified ufo script files - might produce problems\n");

	CM_LoadMap(CL_GetConfigString(CS_TILES), day, CL_GetConfigString(CS_POSITIONS), CL_GetConfigString(CS_ENTITYSTRING), cl.mapData, cl.mapTiles);

#if 0
	if (cl.mapData->mapChecksum != CL_GetConfigStringInteger(CS_MAPCHECKSUM)) {
		UI_Popup(_("Error"), _("Local map version differs from server"));
		Com_Error(ERR_DISCONNECT, "Local map version differs from server: %u != '%i'",
			cl.mapData->mapChecksum, CL_GetConfigStringInteger(CS_MAPCHECKSUM));
	}
#endif

	return true;
}
예제 #8
0
/**
 * @brief After a mission was finished this function is called
 * @param msg The network message buffer
 * @param winner The winning team
 * @param numSpawned The amounts of all spawned actors per team
 * @param numAlive The amount of survivors per team
 * @param numKilled The amount of killed actors for all teams. The first dimension contains
 * the attacker team, the second the victim team
 * @param numStunned The amount of stunned actors for all teams. The first dimension contains
 * the attacker team, the second the victim team
 */
void GAME_SK_Results (struct dbuffer *msg, int winner, int *numSpawned, int *numAlive, int numKilled[][MAX_TEAMS], int numStunned[][MAX_TEAMS])
{
	char resultText[UI_MAX_SMALLTEXTLEN];
	int enemiesKilled, enemiesStunned;
	int i;
	const int team = cls.team;

	CL_Drop();

	if (winner == 0) {
		UI_Popup(_("Game Drawn!"), _("The game was a draw!\n\nNo survivors left on any side."));
		return;
	}

	enemiesKilled = enemiesStunned = 0;
	for (i = 0; i < MAX_TEAMS; i++) {
		if (i != team && i != TEAM_CIVILIAN) {
			enemiesKilled += numKilled[team][i];
			enemiesStunned += numStunned[team][i];
		}
	}

	Com_sprintf(resultText, sizeof(resultText),
			_("Enemies killed:\t\t%i\n"
			  "Team survivors:\t\t%i\n"
			  "Enemy survivors:\t\t%i\n"
			  "Friendly fire:\t\t%i\n"
			  "Civilians killed:\t\t%i\n"
			  "Civilians killed by enemy:\t\t%i\n"),
			enemiesKilled + enemiesStunned, numAlive[team], numAlive[TEAM_ALIEN],
			numKilled[team][team], numKilled[team][TEAM_CIVILIAN], numKilled[TEAM_ALIEN][TEAM_CIVILIAN]);
	if (winner == team) {
		Com_sprintf(popupText, lengthof(popupText), "%s\n%s", _("You won the game!"), resultText);
		UI_Popup(_("Congratulations"), popupText);
	} else {
		Com_sprintf(popupText, lengthof(popupText), "%s\n%s", _("You've lost the game!"), resultText);
		UI_Popup(_("Better luck next time"), popupText);
	}
}
예제 #9
0
/**
 * @brief Update the equipment weight for the selected actor.
 */
static void INV_UpdateActorLoad_f (void)
{
	if (Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <callback>\n", Cmd_Argv(0));
		return;
	}

	const character_t* chr = GAME_GetSelectedChr();
	if (chr == nullptr)
		return;

	const float invWeight = chr->inv.getWeight();
	const int maxWeight = GAME_GetChrMaxLoad(chr);
	const float penalty = GET_ENCUMBRANCE_PENALTY(invWeight, maxWeight);
	const int normalTU = GET_TU(chr->score.skills[ABILITY_SPEED], 1.0f - WEIGHT_NORMAL_PENALTY);
	const int tus = GET_TU(chr->score.skills[ABILITY_SPEED], penalty);
	const int tuPenalty = tus - normalTU;
	int count = 0;

	const Container* cont = nullptr;
	while ((cont = chr->inv.getNextCont(cont))) {
		if (cont->def()->temp)
			continue;
		for (Item* invList = cont->_invList, *next; invList; invList = next) {
			next = invList->getNext();
			const fireDef_t* fireDef = invList->getFiredefs();
			if (fireDef == nullptr)
				continue;
			for (int i = 0; i < MAX_FIREDEFS_PER_WEAPON; i++) {
				if (fireDef[i].time <= 0)
					continue;
				if (fireDef[i].time <= tus)
					continue;
				if (count <= 0)
					Com_sprintf(popupText, sizeof(popupText), _("This soldier no longer has enough TUs to use the following items:\n\n"));
				Q_strcat(popupText, sizeof(popupText), "%s: %s (%i)\n", _(invList->def()->name), _(fireDef[i].name), fireDef[i].time);
				++count;
			}
		}
	}

	if ((Cmd_Argc() < 3 || atoi(Cmd_Argv(2)) == 0) && count > 0)
		UI_Popup(_("Warning"), popupText);

	char label[MAX_VAR];
	char tooltip[MAX_VAR];
	Com_sprintf(label, sizeof(label), "%g/%i %s %s", invWeight / WEIGHT_FACTOR, maxWeight, _("Kg"),
			(count > 0 ? _("Warning!") : ""));
	Com_sprintf(tooltip, sizeof(tooltip), "%s %i (%+i)", _("TU:"), tus, tuPenalty);
	UI_ExecuteConfunc("%s \"%s\" \"%s\" %f %i", Cmd_Argv(1), label, tooltip, WEIGHT_NORMAL_PENALTY - (1.0f - penalty), count);
}
예제 #10
0
/**
 * @brief Loads the quick save slot
 * @sa SAV_GameQuickSave_f
 */
static void SAV_GameQuickLoad_f (void)
{
	const char *error = NULL;

	if (cgi->CL_OnBattlescape()) {
		Com_Printf("Could not load the campaign while you are on the battlefield\n");
		return;
	}

	if (!SAV_GameLoad("slotquick", &error)) {
		Cbuf_Execute(); /* wipe outstanding campaign commands */
		Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error loading game."), error ? error : "");
		UI_Popup(_("Error"), popupText);
	} else {
		MS_AddNewMessage(_("Campaign loaded"), _("Quicksave campaign was successfully loaded."), qfalse, MSG_INFO, NULL);
		CP_CheckBaseAttacks();
	}
}
예제 #11
0
/**
 * @brief Loads the last saved game
 * @note At saving the archive cvar cl_lastsave was set to the latest savegame
 * @sa SAV_GameLoad
 */
static void SAV_GameContinue_f (void)
{
	const char *error = NULL;

	if (cgi->CL_OnBattlescape()) {
		UI_PopWindow(qfalse);
		return;
	}

	if (!CP_IsRunning()) {
		/* try to load the last saved campaign */
		if (!SAV_GameLoad(cl_lastsave->string, &error)) {
			Cbuf_Execute(); /* wipe outstanding campaign commands */
			Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error loading game."), error ? error : "");
			UI_Popup(_("Error"), popupText);
			Cmd_ExecuteString("game_exit");
		}
	} else {
		/* just continue the current running game */
		UI_PopWindow(qfalse);
	}
}
예제 #12
0
/**
 * @brief Responses to broadcasts, etc
 * @sa CL_ReadPackets
 * @sa CL_Frame
 * @sa SVC_DirectConnect
 * @param[in,out] msg The client stream message buffer to read from
 */
static void CL_ConnectionlessPacket (dbuffer* msg)
{
	char s[512];
	NET_ReadStringLine(msg, s, sizeof(s));

	Cmd_TokenizeString(s, false);

	const char* c = Cmd_Argv(0);
	Com_DPrintf(DEBUG_CLIENT, "server OOB: %s (%s)\n", c, Cmd_Args());

	/* server connection */
	if (Q_streq(c, CL_CMD_CLIENT_CONNECT)) {
		int i;
		for (i = 1; i < Cmd_Argc(); i++) {
			if (char const* const p = Q_strstart(Cmd_Argv(i), "dlserver=")) {
				Com_sprintf(cls.downloadReferer, sizeof(cls.downloadReferer), "ufo://%s", cls.servername);
				CL_SetHTTPServer(p);
				if (cls.downloadServer[0])
					Com_Printf("HTTP downloading enabled, URL: %s\n", cls.downloadServer);
			}
		}
		if (cls.state == ca_connected) {
			Com_Printf("Dup connect received. Ignored.\n");
			return;
		}
		dbuffer buf(5);
		NET_WriteByte(&buf, clc_stringcmd);
		NET_WriteString(&buf, NET_STATE_NEW "\n");
		NET_WriteMsg(cls.netStream, buf);
		GAME_InitMissionBriefing(_("Loading"));
		return;
	}

	/* remote command from gui front end */
	if (Q_streq(c, CL_CMD_COMMAND)) {
		if (!NET_StreamIsLoopback(cls.netStream)) {
			Com_Printf("Command packet from remote host. Ignored.\n");
			return;
		} else {
			char str[512];
			NET_ReadString(msg, str, sizeof(str));
			Cbuf_AddText("%s\n", str);
		}
		return;
	}

	/* ping from server */
	if (Q_streq(c, CL_CMD_PING)) {
		NET_OOB_Printf(cls.netStream, SV_CMD_ACK);
		return;
	}

	/* echo request from server */
	if (Q_streq(c, CL_CMD_ECHO)) {
		NET_OOB_Printf(cls.netStream, "%s", Cmd_Argv(1));
		return;
	}

	/* print */
	if (Q_streq(c, SV_CMD_PRINT)) {
		NET_ReadString(msg, popupText, sizeof(popupText));
		/* special reject messages needs proper handling */
		if (strstr(popupText, REJ_PASSWORD_REQUIRED_OR_INCORRECT)) {
			UI_PushWindow("serverpassword");
			if (Q_strvalid(Cvar_GetString("password"))) {
				Cvar_Set("password", "");
				CL_Drop();
				UI_Popup(_("Connection failure"), _("The password you specified was wrong."));
			} else {
				CL_Drop();
				UI_Popup(_("Connection failure"), _("This server requires a password."));
			}
		} else if (strstr(popupText, REJ_SERVER_FULL)) {
			CL_Drop();
			UI_Popup(_("Connection failure"), _("This server is full."));
		} else if (strstr(popupText, REJ_BANNED)) {
			CL_Drop();
			UI_Popup(_("Connection failure"), _("You are banned on this server."));
		} else if (strstr(popupText, REJ_GAME_ALREADY_STARTED)) {
			CL_Drop();
			UI_Popup(_("Connection failure"), _("The game has already started."));
		} else if (strstr(popupText, REJ_SERVER_VERSION_MISMATCH)) {
			CL_Drop();
			UI_Popup(_("Connection failure"), _("The server is running a different version of the game."));
		} else if (strstr(popupText, BAD_RCON_PASSWORD)) {
			Cvar_Set("rcon_password", "");
			UI_Popup(_("Bad rcon password"), _("The rcon password you specified was wrong."));
		} else if (strstr(popupText, REJ_CONNECTION_REFUSED)) {
			CL_Drop();
			UI_Popup(_("Connection failure"), _("The server refused the connection."));
		} else if (Q_strvalid(popupText)) {
			UI_Popup(_("Notice"), _(popupText));
		}
		return;
	}

	if (!GAME_HandleServerCommand(c, msg))
		Com_Printf("Unknown command received \"%s\"\n", c);
}