00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00080 MAP_NotifyMissionRemoved(mission);
00081
00082 CP_MissionRemove(mission);
00083 }
00084
00088 void CP_BaseAttackMissionOnSpawn (void)
00089 {
00090
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
00106 mission->ufo->landed = qfalse;
00107 } else {
00108
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
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
00131 ccs.missionAircraft = NULL;
00132
00133
00134
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
00157 CP_UFORemoveFromGeoscape(mission, qfalse);
00158 }
00159
00160
00161
00162
00163
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
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
00190 memset(&baseAttackFakeAircraft, 0, sizeof(baseAttackFakeAircraft));
00191 baseAttackFakeAircraft.homebase = base;
00192
00193 VectorCopy(base->pos, baseAttackFakeAircraft.pos);
00194 #if 0
00195
00196
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
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;
00230 B_SetCurrentSelectedBase(base);
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
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
00299 assert(base && (randomNumber < 0));
00300
00301
00302 if (base->baseStatus == BASE_UNDER_ATTACK)
00303 return NULL;
00304
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
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
00376 CP_MissionBegin(mission);
00377 break;
00378 case STAGE_COME_FROM_ORBIT:
00379
00380 CP_BaseAttackGoToBase(mission);
00381 break;
00382 case STAGE_MISSION_GOTO:
00383
00384 CP_BaseAttackStartMission(mission);
00385 break;
00386 case STAGE_BASE_ATTACK:
00387
00388 CP_BaseAttackMissionDestroyBase(mission);
00389 break;
00390 case STAGE_RETURN_TO_ORBIT:
00391
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 }