cp_parse.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 "../../shared/parse.h"
00028 #include "cp_campaign.h"
00029 #include "cp_rank.h"
00030 #include "cp_parse.h"
00031 
00036 static int CL_GetAlienMissionTypeByID (const char *type)
00037 {
00038     if (!strcmp(type, "recon"))
00039         return INTERESTCATEGORY_RECON;
00040     else if (!strcmp(type, "terror"))
00041         return INTERESTCATEGORY_TERROR_ATTACK;
00042     else if (!strcmp(type, "baseattack"))
00043         return INTERESTCATEGORY_BASE_ATTACK;
00044     else if (!strcmp(type, "building"))
00045         return INTERESTCATEGORY_BUILDING;
00046     else if (!strcmp(type, "supply"))
00047         return INTERESTCATEGORY_SUPPLY;
00048     else if (!strcmp(type, "xvi"))
00049         return INTERESTCATEGORY_XVI;
00050     else if (!strcmp(type, "intercept"))
00051         return INTERESTCATEGORY_INTERCEPT;
00052     else if (!strcmp(type, "harvest"))
00053         return INTERESTCATEGORY_HARVEST;
00054     else if (!strcmp(type, "alienbase"))
00055         return INTERESTCATEGORY_ALIENBASE;
00056     else if (!strcmp(type, "rescue"))
00057         return INTERESTCATEGORY_RESCUE;
00058     else {
00059         Com_Printf("CL_GetAlienMissionTypeByID: unknown alien mission category '%s'\n", type);
00060         return INTERESTCATEGORY_NONE;
00061     }
00062 }
00063 
00064 static const value_t alien_group_vals[] = {
00065     {"mininterest", V_INT, offsetof(alienTeamGroup_t, minInterest), 0},
00066     {"maxinterest", V_INT, offsetof(alienTeamGroup_t, maxInterest), 0},
00067     {NULL, 0, 0, 0}
00068 };
00069 
00073 static void CL_ParseAlienTeam (const char *name, const char **text)
00074 {
00075     const char *errhead = "CL_ParseAlienTeam: unexpected end of file (alienteam ";
00076     const char *token;
00077     const value_t *vp;
00078     int i;
00079     alienTeamCategory_t *alienCategory;
00080 
00081     /* get it's body */
00082     token = Com_Parse(text);
00083 
00084     if (!*text || *token != '{') {
00085         Com_Printf("CL_ParseAlienTeam: alien team category \"%s\" without body ignored\n", name);
00086         return;
00087     }
00088 
00089     if (ccs.numAlienCategories >= ALIENCATEGORY_MAX) {
00090         Com_Printf("CL_ParseAlienTeam: maximum number of alien team category reached (%i)\n", ALIENCATEGORY_MAX);
00091         return;
00092     }
00093 
00094     /* search for category with same name */
00095     for (i = 0; i < ccs.numAlienCategories; i++)
00096         if (!strcmp(name, ccs.alienCategories[i].id))
00097             break;
00098     if (i < ccs.numAlienCategories) {
00099         Com_Printf("CL_ParseAlienTeam: alien category def \"%s\" with same name found, second ignored\n", name);
00100         return;
00101     }
00102 
00103     alienCategory = &ccs.alienCategories[ccs.numAlienCategories++];
00104     Q_strncpyz(alienCategory->id, name, sizeof(alienCategory->id));
00105 
00106     do {
00107         token = Com_EParse(text, errhead, name);
00108         if (!*text)
00109             break;
00110         if (*token == '}')
00111             break;
00112 
00113         if (!strcmp(token, "equipment")) {
00114             linkedList_t **list = &alienCategory->equipment;
00115             token = Com_EParse(text, errhead, name);
00116             if (!*text || *token != '{') {
00117                 Com_Printf("CL_ParseAlienTeam: alien team category \"%s\" has equipment with no opening brace\n", name);
00118                 break;
00119             }
00120             do {
00121                 token = Com_EParse(text, errhead, name);
00122                 if (!*text || *token == '}')
00123                     break;
00124                 LIST_AddString(list, token);
00125             } while (*text);
00126         } else if (!strcmp(token, "category")) {
00127             token = Com_EParse(text, errhead, name);
00128             if (!*text || *token != '{') {
00129                 Com_Printf("CL_ParseAlienTeam: alien team category \"%s\" has category with no opening brace\n", name);
00130                 break;
00131             }
00132             do {
00133                 token = Com_EParse(text, errhead, name);
00134                 if (!*text || *token == '}')
00135                     break;
00136                 alienCategory->missionCategories[alienCategory->numMissionCategories] = CL_GetAlienMissionTypeByID(token);
00137                 if (alienCategory->missionCategories[alienCategory->numMissionCategories] == INTERESTCATEGORY_NONE)
00138                     Com_Printf("CL_ParseAlienTeam: alien team category \"%s\" is used with no mission category. It won't be used in game.\n", name);
00139                 alienCategory->numMissionCategories++;
00140             } while (*text);
00141         } else if (!strcmp(token, "team")) {
00142             alienTeamGroup_t *group;
00143 
00144             token = Com_EParse(text, errhead, name);
00145             if (!*text || *token != '{') {
00146                 Com_Printf("CL_ParseAlienTeam: alien team \"%s\" has team with no opening brace\n", name);
00147                 break;
00148             }
00149 
00150             if (alienCategory->numAlienTeamGroups >= MAX_ALIEN_GROUP_PER_CATEGORY) {
00151                 Com_Printf("CL_ParseAlienTeam: maximum number of alien team reached (%i) in category \"%s\"\n", MAX_ALIEN_GROUP_PER_CATEGORY, name);
00152                 break;
00153             }
00154 
00155             group = &alienCategory->alienTeamGroups[alienCategory->numAlienTeamGroups];
00156             group->idx = alienCategory->numAlienTeamGroups;
00157             group->categoryIdx = alienCategory - ccs.alienCategories;
00158             alienCategory->numAlienTeamGroups++;
00159 
00160             do {
00161                 token = Com_EParse(text, errhead, name);
00162 
00163                 /* check for some standard values */
00164                 for (vp = alien_group_vals; vp->string; vp++)
00165                     if (!strcmp(token, vp->string)) {
00166                         /* found a definition */
00167                         token = Com_EParse(text, errhead, name);
00168                         if (!*text)
00169                             return;
00170 
00171                         Com_EParseValue(group, token, vp->type, vp->ofs, vp->size);
00172                         break;
00173                     }
00174 
00175                 if (!vp->string) {
00176                     teamDef_t *teamDef;
00177                     if (!*text || *token == '}')
00178                         break;
00179 
00180                     /* This is an alien team */
00181                     if (group->numAlienTeams >= MAX_TEAMS_PER_MISSION)
00182                         Com_Error(ERR_DROP, "CL_ParseAlienTeam: MAX_TEAMS_PER_MISSION hit");
00183                     teamDef = Com_GetTeamDefinitionByID(token);
00184                     if (teamDef)
00185                         group->alienTeams[group->numAlienTeams++] = teamDef;
00186                 }
00187             } while (*text);
00188         } else {
00189             Com_Printf("CL_ParseAlienTeam: unknown token \"%s\" ignored (category %s)\n", token, name);
00190             continue;
00191         }
00192     } while (*text);
00193 }
00194 
00198 static void CL_ParseResearchedCampaignItems (const char *name, const char **text)
00199 {
00200     const char *errhead = "CL_ParseResearchedCampaignItems: unexpected end of file (equipment ";
00201     const char *token;
00202     int i;
00203     const campaign_t* campaign;
00204 
00205     campaign = CL_GetCampaign(cp_campaign->string);
00206     if (!campaign) {
00207         Com_Printf("CL_ParseResearchedCampaignItems: failed\n");
00208         return;
00209     }
00210     /* Don't parse if it is not definition for current type of campaign. */
00211     if (strcmp(campaign->researched, name))
00212         return;
00213 
00214     /* get it's body */
00215     token = Com_Parse(text);
00216 
00217     if (!*text || *token != '{') {
00218         Com_Printf("CL_ParseResearchedCampaignItems: equipment def \"%s\" without body ignored (%s)\n",
00219                 name, token);
00220         return;
00221     }
00222 
00223     Com_DPrintf(DEBUG_CLIENT, "..campaign research list '%s'\n", name);
00224     do {
00225         token = Com_EParse(text, errhead, name);
00226         if (!*text || *token == '}')
00227             return;
00228 
00229         for (i = 0; i < ccs.numTechnologies; i++) {
00230             technology_t *tech = RS_GetTechByIDX(i);
00231             assert(tech);
00232             if (!strcmp(token, tech->id)) {
00233                 tech->mailSent = MAILSENT_FINISHED;
00234                 tech->markResearched.markOnly[tech->markResearched.numDefinitions] = qtrue;
00235                 tech->markResearched.campaign[tech->markResearched.numDefinitions] = Mem_PoolStrDup(name, cp_campaignPool, 0);
00236                 tech->markResearched.numDefinitions++;
00237                 Com_DPrintf(DEBUG_CLIENT, "...tech %s\n", tech->id);
00238                 break;
00239             }
00240         }
00241 
00242         if (i == ccs.numTechnologies)
00243             Com_Printf("CL_ParseResearchedCampaignItems: unknown token \"%s\" ignored (tech %s)\n", token, name);
00244 
00245     } while (*text);
00246 }
00247 
00256 static void CL_ParseResearchableCampaignStates (const char *name, const char **text, qboolean researchable)
00257 {
00258     const char *errhead = "CL_ParseResearchableCampaignStates: unexpected end of file (equipment ";
00259     const char *token;
00260     int i;
00261     const campaign_t* campaign;
00262 
00263     campaign = CL_GetCampaign(cp_campaign->string);
00264     if (!campaign) {
00265         Com_Printf("CL_ParseResearchableCampaignStates: failed\n");
00266         return;
00267     }
00268 
00269     /* get it's body */
00270     token = Com_Parse(text);
00271 
00272     if (!*text || *token != '{') {
00273         Com_Printf("CL_ParseResearchableCampaignStates: equipment def \"%s\" without body ignored\n", name);
00274         return;
00275     }
00276 
00277     if (strcmp(campaign->researched, name)) {
00278         Com_DPrintf(DEBUG_CLIENT, "..don't use '%s' as researchable list\n", name);
00279         return;
00280     }
00281 
00282     Com_DPrintf(DEBUG_CLIENT, "..campaign researchable list '%s'\n", name);
00283     do {
00284         token = Com_EParse(text, errhead, name);
00285         if (!*text || *token == '}')
00286             return;
00287 
00288         for (i = 0; i < ccs.numTechnologies; i++) {
00289             technology_t *tech = RS_GetTechByIDX(i);
00290             if (!strcmp(token, tech->id)) {
00291                 if (researchable) {
00292                     tech->mailSent = MAILSENT_PROPOSAL;
00293                     RS_MarkOneResearchable(tech);
00294                 } else
00295                     Com_Printf("@todo Mark unresearchable");
00296                 Com_DPrintf(DEBUG_CLIENT, "...tech %s\n", tech->id);
00297                 break;
00298             }
00299         }
00300 
00301         if (i == ccs.numTechnologies)
00302             Com_Printf("CL_ParseResearchableCampaignStates: unknown token \"%s\" ignored (tech %s)\n", token, name);
00303 
00304     } while (*text);
00305 }
00306 
00307 /* =========================================================== */
00308 
00309 static const value_t salary_vals[] = {
00310     {"soldier_base", V_INT, offsetof(salary_t, base[EMPL_SOLDIER]), MEMBER_SIZEOF(salary_t, base[EMPL_SOLDIER])},
00311     {"soldier_rankbonus", V_INT, offsetof(salary_t, rankBonus[EMPL_SOLDIER]), MEMBER_SIZEOF(salary_t, rankBonus[EMPL_SOLDIER])},
00312     {"worker_base", V_INT, offsetof(salary_t, base[EMPL_WORKER]), MEMBER_SIZEOF(salary_t, base[EMPL_WORKER])},
00313     {"worker_rankbonus", V_INT, offsetof(salary_t, rankBonus[EMPL_WORKER]), MEMBER_SIZEOF(salary_t, rankBonus[EMPL_WORKER])},
00314     {"scientist_base", V_INT, offsetof(salary_t, base[EMPL_SCIENTIST]), MEMBER_SIZEOF(salary_t, base[EMPL_SCIENTIST])},
00315     {"scientist_rankbonus", V_INT, offsetof(salary_t, rankBonus[EMPL_SCIENTIST]), MEMBER_SIZEOF(salary_t, rankBonus[EMPL_SCIENTIST])},
00316     {"pilot_base", V_INT, offsetof(salary_t, base[EMPL_PILOT]), MEMBER_SIZEOF(salary_t, base[EMPL_PILOT])},
00317     {"pilot_rankbonus", V_INT, offsetof(salary_t, rankBonus[EMPL_PILOT]), MEMBER_SIZEOF(salary_t, rankBonus[EMPL_PILOT])},
00318     {"robot_base", V_INT, offsetof(salary_t, base[EMPL_ROBOT]), MEMBER_SIZEOF(salary_t, base[EMPL_ROBOT])},
00319     {"robot_rankbonus", V_INT, offsetof(salary_t, rankBonus[EMPL_ROBOT]), MEMBER_SIZEOF(salary_t, rankBonus[EMPL_ROBOT])},
00320     {"aircraft_factor", V_INT, offsetof(salary_t, aircraftFactor), MEMBER_SIZEOF(salary_t, aircraftFactor)},
00321     {"aircraft_divisor", V_INT, offsetof(salary_t, aircraftDivisor), MEMBER_SIZEOF(salary_t, aircraftDivisor)},
00322     {"base_upkeep", V_INT, offsetof(salary_t, baseUpkeep), MEMBER_SIZEOF(salary_t, baseUpkeep)},
00323     {"admin_initial", V_INT, offsetof(salary_t, adminInitial), MEMBER_SIZEOF(salary_t, adminInitial)},
00324     {"admin_soldier", V_INT, offsetof(salary_t, admin[EMPL_SOLDIER]), MEMBER_SIZEOF(salary_t, admin[EMPL_SOLDIER])},
00325     {"admin_worker", V_INT, offsetof(salary_t, admin[EMPL_WORKER]), MEMBER_SIZEOF(salary_t, admin[EMPL_WORKER])},
00326     {"admin_scientist", V_INT, offsetof(salary_t, admin[EMPL_SCIENTIST]), MEMBER_SIZEOF(salary_t, admin[EMPL_SCIENTIST])},
00327     {"admin_pilot", V_INT, offsetof(salary_t, admin[EMPL_PILOT]), MEMBER_SIZEOF(salary_t, admin[EMPL_PILOT])},
00328     {"admin_robot", V_INT, offsetof(salary_t, admin[EMPL_ROBOT]), MEMBER_SIZEOF(salary_t, admin[EMPL_ROBOT])},
00329     {"debt_interest", V_FLOAT, offsetof(salary_t, debtInterest), MEMBER_SIZEOF(salary_t, debtInterest)},
00330     {NULL, 0, 0, 0}
00331 };
00332 
00343 static void CL_ParseSalary (const char *name, const char **text, int campaignID)
00344 {
00345     const char *errhead = "CL_ParseSalary: unexpected end of file ";
00346     salary_t *s;
00347     const value_t *vp;
00348     const char *token;
00349 
00350     /* initialize the campaign */
00351     s = &ccs.salaries[campaignID];
00352 
00353     /* get it's body */
00354     token = Com_Parse(text);
00355 
00356     if (!*text || *token != '{') {
00357         Com_Printf("CL_ParseSalary: salary def without body ignored\n");
00358         return;
00359     }
00360 
00361     do {
00362         token = Com_EParse(text, errhead, name);
00363         if (!*text)
00364             break;
00365         if (*token == '}')
00366             break;
00367 
00368         /* check for some standard values */
00369         for (vp = salary_vals; vp->string; vp++)
00370             if (!strcmp(token, vp->string)) {
00371                 /* found a definition */
00372                 token = Com_EParse(text, errhead, name);
00373                 if (!*text)
00374                     return;
00375 
00376                 Com_EParseValue(s, token, vp->type, vp->ofs, vp->size);
00377                 break;
00378             }
00379         if (!vp->string) {
00380             Com_Printf("CL_ParseSalary: unknown token \"%s\" ignored (campaignID %i)\n", token, campaignID);
00381             Com_EParse(text, errhead, name);
00382         }
00383     } while (*text);
00384 }
00385 
00386 /* =========================================================== */
00387 
00388 static const value_t campaign_vals[] = {
00389     {"team", V_TEAM, offsetof(campaign_t, team), MEMBER_SIZEOF(campaign_t, team)},
00390     {"soldiers", V_INT, offsetof(campaign_t, soldiers), MEMBER_SIZEOF(campaign_t, soldiers)},
00391     {"workers", V_INT, offsetof(campaign_t, workers), MEMBER_SIZEOF(campaign_t, workers)},
00392     {"xvirate", V_INT, offsetof(campaign_t, maxAllowedXVIRateUntilLost), MEMBER_SIZEOF(campaign_t, maxAllowedXVIRateUntilLost)},
00393     {"maxdebts", V_INT, offsetof(campaign_t, negativeCreditsUntilLost), MEMBER_SIZEOF(campaign_t, negativeCreditsUntilLost)},
00394     {"minhappiness", V_FLOAT, offsetof(campaign_t, minhappiness), MEMBER_SIZEOF(campaign_t, minhappiness)},
00395     {"scientists", V_INT, offsetof(campaign_t, scientists), MEMBER_SIZEOF(campaign_t, scientists)},
00396     {"ugvs", V_INT, offsetof(campaign_t, ugvs), MEMBER_SIZEOF(campaign_t, ugvs)},
00397     {"equipment", V_STRING, offsetof(campaign_t, equipment), 0},
00398     {"market", V_STRING, offsetof(campaign_t, market), 0},
00399     {"asymptotic_market", V_STRING, offsetof(campaign_t, asymptoticMarket), 0},
00400     {"researched", V_STRING, offsetof(campaign_t, researched), 0},
00401     {"difficulty", V_INT, offsetof(campaign_t, difficulty), MEMBER_SIZEOF(campaign_t, difficulty)},
00402     {"map", V_STRING, offsetof(campaign_t, map), 0},
00403     {"credits", V_INT, offsetof(campaign_t, credits), MEMBER_SIZEOF(campaign_t, credits)},
00404     {"visible", V_BOOL, offsetof(campaign_t, visible), MEMBER_SIZEOF(campaign_t, visible)},
00405     {"text", V_TRANSLATION_STRING, offsetof(campaign_t, text), 0}, /* just a gettext placeholder */
00406     {"name", V_TRANSLATION_STRING, offsetof(campaign_t, name), 0},
00407     {"date", V_DATE, offsetof(campaign_t, date), 0},
00408     {"basecost", V_INT, offsetof(campaign_t, basecost), MEMBER_SIZEOF(campaign_t, basecost)},
00409     {"firstbase", V_STRING, offsetof(campaign_t, firstBaseTemplate), 0},
00410     {NULL, 0, 0, 0}
00411 };
00412 
00416 void CL_ParseCampaign (const char *name, const char **text)
00417 {
00418     const char *errhead = "CL_ParseCampaign: unexpected end of file (campaign ";
00419     campaign_t *cp;
00420     const value_t *vp;
00421     const char *token;
00422     int i;
00423     salary_t *s;
00424 
00425     /* search for campaigns with same name */
00426     for (i = 0; i < ccs.numCampaigns; i++)
00427         if (!strcmp(name, ccs.campaigns[i].id))
00428             break;
00429 
00430     if (i < ccs.numCampaigns) {
00431         Com_Printf("CL_ParseCampaign: campaign def \"%s\" with same name found, second ignored\n", name);
00432         return;
00433     }
00434 
00435     if (ccs.numCampaigns >= MAX_CAMPAIGNS) {
00436         Com_Printf("CL_ParseCampaign: Max campaigns reached (%i)\n", MAX_CAMPAIGNS);
00437         return;
00438     }
00439 
00440     /* initialize the campaign */
00441     cp = &ccs.campaigns[ccs.numCampaigns++];
00442     memset(cp, 0, sizeof(*cp));
00443 
00444     cp->idx = ccs.numCampaigns - 1;
00445     Q_strncpyz(cp->id, name, sizeof(cp->id));
00446 
00447     /* some default values */
00448     cp->team = TEAM_PHALANX;
00449     Q_strncpyz(cp->researched, "researched_human", sizeof(cp->researched));
00450 
00451     /* get it's body */
00452     token = Com_Parse(text);
00453 
00454     if (!*text || *token != '{') {
00455         Com_Printf("CL_ParseCampaign: campaign def \"%s\" without body ignored\n", name);
00456         ccs.numCampaigns--;
00457         return;
00458     }
00459 
00460     /* some default values */
00461     s = &ccs.salaries[cp->idx];
00462     s->base[EMPL_SOLDIER] = 3000;
00463     s->rankBonus[EMPL_SOLDIER] = 500;
00464     s->base[EMPL_WORKER] = 3000;
00465     s->rankBonus[EMPL_WORKER] = 500;
00466     s->base[EMPL_SCIENTIST] = 3000;
00467     s->rankBonus[EMPL_SCIENTIST] = 500;
00468     s->base[EMPL_PILOT] = 3000;
00469     s->rankBonus[EMPL_PILOT] = 500;
00470     s->base[EMPL_ROBOT] = 7500;
00471     s->rankBonus[EMPL_ROBOT] = 1500;
00472     s->aircraftFactor = 1;
00473     s->aircraftDivisor = 25;
00474     s->baseUpkeep = 20000;
00475     s->adminInitial = 1000;
00476     s->admin[EMPL_SOLDIER] = 75;
00477     s->admin[EMPL_WORKER] = 75;
00478     s->admin[EMPL_SCIENTIST] = 75;
00479     s->admin[EMPL_PILOT] = 75;
00480     s->admin[EMPL_ROBOT] = 150;
00481     s->debtInterest = 0.005;
00482 
00483     do {
00484         token = Com_EParse(text, errhead, name);
00485         if (!*text)
00486             break;
00487         if (*token == '}')
00488             break;
00489 
00490         /* check for some standard values */
00491         for (vp = campaign_vals; vp->string; vp++)
00492             if (!strcmp(token, vp->string)) {
00493                 /* found a definition */
00494                 token = Com_EParse(text, errhead, name);
00495                 if (!*text)
00496                     return;
00497 
00498                 Com_EParseValue(cp, token, vp->type, vp->ofs, vp->size);
00499                 break;
00500             }
00501         if (!strcmp(token, "salary")) {
00502             CL_ParseSalary(token, text, cp->idx);
00503         } else if (!strcmp(token, "events")) {
00504             token = Com_EParse(text, errhead, name);
00505             if (!*text)
00506                 return;
00507             cp->events = CP_GetEventsByID(token);
00508         } else if (!vp->string) {
00509             Com_Printf("CL_ParseCampaign: unknown token \"%s\" ignored (campaign %s)\n", token, name);
00510             Com_EParse(text, errhead, name);
00511         }
00512     } while (*text);
00513 
00514     if (cp->difficulty < -4)
00515         cp->difficulty = -4;
00516     else if (cp->difficulty > 4)
00517         cp->difficulty = 4;
00518 }
00519 
00526 static void CL_ParseComponents (const char *name, const char **text)
00527 {
00528     components_t *comp;
00529     const char *errhead = "CL_ParseComponents: unexpected end of file.";
00530     const char *token;
00531 
00532     /* get body */
00533     token = Com_Parse(text);
00534     if (!*text || *token != '{') {
00535         Com_Printf("CL_ParseComponents: \"%s\" components def without body ignored.\n", name);
00536         return;
00537     }
00538     if (ccs.numComponents >= MAX_ASSEMBLIES) {
00539         Com_Printf("CL_ParseComponents: too many technology entries. limit is %i.\n", MAX_ASSEMBLIES);
00540         return;
00541     }
00542 
00543     /* New components-entry (next free entry in global comp-list) */
00544     comp = &ccs.components[ccs.numComponents];
00545     ccs.numComponents++;
00546 
00547     memset(comp, 0, sizeof(*comp));
00548 
00549     /* set standard values */
00550     Q_strncpyz(comp->assemblyId, name, sizeof(comp->assemblyId));
00551     comp->assemblyItem = INVSH_GetItemByIDSilent(comp->assemblyId);
00552     if (comp->assemblyItem)
00553         Com_DPrintf(DEBUG_CLIENT, "CL_ParseComponents: linked item: %s with components: %s\n", name, comp->assemblyId);
00554 
00555     do {
00556         /* get the name type */
00557         token = Com_EParse(text, errhead, name);
00558         if (!*text)
00559             break;
00560         if (*token == '}')
00561             break;
00562 
00563         /* get values */
00564         if (!strcmp(token, "item")) {
00565             /* Defines what items need to be collected for this item to be researchable. */
00566             if (comp->numItemtypes < MAX_COMP) {
00567                 /* Parse item name */
00568                 token = Com_Parse(text);
00569 
00570                 comp->items[comp->numItemtypes] = INVSH_GetItemByID(token); /* item id -> item pointer */
00571 
00572                 /* Parse number of items. */
00573                 token = Com_Parse(text);
00574                 comp->itemAmount[comp->numItemtypes] = atoi(token);
00575                 token = Com_Parse(text);
00576                 /* If itemcount needs to be scaled */
00577                 if (token[0] == '%')
00578                     comp->itemAmount2[comp->numItemtypes] = COMP_ITEMCOUNT_SCALED;
00579                 else
00580                     comp->itemAmount2[comp->numItemtypes] = atoi(token);
00581 
00583                 /* comp->item_idx[comp->numItemtypes] = xxx */
00584 
00585                 comp->numItemtypes++;
00586             } else {
00587                 Com_Printf("CL_ParseComponents: \"%s\" Too many 'items' defined. Limit is %i - ignored.\n", name, MAX_COMP);
00588             }
00589         } else if (!strcmp(token, "time")) {
00590             /* Defines how long disassembly lasts. */
00591             token = Com_Parse(text);
00592             comp->time = atoi(token);
00593         } else {
00594             Com_Printf("CL_ParseComponents: Error in \"%s\" - unknown token: \"%s\".\n", name, token);
00595         }
00596     } while (*text);
00597 }
00598 
00604 components_t *CL_GetComponentsByItem (const objDef_t *item)
00605 {
00606     int i;
00607 
00608     for (i = 0; i < ccs.numComponents; i++) {
00609         components_t *comp = &ccs.components[i];
00610         if (comp->assemblyItem == item) {
00611             Com_DPrintf(DEBUG_CLIENT, "CL_GetComponentsByItem: found components id: %s\n", comp->assemblyId);
00612             return comp;
00613         }
00614     }
00615     Com_Error(ERR_DROP, "CL_GetComponentsByItem: could not find components id for: %s", item->id);
00616 }
00617 
00623 components_t *CL_GetComponentsByID (const char *id)
00624 {
00625     int i;
00626 
00627     for (i = 0; i < ccs.numComponents; i++) {
00628         components_t *comp = &ccs.components[i];
00629         if (!strcmp(comp->assemblyId, id)) {
00630             return comp;
00631         }
00632     }
00633     Com_Error(ERR_DROP, "CL_GetComponentsByItem: could not find components id for: %s", id);
00634 }
00635 
00646 static void CL_ParseScriptFirst (const char *type, const char *name, const char **text)
00647 {
00648     /* check for client interpretable scripts */
00649     if (!strcmp(type, "up_chapters"))
00650         UP_ParseChapters(name, text);
00651     else if (!strcmp(type, "building"))
00652         B_ParseBuildings(name, text, qfalse);
00653     else if (!strcmp(type, "installation"))
00654         INS_ParseInstallations(name, text);
00655     else if (!strcmp(type, "tech"))
00656         RS_ParseTechnologies(name, text);
00657     else if (!strcmp(type, "nation"))
00658         CL_ParseNations(name, text);
00659     else if (!strcmp(type, "city"))
00660         CL_ParseCities(name, text);
00661     else if (!strcmp(type, "rank"))
00662         CL_ParseRanks(name, text);
00663     else if (!strcmp(type, "aircraft"))
00664         AIR_ParseAircraft(name, text, qfalse);
00665     else if (!strcmp(type, "mail"))
00666         CL_ParseEventMails(name, text);
00667     else if (!strcmp(type, "events"))
00668         CL_ParseCampaignEvents(name, text);
00669     else if (!strcmp(type, "components"))
00670         CL_ParseComponents(name, text);
00671     else if (!strcmp(type, "alienteam"))
00672         CL_ParseAlienTeam(name, text);
00673     else if (!strcmp(type, "msgoptions"))
00674         MSO_ParseSettings(name, text);
00675     else if (!strcmp(type, "msgcategory"))
00676         MSO_ParseCategories(name, text);
00677 }
00678 
00690 static void CL_ParseScriptSecond (const char *type, const char *name, const char **text)
00691 {
00692     /* check for client interpretable scripts */
00693     if (!strcmp(type, "building"))
00694         B_ParseBuildings(name, text, qtrue);
00695     else if (!strcmp(type, "aircraft"))
00696         AIR_ParseAircraft(name, text, qtrue);
00697     else if (!strcmp(type, "basetemplate"))
00698         B_ParseBaseTemplate(name, text);
00699     else if (!strcmp(type, "researched"))
00700         CL_ParseResearchedCampaignItems(name, text);
00701     else if (!strcmp(type, "researchable"))
00702         CL_ParseResearchableCampaignStates(name, text, qtrue);
00703     else if (!strcmp(type, "notresearchable"))
00704         CL_ParseResearchableCampaignStates(name, text, qfalse);
00705     else if (!strcmp(type, "campaign"))
00706         CL_ParseCampaign(name, text);
00707 }
00708 
00712 static qboolean CP_ItemsSanityCheck (void)
00713 {
00714     int i;
00715     qboolean result = qtrue;
00716 
00717     for (i = 0; i < csi.numODs; i++) {
00718         const objDef_t *item = INVSH_GetItemByIDX(i);
00719 
00720         /* Warn if item has no size set. */
00721         if (item->size <= 0 && B_ItemIsStoredInBaseStorage(item)) {
00722             result = qfalse;
00723             Com_Printf("CP_ItemsSanityCheck: Item %s has zero size set.\n", item->id);
00724         }
00725 
00726         /* Warn if no price is set. */
00727         if (item->price <= 0 && BS_IsOnMarket(item)) {
00728             result = qfalse;
00729             Com_Printf("CP_ItemsSanityCheck: Item %s has zero price set.\n", item->id);
00730         }
00731 
00732         if (item->price > 0 && !BS_IsOnMarket(item) && !PR_ItemIsProduceable(item)) {
00733             result = qfalse;
00734             Com_Printf("CP_ItemsSanityCheck: Item %s has a price set though it is neither available on the market and production.\n", item->id);
00735         }
00736 
00737         /* extension and headgear are mutual exclusive */
00738         if (item->extension && item->headgear) {
00739             result = qfalse;
00740             Com_Printf("CP_ItemsSanityCheck: Item %s has both extension and headgear set.\n",  item->id);
00741         }
00742     }
00743 
00744     return result;
00745 }
00746 
00748 typedef struct {
00749     qboolean (*check)(void);    
00750     const char* name;           
00751 } sanity_functions_t;
00752 
00754 static const sanity_functions_t sanity_functions[] = {
00755     {B_ScriptSanityCheck, "buildings"},
00756     {RS_ScriptSanityCheck, "tech"},
00757     {AIR_ScriptSanityCheck, "aircraft"},
00758     {CP_ItemsSanityCheck, "items"},
00759     {NAT_ScriptSanityCheck, "nations"},
00760 
00761     {NULL, NULL}
00762 };
00763 
00768 void CL_ScriptSanityCheck (void)
00769 {
00770     qboolean status;
00771     const sanity_functions_t *s;
00772 
00773     Com_Printf("Sanity check for script data\n");
00774     s = sanity_functions;
00775     while (s->check) {
00776         status = s->check();
00777         Com_Printf("...%s %s\n", s->name, (status ? "ok" : "failed"));
00778         s++;
00779     }
00780 }
00781 
00788 void CL_ReadSinglePlayerData (void)
00789 {
00790     const char *type, *name, *text;
00791     int i;
00792 
00793     /* pre-stage parsing */
00794     FS_BuildFileList("ufos/*.ufo");
00795     FS_NextScriptHeader(NULL, NULL, NULL);
00796     text = NULL;
00797 
00798     while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != NULL)
00799         CL_ParseScriptFirst(type, name, &text);
00800 
00801     /* fill in IDXs for required research techs */
00802     RS_RequiredLinksAssign();
00803 
00804     /* stage two parsing */
00805     FS_NextScriptHeader(NULL, NULL, NULL);
00806     text = NULL;
00807 
00808     Com_DPrintf(DEBUG_CLIENT, "Second stage parsing started...\n");
00809     while ((type = FS_NextScriptHeader("ufos/*.ufo", &name, &text)) != NULL)
00810         CL_ParseScriptSecond(type, name, &text);
00811 
00812     for (i = 0; i < csi.numTeamDefs; i++) {
00813         const teamDef_t *teamDef = &csi.teamDef[i];
00814         if (!CHRSH_IsTeamDefAlien(teamDef))
00815             continue;
00816 
00817         ccs.teamDefTechs[teamDef->idx] = RS_GetTechByID(teamDef->tech);
00818         if (ccs.teamDefTechs[teamDef->idx] == NULL)
00819             Com_Error(ERR_DROP, "Could not find a tech for teamdef %s", teamDef->id);
00820     }
00821 
00822 
00823     Com_Printf("Campaign data loaded - size "UFO_SIZE_T" bytes\n", sizeof(ccs));
00824     Com_Printf("...techs: %i\n", ccs.numTechnologies);
00825     Com_Printf("...buildings: %i\n", ccs.numBuildingTemplates);
00826     Com_Printf("...ranks: %i\n", ccs.numRanks);
00827     Com_Printf("...nations: %i\n", ccs.numNations);
00828     Com_Printf("...cities: %i\n", ccs.numCities);
00829     Com_Printf("\n");
00830 }

Generated by  doxygen 1.6.2