Esempio n. 1
0
/**
 * @brief Choose nation if needed for given mission.
 * @param[in] mission Pointer to the mission we are creating.
 * @param[out] nationList linkedList that will contain the name of the nation where the mission should take place.
 * @note nationList should be empty if no nation should be favoured.
 * @return True if nationList has been filled, false else.
 */
static bool CP_ChooseNation (const mission_t* mission, linkedList_t** nationList)
{
	int randomNumber, max = 0;
	/* Increase this factor to make probability to select non-infected nation higher
	 * Used to make sure that non-infected nation can still be attacked */
	const int OFFSET = 1;
	int i;

	if (mission->ufo)
		return false;

	/* favour mission with higher XVI level */
	for (i = 0; i < ccs.numNations; i++) {
		const nation_t* nation = NAT_GetNationByIDX(i);
		const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
		max += OFFSET + stats->xviInfection;
	}

	randomNumber = (int) (frand() * (float) max);

	/* Select the corresponding nation */
	for (i = 0; i < ccs.numNations; i++) {
		const nation_t* nation = NAT_GetNationByIDX(i);
		const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
		randomNumber -= OFFSET + stats->xviInfection;
		if (randomNumber < 0) {
			cgi->LIST_AddString(nationList, nation->id);
			return true;
		}
	}

	return false;
}
/**
 * @brief Function to initialize list to sell recovered UFO to desired nation.
 * @note Command to call this: cp_uforecovery_sell_init.
 */
static void UR_DialogInitSell_f (void)
{
	int i;

	/* Do nothing if recovery process is finished. */
	if (ufoRecovery.recoveryDone)
		return;
	/* Do nothing without a ufoTemplate set */
	if (!ufoRecovery.ufoTemplate)
		return;

	for (i = 0; i < ccs.numNations; i++) {
		const nation_t *nation = NAT_GetNationByIDX(i);
		const nationInfo_t *stats = NAT_GetCurrentMonthInfo(nation);
		int price;

		price = (int) (ufoRecovery.ufoTemplate->price * (.85f + frand() * .3f));
		/* Nation will pay less if corrupted */
		price = (int) (price * exp(-stats->xviInfection / 20.0f));

		ufoRecovery.ufoNations[i].nation = nation;
		ufoRecovery.ufoNations[i].price = price;
	}
	UR_SortNations(UR_GetSortFunctionByColumn(ufoRecovery.sortedColumn), ufoRecovery.sortDescending);
	UR_DialogFillNations();
	cgi->UI_ExecuteConfunc("btnatsel disable");
}
Esempio n. 3
0
/**
 * @brief Return the average XVI rate
 * @note XVI = eXtraterrestial Viral Infection
 */
int CP_GetAverageXVIRate (void)
{
	assert(ccs.numNations);

	/* check for XVI infection rate */
	int xviRate = 0;
	for (int i = 0; i < ccs.numNations; i++) {
		const nation_t* nation = NAT_GetNationByIDX(i);
		const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
		xviRate += stats->xviInfection;
	}
	xviRate /= ccs.numNations;
	return xviRate;
}
/**
 * @brief Function to start UFO selling process.
 * @note Command to call this: cp_uforecovery_sell_start.
 */
static void UR_DialogStartSell_f (void)
{
	int price = -1;
	const nation_t *nation;
	int i;

	if (!ufoRecovery.nation)
		return;

	nation = ufoRecovery.nation;

	i = UR_DialogGetCurrentNationIndex();
	price = ufoRecovery.ufoNations[i].price;

	assert(price >= 0);
#if 0
	if (ufoRecovery.selectedStorage) {
		Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Sold previously recovered %s from %s to nation %s, gained %i credits."), UFO_TypeToName(
				ufoRecovery.selectedStorage->ufoTemplate->ufotype), ufoRecovery.selectedStorage->base->name, _(nation->name), price);
	} else
#endif
	{
		Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Recovered %s from the battlefield. UFO sold to nation %s, gained %i credits."), UFO_GetName(ufoRecovery.ufoTemplate), _(nation->name), price);
	}
	MS_AddNewMessage(_("UFO Recovery"), cp_messageBuffer);
	CP_UpdateCredits(ccs.credits + price);

	/* update nation happiness */
	for (i = 0; i < ccs.numNations; i++) {
		nation_t *nat = NAT_GetNationByIDX(i);
		float ufoHappiness;

		assert(nat);
		if (nat == nation)
			/* nation is happy because it got the UFO */
			ufoHappiness = HAPPINESS_UFO_SALE_GAIN;
		else
			/* nation is unhappy because it wanted the UFO */
			ufoHappiness = HAPPINESS_UFO_SALE_LOSS;

		NAT_SetHappiness(ccs.curCampaign->minhappiness, nat, nat->stats[0].happiness + ufoHappiness);
	}

	/* UFO recovery process is done, disable buttons. */
	UR_DialogRecoveryDone();
}
Esempio n. 5
0
/**
 * @brief Return a nation-pointer by the nations id (nation_t->id) text.
 * @param[in] nationID nation id as defined in (nation_t->id)
 * @return nation_t pointer or NULL if nothing found (=error).
 */
nation_t *NAT_GetNationByID (const char *nationID)
{
	int i;

	if (!nationID) {
		Com_Printf("NAT_GetNationByID: NULL nationID\n");
		return NULL;
	}
	for (i = 0; i < ccs.numNations; i++) {
		nation_t *nation = NAT_GetNationByIDX(i);
		if (Q_streq(nation->id, nationID))
			return nation;
	}

	Com_Printf("NAT_GetNationByID: Could not find nation '%s'\n", nationID);

	/* No matching nation found - ERROR */
	return NULL;
}
Esempio n. 6
0
/**
 * @brief Recreates all the employees for a particular employee type in the global list.
 * But it does not overwrite any employees already hired.
 * @param[in] type The type of the employee list to process.
 * @param[in] excludeUnhappyNations True if a nation is unhappy then they wont
 * send any pilots, false if happiness of nations in not considered.
 * @sa CP_NationHandleBudget
 */
int E_RefreshUnhiredEmployeeGlobalList (const employeeType_t type, const qboolean excludeUnhappyNations)
{
	const nation_t *happyNations[MAX_NATIONS];
	int numHappyNations = 0;
	int idx, nationIdx, cnt;
	employee_t *employee;

	happyNations[0] = NULL;
	/* get a list of nations,  if excludeHappyNations is qtrue then also exclude
	 * unhappy nations (unhappy nation: happiness <= 0) from the list */
	for (idx = 0; idx < ccs.numNations; idx++) {
		const nation_t *nation = NAT_GetNationByIDX(idx);
		const nationInfo_t *stats = NAT_GetCurrentMonthInfo(nation);
		if (stats->happiness > 0 || !excludeUnhappyNations) {
			happyNations[numHappyNations] = nation;
			numHappyNations++;
		}
	}

	if (!numHappyNations)
		return 0;

	idx = 0;
	/* Fill the global data employee list with employees, evenly distributed
	 * between nations in the happyNations list */
	E_Foreach(type, employee) {
		/* we don't want to overwrite employees that have already been hired */
		if (!E_IsHired(employee)) {
			E_DeleteEmployee(employee);
			idx++;
		}
	}

	nationIdx = 0;
	cnt = 0;
	while (idx-- > 0) {
		if (E_CreateEmployee(type, happyNations[nationIdx], NULL) != NULL)
			cnt++;
		nationIdx = (nationIdx + 1) % numHappyNations;
	}

	return cnt;
}
Esempio n. 7
0
static int CP_CheckTriggerEvent (const char *expression, const void* userdata)
{
	const char *type;

	/* check that a particular installation type is built already */
	type = Q_strstart(expression, "installation");
	if (type != 0) {
		if (strlen(type) <= 1)
			return -1;
		char value[MAX_VAR];
		Q_strncpyz(value, type + 1, sizeof(value));
		value[strlen(value) - 1] = '\0';
		const installationType_t insType = INS_GetType(value);
		if (INS_HasType(insType, INSTALLATION_NOT_USED))
			return 1;
		return 0;
	}

	/* check whether a particular ufo was detected */
	type = Q_strstart(expression, "ufo");
	if (type != 0) {
		if (strlen(type) <= 1)
			return -1;
		char value[MAX_VAR];
		Q_strncpyz(value, type + 1, sizeof(value));
		value[strlen(value) - 1] = '\0';
		const char* detectedUFO = static_cast<const char*>(userdata);
		if (Q_strnull(detectedUFO))
			return -1;
		return Q_streq(detectedUFO, value);
	}

	/* check that the given xvi level is reached in any nation */
	type = Q_strstart(expression, "xvi");
	if (type != 0) {
		int xvi;
		if (sscanf(type, "[%i]", &xvi) != 1)
			return -1;
		int i;
		/* check for XVI infection rate */
		for (i = 0; i < ccs.numNations; i++) {
			const nation_t *nation = NAT_GetNationByIDX(i);
			const nationInfo_t *stats = NAT_GetCurrentMonthInfo(nation);
			if (stats->xviInfection >= xvi)
				return 1;
		}
		return 0;
	}

	/* check for nation happiness - also see the lost conditions in the campaign */
	type = Q_strstart(expression, "nationhappiness");
	if (type != 0) {
		int nationAmount;

		if (sscanf(type, "[%i]", &nationAmount) != 1)
			return -1;

		int j, nationBelowLimit = 0;
		for (j = 0; j < ccs.numNations; j++) {
			const nation_t *nation = NAT_GetNationByIDX(j);
			const nationInfo_t *stats = NAT_GetCurrentMonthInfo(nation);
			if (stats->happiness < ccs.curCampaign->minhappiness) {
				nationBelowLimit++;
				if (nationBelowLimit >= nationAmount)
					return 1;
			}
		}
		return 0;
	}

	/* check that the given average xvi level is reached */
	type = Q_strstart(expression, "averagexvi");
	if (type != 0) {
		int xvipercent;
		if (sscanf(type, "[%i]", &xvipercent) != 1)
			return -1;
		if (xvipercent < 0 || xvipercent > 100)
			return -1;
		const int xvi = CP_GetAverageXVIRate();
		if (xvi > ccs.curCampaign->maxAllowedXVIRateUntilLost * xvipercent / 100)
			return 1;
		return 0;
	}

	type = Q_strstart(expression, "difficulty");
	if (type != 0) {
		int difficulty;
		if (sscanf(type, "[%i]", &difficulty) != 1)
			return -1;
		return ccs.curCampaign->difficulty == difficulty;
	}

	/* check that these days have passed in the campaign */
	type = Q_strstart(expression, "days");
	if (type != 0) {
		int days;
		if (sscanf(type, "[%i]", &days) != 1)
			return -1;
		date_t d = ccs.curCampaign->date;
		d.day += days;
		if (Date_IsDue(&d))
			return 1;
		return 0;
	}

	type = Q_strstart(expression, "alienscaptured");
	if (type != 0) {
		if (ccs.campaignStats.capturedAliens > 0)
			return 1;
		return 0;
	}

	type = Q_strstart(expression, "samsitearmed");
	if (type != 0) {
		if (!INS_HasType(INSTALLATION_DEFENCE))
			return 1;

		INS_ForeachOfType(installation, INSTALLATION_DEFENCE) {
			if (installation->installationStatus == INSTALLATION_WORKING) {
				for (int i = 0; i < installation->installationTemplate->maxBatteries; i++) {
					const aircraftSlot_t *slot = &installation->batteries[i].slot;
					if (slot->ammoLeft > 0)
						return 1;
				}
			}
		}

		return 0;
	}

	return -1;
}
Esempio n. 8
0
/**
 * @brief Shows the current stats from stats_t stats
 * @todo This is very redundant with NAT_HandleBudget Ivestigate and clean up.
 */
void CP_StatsUpdate_f (void)
{
	char *pos;
	static char statsBuffer[MAX_STATS_BUFFER];
	int hired[MAX_EMPL];
	int i, costs = 0, sum = 0, totalfunds = 0;
	base_t *base;
	const campaign_t *campaign = ccs.curCampaign;
	const salary_t *salary = &campaign->salaries;
	const rank_t *rank;

	/* delete buffer */
	OBJZERO(statsBuffer);
	OBJZERO(hired);

	pos = statsBuffer;

	/* missions */
	cgi->UI_RegisterText(TEXT_STATS_MISSION, pos);
	Com_sprintf(pos, MAX_STATS_BUFFER, _("Won:\t%i\nLost:\t%i\n\n"), ccs.campaignStats.missionsWon, ccs.campaignStats.missionsLost);

	/* bases */
	pos += (strlen(pos) + 1);
	cgi->UI_RegisterText(TEXT_STATS_BASES, pos);
	Com_sprintf(pos, (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos), _("Built:\t%i\nActive:\t%i\nAttacked:\t%i\n"),
			ccs.campaignStats.basesBuilt, B_GetCount(), ccs.campaignStats.basesAttacked),

	/* installations */
	pos += (strlen(pos) + 1);
	cgi->UI_RegisterText(TEXT_STATS_INSTALLATIONS, pos);

	INS_Foreach(inst) {
		Q_strcat(pos, va("%s\n", inst->name), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
	}

	/* nations */
	pos += (strlen(pos) + 1);
	cgi->UI_RegisterText(TEXT_STATS_NATIONS, pos);
	for (i = 0; i < ccs.numNations; i++) {
		const nation_t *nation = NAT_GetNationByIDX(i);
		Q_strcat(pos, va(_("%s\t%s\n"), _(nation->name), NAT_GetHappinessString(nation)), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
		totalfunds += NAT_GetFunding(nation, 0);
	}
	Q_strcat(pos, va(_("\nFunding this month:\t%d"), totalfunds), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));

	/* costs */
	for (i = 0; i < MAX_EMPL; i++) {
		E_Foreach(i, employee) {
			const employeeType_t type = (employeeType_t)i;
			if (!E_IsHired(employee))
				continue;
			rank = CL_GetRankByIdx(employee->chr.score.rank);
			costs += CP_GetSalaryBaseEmployee(salary, type) + rank->level * CP_GetSalaryRankBonusEmployee(salary, type);
			hired[employee->type]++;
		}
	}

	/* employees - this is between the two costs parts to count the hired employees */
	pos += (strlen(pos) + 1);
	cgi->UI_RegisterText(TEXT_STATS_EMPLOYEES, pos);
	for (i = 0; i < MAX_EMPL; i++) {
		const employeeType_t type = (employeeType_t)i;
		Q_strcat(pos, va(_("%s\t%i\n"), E_GetEmployeeString(type, hired[i]), hired[i]), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
	}

	/* costs - second part */
	pos += (strlen(pos) + 1);
	cgi->UI_RegisterText(TEXT_STATS_COSTS, pos);
	Q_strcat(pos, va(_("Employees:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
	sum += costs;

	costs = 0;
	AIR_Foreach(aircraft) {
		if (aircraft->status == AIR_CRASHED)
			continue;
		costs += aircraft->price * salary->aircraftFactor / salary->aircraftDivisor;
	}
	Q_strcat(pos, va(_("Aircraft:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
	sum += costs;

	base = NULL;
	while ((base = B_GetNext(base)) != NULL) {
		costs = CP_GetSalaryUpKeepBase(salary, base);
		Q_strcat(pos, va(_("Base (%s):\t%i c\n"), base->name, costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
		sum += costs;
	}

	costs = CP_GetSalaryAdministrative(salary);
	Q_strcat(pos, va(_("Administrative costs:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
	sum += costs;

	if (ccs.credits < 0) {
		const float interest = ccs.credits * campaign->salaries.debtInterest;

		costs = (int)ceil(interest);
		Q_strcat(pos, va(_("Debt:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
		sum += costs;
	}
	Q_strcat(pos, va(_("\n\t-------\nSum:\t%i c\n"), sum), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));

	/* campaign */
	pos += (strlen(pos) + 1);
	cgi->UI_RegisterText(TEXT_GENERIC, pos);
	Q_strcat(pos, va(_("Max. allowed debts: %ic\n"), campaign->negativeCreditsUntilLost),
		(ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));

	/* only show the xvi spread data when it's available */
	if (CP_IsXVIVisible()) {
		Q_strcat(pos, va(_("Max. allowed eXtraterrestial Viral Infection: %i%%\n"
			"Current eXtraterrestial Viral Infection: %i%%"),
			campaign->maxAllowedXVIRateUntilLost,
			CP_GetAverageXVIRate()),
			(ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos));
	}
}
Esempio n. 9
0
/**
 * @brief Hack to get a random nation for the initial
 */
static inline const nation_t *E_RandomNation (void)
{
	const int nationIndex = rand() % ccs.numNations;
	return NAT_GetNationByIDX(nationIndex);
}
Esempio n. 10
0
/**
 * @brief Update xviInfection value for each nation, using the XVI overlay.
 * @note should be executed after all daily event that could change XVI overlay
 */
void CP_UpdateNationXVIInfection (void)
{
	/* No need to update XVI levels if the overlay didn't change */
	if (!xviNationInfectionNeedsUpdate)
		return;

	/* width in pixel of the XVI overlay */
	int width;
	/* height in pixel of the XVI overlay */
	int height;
	CP_GetXVIMapDimensions(&width, &height);

	const float heightPerDegree = height / 180.0f;
	const float widthPerDegree = width / 360.0f;
	/* parameter used to normalize nation XVI level.
	 * decrease this factor to increase XVI level per nation */
	const float AREA_FACTOR = 650.0f;
	/* area used to normalized XVI infection level for each nation.
	 * depend on overlay size so that if we change resolution of
	 * overlay it doesn't impact nation XIInfection */
	const float normalizingArea = width * height / AREA_FACTOR;

	/* temporary array to store the XVI levels */
	float xviInfection[MAX_NATIONS];
	/* Initialize array */
	OBJZERO(xviInfection);

	for (int y = 0; y < height; y++) {
		int sum[MAX_NATIONS];
		const byte* previousNationColor;
		const nation_t* nation;
		/* current position (in latitude / longitude) */
		vec2_t currentPos;

		OBJZERO(sum);

		Vector2Set(currentPos, 180.0f, 90.0f - y / heightPerDegree);
		previousNationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr);
		nation = GEO_GetNation(currentPos);

		for (int x = 0; x < width; x++) {
			const byte* nationColor;
			currentPos[0] = 180.0f - x / widthPerDegree;
			nationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr);
			if (!VectorCompare(nationColor, previousNationColor)) {
				previousNationColor = nationColor;
				nation = GEO_GetNation(currentPos);
			}
			if (nation) {
				const int xviLevel = CP_GetXVILevel(x, y);
				if (xviLevel > 0)
					sum[nation->idx] += xviLevel;
			}
		}
		/* divide the total XVI infection by the area of a pixel
		 * because pixel are smaller as you go closer from the pole */
		for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++)
			xviInfection[nationIdx] += ((float) sum[nationIdx]) / (cos(torad * currentPos[1]) * normalizingArea);
	}

	/* copy the new values of XVI infection level into nation array */
	for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++) {
		nation_t* nation = NAT_GetNationByIDX(nationIdx);
		nation->stats[0].xviInfection = ceil(xviInfection[nation->idx]);
	}

	xviNationInfectionNeedsUpdate = false;
}