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 "cp_campaign.h"
00028 #include "cp_alienbase.h"
00029 #include "cp_map.h"
00030 #include "cp_missions.h"
00031 #include "save/save_alienbase.h"
00032
00033 #define MAPDEF_ALIENBASE "alienbase"
00034 #define ALIENBASE_DISCOVERED_TECH "rs_alien_base_discovered_event"
00035
00043 void AB_SetAlienBasePosition (vec2_t pos)
00044 {
00045 int counter;
00046 vec2_t randomPos;
00047 float minDistance = 0.0f;
00048 const int maxLoopPosition = 6;
00050 counter = 0;
00051 while (counter < maxLoopPosition) {
00052 float distance = 0.0f;
00053 alienBase_t* base = NULL;
00054
00055
00056 CP_GetRandomPosOnGeoscape(randomPos, qtrue);
00057
00058
00059 if (MAP_PositionCloseToBase(randomPos))
00060 continue;
00061
00062
00063 if (AB_Exists()) {
00064 Vector2Copy(randomPos, pos);
00065 return;
00066 }
00067
00068
00069 while ((base = AB_GetNext(base)) != NULL) {
00070 const float currentDistance = GetDistanceOnGlobe(base->pos, randomPos);
00071 if (distance < currentDistance) {
00072 distance = currentDistance;
00073 }
00074 }
00075
00076
00077 if (minDistance < distance) {
00078 Vector2Copy(randomPos, pos);
00079 minDistance = distance;
00080 }
00081
00082 counter++;
00083 }
00084 if (counter == maxLoopPosition)
00085 Vector2Copy(randomPos, pos);
00086 }
00087
00093 alienBase_t* AB_BuildBase (const vec2_t pos)
00094 {
00095 alienBase_t base;
00096 const float initialStealthValue = 50.0f;
00098 memset(&base, 0, sizeof(base));
00099 Vector2Copy(pos, base.pos);
00100 base.stealth = initialStealthValue;
00101 base.idx = ccs.campaignStats.alienBasesBuilt++;
00102
00103 return (alienBase_t*)(LIST_Add(&ccs.alienBases, (void*)&base, sizeof(base)))->data;
00104 }
00105
00110 void AB_DestroyBase (alienBase_t *base)
00111 {
00112 assert(base);
00113
00114 LIST_Remove(&ccs.alienBases, (void*)base);
00115
00116
00117 if (!AB_Exists())
00118 ccs.interest[INTERESTCATEGORY_SUPPLY] = 0;
00119 }
00120
00125 alienBase_t* AB_GetNext (alienBase_t *lastBase)
00126 {
00127 return (alienBase_t*)LIST_GetNext(ccs.alienBases, lastBase);
00128 }
00129
00135 alienBase_t* AB_GetByIDX (int baseIDX)
00136 {
00137 alienBase_t* base = NULL;
00138
00139 while ((base = AB_GetNext(base)) != NULL) {
00140 if (base->idx == baseIDX)
00141 return base;
00142 }
00143 return NULL;
00144 }
00145
00149 void CP_SpawnAlienBaseMission (alienBase_t *alienBase)
00150 {
00151 mission_t *mission;
00152
00153 mission = CP_CreateNewMission(INTERESTCATEGORY_ALIENBASE, qtrue);
00154 if (!mission) {
00155 Com_Printf("CP_SpawnAlienBaseMission: Could not add mission, abort\n");
00156 return;
00157 }
00158
00159 mission->stage = STAGE_BASE_DISCOVERED;
00160 mission->data = (void *) alienBase;
00161
00162 mission->mapDef = Com_GetMapDefinitionByID(MAPDEF_ALIENBASE);
00163 if (!mission->mapDef)
00164 Com_Error(ERR_FATAL, "Could not find mapdef "MAPDEF_ALIENBASE);
00165
00166 Vector2Copy(alienBase->pos, mission->pos);
00167 mission->posAssigned = qtrue;
00168
00169 Com_sprintf(mission->location, sizeof(mission->location), _("Alien base"));
00170
00171
00172 CP_MissionDisableTimeLimit(mission);
00173
00174 CP_MissionAddToGeoscape(mission, qfalse);
00175
00176 if (!RS_MarkStoryLineEventResearched(ALIENBASE_DISCOVERED_TECH))
00177 Com_DPrintf(DEBUG_CLIENT, ALIENBASE_DISCOVERED_TECH" is not marked as researched\n");
00178 else
00179 Cmd_ExecuteString("addeventmail alien_base_discovered");
00180 }
00181
00190 static void AB_UpdateStealthForOneBase (const aircraft_t const *aircraft, alienBase_t *base)
00191 {
00192 float distance;
00193 float probability = 0.0001f;
00194 const float radarratio = 0.4f;
00195 const float decreasingFactor = 5.0f;
00197
00198 if (base->stealth < 0)
00199 return;
00200
00201
00202 distance = GetDistanceOnGlobe(aircraft->pos, base->pos);
00203 if (distance > aircraft->radar.range)
00204 return;
00205
00206
00207 probability *= base->supply;
00208
00209
00210 if (distance > aircraft->radar.range * radarratio)
00211 probability /= decreasingFactor;
00212
00213
00214 probability *= DETECTION_INTERVAL;
00215
00216 base->stealth -= probability;
00217
00218
00219 if (base->stealth < 0) {
00220 base->stealth = -10.0f;
00221 CP_SpawnAlienBaseMission(base);
00222 }
00223 }
00224
00231 void AB_UpdateStealthForAllBase (void)
00232 {
00233 int baseIdx;
00234
00235 for (baseIdx = 0; baseIdx < MAX_BASES; baseIdx++) {
00236 base_t *base = B_GetFoundedBaseByIDX(baseIdx);
00237 aircraft_t *aircraft;
00238
00239 aircraft = NULL;
00240 while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00241 alienBase_t* alienBase = NULL;
00242
00243
00244 if (!AIR_IsAircraftOnGeoscape(aircraft))
00245 continue;
00246
00247 while ((alienBase = AB_GetNext(alienBase)) != NULL)
00248 AB_UpdateStealthForOneBase(aircraft, alienBase);
00249 }
00250 }
00251 }
00252
00258 void AB_BaseSearchedByNations (void)
00259 {
00260 const int daysPerWeek = 7;
00261 float probability = 1.0f;
00262 const float xviLevel = 20.0f;
00264 alienBase_t* base = NULL;
00265
00266
00267 if (ccs.date.day % daysPerWeek)
00268 return;
00269
00270 while ((base = AB_GetNext(base)) != NULL) {
00271 const nation_t *nation = MAP_GetNation(base->pos);
00272
00273
00274 if (nation && nation->stats[0].xviInfection)
00275 probability /= 1.0f + nation->stats[0].xviInfection / xviLevel;
00276
00277
00278 probability *= base->supply;
00279
00280 base->stealth -= probability;
00281 }
00282 }
00283
00288 qboolean AB_CheckSupplyMissionPossible (void)
00289 {
00290 return AB_Exists();
00291 }
00292
00297 alienBase_t* AB_ChooseBaseToSupply (void)
00298 {
00299 const int baseIDX = rand() % AB_GetAlienBaseNumber();
00300 return AB_GetByIDX(baseIDX);
00301 }
00302
00308 void AB_SupplyBase (alienBase_t *base, qboolean decreaseStealth)
00309 {
00310 const float decreasedStealthValue = 5.0f;
00312 assert(base);
00313
00314 base->supply++;
00315 if (decreaseStealth && base->stealth >= 0.0f)
00316 base->stealth -= decreasedStealthValue;
00317 }
00318
00323 int AB_GetAlienBaseNumber (void)
00324 {
00325 return LIST_Count(ccs.alienBases);
00326 }
00327
00328 #ifdef DEBUG
00329
00332 static void AB_AlienBaseDiscovered_f (void)
00333 {
00334 alienBase_t* base = NULL;
00335
00336 while ((base = AB_GetNext(base)) != NULL) {
00337 base->stealth = -10.0f;
00338 CP_SpawnAlienBaseMission(base);
00339 }
00340 }
00341
00346 static void AB_AlienBaseList_f (void)
00347 {
00348 alienBase_t* base = NULL;
00349
00350 while ((base = AB_GetNext(base)) != NULL) {
00351 Com_Printf("Alien Base: %i\n", base->idx);
00352 Com_Printf("...pos: (%f, %f)\n", base->pos[0], base->pos[1]);
00353 Com_Printf("...supply: %i\n", base->supply);
00354 if (base->stealth < 0)
00355 Com_Printf("...base discovered\n");
00356 else
00357 Com_Printf("...stealth: %f\n", base->stealth);
00358 }
00359 }
00360 #endif
00361
00365 void AB_InitStartup (void)
00366 {
00367 #ifdef DEBUG
00368 Cmd_AddCommand("debug_listalienbase", AB_AlienBaseList_f, "Print Alien Bases information to game console");
00369 Cmd_AddCommand("debug_alienbasevisible", AB_AlienBaseDiscovered_f, "Set all alien bases to discovered");
00370 #endif
00371 }
00372
00378 qboolean AB_LoadXML (mxml_node_t *p)
00379 {
00380 int i;
00381 mxml_node_t *n, *s;
00382
00383 n = mxml_GetNode(p, SAVE_ALIENBASE_ALIENBASES);
00384 if (!n)
00385 return qfalse;
00386
00387 for (i = 0, s = mxml_GetNode(n, SAVE_ALIENBASE_BASE); s; i++, s = mxml_GetNextNode(s, n, SAVE_ALIENBASE_BASE)) {
00388 alienBase_t base;
00389
00390 base.idx = mxml_GetInt(s, SAVE_ALIENBASE_IDX, -1);
00391
00392 if (base.idx == -1) {
00393 Com_Printf("No IDX defined for Alienbase %d. This must be an old save.\n", i);
00394 base.idx = i;
00395 }
00396 if (!mxml_GetPos2(s, SAVE_ALIENBASE_POS, base.pos)) {
00397 Com_Printf("Position is invalid for Alienbase (idx %d)\n", base.idx);
00398 return qfalse;
00399 }
00400 base.supply = mxml_GetInt(s, SAVE_ALIENBASE_SUPPLY, 0);
00401 base.stealth = mxml_GetFloat(s, SAVE_ALIENBASE_STEALTH, 0.0);
00402 LIST_Add(&ccs.alienBases, (void*)&base, sizeof(base));
00403 }
00404
00405 return qtrue;
00406 }
00407
00413 qboolean AB_SaveXML (mxml_node_t *p)
00414 {
00415 mxml_node_t *n = mxml_AddNode(p, SAVE_ALIENBASE_ALIENBASES);
00416 alienBase_t* base = NULL;
00417
00418 while ((base = AB_GetNext(base)) != NULL) {
00419 mxml_node_t *s = mxml_AddNode(n, SAVE_ALIENBASE_BASE);
00420 mxml_AddInt(s, SAVE_ALIENBASE_IDX, base->idx);
00421 mxml_AddPos2(s, SAVE_ALIENBASE_POS, base->pos);
00422 mxml_AddIntValue(s, SAVE_ALIENBASE_SUPPLY, base->supply);
00423 mxml_AddFloatValue(s, SAVE_ALIENBASE_STEALTH, base->stealth);
00424 }
00425
00426 return qtrue;
00427 }
00428