Example #1
0
/**
 * @brief Run base defences.
 * @param[in] dt Time elapsed since last call of this function.
 */
void AIRFIGHT_CampaignRunBaseDefence (int dt)
{
    installation_t *installation;
    base_t *base;

    base = NULL;
    while ((base = B_GetNext(base)) != NULL) {
        int idx;

        if (B_IsUnderAttack(base))
            continue;

        for (idx = 0; idx < base->numBatteries; idx++) {
            baseWeapon_t *battery = &base->batteries[idx];
            aircraftSlot_t *slot = &battery->slot;
            if (slot->delayNextShot > 0)
                slot->delayNextShot -= dt;
            if (slot->ammoLeft <= 0)
                AII_ReloadWeapon(slot);
        }

        for (idx = 0; idx < base->numLasers; idx++) {
            baseWeapon_t *battery = &base->lasers[idx];
            aircraftSlot_t *slot = &battery->slot;
            if (slot->delayNextShot > 0)
                slot->delayNextShot -= dt;
            if (slot->ammoLeft <= 0)
                AII_ReloadWeapon(slot);
        }

        if (AII_BaseCanShoot(base)) {
            if (B_GetBuildingStatus(base, B_DEFENCE_MISSILE))
                AIRFIGHT_BaseShoot(base, base->batteries, base->numBatteries);
            if (B_GetBuildingStatus(base, B_DEFENCE_LASER))
                AIRFIGHT_BaseShoot(base, base->lasers, base->numLasers);
        }
    }

    INS_Foreach(installation) {
        int idx;

        if (installation->installationTemplate->maxBatteries <= 0)
            continue;

        for (idx = 0; idx < installation->installationTemplate->maxBatteries; idx++) {
            baseWeapon_t *battery = &installation->batteries[idx];
            aircraftSlot_t *slot = &battery->slot;
            if (slot->delayNextShot > 0)
                slot->delayNextShot -= dt;
            if (slot->ammoLeft <= 0)
                AII_ReloadWeapon(slot);
        }

        if (AII_InstallationCanShoot(installation)) {
            AIRFIGHT_InstallationShoot(installation, installation->batteries, installation->installationTemplate->maxBatteries);
        }
    }
}
Example #2
0
/**
 * @brief Returns the base pointer the production belongs to
 * @param[in] production pointer to the production entry
 * @return base_t pointer to the base
 */
base_t* PR_ProductionBase (const production_t* production)
{
	base_t* base = nullptr;
	while ((base = B_GetNext(base)) != nullptr) {
		const ptrdiff_t diff = ((ptrdiff_t)((production) - PR_GetProductionForBase(base)->items));

		if (diff >= 0 && diff < MAX_PRODUCTIONS)
			return base;
	}
	return nullptr;
}
Example #3
0
/**
 * @brief Display the popup_homebase
 * @param[in] aircraft Pointer to aircraft we want to change homebase.
 * @param[in] alwaysDisplay False if popup should be displayed only if at least one base is available.
 * @return true if popup is displayed.
 */
qboolean CL_DisplayHomebasePopup (aircraft_t *aircraft, qboolean alwaysDisplay)
{
	int homebase;
	int numAvailableBases = 0;
	baseCapacities_t capacity;
	linkedList_t* popupListText = NULL;
	base_t *base;

	assert(aircraft);

	capacity = AIR_GetCapacityByAircraftWeight(aircraft);

	LIST_Delete(&popupListData);

	popupNum = 0;
	homebase = -1;

	base = NULL;
	while ((base = B_GetNext(base)) != NULL) {
		char text[MAX_VAR];
		char const* msg;

		if (base == aircraft->homebase) {
			msg = _("current homebase of aircraft");
			LIST_Add(&popupListData, (byte *)&INVALID_BASE, sizeof(int));
			homebase = popupNum;
		} else {
			msg = AIR_CheckMoveIntoNewHomebase(aircraft, base, capacity);
			if (!msg) {
				msg = _("base can hold aircraft");
				LIST_Add(&popupListData, (byte *)&base->idx, sizeof(int));
				numAvailableBases++;
			} else {
				LIST_Add(&popupListData, (byte *)&INVALID_BASE, sizeof(int));
			}
		}

		Com_sprintf(text, sizeof(text), "%s\t%s", base->name, msg);
		LIST_AddString(&popupListText, text);
		popupNum++;
	}

	if (alwaysDisplay || numAvailableBases > 0) {
		CL_GameTimeStop();
		popupListNode = UI_PopupList(_("Change homebase of aircraft"), _("Base\tStatus"), popupListText, "change_homebase <lineselected>;");
		VectorSet(popupListNode->selectedColor, 0.0, 0.78, 0.0);	/**< Set color for selected entry. */
		popupListNode->selectedColor[3] = 1.0;
		UI_TextNodeSelectLine(popupListNode, homebase);
		MAP_SelectAircraft(aircraft);
		return qtrue;
	}

	return qfalse;
}
Example #4
0
/**
 * @brief Counts live aliens in all bases.
 */
int AL_CountAll (void)
{
	int amount = 0;
	base_t* base = nullptr;

	while ((base = B_GetNext(base)) != nullptr) {
		if (base->alienContainment)
			amount += base->alienContainment->getAlive();
	}
	return amount;
}
Example #5
0
/**
 * @brief Set percentDone values after loading the campaign
 * @note it need to be done after B_PostLoadInitCapacity
 * @sa PR_PostLoadInit
 */
static bool PR_PostLoadInitProgress (void)
{
	base_t* base = nullptr;
	while ((base = B_GetNext(base)) != nullptr) {
		production_queue_t* pq = PR_GetProductionForBase(base);
		for (int j = 0; j < pq->numItems; j++) {
			production_t* prod = &pq->items[j];
			prod->totalFrames = PR_CalculateTotalFrames(base, &prod->data);
		}
	}

	return true;
}
Example #6
0
/**
 * @brief Counts live aliens in all bases.
 * @note This should be called whenever you add or remove
 * @note aliens from alien containment.
 * @return amount of all live aliens stored in containments
 * @sa B_AircraftReturnedToHomeBase
 * @sa AC_Init_f
 */
int AL_CountAll (void)
{
	int amount = 0;
	base_t *base = NULL;

	while ((base = B_GetNext(base)) != NULL) {
		int j;
		if (!B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT))
			continue;
		for (j = 0; j < ccs.numAliensTD; j++) {
			const aliensCont_t *ac = &base->alienscont[j];
			if (ac->teamDef)
				amount += ac->amountAlive;
		}
	}
	return amount;
}
Example #7
0
/**
 * @brief Checks capacity overflows on bases
 * @sa CP_CampaignRun
 */
void CAP_CheckOverflow (void)
{
	base_t *base = nullptr;

	while ((base = B_GetNext(base)) != nullptr) {
		int i;

		for (i = CAP_ALIENS; i < MAX_CAP; i++) {
			baseCapacities_t capacityType = (baseCapacities_t)i;
			capacities_t *cap = CAP_Get(base, capacityType);

			if (cap->cur <= cap->max)
				continue;

			switch (capacityType) {
			case CAP_WORKSPACE:
				PR_UpdateProductionCap(base);
				break;
			case CAP_ITEMS:
				CAP_RemoveItemsExceedingCapacity(base);
				break;
			case CAP_ALIENS:
				AL_RemoveAliensExceedingCapacity(base);
				break;
			case CAP_LABSPACE:
				RS_RemoveScientistsExceedingCapacity(base);
				break;
			case CAP_AIRCRAFT_SMALL:
			case CAP_AIRCRAFT_BIG:
				CAP_RemoveAircraftExceedingCapacity(base, capacityType);
				break;
			case CAP_EMPLOYEES:
				E_DeleteEmployeesExceedingCapacity(base);
				break;
			case CAP_ANTIMATTER:
				CAP_RemoveAntimatterExceedingCapacity(base);
				break;
			default:
				/* nothing to do */
				break;
			}
		}
	}
}
Example #8
0
/**
 * @brief Checks capacity overflows on bases
 * @sa CP_CampaignRun
 */
void CAP_CheckOverflow (void)
{
	base_t* base = nullptr;

	while ((base = B_GetNext(base)) != nullptr) {
		for (int i = CAP_ALIENS; i < MAX_CAP; i++) {
			baseCapacities_t capacityType = (baseCapacities_t)i;
			capacities_t* cap = CAP_Get(base, capacityType);

			if (cap->cur <= cap->max)
				continue;

			switch (capacityType) {
			case CAP_ANTIMATTER:
				CAP_RemoveAntimatterExceedingCapacity(base);
				break;
			case CAP_WORKSPACE:
				PR_UpdateProductionCap(base);
				break;
			case CAP_LABSPACE:
				RS_RemoveScientistsExceedingCapacity(base);
				break;
			case CAP_AIRCRAFT_SMALL:
			case CAP_AIRCRAFT_BIG:
			case CAP_ALIENS:
			case CAP_EMPLOYEES:
			case CAP_ITEMS:
				if (base->baseStatus != BASE_DESTROYED) {
					const buildingType_t bldgType = B_GetBuildingTypeByCapacity((baseCapacities_t)i);
					const building_t* bldg = B_GetBuildingTemplateByType(bldgType);
					CP_GameTimeStop();
					cgi->Cmd_ExecuteString("ui_push popup_cap_overload base %d \"%s\" \"%s\" %d %d",
						base->idx, base->name, _(bldg->name), cap->max - cap->cur, cap->max);
				}
				break;
			default:
				/* nothing to do */
				break;
			}
		}
	}
}
Example #9
0
/**
 * @brief Update alien interest for all PHALANX bases.
 * @note called every @c DETECTION_INTERVAL
 * @sa UFO_UpdateAlienInterestForOneBase
 * @sa CP_CampaignRun
 */
void UFO_UpdateAlienInterestForAllBasesAndInstallations (void)
{
	aircraft_t *ufo;

	ufo = NULL;
	while ((ufo = UFO_GetNext(ufo)) != NULL) {
		base_t *base;

		/* landed UFO can't detect any phalanx base or installation */
		if (ufo->landed)
			continue;

		base = NULL;
		while ((base = B_GetNext(base)) != NULL)
			UFO_UpdateAlienInterestForOneBase(ufo, base);

		INS_Foreach(installation)
			UFO_UpdateAlienInterestForOneInstallation(ufo, installation);
	}
}
/**
 * @brief Counts killed or captured aliens of given type in all bases.
 * @param[in] alienidx
 * @param[in] alive boolean whether the alien is alive or already dead
 * @return amount of killed aliens of given type
 */
static int AL_CountForMenu (int alienidx, bool alive)
{
	int amount = 0;
	base_t *base;

	assert(alienidx >= 0);
	assert(alienidx < MAX_ALIENCONT_CAP);

	base = NULL;
	while ((base = B_GetNext(base)) != NULL) {
		aliensCont_t *ac = &base->alienscont[alienidx];
		if (!B_GetBuildingStatus(base, B_ALIEN_CONTAINMENT))
			continue;
		if (ac->teamDef) {
			if (!alive)
				amount += ac->amountDead;
			else
				amount += ac->amountAlive;
		}
	}
	return amount;
}
Example #11
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));
	}
}
Example #12
0
/**
 * @brief Check events for UFOs: Appears or disappears on radars
 * @return qtrue if any new ufo was detected during this iteration, qfalse otherwise
 */
qboolean UFO_CampaignCheckEvents (void)
{
	qboolean newDetection;
	aircraft_t *ufo;

	newDetection = qfalse;

	/* For each ufo in geoscape */
	ufo = NULL;
	while ((ufo = UFO_GetNext(ufo)) != NULL) {
		char detectedBy[MAX_VAR] = "";
		float minDistance = -1;
		/* detected tells us whether or not a UFO is detected NOW, whereas ufo->detected tells
		 * us whether or not the UFO was detected PREVIOUSLY. */
		qboolean detected = qfalse;
		base_t *base;

		/* don't update UFO status id UFO is landed or crashed */
		if (ufo->landed)
			continue;

		/* note: We can't exit these loops as soon as we found the UFO detected
		 * RADAR_CheckUFOSensored registers the UFO in every radars' detection list
		 * which detect it */

		/* Check if UFO is detected by an aircraft */
		AIR_Foreach(aircraft) {
			if (!AIR_IsAircraftOnGeoscape(aircraft))
				continue;
			/* maybe the ufo is already detected, don't reset it */
			if (RADAR_CheckUFOSensored(&aircraft->radar, aircraft->pos, ufo, detected | ufo->detected)) {
				const int distance = GetDistanceOnGlobe(aircraft->pos, ufo->pos);
				detected = qtrue;
				if (minDistance < 0 || minDistance > distance) {
					minDistance = distance;
					Q_strncpyz(detectedBy, aircraft->name, sizeof(detectedBy));
				}
			}
		}

		/* Check if UFO is detected by a base */
		base = NULL;
		while ((base = B_GetNext(base)) != NULL) {
			if (!B_GetBuildingStatus(base, B_POWER))
				continue;

			/* maybe the ufo is already detected, don't reset it */
			if (RADAR_CheckUFOSensored(&base->radar, base->pos, ufo, detected | ufo->detected)) {
				const int distance = GetDistanceOnGlobe(base->pos, ufo->pos);
				detected = qtrue;
				if (minDistance < 0 || minDistance > distance) {
					minDistance = distance;
					Q_strncpyz(detectedBy, base->name, sizeof(detectedBy));
				}
			}

		}

		/* Check if UFO is detected by a radartower */
		INS_Foreach(installation) {
			/* maybe the ufo is already detected, don't reset it */
			if (RADAR_CheckUFOSensored(&installation->radar, installation->pos, ufo, detected | ufo->detected)) {
				const int distance = GetDistanceOnGlobe(installation->pos, ufo->pos);
				detected = qtrue;
				if (minDistance < 0 || minDistance > distance) {
					minDistance = distance;
					Q_strncpyz(detectedBy, installation->name, sizeof(detectedBy));
				}
			}
		}

		/* Check if ufo appears or disappears on radar */
		if (detected != ufo->detected) {
			if (detected) {
				/* if UFO is aiming a PHALANX aircraft, warn player */
				if (ufo->aircraftTarget) {
					/* stop time and notify */
					MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is flying toward %s"), ufo->aircraftTarget->name), qfalse,
							MSG_STANDARD, NULL);
					/** @todo present a popup with possible orders like: return to base, attack the ufo, try to flee the rockets
					 * @sa UFO_SearchAircraftTarget */
				} else {
					MSO_CheckAddNewMessage(NT_UFO_SPOTTED, _("Notice"), va(_("Our radar detected a new UFO near %s"), detectedBy), qfalse,
							MSG_UFOSPOTTED, NULL);
				}
				newDetection = qtrue;
				UFO_DetectNewUFO(ufo);
			} else if (!detected) {
				MSO_CheckAddNewMessage(NT_UFO_SIGNAL_LOST, _("Notice"), _("Our radar has lost the tracking on a UFO"), qfalse, MSG_UFOLOST, NULL);
				/* Make this UFO undetected */
				ufo->detected = qfalse;
				/* Notify that ufo disappeared */
				AIR_AircraftsUFODisappear(ufo);
				MAP_NotifyUFODisappear(ufo);

				/* Deactivate Radar overlay */
				RADAR_DeactivateRadarOverlay();
			}
		}
	}
	return newDetection;
}