Esempio n. 1
0
/**
 * @brief Load callback for savin in XML Format
 * @param[in] parent Parent XML node in the savegame
 * @todo Remove: Fallback for compatibility
 */
bool AC_LoadXML (xmlNode_t* parent)
{
	xmlNode_t* aliencont = cgi->XML_GetNode(parent, SAVE_ALIENCONT_ALIENCONT);
	if (!aliencont)
		return true;
	FOREACH_XMLNODE(contNode, aliencont, SAVE_ALIENCONT_CONT) {
		const int baseIdx = cgi->XML_GetInt(contNode, SAVE_ALIENCONT_BASEIDX, MAX_BASES);
		base_t* base = B_GetFoundedBaseByIDX(baseIdx);
		if (!base) {
			Com_Printf("AC_LoadXML: Invalid base idx '%i'\n", baseIdx);
			continue;
		}

		FOREACH_XMLNODE(alienNode, contNode, SAVE_ALIENCONT_ALIEN) {
			const char* teamId = cgi->XML_GetString(alienNode, SAVE_ALIENCONT_TEAMID);
			const int alive = cgi->XML_GetInt(alienNode, SAVE_ALIENCONT_AMOUNTALIVE, 0);
			const int dead = cgi->XML_GetInt(alienNode, SAVE_ALIENCONT_AMOUNTDEAD, 0);

			if (alive == 0 && dead == 0)
				continue;

			if (!base->alienContainment)
				base->alienContainment = new AlienContainment(CAP_Get(base, CAP_ALIENS), nullptr);

			base->alienContainment->add(teamId, alive, dead);
		}
	}

	return true;
}
/**
 * @brief Alien containment menu init function.
 * @note Command to call this: ui_aliencont_init
 * @note Should be called whenever the alien containment menu gets active.
 */
static void AC_Init_f (void)
{
	base_t* base;
	if (cgi->Cmd_Argc() < 2)
		base = B_GetCurrentSelectedBase();
	else
		base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
	if (!base) {
		Com_Printf("No base selected\n");
		return;
	}

	cgi->UI_ExecuteConfunc("ui_aliencont_cap %d %d", CAP_GetCurrent(base, CAP_ALIENS), CAP_GetMax(base, CAP_ALIENS));
	cgi->UI_ExecuteConfunc("ui_aliencont_clear");
	if (!base->alienContainment)
		return;
	linkedList_t* list = base->alienContainment->list();
	LIST_Foreach(list, alienCargo_t, item) {
		const technology_t* tech = RS_GetTechForTeam(item->teamDef);
		cgi->UI_ExecuteConfunc("ui_aliencont_add \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" %f %d %d",
			item->teamDef->id, _(item->teamDef->name), tech->id, tech->image,
			(RS_IsResearched_ptr(tech)) ? _("Researched") : _("Awaiting autopsy"),
			(1.0f - tech->time / tech->overallTime) * 100, item->alive, item->dead);
	}
	cgi->LIST_Delete(&list);
}
/**
 * @brief onDestroy Callback for Antimatter Storage
 */
static void B_Destroy_AntimaterStorage_f (void)
{
	base_t *base;
	const float prob = frand();

	if (cgi->Cmd_Argc() < 4) {	/** note: third parameter not used but we must be sure we have probability parameter */
		Com_Printf("Usage: %s <probability> <baseID> <buildingType>\n", cgi->Cmd_Argv(0));
		return;
	}

	base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(2)));
	if (!base)
		return;
	if (CAP_GetCurrent(base, CAP_ANTIMATTER) <= 0)
		return;

	CAP_RemoveAntimatterExceedingCapacity(base);

	if (base->baseStatus != BASE_WORKING)
		return;

	if (prob < atof(cgi->Cmd_Argv(1))) {
		MS_AddNewMessage(_("Notice"), va(_("%s has been destroyed by an antimatter storage breach."), base->name));
		cgi->UI_PopWindow(false);
		B_Destroy(base);
	}
}
/**
 * @brief Console command to kill all aliens on a base.
 * @note if the first argrument is a base index that, otherwise the current base will remove it's aliens
 * @sa AC_KillAll
 */
static void AC_KillAll_f (void)
{
	base_t *base;

	if (Cmd_Argc() < 2) {
		base = B_GetCurrentSelectedBase();
	} else {
		base = B_GetFoundedBaseByIDX(atoi(Cmd_Argv(1)));
	}

	/* Can be called from everywhere. */
	if (!base)
		return;

	AC_KillAll(base);
	/* Reinit menu to display proper values. */
	AC_UpdateMenu(base);
}
Esempio n. 5
0
/**
 * @brief User select a base in the popup_homebase
 * change homebase to selected base.
 */
static void CL_PopupChangeHomebase_f (void)
{
	linkedList_t* data = popupListData;	/**< Use this so we do not change the original popupListData pointer. */
	int selectedPopupIndex;
	int i;
	base_t *base;
	int baseIdx;
	aircraft_t *aircraft = MAP_GetSelectedAircraft();

	/* If popup is opened, that means an aircraft is selected */
	if (!aircraft) {
		Com_Printf("CL_PopupChangeHomebase_f: An aircraft must be selected\n");
		return;
	}

	if (Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <popupIndex>\tpopupIndex=num in base list\n", Cmd_Argv(0));
		return;
	}

	/* read and range check */
	selectedPopupIndex = atoi(Cmd_Argv(1));
	Com_DPrintf(DEBUG_CLIENT, "CL_PopupHomebaseClick_f (popupNum %i, selectedPopupIndex %i)\n", popupNum, selectedPopupIndex);
	if (selectedPopupIndex < 0 || selectedPopupIndex >= popupNum)
		return;

	/* Convert list index to base idx */
	baseIdx = INVALID_BASE;
	for (i = 0; data; data = data->next, i++) {
		if (i == selectedPopupIndex) {
			baseIdx = *(int*)data->data;
			break;
		}
	}

	base = B_GetFoundedBaseByIDX(baseIdx);
	if (base == NULL)
		return;

	AIR_MoveAircraftIntoNewHomebase(aircraft, base);

	UI_PopWindow(qfalse);
	CL_DisplayHomebasePopup(aircraft, qtrue);
}
/**
 * @brief Console command to kill all aliens on a base.
 * @note if the first argrument is a base index that, otherwise the current base will remove it's aliens
 * @sa AC_KillAll
 */
static void AC_KillAll_f (void)
{
	base_t* base;

	if (cgi->Cmd_Argc() < 2) {
		base = B_GetCurrentSelectedBase();
	} else {
		base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(1)));
	}

	if (!base)
		return;
	if (!base->alienContainment)
		return;

	linkedList_t* list = base->alienContainment->list();
	LIST_Foreach(list, alienCargo_t, item) {
		base->alienContainment->add(item->teamDef, -item->alive, item->alive);
	}
/**
 * @brief Open menu for basesummary.
 */
static void BaseSummary_SelectBase_f (void)
{
	const base_t *base;

	if (cgi->Cmd_Argc() >= 2) {
		const int i = atoi(cgi->Cmd_Argv(1));
		base = B_GetFoundedBaseByIDX(i);
		if (base == NULL) {
			Com_Printf("Invalid base index given (%i).\n", i);
			return;
		}
	} else {
		base = B_GetCurrentSelectedBase();
	}

	if (base != NULL) {
		BaseSummary_Init(base);
		cgi->UI_ExecuteConfunc("basesummary_change_color %i", base->idx);
	}
}
Esempio n. 8
0
/**
 * @brief Load callback for savin in XML Format
 * @sa AC_LoadXML
 * @sa B_SaveXML
 * @sa SAV_GameLoadXML
 */
qboolean AC_LoadXML (mxml_node_t * parent)
{
	mxml_node_t *aliencont;
	mxml_node_t *contNode;
	int i;

	aliencont = mxml_GetNode(parent, SAVE_ALIENCONT_ALIENCONT);
	ccs.breathingMailSent = mxml_GetBool(aliencont, SAVE_ALIENCONT_BREATHINGMAILSENT, qfalse);

	/* Init alienContainers */
	for (i = 0; i < MAX_BASES; i++) {
		base_t *base = B_GetBaseByIDX(i);

		AL_FillInContainment(base);
	}
	/* Load data */
	for (contNode = mxml_GetNode(aliencont, SAVE_ALIENCONT_CONT); contNode;
			contNode = mxml_GetNextNode(contNode, aliencont, SAVE_ALIENCONT_CONT)) {
		int j = mxml_GetInt(contNode, SAVE_ALIENCONT_BASEIDX, MAX_BASES);
		base_t *base = B_GetFoundedBaseByIDX(j);
		int k;
		mxml_node_t *alienNode;

		if (!base) {
			Com_Printf("AC_LoadXML: Invalid base idx '%i'\n", j);
			continue;
		}

		for (k = 0, alienNode = mxml_GetNode(contNode, SAVE_ALIENCONT_ALIEN); alienNode && k < MAX_ALIENCONT_CAP; alienNode = mxml_GetNextNode(alienNode, contNode, SAVE_ALIENCONT_ALIEN), k++) {
			const char *const s = mxml_GetString(alienNode, SAVE_ALIENCONT_TEAMID);
			/* Fill Alien Containment with default values like the tech pointer. */
			base->alienscont[k].teamDef = Com_GetTeamDefinitionByID(s);
			if (base->alienscont[k].teamDef) {
				base->alienscont[k].amountAlive = mxml_GetInt(alienNode, SAVE_ALIENCONT_AMOUNTALIVE, 0);
				base->alienscont[k].amountDead = mxml_GetInt(alienNode, SAVE_ALIENCONT_AMOUNTDEAD, 0);
			}
		}
	}

	return qtrue;
}
/**
 * @brief Called when a base is opened or a new base is created on geoscape.
 * For a new base the baseID is -1.
 */
static void B_SelectBase_f (void)
{
	int baseID;

	if (cgi->Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <baseID>\n", cgi->Cmd_Argv(0));
		return;
	}
	baseID = atoi(cgi->Cmd_Argv(1));
	/* check against MAX_BASES here! - only -1 will create a new base
	 * if we would check against ccs.numBases here, a click on the base summary
	 * base nodes would try to select unfounded bases */
	if (baseID >= 0 && baseID < MAX_BASES) {
		const base_t *base = B_GetFoundedBaseByIDX(baseID);
		/* don't create a new base if the index was valid */
		if (base)
			B_SelectBase(base);
	} else if (baseID == CREATE_NEW_BASE_ID) {
		/* create a new base */
		B_SelectBase(NULL);
	}
}
Esempio n. 10
0
/**
 * @brief Remove a defence system from base.
 * @note 1st argument is the basedefence system type to destroy (sa basedefenceType_t).
 * @note 2nd argument is the idx of the base in which you want the battery to be destroyed.
 * @note if the first argument is BASEDEF_RANDOM, the type of the battery to destroy is randomly selected
 * @note the building must already be removed from ccs.buildings[baseIdx][]
 */
static void BDEF_RemoveBattery_f (void)
{
	basedefenceType_t basedefType;
	int baseIdx;
	base_t* base;

	if (cgi->Cmd_Argc() < 3) {
		Com_Printf("Usage: %s <basedefType> <baseIdx>", cgi->Cmd_Argv(0));
		return;
	} else {
		char type[MAX_VAR];

		Q_strncpyz(type, cgi->Cmd_Argv(1), sizeof(type));
		if (Q_streq(type, "missile"))
			basedefType = BASEDEF_MISSILE;
		else if (Q_streq(type, "laser"))
			basedefType = BASEDEF_LASER;
		else if (Q_streq(type, "random"))
			basedefType = BASEDEF_RANDOM;
		else
			return;
		baseIdx = atoi(cgi->Cmd_Argv(2));
	}

	/* Check that the baseIdx exists */
	if (baseIdx < 0 || baseIdx >= B_GetCount()) {
		Com_Printf("BDEF_RemoveBattery_f: baseIdx %i doesn't exist: there is only %i bases in game.\n",
				baseIdx, B_GetCount());
		return;
	}

	base = B_GetFoundedBaseByIDX(baseIdx);
	if (!base) {
		Com_Printf("BDEF_RemoveBattery_f: baseIdx %i is not founded.\n", baseIdx);
		return;
	}

	if (basedefType == BASEDEF_RANDOM) {
		/* Type of base defence to destroy is randomly selected */
		if (base->numBatteries <= 0 && base->numLasers <= 0) {
			Com_Printf("No base defence to destroy\n");
			return;
		} else if (base->numBatteries <= 0) {
			/* only laser battery is possible */
			basedefType = BASEDEF_LASER;
		} else if (base->numLasers <= 0) {
			/* only missile battery is possible */
			basedefType = BASEDEF_MISSILE;
		} else {
			/* both type are possible, choose one randomly */
			basedefType = (basedefenceType_t)(rand() % 2 + BASEDEF_MISSILE);
		}
	} else {
		/* Check if the removed building was under construction */
		buildingType_t type;
		int workingNum, max;
		building_t* building;

		switch (basedefType) {
		case BASEDEF_MISSILE:
			type = B_DEFENCE_MISSILE;
			max = base->numBatteries;
			break;
		case BASEDEF_LASER:
			type = B_DEFENCE_LASER;
			max = base->numLasers;
			break;
		default:
			Com_Printf("BDEF_RemoveBattery_f: base defence type %i doesn't exist.\n", basedefType);
			return;
		}

		building = nullptr;
		workingNum = 0;
		while ((building = B_GetNextBuildingByType(base, building, type)))
			if (building->buildingStatus == B_STATUS_WORKING)
				workingNum++;

		if (workingNum == max) {
			/* Removed building was under construction, do nothing */
			return;
		} else if (workingNum != max - 1) {
			/* Should never happen, we only remove building one by one */
			Com_Printf("BDEF_RemoveBattery_f: Error while checking number of batteries (%i instead of %i) in base '%s'.\n",
				workingNum, max, base->name);
			return;
		}

		/* If we reached this point, that means we are removing a working building: continue */
	}

	BDEF_RemoveBattery(base, basedefType, -1);
}
Esempio n. 11
0
/**
 * @brief Fill market item list
 */
static void BS_FillMarket_f (void)
{
	const base_t* base = B_GetCurrentSelectedBase();
	itemFilterTypes_t type;

	if (cgi->Cmd_Argc() < 2) {
		cgi->Com_Printf("Usage: %s <category>\n", cgi->Cmd_Argv(0));
		return;
	}
	if (cgi->Cmd_Argc() >= 3)
		base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(2)));
	if (!base) {
		cgi->Com_Printf("No/invalid base selected.\n");
		return;
	}

	type = cgi->INV_GetFilterTypeID(cgi->Cmd_Argv(1));
	cgi->UI_ExecuteConfunc("ui_market_clear");
	switch (type) {
	case FILTER_UGVITEM:
		/* show own UGV */
		E_Foreach(EMPL_ROBOT, robot) {
			const ugv_t* ugv = robot->getUGV();
			const technology_t* tech = RS_GetTechByProvided(ugv->id);

			if (!robot->isHiredInBase(base))
				continue;

			cgi->UI_ExecuteConfunc("ui_market_add \"ugv-%d\" \"%s\" 1 0 0 %d - \"%s\"", robot->chr.ucn, _(tech->name), ugv->price, robot->isAwayFromBase() ? _("UGV is away from home") : "-");
		}
		/* show buyable UGV */
		for (int i = 0; i < cgi->csi->numUGV; i++) {
			const ugv_t* ugv = &cgi->csi->ugvs[i];
			const technology_t* tech = RS_GetTechByProvided(ugv->id);
			const objDef_t* ugvWeapon = INVSH_GetItemByID(ugv->weapon);
			const int buyable = std::min(E_CountUnhiredRobotsByType(ugv), BS_GetItemOnMarket(ugvWeapon));

			assert(tech);
			if (!RS_IsResearched_ptr(tech))
				continue;
			if (buyable <= 0)
				continue;

			cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" 0 %d %d %d - -", ugv->id, _(tech->name), buyable, ugv->price, ugv->price);
		}
		/* show (UGV) items, fall through */
	case FILTER_S_PRIMARY:
	case FILTER_S_SECONDARY:
	case FILTER_S_HEAVY:
	case FILTER_S_IMPLANT:
	case FILTER_S_MISC:
	case FILTER_S_ARMOUR:
	case FILTER_DUMMY:
	case FILTER_CRAFTITEM:
	case MAX_FILTERTYPES: {
		for (int i = 0; i < cgi->csi->numODs; i++) {
			const objDef_t* od = &cgi->csi->ods[i];
			const technology_t* tech = RS_GetTechForItem(od);

			if (!BS_IsOnMarket(od))
				continue;
			if (B_ItemInBase(od, base) + BS_GetItemOnMarket(od) <= 0)
				continue;
			if (type != MAX_FILTERTYPES && !cgi->INV_ItemMatchesFilter(od, type))
				continue;
			cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" %d %d %d %d %s -", od->id, _(od->name), B_ItemInBase(od, base), BS_GetItemOnMarket(od), BS_GetItemBuyingPrice(od), BS_GetItemSellingPrice(od), RS_IsResearched_ptr(tech) ? va("%d", ccs.eMarket.autosell[i]) : "-");
		}
		break;
	}
	case FILTER_AIRCRAFT: {
		AIR_ForeachFromBase(aircraft, base) {
			cgi->UI_ExecuteConfunc("ui_market_add \"aircraft_%d\" \"%s\" 1 0 0 %d - \"%s\"", aircraft->idx, aircraft->name, BS_GetAircraftSellingPrice(aircraft), AIR_IsAircraftInBase(aircraft) ? "-" : _("Aircraft is away from home"));
		}
		for (int i = 0; i < ccs.numAircraftTemplates; i++) {
			const aircraft_t* aircraft = &ccs.aircraftTemplates[i];
			if (!BS_AircraftIsOnMarket(aircraft))
				continue;
			if (!RS_IsResearched_ptr(aircraft->tech))
				continue;
			if (BS_GetAircraftOnMarket(aircraft) <= 0)
				continue;
			cgi->UI_ExecuteConfunc("ui_market_add \"%s\" \"%s\" 0 %d %d %d - -", aircraft->id, _(aircraft->tech->name), BS_GetAircraftOnMarket(aircraft), BS_GetAircraftBuyingPrice(aircraft), BS_GetAircraftSellingPrice(aircraft));
		}
		break;
	}
	default:
		break;
	}
Esempio n. 12
0
/**
 * @brief Buy/Sell item/aircraft/ugv on the market
 */
static void BS_Buy_f (void)
{
	const char* itemid;
	int count;
	base_t* base = B_GetCurrentSelectedBase();
	const aircraft_t* aircraft;
	const ugv_t* ugv;
	const objDef_t* od;

	if (cgi->Cmd_Argc() < 2) {
		cgi->Com_Printf("Usage: %s <item-id> <count> [base-idx] \nNegative count means selling. If base index is omitted buys on the currently selected base.\n",
				cgi->Cmd_Argv(0));
		return;
	}

	itemid = cgi->Cmd_Argv(1);
	count = atoi(cgi->Cmd_Argv(2));

	if (cgi->Cmd_Argc() >= 4)
		base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(3)));

	if (char const* const rest = Q_strstart(itemid, "aircraft_")) {
		/* aircraft sell - with aircraft golbal idx */
		int idx = atoi(rest);
		aircraft_t* aircraft = AIR_AircraftGetFromIDX(idx);

		if (!aircraft) {
			cgi->Com_Printf("Invalid aircraft index!\n");
			return;
		}
		AIR_RemoveEmployees(*aircraft);
		BS_SellAircraft(aircraft);
		return;
	}

	if (char const* const rest = Q_strstart(itemid, "ugv-")) {
		/* ugv sell - with unique character number index */
		int ucn = atoi(rest);
		Employee* robot = E_GetEmployeeByTypeFromChrUCN(EMPL_ROBOT, ucn);

		if (!robot) {
			cgi->Com_Printf("Invalid UCN for UGV!\n");
			return;
		}

		BS_SellUGV(robot);
		return;
	}

	if (!base) {
		cgi->Com_Printf("No/invalid base selected.\n");
		return;
	}

	aircraft = AIR_GetAircraftSilent(itemid);
	if (aircraft) {
		if (!B_GetBuildingStatus(base, B_COMMAND)) {
			CP_Popup(_("Note"), _("No Command Centre in this base.\nHangars are not functional.\n"));
			return;
		}
		/* We cannot buy aircraft if there is no power in our base. */
		if (!B_GetBuildingStatus(base, B_POWER)) {
			CP_Popup(_("Note"), _("No power supplies in this base.\nHangars are not functional."));
			return;
		}
		/* We cannot buy aircraft without any hangar. */
		if (!AIR_AircraftAllowed(base)) {
			CP_Popup(_("Note"), _("Build a hangar first."));
			return;
		}
		/* Check free space in hangars. */
		if (CAP_GetFreeCapacity(base, AIR_GetHangarCapacityType(aircraft)) <= 0) {
			CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough space in hangars.\n"));
			return;
		}

		if (ccs.credits < BS_GetAircraftBuyingPrice(aircraft)) {
			CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough credits.\n"));
			return;
		}

		BS_BuyAircraft(aircraft, base);
		return;
	}

	ugv = cgi->Com_GetUGVByIDSilent(itemid);
	if (ugv) {
		const objDef_t* ugvWeapon = INVSH_GetItemByID(ugv->weapon);
		if (!ugvWeapon)
			cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get weapon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id);

		if (E_CountUnhiredRobotsByType(ugv) < 1)
			return;
		if (ccs.eMarket.numItems[ugvWeapon->idx] < 1)
			return;

		if (ccs.credits < ugv->price) {
			CP_Popup(_("Not enough money"), _("You cannot buy this item as you don't have enough credits."));
			return;
		}

		if (CAP_GetFreeCapacity(base, CAP_ITEMS) < UGV_SIZE + ugvWeapon->size) {
			CP_Popup(_("Not enough storage space"), _("You cannot buy this item.\nNot enough space in storage.\nBuild more storage facilities."));
			return;
		}

		BS_BuyUGV(ugv, base);
		return;
	}

	if (count == 0) {
		cgi->Com_Printf("Invalid number of items to buy/sell: %s\n", cgi->Cmd_Argv(2));
		return;
	}

	/* item */
	od = INVSH_GetItemByID(cgi->Cmd_Argv(1));
	if (od) {
		if (!BS_IsOnMarket(od))
			return;

		if (count > 0) {
			/* buy */
			const int price = BS_GetItemBuyingPrice(od);
			count = std::min(count, BS_GetItemOnMarket(od));

			/* no items available on market */
			if (count <= 0)
				return;

			if (price <= 0) {
				cgi->Com_Printf("Item on market with invalid buying price: %s (%d)\n", od->id, BS_GetItemBuyingPrice(od));
				return;
			}
			/** @todo warn if player can buy less item due to available credits? */
			count = std::min(count, ccs.credits / price);
			/* not enough money for a single item */
			if (count <= 0) {
				CP_Popup(_("Not enough money"), _("You cannot buy this item as you don't have enough credits."));
				return;
			}

			if (od->size <= 0) {
				cgi->Com_Printf("Item on market with invalid size: %s (%d)\n", od->id, od->size);
				return;
			}
			count = std::min(count, CAP_GetFreeCapacity(base, CAP_ITEMS) / od->size);
			if (count <= 0) {
				CP_Popup(_("Not enough storage space"), _("You cannot buy this item.\nNot enough space in storage.\nBuild more storage facilities."));
				return;
			}

			BS_BuyItem(od, base, count);
		} else {
			/* sell */
			count = std::min(-1 * count, B_ItemInBase(od, base));
			/* no items in storage */
			if (count <= 0)
				return;
			BS_SellItem(od, base, count);
		}
		return;
	}
	cgi->Com_Printf("Invalid item ID\n");
}