/** * @brief Sells the given aircraft with all the equipment. * @param aircraft The aircraft to sell * @return @c true if the aircraft could get sold, @c false otherwise */ bool BS_SellAircraft (aircraft_t* aircraft) { int j; if (AIR_GetTeamSize(aircraft) > 0) return false; if (!AIR_IsAircraftInBase(aircraft)) return false; /* sell off any items which are mounted on it */ for (j = 0; j < aircraft->maxWeapons; j++) { const aircraftSlot_t* slot = &aircraft->weapons[j]; BS_ProcessCraftItemSale(slot->item, 1); BS_ProcessCraftItemSale(slot->ammo, 1); } BS_ProcessCraftItemSale(aircraft->shield.item, 1); /* there should be no ammo here, but checking can't hurt */ BS_ProcessCraftItemSale(aircraft->shield.ammo, 1); for (j = 0; j < aircraft->maxElectronics; j++) { const aircraftSlot_t* slot = &aircraft->electronics[j]; BS_ProcessCraftItemSale(slot->item, 1); /* there should be no ammo here, but checking can't hurt */ BS_ProcessCraftItemSale(slot->ammo, 1); } /* the capacities are also updated here */ BS_AddAircraftToMarket(aircraft, 1); CP_UpdateCredits(ccs.credits + BS_GetAircraftSellingPrice(aircraft)); AIR_DeleteAircraft(aircraft); return true; }
/** * @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 Sells aircraft or craftitem. * @sa BS_BuyAircraft_f */ static void BS_SellAircraft_f (void) { int num; base_t *base = B_GetCurrentSelectedBase(); if (Cmd_Argc() < 2) { Com_Printf("Usage: %s <num>\n", Cmd_Argv(0)); return; } if (!base) return; num = atoi(Cmd_Argv(1)); if (num < 0 || num >= buyList.length) return; if (buyCat == FILTER_AIRCRAFT) { const aircraft_t *aircraftTemplate = buyList.l[num].aircraft; qboolean aircraftOutNote = qfalse; qboolean teamNote = qfalse; aircraft_t *aircraft = NULL; if (!aircraftTemplate) return; AIR_ForeachFromBase(a, base) { if (Q_streq(a->id, aircraftTemplate->id)) { if (AIR_GetTeamSize(a) > 0) { teamNote = qtrue; continue; } if (!AIR_IsAircraftInBase(a)) { /* aircraft is not in base */ aircraftOutNote = qtrue; continue; } aircraft = a; break; } } if (aircraft) { BS_SellAircraft(aircraft); /* reinit the menu */ BS_BuyType(base); } else { if (teamNote) CP_Popup(_("Note"), _("You can't sell an aircraft if it still has a team assigned")); else if (aircraftOutNote) CP_Popup(_("Note"), _("You can't sell an aircraft that is not in base")); else Com_DPrintf(DEBUG_CLIENT, "BS_SellAircraft_f: There are no aircraft available (with no team assigned) for selling\n"); } } }
/** * @brief Update aircraft selection list with the current base aircraft names */ static void AIR_AircraftFillList_f (void) { base_t* base = B_GetCurrentSelectedBase(); cgi->UI_ExecuteConfunc("ui_aircraft_clear"); int idx = 0; AIR_ForeachFromBase(aircraft, base) { const float health = aircraft->stats[AIR_STATS_DAMAGE] > 0 ? (float)aircraft->damage * 100.0f / aircraft->stats[AIR_STATS_DAMAGE] : 0.0f; const char* inBase = AIR_IsAircraftInBase(aircraft) ? "1" : "0"; char teamStr[MAX_VAR]; Com_sprintf(teamStr, sizeof(teamStr), _("%i of %i"), AIR_GetTeamSize(aircraft), aircraft->maxTeamSize); cgi->UI_ExecuteConfunc("ui_aircraft_add %i \"%s\" %3.0f %s \"%s\" \"%s\"", idx, _(aircraft->name), health, inBase, AIR_AircraftStatusToName(aircraft), teamStr); idx++; } }
/** * @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); }