예제 #1
0
파일: ui_popup.c 프로젝트: chrisglass/ufoai
/**
 * @brief Generates a popup that contains up to 3 buttons.
 * @param[in] title Title of the popup.
 * @param[in] text Text to display in the popup (use popupText if text is NULL).
 * @param[in] clickAction1 Action to perform when one clicked on the first button.
 * @param[in] clickText1 String that will be written in first button.
 * @param[in] tooltip1 Tooltip of first button.
 * @param[in] clickAction2 Action to perform when one clicked on the second button.
 * @param[in] clickText2 String that will be written in second button.
 * @param[in] tooltip2 Tooltip of second button.
 * @param[in] clickAction3 Action to perform when one clicked on the third button.
 * @param[in] clickText3 String that will be written in third button.
 * @param[in] tooltip3 Tooltip of third button.
 * @note clickAction AND clickText must be NULL if button should be invisible.
 */
void UI_PopupButton (const char *title, const char *text,
	const char *clickAction1, const char *clickText1, const char *tooltip1,
	const char *clickAction2, const char *clickText2, const char *tooltip2,
	const char *clickAction3, const char *clickText3, const char *tooltip3)
{
	uiNode_t* window;

	Cvar_Set("ui_sys_popup_title", title);
	if (text)
		UI_RegisterText(TEXT_POPUP_INFO, text);
	else
		UI_RegisterText(TEXT_POPUP_INFO, popupText);

	window = UI_GetWindow(POPUPBUTTON_WINDOW_NAME);
	if (!window)
		Com_Error(ERR_FATAL, "Could not get \""POPUPBUTTON_WINDOW_NAME"\" window");

	Cvar_Set("ui_sys_popup_button_text1", clickText1);
	Cvar_Set("ui_sys_popup_button_tooltip1", tooltip1);
	if (!clickAction1 && !clickText1) {
		UI_SetOneButton(window, va("%s1", POPUPBUTTON_NODE_NAME),
			NULL);
	} else {
		UI_SetOneButton(window, va("%s1", POPUPBUTTON_NODE_NAME),
			clickAction1 ? clickAction1 : popupAction1);
	}

	Cvar_Set("ui_sys_popup_button_text2", clickText2);
	Cvar_Set("ui_sys_popup_button_tooltip2", tooltip2);
	if (!clickAction2 && !clickText2) {
		UI_SetOneButton(window, va("%s2", POPUPBUTTON_NODE_NAME), NULL);
	} else {
		UI_SetOneButton(window, va("%s2", POPUPBUTTON_NODE_NAME),
			clickAction2 ? clickAction2 : popupAction2);
	}

	Cvar_Set("ui_sys_popup_button_text3", clickText3);
	Cvar_Set("ui_sys_popup_button_tooltip3", tooltip3);
	if (!clickAction3 && !clickText3) {
		UI_SetOneButton(window, va("%s3", POPUPBUTTON_NODE_NAME), NULL);
	} else {
		UI_SetOneButton(window, va("%s3", POPUPBUTTON_NODE_NAME),
			clickAction3 ? clickAction3 : popupAction3);
	}

	if (!UI_IsWindowOnStack(window->name))
		UI_PushWindow(window->name, NULL, NULL);
}
예제 #2
0
파일: ui_popup.c 프로젝트: chrisglass/ufoai
/**
 * @brief Popup on geoscape
 * @note Only use static strings here - or use popupText if you really have to
 * build the string
 */
void UI_Popup (const char *title, const char *text)
{
	Cvar_Set("ui_sys_popup_title", title);
	UI_RegisterText(TEXT_POPUP_INFO, text);
	if (!UI_IsWindowOnStack(POPUP_WINDOW_NAME))
		UI_PushWindow(POPUP_WINDOW_NAME, NULL, NULL);
}
예제 #3
0
파일: cp_popup.c 프로젝트: chrisglass/ufoai
/**
 * @brief Display the popup_aircraft
 * @sa CL_DisplayPopupIntercept
 */
void CL_DisplayPopupAircraft (aircraft_t* aircraft)
{
	/* Initialise popup_aircraft datas */
	if (!aircraft)
		return;
	popupAircraft.aircraft = aircraft;
	popupAircraft.numItems = 0;
	OBJZERO(popupAircraft.textPopup);
	UI_RegisterText(TEXT_POPUP, popupAircraft.textPopup);

	/* Set static datas in popup_aircraft */
	popupAircraft.itemsAction[popupAircraft.numItems++] = POPUP_AIRCRAFT_ACTION_BACKTOBASE;
	Q_strcat(popupAircraft.textPopup, va(_("Back to base\t%s\n"), aircraft->homebase->name), lengthof(popupAircraft.textPopup));
	popupAircraft.itemsAction[popupAircraft.numItems++] = POPUP_AIRCRAFT_ACTION_STOP;
	Q_strcat(popupAircraft.textPopup, _("Stop\n"), lengthof(popupAircraft.textPopup));
	popupAircraft.itemsAction[popupAircraft.numItems++] = POPUP_AIRCRAFT_CHANGE_HOMEBASE;
	Q_strcat(popupAircraft.textPopup, _("Change homebase\n"), lengthof(popupAircraft.textPopup));

	/* Set missions in popup_aircraft */
	if (AIR_GetTeamSize(aircraft) > 0) {
		mission_t *tempMission;
		MIS_Foreach(tempMission) {
			if (tempMission->stage == STAGE_NOT_ACTIVE || !tempMission->onGeoscape)
				continue;

			if (tempMission->pos) {
				popupAircraft.itemsId[popupAircraft.numItems] = MAP_GetIDXByMission(tempMission);
				popupAircraft.itemsAction[popupAircraft.numItems++] = POPUP_AIRCRAFT_ACTION_MOVETOMISSION;
				Q_strcat(popupAircraft.textPopup, va(_("Mission\t%s (%s)\n"),
					CP_MissionToTypeString(tempMission), _(tempMission->location)), lengthof(popupAircraft.textPopup));
			}
		}
	}
/**
 * @brief Sets aircraftCurrent and updates related cvars and menutexts.
 * @param[in] aircraft Pointer to given aircraft that should be selected in the menu.
 */
void AIR_AircraftSelect (aircraft_t* aircraft)
{
	static char aircraftInfo[256];
	base_t *base;
	int id;

	if (aircraft != NULL)
		base = aircraft->homebase;
	else
		base = NULL;

	if (!AIR_BaseHasAircraft(base)) {
		UI_ResetData(TEXT_AIRCRAFT_INFO);
		return;
	}

	assert(aircraft);
	assert(aircraft->homebase == base);
	CP_UpdateActorAircraftVar(aircraft, EMPL_SOLDIER);

	Cvar_SetValue("mn_equipsoldierstate", CL_EquipSoldierState(aircraft));
	Cvar_Set("mn_aircraftstatus", AIR_AircraftStatusToName(aircraft));
	Cvar_Set("mn_aircraftinbase", AIR_IsAircraftInBase(aircraft) ? "1" : "0");
	Cvar_Set("mn_aircraftname", aircraft->name);
	if (!aircraft->tech)
		Com_Error(ERR_DROP, "No technology assigned to aircraft '%s'", aircraft->id);
	Cvar_Set("mn_aircraft_model", aircraft->tech->mdl);
	Cvar_Set("mn_aircraft_health", va("%3.0f" , aircraft->stats[AIR_STATS_DAMAGE] > 0 ? (double)aircraft->damage * 100 / aircraft->stats[AIR_STATS_DAMAGE] : 0));

	/* generate aircraft info text */
	Com_sprintf(aircraftInfo, sizeof(aircraftInfo), _("Speed:\t%i km/h\n"),
		AIR_AircraftMenuStatsValues(aircraft->stats[AIR_STATS_SPEED], AIR_STATS_SPEED));
	Q_strcat(aircraftInfo, va(_("Fuel:\t%i/%i\n"), AIR_AircraftMenuStatsValues(aircraft->fuel, AIR_STATS_FUELSIZE),
		AIR_AircraftMenuStatsValues(aircraft->stats[AIR_STATS_FUELSIZE], AIR_STATS_FUELSIZE)), sizeof(aircraftInfo));
	Q_strcat(aircraftInfo, va(_("Operational range:\t%i km\n"), AIR_GetOperationRange(aircraft)), sizeof(aircraftInfo));
	Q_strcat(aircraftInfo, va(_("Weapons:\t%i on %i\n"), AIR_GetSlotItems(AC_ITEM_WEAPON, aircraft), aircraft->maxWeapons), sizeof(aircraftInfo));
	Q_strcat(aircraftInfo, va(_("Armour:\t%i on 1\n"), AIR_GetSlotItems(AC_ITEM_SHIELD, aircraft)), sizeof(aircraftInfo));
	Q_strcat(aircraftInfo, va(_("Electronics:\t%i on %i"), AIR_GetSlotItems(AC_ITEM_ELECTRONICS, aircraft), aircraft->maxElectronics), sizeof(aircraftInfo));

	UI_RegisterText(TEXT_AIRCRAFT_INFO, aircraftInfo);

	/** @todo This shouldn't exists. UI should use the global idx as reference */
	/* compute the ID and... */
	id = 0;
	AIR_ForeachFromBase(aircraftInBase, base) {
		if (aircraft == aircraftInBase)
			break;
		id++;
	}

	base->aircraftCurrent = aircraft;
	Cvar_SetValue("mn_aircraft_id", id);

	/* ...update the GUI */
	UI_ExecuteConfunc("aircraft_change %i", id);
}
예제 #5
0
/**
 * @note Mission trigger function
 * @sa CP_MissionTriggerFunctions
 * @sa CP_ExecuteMissionTrigger
 */
static void CP_EndGame_f (void)
{
	UI_RegisterText(TEXT_STANDARD, _("Congratulations! You have reached the end of the UFO:AI campaign.\n"
		"However, this is not the end of the road. The game remains in development.\n"
		"The campaign will be expanded with new missions, new enemies, "
		"new UFOs, new player controllable craft and more research.\n\n"
		"And YOU can help make it happen! Visit our forums or IRC channel to find\n"
		"out what you can do to help finish this game. Alternatively, you can just\n"
		"come by and talk about the game, or find other players for a multiplayer game.\n\n"
		"Thank you for playing, and we hope to see you around.\n\n"
		"   - The UFO:AI development team"));
	CP_EndCampaign(qtrue);
}
예제 #6
0
파일: ui_popup.c 프로젝트: chrisglass/ufoai
/**
 * @brief Generates a popup that contains a list of selectable choices.
 * @param[in] title Title of the popup.
 * @param[in] headline First line of text written in the popup.
 * @param[in] entries List of the selectables choices.
 * @param[in] clickAction Action to perform when one clicked on the popup.
 */
uiNode_t *UI_PopupList (const char *title, const char *headline, linkedList_t* entries, const char *clickAction)
{
	uiNode_t* window;
	uiNode_t* listNode;

	Cvar_Set("ui_sys_popup_title", title);
	UI_RegisterText(TEXT_POPUP_INFO, headline);

	/* make sure, that we are using the linked list */
	UI_ResetData(TEXT_LIST);
	UI_RegisterLinkedListText(TEXT_LIST, entries);

	window = UI_GetWindow(POPUPLIST_WINDOW_NAME);
	if (!window)
		Com_Error(ERR_FATAL, "Could not get "POPUPLIST_WINDOW_NAME" window");
	listNode = UI_GetNode(window, POPUPLIST_NODE_NAME);
	if (!listNode)
		Com_Error(ERR_FATAL, "Could not get "POPUPLIST_NODE_NAME" node in "POPUPLIST_WINDOW_NAME" window");

	/* free previous actions */
	if (listNode->onClick) {
		assert(listNode->onClick->d.terminal.d1.data);
		Mem_Free(listNode->onClick->d.terminal.d1.data);
		Mem_Free(listNode->onClick);
		listNode->onClick = NULL;
	}

	if (clickAction) {
		UI_PoolAllocAction(&listNode->onClick, EA_CMD, clickAction);
	} else {
		listNode->onClick = NULL;
	}

	if (!UI_IsWindowOnStack(window->name))
		UI_PushWindow(window->name, NULL, NULL);
	return listNode;
}
/**
 * @brief Prints the description for items (weapons, armour, ...)
 * @param[in] od The object definition of the item
 * @note Not only called from UFOpaedia but also from other places to display
 * weapon and ammo statistics
 * @todo Do we need to add checks for @c od->isDummy here somewhere?
 */
void INV_ItemDescription (const objDef_t* od)
{
    static char itemText[UI_MAX_SMALLTEXTLEN];
    int i;
    int count;

    currentDisplayedObject = od;
    Cvar_Set("mn_firemodename", "");
    Cvar_Set("mn_linkname", "");

    if (!od) {	/* If nothing selected return */
        Cvar_Set("mn_itemname", "");
        Cvar_Set("mn_item", "");
        UI_ResetData(TEXT_ITEMDESCRIPTION);
        itemIndex = fireModeIndex = 0;
        UI_ExecuteConfunc("itemdesc_view 0 0;");
        return;
    }

    /* select item */
    Cvar_Set("mn_itemname", "%s", _(od->name));
    Cvar_Set("mn_item", "%s", od->id);

    count = 0;
    if (GAME_ItemIsUseable(od)) {
        if (od->isAmmo()) {
            /* We display the pre/next buttons for changing weapon only if there are at least 2 researched weapons
             * we are counting the number of weapons that are usable with this ammo */
            for (i = 0; i < od->numWeapons; i++)
                if (GAME_ItemIsUseable(od->weapons[i]))
                    count++;
            if (itemIndex >= od->numWeapons || itemIndex < 0)
                itemIndex = 0;
            if (count > 0) {
                while (!GAME_ItemIsUseable(od->weapons[itemIndex])) {
                    itemIndex++;
                    if (itemIndex >= od->numWeapons)
                        itemIndex = 0;
                }
                Cvar_ForceSet("mn_linkname", _(od->weapons[itemIndex]->name));
            }
        } else if (od->weapon) {
            /* We display the pre/next buttons for changing ammo only if there are at least 2 researched ammo
             * we are counting the number of ammo that is usable with this weapon */
            for (i = 0; i < od->numAmmos; i++)
                if (GAME_ItemIsUseable(od->ammos[i]))
                    count++;

            if (itemIndex >= od->numAmmos || itemIndex < 0)
                itemIndex = 0;

            /* Only display ammos if at least one has been researched */
            if (count > 0) {
                /* We have a weapon that uses ammos */
                while (!GAME_ItemIsUseable(od->ammos[itemIndex])) {
                    itemIndex++;
                    if (itemIndex >= od->numAmmos)
                        itemIndex = 0;
                }
                Cvar_ForceSet("mn_linkname", _(od->ammos[itemIndex]->name));
            }
        } else {
            Cvar_ForceSet("mn_linkname", "");
        }
    }

    /* set description text if item has been researched or one of its ammo/weapon has been researched */
    if (count > 0 || GAME_ItemIsUseable(od)) {
        int numFiredefs = 0;

        *itemText = '\0';
        if (od->isArmour()) {
            Com_sprintf(itemText, sizeof(itemText), _("Size:\t%i\n"), od->size);
            Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight);
            Q_strcat(itemText, sizeof(itemText), "\n");
            Q_strcat(itemText, sizeof(itemText), _("^BDamage type:\tProtection:\n"));
            for (i = 0; i < csi.numDTs; i++) {
                const damageType_t* dt = &csi.dts[i];
                if (!dt->showInMenu)
                    continue;
                Q_strcat(itemText, sizeof(itemText), _("%s\t%i\n"), _(dt->id), od->ratings[i]);
            }
        } else if ((od->weapon && od->numAmmos) || od->isAmmo()) {
            const objDef_t* odAmmo;

            if (count > 0) {
                int weaponIndex;
                if (od->weapon) {
                    Com_sprintf(itemText, sizeof(itemText), _("%s weapon\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed")));
                    if (od->ammo > 0)
                        Q_strcat(itemText, sizeof(itemText), _("Max ammo:\t%i\n"), od->ammo);
                    odAmmo = (od->numAmmos) ? od->ammos[itemIndex] : od;
                    assert(odAmmo);
                    for (weaponIndex = 0; (weaponIndex < odAmmo->numWeapons) && (odAmmo->weapons[weaponIndex] != od); weaponIndex++) {}
                } else {
                    odAmmo = od;
                    weaponIndex = itemIndex;
                }

                Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight);
                /** @todo is there ammo with no firedefs? */
                if (GAME_ItemIsUseable(odAmmo) && odAmmo->numFiredefs[weaponIndex] > 0) {
                    const fireDef_t* fd;
                    numFiredefs = odAmmo->numFiredefs[weaponIndex];

                    /* This contains everything common for weapons and ammos */
                    /* We check if the wanted firemode to display exists. */
                    if (fireModeIndex > numFiredefs - 1)
                        fireModeIndex = 0;
                    if (fireModeIndex < 0)
                        fireModeIndex = numFiredefs - 1;

                    fd = &odAmmo->fd[weaponIndex][fireModeIndex];

                    /* We always display the name of the firemode for an ammo */
                    Cvar_Set("mn_firemodename", "%s", _(fd->name));

                    /* We display the characteristics of this firemode */
                    Q_strcat(itemText, sizeof(itemText), _("Skill:\t%s\n"), CL_WeaponSkillToName(fd->weaponSkill));
                    Q_strcat(itemText, sizeof(itemText), _("Damage:\t%i\n"), (int) (fd->damage[0] + fd->spldmg[0]) * fd->shots);
                    Q_strcat(itemText, sizeof(itemText), _("Time units:\t%i\n"), fd->time);
                    Q_strcat(itemText, sizeof(itemText), _("Range:\t%g\n"), fd->range / UNIT_SIZE);
                    Q_strcat(itemText, sizeof(itemText), _("Spreads:\t%g\n"), (fd->spread[0] + fd->spread[1]) / 2);
                }
            } else {
                Com_sprintf(itemText, sizeof(itemText), _("%s. No detailed info available.\n"), od->isAmmo() ? _("Ammunition") : _("Weapon"));
                Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight);
            }
        } else if (od->weapon) {
            Com_sprintf(itemText, sizeof(itemText), _("%s ammo-less weapon\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed")));
            Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight);
        } else {
            /* just an item - only primary definition */
            Com_sprintf(itemText, sizeof(itemText), _("%s auxiliary equipment\n"), (od->fireTwoHanded ? _("Two-handed") : _("One-handed")));
            Q_strcat(itemText, sizeof(itemText), _("Weight:\t%g Kg\n"), od->weight);
            if (od->numWeapons > 0 && od->numFiredefs[0] > 0) {
                const fireDef_t* fd = &od->fd[0][0];
                Q_strcat(itemText, sizeof(itemText), _("Action:\t%s\n"), _(fd->name));
                Q_strcat(itemText, sizeof(itemText), _("Time units:\t%i\n"), fd->time);
                Q_strcat(itemText, sizeof(itemText), _("Range:\t%g\n"), fd->range / UNIT_SIZE);
            }
        }

        UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText);
        UI_ExecuteConfunc("itemdesc_view %i %i;", count, numFiredefs);
    } else {
        Com_sprintf(itemText, sizeof(itemText), _("Unknown - not useable"));
        UI_RegisterText(TEXT_ITEMDESCRIPTION, itemText);
        UI_ExecuteConfunc("itemdesc_view 0 0;");
    }
}
예제 #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;

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

	pos = statsBuffer;

	/* missions */
	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);
	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);
	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);
	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) {
			if (!E_IsHired(employee))
				continue;
			costs += CP_GetSalaryBaseEmployee(salary, i) + employee->chr.score.rank * CP_GetSalaryRankBonusEmployee(salary, i);
			hired[employee->type]++;
		}
	}

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

	/* costs - second part */
	pos += (strlen(pos) + 1);
	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);
	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_IsXVIResearched()) {
		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));
	}
}
예제 #9
0
/**
 * @brief Start Base Attack.
 * @note Base attack mission -- Stage 2
 */
void CP_BaseAttackStartMission (mission_t *mission)
{
	base_t *base = mission->data.base;
	linkedList_t *hiredSoldiersInBase = NULL;
	employee_t *employee;

	assert(base);

	mission->stage = STAGE_BASE_ATTACK;

	CP_MissionDisableTimeLimit(mission);

	if (mission->ufo) {
		/* ufo becomes invisible on geoscape, but don't remove it from ufo global array (may reappear)*/
		CP_UFORemoveFromGeoscape(mission, qfalse);
	}

	/* we always need at least one command centre in the base - because the
	 * phalanx soldiers have their starting positions here.
	 * There should also always be an entrance - the aliens start there
	 * but we don't need to check that as entrance can't be destroyed */
	if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, B_COMMAND)) {
		/** @todo handle command centre properly */
		Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no Command Center: it can't defend itself. Destroy base.\n", base->name);
		CP_BaseAttackMissionDestroyBase(mission);
		return;
	}

	base->baseStatus = BASE_UNDER_ATTACK;
	ccs.campaignStats.basesAttacked++;

#if 0
	/** @todo implement onattack: add it to basemanagement.ufo and implement functions */
	if (base->onAttack[0] != '\0')
		/* execute next frame */
		Cbuf_AddText(va("%s %i", base->onAttack, base->id));
#endif

	MAP_SelectMission(mission);
	mission->active = qtrue;
	ccs.mapAction = MA_BASEATTACK;
	Com_DPrintf(DEBUG_CLIENT, "Base attack: %s at %.0f:%.0f\n", mission->id, mission->pos[0], mission->pos[1]);

	/** @todo EMPL_ROBOT */
	E_GetHiredEmployees(base, EMPL_SOLDIER, &hiredSoldiersInBase);

	/* Fill the fake aircraft */
	OBJZERO(baseAttackFakeAircraft);
	baseAttackFakeAircraft.homebase = base;
	/* needed for transfer of alien corpses */
	VectorCopy(base->pos, baseAttackFakeAircraft.pos);
#if 0
	/** @todo active this once more than 8 soldiers are working */
	/* needed to spawn soldiers on map */
	baseAttackFakeAircraft.maxTeamSize = LIST_Count(hiredSoldiersInBase);
#else
	baseAttackFakeAircraft.maxTeamSize = MAX_ACTIVETEAM;
#endif

	if (!hiredSoldiersInBase) {
		Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers: it can't defend itself. Destroy base.\n", base->name);
		CP_BaseAttackMissionDestroyBase(mission);
		return;
	}

	LIST_Foreach(hiredSoldiersInBase, employee_t, employee) {
		if (E_IsAwayFromBase(employee))
			continue;
		AIR_AddToAircraftTeam(&baseAttackFakeAircraft, employee);
	}
	if (AIR_GetTeamSize(&baseAttackFakeAircraft) == 0) {
		Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers at home: it can't defend itself. Destroy base.\n", base->name);
		CP_BaseAttackMissionDestroyBase(mission);
		return;
	}
#if 0
	/** @todo active this once more than 8 soldiers are working */
	/* all soldiers in the base should get used */
	baseAttackFakeAircraft.maxTeamSize = AIR_GetTeamSize(&baseAttackFakeAircraft);
#endif

	LIST_Delete(&hiredSoldiersInBase);
	base->aircraftCurrent = &baseAttackFakeAircraft;
	MAP_SetMissionAircraft(&baseAttackFakeAircraft);
	/** @todo remove me - this is not needed because we are using the base->aircraftCurrent
	 * pointer for resolving the aircraft - only CL_GameAutoGo needs this */
	MAP_SetInterceptorAircraft(&baseAttackFakeAircraft);	/* needed for updating soldier stats sa CL_UpdateCharacterStats*/
	B_SetCurrentSelectedBase(base);						/* needed for equipment menu */

	Com_sprintf(popupText, sizeof(popupText), _("Base '%s' is under attack! What to do ?"), base->name);
	UI_RegisterText(TEXT_POPUP, popupText);

	CL_GameTimeStop();
	UI_PushWindow("popup_baseattack", NULL, NULL);
}