cp_mission_baseattack.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "../../cl_shared.h"
00027 #include "../../ui/ui_main.h"
00028 #include "../../ui/ui_popup.h"
00029 #include "../cp_campaign.h"
00030 #include "../cp_map.h"
00031 #include "../cp_ufo.h"
00032 #include "../cp_missions.h"
00033 #include "../cp_time.h"
00034 #include "../cp_alien_interest.h"
00035 
00041 static aircraft_t baseAttackFakeAircraft;
00042 
00048 void CP_BaseAttackMissionIsSuccess (mission_t *mission)
00049 {
00050     CL_ChangeIndividualInterest(0.3f, INTERESTCATEGORY_RECON);
00051     CL_ChangeIndividualInterest(0.1f, INTERESTCATEGORY_HARVEST);
00052     CL_ChangeIndividualInterest(-0.5f, INTERESTCATEGORY_TERROR_ATTACK);
00053     CL_ChangeIndividualInterest(-0.5f, INTERESTCATEGORY_INTERCEPT);
00054 
00055     CP_MissionRemove(mission);
00056 }
00057 
00061 void CP_BaseAttackMissionIsFailure (mission_t *mission)
00062 {
00063     base_t *base;
00064 
00065     base = (base_t *)mission->data;
00066 
00067     if (base)
00068         base->baseStatus = BASE_WORKING;
00069     ccs.mapAction = MA_NONE;
00070 
00071     /* we really don't want to use the fake aircraft anywhere */
00072     if (base)
00073         base->aircraftCurrent = AIR_GetNextFromBase(base, NULL);
00074     ccs.missionAircraft = NULL;
00075 
00076     CL_ChangeIndividualInterest(0.05f, INTERESTCATEGORY_BUILDING);
00077     CL_ChangeIndividualInterest(0.1f, INTERESTCATEGORY_BASE_ATTACK);
00078 
00079     /* reset ccs.selectedMission */
00080     MAP_NotifyMissionRemoved(mission);
00081 
00082     CP_MissionRemove(mission);
00083 }
00084 
00088 void CP_BaseAttackMissionOnSpawn (void)
00089 {
00090     /* Prevent multiple bases from being attacked. by resetting interest. */
00091     CL_ChangeIndividualInterest(-1.0f, INTERESTCATEGORY_BASE_ATTACK);
00092 }
00093 
00098 void CP_BaseAttackMissionLeave (mission_t *mission)
00099 {
00100     mission->stage = STAGE_RETURN_TO_ORBIT;
00101 
00102     if (mission->ufo) {
00103         CP_MissionDisableTimeLimit(mission);
00104         UFO_SetRandomDest(mission->ufo);
00105         /* Display UFO on geoscape if it is detected */
00106         mission->ufo->landed = qfalse;
00107     } else {
00108         /* Go to next stage on next frame */
00109         mission->finalDate = ccs.date;
00110     }
00111 }
00112 
00118 void CP_BaseAttackMissionDestroyBase (mission_t *mission)
00119 {
00120     base_t *base;
00121 
00122     base = (base_t *)mission->data;
00123     assert(base);
00124     /* Base attack is over, alien won */
00125     Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Your base: %s has been destroyed! All employees killed and all equipment destroyed."), base->name);
00126     MS_AddNewMessage(_("Notice"), cp_messageBuffer, qfalse, MSG_STANDARD, NULL);
00127     B_Destroy(base);
00128     CL_GameTimeStop();
00129 
00130     /* we really don't want to use the fake aircraft anywhere */
00131     ccs.missionAircraft = NULL;
00132 
00133     /* HACK This hack is only needed until base will be really destroyed
00134      * we must recalculate items in storage because of the items we collected on battlefield */
00135     B_UpdateStorageCap(base);
00136     base->aircraftCurrent = NULL;
00137     base->baseStatus = BASE_WORKING;
00138 }
00139 
00144 void CP_BaseAttackStartMission (mission_t *mission)
00145 {
00146     base_t *base = (base_t *)mission->data;
00147     linkedList_t *hiredSoldiersInBase = NULL, *pos;
00148 
00149     assert(base);
00150 
00151     mission->stage = STAGE_BASE_ATTACK;
00152 
00153     CP_MissionDisableTimeLimit(mission);
00154 
00155     if (mission->ufo) {
00156         /* ufo becomes invisible on geoscape, but don't remove it from ufo global array (may reappear)*/
00157         CP_UFORemoveFromGeoscape(mission, qfalse);
00158     }
00159 
00160     /* we always need at least one command centre in the base - because the
00161      * phalanx soldiers have their starting positions here.
00162      * There should also always be an entrance - the aliens start there
00163      * but we don't need to check that as entrance can't be destroyed */
00164     if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, B_COMMAND)) {
00166         Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no Command Center: it can't defend itself. Destroy base.\n", base->name);
00167         CP_BaseAttackMissionDestroyBase(mission);
00168         return;
00169     }
00170 
00171     base->baseStatus = BASE_UNDER_ATTACK;
00172     ccs.campaignStats.basesAttacked++;
00173 
00174 #if 0
00175 
00176     if (base->onAttack[0] != '\0')
00177         /* execute next frame */
00178         Cbuf_AddText(va("%s %i", base->onAttack, base->id));
00179 #endif
00180 
00181     MAP_SelectMission(mission);
00182     ccs.selectedMission->active = qtrue;
00183     ccs.mapAction = MA_BASEATTACK;
00184     Com_DPrintf(DEBUG_CLIENT, "Base attack: %s at %.0f:%.0f\n", ccs.selectedMission->id, ccs.selectedMission->pos[0], ccs.selectedMission->pos[1]);
00185 
00187     E_GetHiredEmployees(base, EMPL_SOLDIER, &hiredSoldiersInBase);
00188 
00189     /* Fill the fake aircraft */
00190     memset(&baseAttackFakeAircraft, 0, sizeof(baseAttackFakeAircraft));
00191     baseAttackFakeAircraft.homebase = base;
00192     /* needed for transfer of alien corpses */
00193     VectorCopy(base->pos, baseAttackFakeAircraft.pos);
00194 #if 0
00195 
00196     /* needed to spawn soldiers on map */
00197     baseAttackFakeAircraft.maxTeamSize = LIST_Count(hiredSoldiersInBase);
00198 #else
00199     baseAttackFakeAircraft.maxTeamSize = MAX_ACTIVETEAM;
00200 #endif
00201 
00202     if (!hiredSoldiersInBase) {
00203         Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers: it can't defend itself. Destroy base.\n", base->name);
00204         CP_BaseAttackMissionDestroyBase(mission);
00205         return;
00206     }
00207 
00208     for (pos = hiredSoldiersInBase; pos != NULL; pos = pos->next) {
00209         if (E_IsAwayFromBase((employee_t *)pos->data))
00210             continue;
00211         AIR_AddToAircraftTeam(&baseAttackFakeAircraft, (employee_t *)pos->data);
00212     }
00213     if (AIR_GetTeamSize(&baseAttackFakeAircraft) == 0) {
00214         Com_DPrintf(DEBUG_CLIENT, "CP_BaseAttackStartMission: Base '%s' has no soldiers at home: it can't defend itself. Destroy base.\n", base->name);
00215         CP_BaseAttackMissionDestroyBase(mission);
00216         return;
00217     }
00218 #if 0
00219 
00220     /* all soldiers in the base should get used */
00221     baseAttackFakeAircraft.maxTeamSize = AIR_GetTeamSize(&baseAttackFakeAircraft);
00222 #endif
00223 
00224     LIST_Delete(&hiredSoldiersInBase);
00225     base->aircraftCurrent = &baseAttackFakeAircraft;
00226     ccs.missionAircraft = &baseAttackFakeAircraft;
00229     ccs.interceptAircraft = &baseAttackFakeAircraft;    /* needed for updating soldier stats sa CL_UpdateCharacterStats*/
00230     B_SetCurrentSelectedBase(base);                     /* needed for equipment menu */
00231 
00232     Com_sprintf(popupText, sizeof(popupText), _("Base '%s' is under attack! What to do ?"), base->name);
00233     UI_RegisterText(TEXT_POPUP, popupText);
00234 
00235     CL_GameTimeStop();
00236     UI_PushWindow("popup_baseattack", NULL);
00237 }
00238 
00239 
00244 void CP_CheckBaseAttacks_f (void)
00245 {
00246     linkedList_t *missionlist = ccs.missions;
00247     base_t *base = NULL;
00248 
00249     if (Cmd_Argc() == 2) {
00250         const int baseIDX = atoi(Cmd_Argv(1));
00251         if (baseIDX >= 0 && baseIDX < MAX_BASES)
00252             base = B_GetFoundedBaseByIDX(baseIDX);
00253         else
00254             Com_Printf("CP_CheckBaseAttacks_f: Invalid base index: %i\n", baseIDX);
00255     }
00256 
00257     while (missionlist) {
00258         mission_t *mission = (mission_t*) missionlist->data;
00259 
00260         if (mission->category == INTERESTCATEGORY_BASE_ATTACK && mission->stage == STAGE_BASE_ATTACK) {
00261             if (base && ((base_t*) mission->data != base))
00262                 continue;
00263             CP_BaseAttackStartMission(mission);
00264         }
00265         missionlist = missionlist->next;
00266     }
00267 }
00268 
00274 static base_t *CP_BaseAttackChooseBase (void)
00275 {
00276     float randomNumber;
00277     float sum = 0.0f;
00278     int baseIdx;
00279     base_t *base = NULL;
00280 
00281     /* Choose randomly a base depending on alienInterest values for those bases */
00282     for (baseIdx = 0; baseIdx < ccs.numBases; baseIdx++) {
00283         base = B_GetFoundedBaseByIDX(baseIdx);
00284         if (!base)
00285             continue;
00286         sum += base->alienInterest;
00287     }
00288     randomNumber = frand() * sum;
00289     for (baseIdx = 0; baseIdx < ccs.numBases; baseIdx++) {
00290         base = B_GetFoundedBaseByIDX(baseIdx);
00291         if (!base)
00292             continue;
00293         randomNumber -= base->alienInterest;
00294         if (randomNumber < 0)
00295             break;
00296     }
00297 
00298     /* Make sure we have a base */
00299     assert(base && (randomNumber < 0));
00300 
00301     /* base is already under attack */
00302     if (base->baseStatus == BASE_UNDER_ATTACK)
00303         return NULL;
00304     /* base not (yet) working */
00305     if (!B_GetBuildingStatus(base, B_COMMAND))
00306         return NULL;
00307 
00308     return base;
00309 }
00310 
00315 static void CP_BaseAttackGoToBase (mission_t *mission)
00316 {
00317     base_t *base;
00318 
00319     mission->stage = STAGE_MISSION_GOTO;
00320 
00321     base = CP_BaseAttackChooseBase();
00322     if (!base) {
00323         Com_Printf("CP_BaseAttackGoToBase: no base found\n");
00324         CP_MissionRemove(mission);
00325         return;
00326     }
00327     mission->data = (void *)base;
00328 
00329     mission->mapDef = Com_GetMapDefinitionByID("baseattack");
00330     if (!mission->mapDef) {
00331         CP_MissionRemove(mission);
00332         Com_Error(ERR_DROP, "Could not find mapdef baseattack");
00333         return;
00334     }
00335 
00336     Vector2Copy(base->pos, mission->pos);
00337     mission->posAssigned = qtrue;
00338 
00339     Com_sprintf(mission->location, sizeof(mission->location), "%s", base->name);
00340 
00341     if (mission->ufo) {
00342         CP_MissionDisableTimeLimit(mission);
00343         UFO_SendToDestination(mission->ufo, mission->pos);
00344     } else {
00345         /* Go to next stage on next frame */
00346         mission->finalDate = ccs.date;
00347     }
00348 }
00349 
00357 int CP_BaseAttackMissionAvailableUFOs (const mission_t const *mission, ufoType_t *ufoTypes)
00358 {
00359     int num = 0;
00360     ufoTypes[num++] = UFO_FIGHTER;
00361     if (UFO_ShouldAppearOnGeoscape(UFO_BOMBER))
00362         ufoTypes[num++] = UFO_BOMBER;
00363 
00364     return num;
00365 }
00366 
00371 void CP_BaseAttackMissionNextStage (mission_t *mission)
00372 {
00373     switch (mission->stage) {
00374     case STAGE_NOT_ACTIVE:
00375         /* Create mission */
00376         CP_MissionBegin(mission);
00377         break;
00378     case STAGE_COME_FROM_ORBIT:
00379         /* Choose a base to attack and go to this base */
00380         CP_BaseAttackGoToBase(mission);
00381         break;
00382     case STAGE_MISSION_GOTO:
00383         /* just arrived on base location: attack it */
00384         CP_BaseAttackStartMission(mission);
00385         break;
00386     case STAGE_BASE_ATTACK:
00387         /* Leave earth */
00388         CP_BaseAttackMissionDestroyBase(mission);
00389         break;
00390     case STAGE_RETURN_TO_ORBIT:
00391         /* mission is over, remove mission */
00392         CP_BaseAttackMissionIsSuccess(mission);
00393         break;
00394     default:
00395         Com_Printf("CP_BaseAttackMissionNextStage: Unknown stage: %i, removing mission.\n", mission->stage);
00396         CP_MissionRemove(mission);
00397         break;
00398     }
00399 }

Generated by  doxygen 1.6.2