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 "../../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
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
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
00164 for (vp = alien_group_vals; vp->string; vp++)
00165 if (!strcmp(token, vp->string)) {
00166
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
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
00211 if (strcmp(campaign->researched, name))
00212 return;
00213
00214
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
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
00351 s = &ccs.salaries[campaignID];
00352
00353
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
00369 for (vp = salary_vals; vp->string; vp++)
00370 if (!strcmp(token, vp->string)) {
00371
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},
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
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
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
00448 cp->team = TEAM_PHALANX;
00449 Q_strncpyz(cp->researched, "researched_human", sizeof(cp->researched));
00450
00451
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
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
00491 for (vp = campaign_vals; vp->string; vp++)
00492 if (!strcmp(token, vp->string)) {
00493
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
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
00544 comp = &ccs.components[ccs.numComponents];
00545 ccs.numComponents++;
00546
00547 memset(comp, 0, sizeof(*comp));
00548
00549
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
00557 token = Com_EParse(text, errhead, name);
00558 if (!*text)
00559 break;
00560 if (*token == '}')
00561 break;
00562
00563
00564 if (!strcmp(token, "item")) {
00565
00566 if (comp->numItemtypes < MAX_COMP) {
00567
00568 token = Com_Parse(text);
00569
00570 comp->items[comp->numItemtypes] = INVSH_GetItemByID(token);
00571
00572
00573 token = Com_Parse(text);
00574 comp->itemAmount[comp->numItemtypes] = atoi(token);
00575 token = Com_Parse(text);
00576
00577 if (token[0] == '%')
00578 comp->itemAmount2[comp->numItemtypes] = COMP_ITEMCOUNT_SCALED;
00579 else
00580 comp->itemAmount2[comp->numItemtypes] = atoi(token);
00581
00583
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
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
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
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
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
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
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
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
00802 RS_RequiredLinksAssign();
00803
00804
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 }