cp_alienbase.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 "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         /* Get a random position */
00056         CP_GetRandomPosOnGeoscape(randomPos, qtrue);
00057 
00058         /* Alien base must not be too close from phalanx base */
00059         if (MAP_PositionCloseToBase(randomPos))
00060             continue;
00061 
00062         /* If this is the first alien base, there's no further condition: select this pos and quit */
00063         if (AB_Exists()) {
00064             Vector2Copy(randomPos, pos);
00065             return;
00066         }
00067 
00068         /* Calculate minimim distance between THIS position (pos) and all alien bases */
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         /* If this position is farther than previous ones, select it */
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     /* Alien loose all their interest in supply if there's no base to send the supply */
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     /* Alien base stay until it's destroyed */
00172     CP_MissionDisableTimeLimit(mission);
00173     /* mission appear on geoscape, player can go there */
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     /* base is already discovered */
00198     if (base->stealth < 0)
00199         return;
00200 
00201     /* aircraft can't find base if it's too far */
00202     distance = GetDistanceOnGlobe(aircraft->pos, base->pos);
00203     if (distance > aircraft->radar.range)
00204         return;
00205 
00206     /* the bigger the base, the higher the probability to find it */
00207     probability *= base->supply;
00208 
00209     /* decrease probability if the base is far from aircraft */
00210     if (distance > aircraft->radar.range * radarratio)
00211         probability /= decreasingFactor;
00212 
00213     /* probability must depend on DETECTION_INTERVAL (in case we change the value) */
00214     probability *= DETECTION_INTERVAL;
00215 
00216     base->stealth -= probability;
00217 
00218     /* base discovered ? */
00219     if (base->stealth < 0) {
00220         base->stealth = -10.0f;     /* just to avoid rounding errors */
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             /* Only aircraft on geoscape can detect alien bases */
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     /* Stealth is updated only once a week */
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         /* If nation is a lot infected, it won't help in finding base (government infected) */
00274         if (nation && nation->stats[0].xviInfection)
00275             probability /= 1.0f + nation->stats[0].xviInfection / xviLevel;
00276 
00277         /* the bigger the base, the higher the probability to find it */
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         /* fallback code for compatibility */
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 

Generated by  doxygen 1.6.2