cp_xvi.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_overlay.h"
00029 #include "cp_map.h"
00030 #include "cp_xvi.h"
00031 #include "save/save_xvi.h"
00032 
00034 static technology_t *rsAlienXVI;
00035 
00037 static qboolean xviNationInfectionNeedsUpdate = qfalse;
00038 
00043 static const float XVI_FACTOR = 15.0f;
00044 
00046 static const int XVI_DECREASE_DAYS = 7;
00047 
00049 #define XVI_EVENT_NAME "rs_alien_xvi_event"
00050 
00055 void CP_SpreadXVIAtPos (const vec2_t pos)
00056 {
00057     if (!CP_IsXVIResearched())
00058         return;
00059 
00060     CP_ChangeXVILevel(pos, XVI_FACTOR);
00061 
00062     xviNationInfectionNeedsUpdate = qtrue;
00063 }
00064 
00069 void CP_ReduceXVIEverywhere (void)
00070 {
00071     if (!CP_IsXVIResearched())
00072         return;
00073 
00074     /* Only decrease XVI if given days has passed */
00075     if (ccs.date.day % XVI_DECREASE_DAYS)
00076         return;
00077 
00078     CP_DecreaseXVILevelEverywhere();
00079 
00080     xviNationInfectionNeedsUpdate = qtrue;
00081 }
00082 
00087 void CP_UpdateNationXVIInfection (void)
00088 {
00089     /* temporary array to store the XVI levels */
00090     float xviInfection[MAX_NATIONS];
00091     int y;
00092     int nationIdx;
00093     /* width in pixel of the XVI overlay */
00094     int width;
00095     /* height in pixel of the XVI overlay */
00096     int height;
00097     float heightPerDegree;
00098     float widthPerDegree;
00099     /* current position (in latitude / longitude) */
00100     vec2_t currentPos;
00101     /* parameter used to normalize nation XVI level.
00102      * decrease this factor to increase XVI level per nation */
00103     const float AREA_FACTOR = 650.0f;
00104     /* area used to normalized XVI infection level for each nation.
00105      * depend on overlay size so that if we change resolution of
00106      * overlay it doesn't impact nation XIInfection */
00107     float normalizingArea;
00108 
00109     /* No need to update XVI levels if the overlay didn't change */
00110     if (!xviNationInfectionNeedsUpdate)
00111         return;
00112 
00113     /* Initialize array */
00114     for (nationIdx = 0; nationIdx < ccs.numNations; nationIdx++)
00115         xviInfection[nationIdx] = 0;
00116 
00117     CP_GetXVIMapDimensions(&width, &height);
00118     heightPerDegree = height / 180.0f;
00119     widthPerDegree = width / 360.0f;
00120     normalizingArea = width * height / AREA_FACTOR;
00121 
00122     for (y = 0; y < height; y++) {
00123         int x;
00124         int sum[MAX_NATIONS];
00125         const byte* previousNationColor;
00126         const nation_t* nation;
00127 
00128         memset(sum, 0, sizeof(sum));
00129 
00130         Vector2Set(currentPos, 180.0f, 90.0f - y / heightPerDegree);
00131         previousNationColor = MAP_GetColor(currentPos, MAPTYPE_NATIONS);
00132         nation = MAP_GetNation(currentPos);
00133 
00134         for (x = 0; x < width; x++) {
00135             const byte* nationColor;
00136             currentPos[0] = 180.0f - x / widthPerDegree;
00137             nationColor = MAP_GetColor(currentPos, MAPTYPE_NATIONS);
00138             if (!VectorCompare(nationColor, previousNationColor)) {
00139                 previousNationColor = nationColor;
00140                 nation = MAP_GetNation(currentPos);
00141             }
00142             if (nation) {
00143                 const int xviLevel = CP_GetXVILevel(x, y);
00144                 if (xviLevel > 0)
00145                     sum[nation->idx] += xviLevel;
00146             }
00147         }
00148         /* divide the total XVI infection by the area of a pixel
00149          * because pixel are smaller as you go closer from the pole */
00150         for (nationIdx = 0; nationIdx < ccs.numNations; nationIdx++)
00151             xviInfection[nationIdx] += ((float) sum[nationIdx]) / (cos(torad * currentPos[1]) * normalizingArea);
00152     }
00153 
00154     /* copy the new values of XVI infection level into nation array */
00155     for (nationIdx = 0; nationIdx < ccs.numNations; nationIdx++) {
00156         nation_t* nation = &ccs.nations[nationIdx];
00157         nation->stats[0].xviInfection = ceil(xviInfection[nation->idx]);
00158     }
00159 
00160     xviNationInfectionNeedsUpdate = qfalse;
00161 }
00162 
00167 int CP_GetAverageXVIRate (void)
00168 {
00169     int XVIRate = 0;
00170     int i;
00171     nation_t* nation;
00172 
00173     assert(ccs.numNations);
00174 
00175     /* check for XVI infection rate */
00176     for (i = 0, nation = ccs.nations; i < ccs.numNations; i++, nation++) {
00177         XVIRate += nation->stats[0].xviInfection;
00178     }
00179     XVIRate /= ccs.numNations;
00180     return XVIRate;
00181 }
00182 
00187 void CP_SpreadXVI (void)
00188 {
00189     const linkedList_t *list = ccs.missions;
00190 
00191     /* don't check if XVI spreading didn't start yet */
00192     if (!CP_IsXVIResearched())
00193         return;
00194 
00195     for (;list; list = list->next) {
00196         const mission_t *mission = (mission_t *)list->data;
00197         if (mission->stage == STAGE_SPREAD_XVI)
00198             CP_SpreadXVIAtPos(mission->pos);
00199     }
00200 }
00201 
00209 qboolean CP_IsXVIResearched (void)
00210 {
00211     return RS_IsResearched_ptr(rsAlienXVI);
00212 }
00213 
00214 void CP_XVIInit (void)
00215 {
00216     rsAlienXVI = RS_GetTechByID(XVI_EVENT_NAME);
00217     if (!rsAlienXVI)
00218         Com_Error(ERR_DROP, "CP_XVIInit: Could not find tech definition for " XVI_EVENT_NAME);
00219 }
00220 
00228 qboolean XVI_SaveXML (mxml_node_t *p)
00229 {
00230     int y;
00231     int width;
00232     int height;
00233     mxml_node_t *n;
00234 
00235     CP_GetXVIMapDimensions(&width, &height);
00236 
00237     n = mxml_AddNode(p, SAVE_XVI_XVI);
00238     mxml_AddInt(n, SAVE_XVI_WIDTH, width);
00239     mxml_AddInt(n, SAVE_XVI_HEIGHT, height);
00240 
00241     for (y = 0; y < height; y++) {
00242         int x;
00243         for (x = 0; x < width; x++) {
00244             const int xviLevel = CP_GetXVILevel(x, y);
00245             /* That saves many bytes in the savegame */
00246             if (xviLevel > 0) {
00247                 mxml_node_t *s = mxml_AddNode(n, SAVE_XVI_ENTRY);
00248                 mxml_AddInt(s, SAVE_XVI_X, x);
00249                 mxml_AddInt(s, SAVE_XVI_Y, y);
00250                 mxml_AddInt(s, SAVE_XVI_LEVEL, xviLevel);
00251             }
00252         }
00253     }
00254     return qtrue;
00255 }
00256 
00263 qboolean XVI_LoadXML (mxml_node_t *p)
00264 {
00265     int width, height;
00266     mxml_node_t *s;
00267     mxml_node_t *n = mxml_GetNode(p, SAVE_XVI_XVI);
00268     /* If there is no XVI, it will not be loaded */
00269     if (!n) {
00270         CP_InitializeXVIOverlay(NULL);
00271         return qtrue;
00272     }
00273 
00274     width = mxml_GetInt(n, SAVE_XVI_WIDTH, 0);
00275     height = mxml_GetInt(n, SAVE_XVI_HEIGHT, 0);
00276 
00277     for (s = mxml_GetNode(n, SAVE_XVI_ENTRY); s; s = mxml_GetNextNode(s, n, SAVE_XVI_ENTRY)) {
00278         const int x = mxml_GetInt(s, SAVE_XVI_X, 0);
00279         const int y = mxml_GetInt(s, SAVE_XVI_Y, 0);
00280         const int level = mxml_GetInt(s, SAVE_XVI_LEVEL, 0);
00281 
00282         if (x >= 0 && x < width && y >= 0 && y <= height)
00283             CP_SetXVILevel(x, y, level);
00284     }
00285     return qtrue;
00286 }
00287 
00292 void CP_StartXVISpreading_f (void)
00293 {
00294     int i, numAlienBases;
00295 
00300     ccs.XVIShowMap = qtrue;
00301 
00302     /* Spawn a few alien bases depending on difficulty level */
00303     if (ccs.curCampaign->difficulty > 0)
00304         numAlienBases = 3;
00305     else if (ccs.curCampaign->difficulty < 0)
00306         numAlienBases = 1;
00307     else
00308         numAlienBases = 2;
00309 
00310     for (i = 0; i < numAlienBases; i++)
00311         CP_CreateNewMission(INTERESTCATEGORY_BUILDING, qfalse);
00312 }
00313 
00317 void CP_UpdateXVIMapButton (void)
00318 {
00319     Cvar_SetValue("mn_xvimap", ccs.XVIShowMap);
00320 }

Generated by  doxygen 1.6.2