g_savegame.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. // Filename:- g_savegame.cpp
  2. //
  3. // leave this line at the top for all g_xxxx.cpp files...
  4. #include "g_headers.h"
  5. #include "IcarusInterface.h"
  6. #include "Q3_Interface.h"
  7. #include "g_local.h"
  8. #include "fields.h"
  9. #include "objectives.h"
  10. #include "../cgame/cg_camera.h"
  11. #include "../qcommon/sstring.h"
  12. extern void OBJ_LoadTacticalInfo(void);
  13. extern void G_LoadSave_WriteMiscData(void);
  14. extern void G_LoadSave_ReadMiscData(void);
  15. extern void G_ReloadSaberData( gentity_t *ent );
  16. extern void FX_Read( void );
  17. extern void FX_Write( void );
  18. static const save_field_t savefields_gEntity[] =
  19. {
  20. {strFOFS(client), F_GCLIENT},
  21. {strFOFS(owner), F_GENTITY},
  22. {strFOFS(classname), F_STRING},
  23. {strFOFS(model), F_STRING},
  24. {strFOFS(model2), F_STRING},
  25. // {strFOFS(model3), F_STRING}, - MCG
  26. {strFOFS(nextTrain), F_GENTITY},
  27. {strFOFS(prevTrain), F_GENTITY},
  28. {strFOFS(message), F_STRING},
  29. {strFOFS(target), F_STRING},
  30. {strFOFS(target2), F_STRING},
  31. {strFOFS(target3), F_STRING},
  32. {strFOFS(target4), F_STRING},
  33. {strFOFS(targetJump), F_STRING},
  34. {strFOFS(targetname), F_STRING},
  35. {strFOFS(team), F_STRING},
  36. {strFOFS(roff), F_STRING},
  37. // {strFOFS(target_ent), F_GENTITY}, - MCG
  38. {strFOFS(chain), F_GENTITY},
  39. {strFOFS(enemy), F_GENTITY},
  40. {strFOFS(activator), F_GENTITY},
  41. {strFOFS(teamchain), F_GENTITY},
  42. {strFOFS(teammaster), F_GENTITY},
  43. {strFOFS(item), F_ITEM},
  44. {strFOFS(NPC_type), F_STRING},
  45. {strFOFS(closetarget), F_STRING},
  46. {strFOFS(opentarget), F_STRING},
  47. {strFOFS(paintarget), F_STRING},
  48. {strFOFS(NPC_targetname), F_STRING},
  49. {strFOFS(NPC_target), F_STRING},
  50. {strFOFS(ownername), F_STRING},
  51. {strFOFS(lastEnemy), F_GENTITY},
  52. {strFOFS(behaviorSet), F_BEHAVIORSET},
  53. {strFOFS(script_targetname),F_STRING},
  54. {strFOFS(m_iIcarusID), F_NULL},
  55. {strFOFS(NPC), F_BOOLPTR},
  56. {strFOFS(soundSet), F_STRING},
  57. {strFOFS(cameraGroup), F_STRING},
  58. {strFOFS(parms), F_BOOLPTR},
  59. {strFOFS(m_pVehicle), F_BOOLPTR},
  60. {NULL, 0, F_IGNORE}
  61. };
  62. static const save_field_t savefields_gNPC[] =
  63. {
  64. // {strNPCOFS(pendingEnemy), F_GENTITY},
  65. {strNPCOFS(touchedByPlayer), F_GENTITY},
  66. {strNPCOFS(aimingBeam), F_GENTITY},
  67. {strNPCOFS(eventOwner), F_GENTITY},
  68. {strNPCOFS(coverTarg), F_GENTITY},
  69. {strNPCOFS(tempGoal), F_GENTITY},
  70. {strNPCOFS(goalEntity), F_GENTITY},
  71. {strNPCOFS(lastGoalEntity), F_GENTITY},
  72. {strNPCOFS(eventualGoal), F_GENTITY},
  73. {strNPCOFS(captureGoal), F_GENTITY},
  74. {strNPCOFS(defendEnt), F_GENTITY},
  75. {strNPCOFS(greetEnt), F_GENTITY},
  76. {strNPCOFS(group), F_GROUP},
  77. {strNPCOFS(blockedEntity), F_GENTITY},
  78. {strNPCOFS(blockedTargetEntity),F_GENTITY},
  79. {strNPCOFS(jumpTarget), F_GENTITY},
  80. {strNPCOFS(watchTarget), F_GENTITY},
  81. {NULL, 0, F_IGNORE}
  82. };
  83. static const save_field_t savefields_LevelLocals[] =
  84. {
  85. {strLLOFS(locationHead), F_GENTITY},
  86. {strLLOFS(alertEvents), F_ALERTEVENT},
  87. {strLLOFS(groups), F_AIGROUPS},
  88. {strLLOFS(knownAnimFileSets),F_ANIMFILESETS},
  89. {NULL, 0, F_IGNORE}
  90. };
  91. static const save_field_t savefields_gVHIC[] =
  92. {
  93. {strVHICOFS(m_pPilot), F_GENTITY},
  94. {strVHICOFS(m_pOldPilot), F_GENTITY},
  95. {strVHICOFS(m_pDroidUnit), F_GENTITY},
  96. {strVHICOFS(m_pParentEntity), F_GENTITY},
  97. //m_ppPassengers //!ptr array?!
  98. {strVHICOFS(m_pVehicleInfo), F_VEHINFO}, //!another ptr! store name field instead and re-hook on load?
  99. {NULL, 0, F_IGNORE}
  100. };
  101. static const save_field_t savefields_gClient[] =
  102. {
  103. // sabers are stomped over by specific code elsewhere, it seems, but the first two fields MUST be saved
  104. // or it crashes on reload
  105. {strCLOFS(ps.saber[0].name),F_STRING},
  106. /* {strCLOFS(ps.saber[0].model),F_STRING},
  107. {strCLOFS(ps.saber[0].skin),F_STRING},
  108. {strCLOFS(ps.saber[0].brokenSaber1),F_STRING},
  109. {strCLOFS(ps.saber[0].brokenSaber2),F_STRING},
  110. */
  111. {strCLOFS(ps.saber[1].name),F_STRING},
  112. /* {strCLOFS(ps.saber[1].model),F_STRING},
  113. {strCLOFS(ps.saber[1].skin),F_STRING},
  114. {strCLOFS(ps.saber[1].brokenSaber1),F_STRING},
  115. {strCLOFS(ps.saber[1].brokenSaber2),F_STRING},
  116. */
  117. {strCLOFS(leader), F_GENTITY},
  118. {strCLOFS(clientInfo.customBasicSoundDir),F_STRING},
  119. {strCLOFS(clientInfo.customCombatSoundDir),F_STRING},
  120. {strCLOFS(clientInfo.customExtraSoundDir),F_STRING},
  121. {strCLOFS(clientInfo.customJediSoundDir),F_STRING},
  122. {NULL, 0, F_IGNORE}
  123. };
  124. list<sstring_t> *strList = NULL;
  125. /////////// char * /////////////
  126. //
  127. //
  128. static int GetStringNum(const char *psString)
  129. {
  130. assert( psString != (char *)0xcdcdcdcd );
  131. // NULL ptrs I'll write out as a strlen of -1...
  132. //
  133. if (!psString)
  134. {
  135. return -1;
  136. }
  137. strList->push_back( psString );
  138. return strlen(psString) + 1; // this gives us the chunk length for the reader later
  139. }
  140. static char *GetStringPtr(int iStrlen, char *psOriginal/*may be NULL*/)
  141. {
  142. if (iStrlen != -1)
  143. {
  144. char sString[768]; // arb, inc if nec.
  145. sString[0]=0;
  146. assert(iStrlen+1<=sizeof(sString));
  147. gi.ReadFromSaveGame('STRG', sString, iStrlen);
  148. #ifndef _XBOX // TAG_G_ALLOC is always blown away, we can never recycle
  149. if (psOriginal && gi.bIsFromZone(psOriginal, TAG_G_ALLOC)) {
  150. if (!strcmp(psOriginal,sString))
  151. {//it's a legal ptr and they're the same so let's just reuse it instead of free/alloc
  152. return psOriginal;
  153. }
  154. gi.Free(psOriginal);
  155. }
  156. #endif
  157. return G_NewString(sString);
  158. }
  159. return NULL;
  160. }
  161. //
  162. //
  163. ////////////////////////////////
  164. /////////// gentity_t * ////////
  165. //
  166. //
  167. static int GetGEntityNum(gentity_t* ent)
  168. {
  169. assert( ent != (gentity_t *) 0xcdcdcdcd);
  170. if (ent == NULL)
  171. {
  172. return -1;
  173. }
  174. // note that I now validate the return value (to avoid triggering asserts on re-load) because of the
  175. // way that the level_locals_t alertEvents struct contains a count of which ones are valid, so I'm guessing
  176. // that some of them aren't (valid)...
  177. //
  178. int iReturnIndex = ent - g_entities;
  179. if (iReturnIndex < 0 || iReturnIndex >= MAX_GENTITIES)
  180. {
  181. iReturnIndex = -1; // will get a NULL ptr on reload
  182. }
  183. return iReturnIndex;
  184. }
  185. static gentity_t *GetGEntityPtr(int iEntNum)
  186. {
  187. if (iEntNum == -1)
  188. {
  189. return NULL;
  190. }
  191. assert(iEntNum >= 0);
  192. assert(iEntNum < MAX_GENTITIES);
  193. return (g_entities + iEntNum);
  194. }
  195. //
  196. //
  197. ////////////////////////////////
  198. static int GetGroupNumber(AIGroupInfo_t *pGroup)
  199. {
  200. assert( pGroup != (AIGroupInfo_t *) 0xcdcdcdcd);
  201. if (pGroup == NULL)
  202. {
  203. return -1;
  204. }
  205. int iReturnIndex = pGroup - level.groups;
  206. if (iReturnIndex < 0 || iReturnIndex >= (sizeof(level.groups) / sizeof(level.groups[0])) )
  207. {
  208. iReturnIndex = -1; // will get a NULL ptr on reload
  209. }
  210. return iReturnIndex;
  211. }
  212. static AIGroupInfo_t *GetGroupPtr(int iGroupNum)
  213. {
  214. if (iGroupNum == -1)
  215. {
  216. return NULL;
  217. }
  218. assert(iGroupNum >= 0);
  219. assert(iGroupNum < (sizeof(level.groups) / sizeof(level.groups[0])));
  220. return (level.groups + iGroupNum);
  221. }
  222. /////////// gclient_t * ////////
  223. //
  224. //
  225. static int GetGClientNum(gclient_t *c, gentity_t *ent)
  226. {
  227. // unfortunately, I now need to see if this is a 'real' client (and therefore resolve to an enum), or
  228. // whether it's one of the NPC or SP_misc_weapon_shooter
  229. //
  230. assert(c != (gclient_t *)0xcdcdcdcd);
  231. if (c == NULL)
  232. {
  233. return -1;
  234. }
  235. if (ent->s.number < MAX_CLIENTS)
  236. { // regular client...
  237. return (c - level.clients);
  238. }
  239. else
  240. { // this must be an NPC or weapon_shooter, so mark it as special...
  241. return -2; // yeuch, but distinguishes it from a valid 0 index, or -1 for client==NULL
  242. }
  243. }
  244. static gclient_t *GetGClientPtr(int c)
  245. {
  246. if (c == -1)
  247. {
  248. return NULL;
  249. }
  250. if (c == -2)
  251. {
  252. return (gclient_t *) -2; // preserve this value so that I know to load in one of Mike's private NPC clients later
  253. }
  254. assert(c >= 0);
  255. assert(c < level.maxclients);
  256. return (level.clients + c);
  257. }
  258. //
  259. //
  260. ////////////////////////////////
  261. /////////// gitem_t * //////////
  262. //
  263. //
  264. static int GetGItemNum (gitem_t *pItem)
  265. {
  266. assert(pItem != (gitem_t*) 0xcdcdcdcd);
  267. if (pItem == NULL)
  268. {
  269. return -1;
  270. }
  271. return pItem - bg_itemlist;
  272. }
  273. static gitem_t *GetGItemPtr(int iItem)
  274. {
  275. if (iItem == -1)
  276. {
  277. return NULL;
  278. }
  279. assert(iItem >= 0);
  280. assert(iItem < bg_numItems);
  281. return &bg_itemlist[iItem];
  282. }
  283. //
  284. //
  285. ////////////////////////////////
  286. /////////// vehicleInfo_t * //////////
  287. //
  288. //
  289. static int GetVehicleInfoNum(vehicleInfo_t *pVehicleInfo)
  290. {
  291. assert(pVehicleInfo != (vehicleInfo_t*) 0xcdcdcdcd);
  292. if (pVehicleInfo == NULL)
  293. {
  294. return -1;
  295. }
  296. return pVehicleInfo - g_vehicleInfo;
  297. }
  298. static vehicleInfo_t *GetVehicleInfoPtr(int iVehicleIndex)
  299. {
  300. if (iVehicleIndex == -1)
  301. {
  302. return NULL;
  303. }
  304. assert(iVehicleIndex > 0);
  305. assert(iVehicleIndex < numVehicles);
  306. return &g_vehicleInfo[iVehicleIndex];
  307. }
  308. //
  309. //
  310. ////////////////////////////////
  311. static void EnumerateField(const save_field_t *pField, const byte *pbBase)
  312. {
  313. void *pv = (void *)(pbBase + pField->iOffset);
  314. switch (pField->eFieldType)
  315. {
  316. case F_STRING:
  317. *(int *)pv = GetStringNum(*(char **)pv);
  318. break;
  319. case F_GENTITY:
  320. *(int *)pv = GetGEntityNum(*(gentity_t **)pv);
  321. break;
  322. case F_GROUP:
  323. *(int *)pv = GetGroupNumber(*(AIGroupInfo_t **)pv);
  324. break;
  325. case F_GCLIENT:
  326. *(int *)pv = GetGClientNum(*(gclient_t **)pv, (gentity_t *) pbBase);
  327. break;
  328. case F_ITEM:
  329. *(int *)pv = GetGItemNum(*(gitem_t **)pv);
  330. break;
  331. case F_VEHINFO:
  332. *(int *)pv = GetVehicleInfoNum(*(vehicleInfo_t **)pv);
  333. break;
  334. case F_BEHAVIORSET:
  335. {
  336. const char **p = (const char **) pv;
  337. for (int i=0; i<NUM_BSETS; i++)
  338. {
  339. pv = &p[i]; // since you can't ++ a void ptr
  340. *(int *)pv = GetStringNum(*(char **)pv);
  341. }
  342. }
  343. break;
  344. /*MCG
  345. case F_BODYQUEUE:
  346. {
  347. gentity_t **p = (gentity_t **) pv;
  348. for (int i=0; i<BODY_QUEUE_SIZE; i++)
  349. {
  350. pv = &p[i]; // since you can't ++ a void ptr
  351. *(int *)pv = GetGEntityNum(*(gentity_t **)pv);
  352. }
  353. }
  354. break;
  355. */
  356. case F_ALERTEVENT: // convert all gentity_t ptrs in an alertEvent array into indexes...
  357. {
  358. alertEvent_t* p = (alertEvent_t *) pv;
  359. for (int i=0; i<MAX_ALERT_EVENTS; i++)
  360. {
  361. p[i].owner = (gentity_t *) GetGEntityNum(p[i].owner);
  362. }
  363. }
  364. break;
  365. case F_AIGROUPS: // convert to ptrs within this into indexes...
  366. {
  367. AIGroupInfo_t* p = (AIGroupInfo_t *) pv;
  368. for (int i=0; i<MAX_FRAME_GROUPS; i++)
  369. {
  370. p[i].enemy = (gentity_t *) GetGEntityNum(p[i].enemy);
  371. p[i].commander = (gentity_t *) GetGEntityNum(p[i].commander);
  372. }
  373. }
  374. break;
  375. case F_ANIMFILESETS:
  376. {
  377. animFileSet_t* p = (animFileSet_t *) pv;
  378. for (int i=0; i<MAX_ANIM_FILES; i++)
  379. {
  380. for ( int j=0; j<MAX_ANIM_EVENTS; j++ )
  381. {
  382. const char *ptAnimEventStringData = p[i].torsoAnimEvents[j].stringData;
  383. *(int *)(&p[i].torsoAnimEvents[j].stringData) = GetStringNum( ptAnimEventStringData );
  384. const char *plAnimEventStringData = p[i].legsAnimEvents[j].stringData;
  385. *(int *)(&p[i].legsAnimEvents[j].stringData) = GetStringNum( plAnimEventStringData );
  386. }
  387. }
  388. }
  389. break;
  390. case F_BOOLPTR:
  391. *(qboolean *)pv = !!(*(int *)pv);
  392. break;
  393. // These are pointers that are always recreated
  394. case F_NULL:
  395. *(void **)pv = NULL;
  396. break;
  397. case F_IGNORE:
  398. break;
  399. default:
  400. G_Error ("EnumerateField: unknown field type");
  401. break;
  402. }
  403. }
  404. static void EnumerateFields(const save_field_t *pFields, const byte *pbData, unsigned long ulChid, int iLen)
  405. {
  406. strList = new list<sstring_t>;
  407. // enumerate all the fields...
  408. //
  409. if (pFields)
  410. {
  411. for (const save_field_t *pField = pFields; pField->psName; pField++)
  412. {
  413. assert(pField->iOffset < iLen);
  414. EnumerateField(pField, pbData);
  415. }
  416. }
  417. // save out raw data...
  418. //
  419. gi.AppendToSaveGame(ulChid, pbData, iLen);
  420. // save out any associated strings..
  421. //
  422. list<sstring_t>::iterator it = strList->begin();
  423. for (unsigned int i=0; i<strList->size(); i++, ++it)
  424. {
  425. gi.AppendToSaveGame('STRG', (void *)(*it).c_str(), (*it).length() + 1);
  426. }
  427. delete strList;
  428. strList = NULL;
  429. }
  430. static void EvaluateField(const save_field_t *pField, byte *pbBase, byte *pbOriginalRefData/* may be NULL*/)
  431. {
  432. void *pv = (void *)(pbBase + pField->iOffset);
  433. void *pvOriginal = (void *)(pbOriginalRefData + pField->iOffset);
  434. switch (pField->eFieldType)
  435. {
  436. case F_STRING:
  437. *(char **)pv = GetStringPtr(*(int *)pv, pbOriginalRefData?*(char**)pvOriginal:NULL);
  438. break;
  439. case F_GENTITY:
  440. *(gentity_t **)pv = GetGEntityPtr(*(int *)pv);
  441. break;
  442. case F_GROUP:
  443. *(AIGroupInfo_t **)pv = GetGroupPtr(*(int *)pv);
  444. break;
  445. case F_GCLIENT:
  446. *(gclient_t **)pv = GetGClientPtr(*(int *)pv);
  447. break;
  448. case F_ITEM:
  449. *(gitem_t **)pv = GetGItemPtr(*(int *)pv);
  450. break;
  451. case F_VEHINFO:
  452. *(vehicleInfo_t **)pv = GetVehicleInfoPtr(*(int *)pv);
  453. break;
  454. case F_BEHAVIORSET:
  455. {
  456. char **p = (char **) pv;
  457. char **pO= (char **) pvOriginal;
  458. for (int i=0; i<NUM_BSETS; i++, p++, pO++)
  459. {
  460. *p = GetStringPtr(*(int *)p, pbOriginalRefData?*(char **)pO:NULL);
  461. }
  462. }
  463. break;
  464. /*MCG
  465. case F_BODYQUEUE:
  466. {
  467. gentity_t **p = (gentity_t **) pv;
  468. for (int i=0; i<BODY_QUEUE_SIZE; i++, p++)
  469. {
  470. *p = GetGEntityPtr(*(int *)p);
  471. }
  472. }
  473. break;
  474. */
  475. case F_ALERTEVENT:
  476. {
  477. alertEvent_t* p = (alertEvent_t *) pv;
  478. for (int i=0; i<MAX_ALERT_EVENTS; i++)
  479. {
  480. p[i].owner = GetGEntityPtr((int)(p[i].owner));
  481. }
  482. }
  483. break;
  484. case F_AIGROUPS: // convert to ptrs within this into indexes...
  485. {
  486. AIGroupInfo_t* p = (AIGroupInfo_t *) pv;
  487. for (int i=0; i<MAX_FRAME_GROUPS; i++)
  488. {
  489. p[i].enemy = GetGEntityPtr((int)(p[i].enemy));
  490. p[i].commander = GetGEntityPtr((int)(p[i].commander));
  491. }
  492. }
  493. break;
  494. case F_ANIMFILESETS:
  495. {
  496. animFileSet_t* p = (animFileSet_t *) pv;
  497. char *pO;
  498. for (int i=0; i<MAX_ANIM_FILES; i++)
  499. {
  500. for ( int j=0; j<MAX_ANIM_EVENTS; j++ )
  501. {
  502. pO = pbOriginalRefData ? level.knownAnimFileSets[i].torsoAnimEvents[j].stringData : NULL;
  503. p[i].torsoAnimEvents[j].stringData = GetStringPtr((int)p[i].torsoAnimEvents[j].stringData, pO);
  504. pO = pbOriginalRefData ? level.knownAnimFileSets[i].legsAnimEvents[j].stringData : NULL;
  505. p[i].legsAnimEvents[j].stringData = GetStringPtr((int)p[i].legsAnimEvents[j].stringData, pO);
  506. }
  507. }
  508. }
  509. break;
  510. // // These fields are patched in when their relevant owners are loaded
  511. case F_BOOLPTR:
  512. case F_NULL:
  513. break;
  514. case F_IGNORE:
  515. break;
  516. default:
  517. G_Error ("EvaluateField: unknown field type");
  518. break;
  519. }
  520. }
  521. // copy of function in sv_savegame
  522. static LPCSTR SG_GetChidText(unsigned long chid)
  523. {
  524. static char chidtext[5];
  525. *(unsigned long *)chidtext = BigLong(chid);
  526. chidtext[4] = 0;
  527. return chidtext;
  528. }
  529. static void EvaluateFields(const save_field_t *pFields, byte *pbData, byte *pbOriginalRefData, unsigned long ulChid, int iSize, qboolean bOkToSizeMisMatch)
  530. {
  531. int iReadSize = gi.ReadFromSaveGame(ulChid, pbData, bOkToSizeMisMatch?0:iSize);
  532. if (iReadSize != iSize)
  533. {
  534. // handle any chunks that are ok to change length (typically this is a last minute hack,
  535. // so hopefully we won't need it any more... ;-)
  536. //
  537. switch (ulChid)
  538. {
  539. // example chunk handler...
  540. //
  541. case 'GCLI':
  542. /* assert(iSize>iReadSize);
  543. memset(&pbData[iReadSize], 0, iSize-iReadSize); // zero out new objectives that weren't in old-format save file
  544. break;
  545. */
  546. default:
  547. // won't return...
  548. //
  549. G_Error(va("EvaluateFields(): variable-sized chunk '%s' without handler!",SG_GetChidText(ulChid)));
  550. break;
  551. }
  552. }
  553. if (pFields)
  554. {
  555. for (const save_field_t *pField = pFields; pField->psName; pField++)
  556. {
  557. EvaluateField(pField, pbData, pbOriginalRefData);
  558. }
  559. }
  560. }
  561. /*
  562. ==============
  563. WriteLevelLocals
  564. All pointer variables (except function pointers) must be handled specially.
  565. ==============
  566. */
  567. static void WriteLevelLocals ()
  568. {
  569. level_locals_t *temp = (level_locals_t *)gi.Malloc(sizeof(level_locals_t), TAG_TEMP_WORKSPACE, qfalse);
  570. *temp = level; // copy out all data into a temp space
  571. EnumerateFields(savefields_LevelLocals, (byte *)temp, 'LVLC', LLOFS(LEVEL_LOCALS_T_SAVESTOP)); // sizeof(temp));
  572. gi.Free(temp);
  573. }
  574. /*
  575. ==============
  576. ReadLevelLocals
  577. All pointer variables (except function pointers) must be handled specially.
  578. ==============
  579. */
  580. static void ReadLevelLocals ()
  581. {
  582. // preserve client ptr either side of the load, because clients are already saved/loaded through Read/Writegame...
  583. //
  584. gclient_t *pClients = level.clients; // save clients
  585. level_locals_t *temp = (level_locals_t *)gi.Malloc(sizeof(level_locals_t), TAG_TEMP_WORKSPACE, qfalse);
  586. *temp = level; // struct copy
  587. EvaluateFields(savefields_LevelLocals, (byte *)temp, (byte *)&level, 'LVLC', LLOFS(LEVEL_LOCALS_T_SAVESTOP),qfalse); // sizeof(level_locals_t));
  588. level = *temp; // struct copy
  589. level.clients = pClients; // restore clients
  590. gi.Free(temp);
  591. }
  592. static void WriteGEntities(qboolean qbAutosave)
  593. {
  594. int iCount = 0;
  595. for (int i=0; i<(qbAutosave?1:globals.num_entities); i++)
  596. {
  597. gentity_t* ent = &g_entities[i];
  598. if ( ent->inuse )
  599. {
  600. iCount++;
  601. }
  602. }
  603. gi.AppendToSaveGame('NMED', &iCount, sizeof(iCount));
  604. for (i=0; i<(qbAutosave?1:globals.num_entities); i++)
  605. {
  606. gentity_t* ent = &g_entities[i];
  607. if ( ent->inuse)
  608. {
  609. gi.AppendToSaveGame('EDNM', (void *)&i, sizeof(i));
  610. qboolean qbLinked = ent->linked;
  611. gi.unlinkentity( ent );
  612. gentity_t tempEnt = *ent; // make local copy
  613. tempEnt.linked = qbLinked;
  614. if (qbLinked)
  615. {
  616. gi.linkentity( ent );
  617. }
  618. EnumerateFields(savefields_gEntity, (byte *)&tempEnt, 'GENT', sizeof(tempEnt));
  619. // now for any fiddly bits that would be rather awkward to build into the enumerator...
  620. //
  621. if (tempEnt.NPC)
  622. {
  623. gNPC_t npc = *ent->NPC; // NOT *tempEnt.NPC; !! :-)
  624. EnumerateFields(savefields_gNPC, (byte *)&npc, 'GNPC', sizeof(npc));
  625. }
  626. if (tempEnt.client == (gclient_t *)-2) // I know, I know...
  627. {
  628. gclient_t client = *ent->client; // NOT *tempEnt.client!!
  629. EnumerateFields(savefields_gClient, (byte *)&client, 'GCLI', sizeof(client));
  630. }
  631. if (tempEnt.parms)
  632. {
  633. gi.AppendToSaveGame('PARM', ent->parms, sizeof(*ent->parms));
  634. }
  635. if (tempEnt.m_pVehicle)
  636. {
  637. Vehicle_t vehicle = *ent->m_pVehicle; // NOT *tempEnt.m_pVehicle!!
  638. EnumerateFields(savefields_gVHIC, (byte *)&vehicle, 'VHIC', sizeof(vehicle));
  639. }
  640. // the scary ghoul2 saver stuff... (fingers crossed)
  641. //
  642. gi.G2API_SaveGhoul2Models(tempEnt.ghoul2);
  643. tempEnt.ghoul2.kill(); // this handle was shallow copied from an ent. We don't want it destroyed
  644. }
  645. }
  646. //Write out all entity timers
  647. TIMER_Save();//WriteEntityTimers();
  648. if (!qbAutosave)
  649. {
  650. //Save out ICARUS information
  651. IIcarusInterface::GetIcarus()->Save();
  652. // this marker needs to be here, it lets me know if Icarus doesn't load everything back later,
  653. // which has happened, and doesn't always show up onscreen until certain game situations.
  654. // This saves time debugging, and makes things easier to track.
  655. //
  656. static int iBlah = 1234;
  657. gi.AppendToSaveGame('ICOK', &iBlah, sizeof(iBlah));
  658. }
  659. if (!qbAutosave )//really shouldn't need to write these bits at all, just restore them from the ents...
  660. {
  661. WriteInUseBits();
  662. }
  663. }
  664. static void ReadGEntities(qboolean qbAutosave)
  665. {
  666. int iCount;
  667. gi.ReadFromSaveGame('NMED', (void *)&iCount, sizeof(iCount));
  668. int iPreviousEntRead = -1;
  669. for (int i=0; i<iCount; i++)
  670. {
  671. int iEntIndex;
  672. gi.ReadFromSaveGame('EDNM', (void *)&iEntIndex, sizeof(iEntIndex));
  673. if (iEntIndex >= globals.num_entities)
  674. {
  675. globals.num_entities = iEntIndex + 1;
  676. }
  677. if (iPreviousEntRead != iEntIndex-1)
  678. {
  679. for (int j=iPreviousEntRead+1; j!=iEntIndex; j++)
  680. {
  681. if ( g_entities[j].inuse ) // not actually necessary
  682. {
  683. G_FreeEntity(&g_entities[j]);
  684. }
  685. }
  686. }
  687. iPreviousEntRead = iEntIndex;
  688. // slightly naff syntax here, but makes a few ops clearer later...
  689. //
  690. gentity_t entity;
  691. gentity_t* pEntOriginal = &entity;
  692. gentity_t* pEnt = &g_entities[iEntIndex];
  693. *pEntOriginal = *pEnt; // struct copy, so we can refer to original
  694. pEntOriginal->ghoul2.kill();
  695. gi.unlinkentity(pEnt);
  696. Quake3Game()->FreeEntity( pEnt );
  697. //
  698. // sneaky: destroy the ghoul2 object within this struct before binary-loading over the top of it...
  699. //
  700. gi.G2API_LoadSaveCodeDestructGhoul2Info(pEnt->ghoul2);
  701. pEnt->ghoul2.kill();
  702. EvaluateFields(savefields_gEntity, (byte *)pEnt, (byte *)pEntOriginal, 'GENT', sizeof(*pEnt),qfalse);
  703. pEnt->ghoul2.kill();
  704. // now for any fiddly bits...
  705. //
  706. if (pEnt->NPC) // will be qtrue/qfalse
  707. {
  708. gNPC_t tempNPC;
  709. EvaluateFields(savefields_gNPC, (byte *)&tempNPC,(byte *)pEntOriginal->NPC, 'GNPC', sizeof (*pEnt->NPC),qfalse);
  710. // so can we pinch the original's one or do we have to alloc a new one?...
  711. //
  712. if (pEntOriginal->NPC)
  713. {
  714. // pinch this G_Alloc handle...
  715. //
  716. pEnt->NPC = pEntOriginal->NPC;
  717. }
  718. else
  719. {
  720. // original didn't have one (hmmm...), so make a new one...
  721. //
  722. //assert(0); // I want to know about this, though not in release
  723. pEnt->NPC = (gNPC_t *) G_Alloc(sizeof(*pEnt->NPC));
  724. }
  725. // copy over the one we've just loaded...
  726. //
  727. *pEnt->NPC = tempNPC; // struct copy
  728. //FIXME: do we need to do these too?
  729. /*
  730. if ( pEnt->s.number )
  731. {//not player
  732. G_LoadAnimFileSet( *pEnt, *pEnt->NPC_type );
  733. G_SetSkin( *pEnt, *pEnt->NPC_type, NULL );// it probably wasn't the default skin, do we need this at all?
  734. }
  735. */
  736. }
  737. if (pEnt->client == (gclient_t*) -2) // one of Mike G's NPC clients?
  738. {
  739. gclient_t tempGClient;
  740. EvaluateFields(savefields_gClient, (byte *)&tempGClient, (byte *)pEntOriginal->client, 'GCLI', sizeof(*pEnt->client),qfalse);
  741. // can we pinch the original's client handle or do we have to alloc a new one?...
  742. //
  743. if (pEntOriginal->client)
  744. {
  745. // pinch this G_Alloc handle...
  746. //
  747. pEnt->client = pEntOriginal->client;
  748. }
  749. else
  750. {
  751. // original didn't have one (hmmm...) so make a new one...
  752. //
  753. pEnt->client = (gclient_t *) G_Alloc(sizeof(*pEnt->client));
  754. }
  755. // copy over the one we've just loaded....
  756. //
  757. *pEnt->client = tempGClient; // struct copy
  758. if ( pEnt->s.number )
  759. {//not player
  760. G_ReloadSaberData( pEnt );
  761. }
  762. }
  763. // Some Icarus thing... (probably)
  764. //
  765. if (pEnt->parms) // will be qtrue/qfalse
  766. {
  767. parms_t tempParms;
  768. gi.ReadFromSaveGame('PARM', &tempParms, sizeof(tempParms));
  769. // so can we pinch the original's one or do we have to alloc a new one?...
  770. //
  771. if (pEntOriginal->parms)
  772. {
  773. // pinch this G_Alloc handle...
  774. //
  775. pEnt->parms = pEntOriginal->parms;
  776. }
  777. else
  778. {
  779. // original didn't have one, so make a new one...
  780. //
  781. pEnt->parms = (parms_t *) G_Alloc(sizeof(*pEnt->parms));
  782. }
  783. // copy over the one we've just loaded...
  784. //
  785. *pEnt->parms = tempParms; // struct copy
  786. }
  787. if (pEnt->m_pVehicle) // will be qtrue/qfalse
  788. {
  789. Vehicle_t tempVehicle;
  790. EvaluateFields(savefields_gVHIC, (byte *)&tempVehicle,(byte *)pEntOriginal->m_pVehicle, 'VHIC', sizeof (*pEnt->m_pVehicle),qfalse);
  791. // so can we pinch the original's one or do we have to alloc a new one?...
  792. //
  793. if (pEntOriginal->m_pVehicle)
  794. {
  795. // pinch this G_Alloc handle...
  796. //
  797. pEnt->m_pVehicle = pEntOriginal->m_pVehicle;
  798. }
  799. else
  800. {
  801. // original didn't have one, so make a new one...
  802. //
  803. pEnt->m_pVehicle = (Vehicle_t *) gi.Malloc( sizeof(Vehicle_t), TAG_G_ALLOC, qfalse );
  804. }
  805. // copy over the one we've just loaded...
  806. //
  807. *pEnt->m_pVehicle = tempVehicle; // struct copy
  808. }
  809. // the scary ghoul2 stuff... (fingers crossed)
  810. //
  811. {
  812. char *pGhoul2Data = NULL;
  813. gi.ReadFromSaveGame('GHL2', 0, 0, (void**)&pGhoul2Data);
  814. gi.G2API_LoadGhoul2Models(pEnt->ghoul2, pGhoul2Data); // if it's going to crash anywhere... <g>
  815. gi.Free(pGhoul2Data);
  816. }
  817. // gi.unlinkentity (pEntOriginal);
  818. // ICARUS_FreeEnt( pEntOriginal );
  819. // *pEntOriginal = *pEnt; // struct copy
  820. // qboolean qbLinked = pEntOriginal->linked;
  821. // pEntOriginal->linked = qfalse;
  822. // if (qbLinked)
  823. // {
  824. // gi.linkentity (pEntOriginal);
  825. // }
  826. // because the sytem stores sfx_t handles directly instead of the set, we have to reget the set's sfx_t...
  827. //
  828. if (pEnt->s.eType == ET_MOVER && pEnt->s.loopSound>0)
  829. {
  830. if ( VALIDSTRING( pEnt->soundSet ))
  831. {
  832. extern int BMS_MID; // from g_mover
  833. pEnt->s.loopSound = CAS_GetBModelSound( pEnt->soundSet, BMS_MID );
  834. if (pEnt->s.loopSound == -1)
  835. {
  836. pEnt->s.loopSound = 0;
  837. }
  838. }
  839. }
  840. // NPCs and other ents store waypoints that aren't valid after a load
  841. pEnt->waypoint = 0;
  842. // Hazard troopers store a troop value that isn't valid either:
  843. if( pEnt->NPC )
  844. pEnt->NPC->troop = 0;
  845. qboolean qbLinked = pEnt->linked;
  846. pEnt->linked = qfalse;
  847. if (qbLinked)
  848. {
  849. gi.linkentity (pEnt);
  850. }
  851. }
  852. //Read in all the entity timers
  853. TIMER_Load();//ReadEntityTimers();
  854. if (!qbAutosave)
  855. {
  856. // now zap any g_ents that were inuse when the level was loaded, but are no longer in use in the saved version
  857. // that we've just loaded...
  858. //
  859. for (i=iPreviousEntRead+1; i<globals.num_entities; i++)
  860. {
  861. if ( g_entities[i].inuse ) // not actually necessary
  862. {
  863. G_FreeEntity(&g_entities[i]);
  864. }
  865. }
  866. //Load ICARUS information
  867. Quake3Game()->ClearEntityList();
  868. IIcarusInterface::GetIcarus()->Load();
  869. // check that Icarus has loaded everything it saved out by having a marker chunk after it...
  870. //
  871. static int iBlah = 1234;
  872. gi.ReadFromSaveGame('ICOK', &iBlah, sizeof(iBlah));
  873. }
  874. if (!qbAutosave)
  875. {
  876. ReadInUseBits();//really shouldn't need to read these bits in at all, just restore them from the ents...
  877. }
  878. }
  879. void WriteLevel(qboolean qbAutosave)
  880. {
  881. if (!qbAutosave) //-always save the client
  882. {
  883. // write out one client - us!
  884. //
  885. assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way ReadGame works
  886. gclient_t client = level.clients[0];
  887. EnumerateFields(savefields_gClient, (byte *)&client, 'GCLI', sizeof(client));
  888. WriteLevelLocals(); // level_locals_t level
  889. }
  890. OBJ_SaveObjectiveData();
  891. FX_Write();
  892. /////////////
  893. WriteGEntities(qbAutosave);
  894. Quake3Game()->VariableSave();
  895. G_LoadSave_WriteMiscData();
  896. extern void CG_WriteTheEvilCGHackStuff(void);
  897. CG_WriteTheEvilCGHackStuff();
  898. // (Do NOT put any write-code below this line)
  899. //
  900. // put out an end-marker so that the load code can check everything was read in...
  901. //
  902. static int iDONE = 1234;
  903. gi.AppendToSaveGame('DONE', &iDONE, sizeof(iDONE));
  904. }
  905. void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition)
  906. {
  907. if ( qbLoadTransition )
  908. {
  909. // I STRONGLY SUSPECT THAT THIS WILL JUST ERR_DROP BECAUSE OF THE LOAD SWAPPING OF THE CHUNK-ORDER
  910. // BELOW BETWEEN OBJECTIVES AND LEVEL_LOCALS, SO I'M GUESSING THIS IS SOME OLD EF1 JUNK?
  911. // IN ANY CASE, LET'S MAKE SURE... // -ste (no idea who wrote the comment stuff below, did it ever work?)
  912. //
  913. assert(0);
  914. //
  915. //loadtransitions do not need to read the objectives and client data from the level they're going to
  916. //In a loadtransition, client data is carried over on the server and will be stomped later anyway.
  917. //The objective info (in client->sess data), however, is read in from G_ReadSessionData which is called before this func,
  918. //we do NOT want to stomp that session data when doing a load transition
  919. //However, we should still save this info out because these savegames may need to be
  920. //loaded normally later- perhaps if you die and need to respawn, perhaps as some kind
  921. //of emergency savegame for resuming, etc.
  922. //SO: We read it in, but throw it away.
  923. //Read & throw away gclient info
  924. gclient_t junkClient;
  925. EvaluateFields(savefields_gClient, (byte *)&junkClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qfalse);
  926. //Read & throw away objective info
  927. objectives_t junkObj[MAX_MISSION_OBJ];
  928. gi.ReadFromSaveGame('OBJT', (void *) &junkObj, 0);
  929. ReadLevelLocals(); // level_locals_t level
  930. }
  931. else
  932. {
  933. if (!qbAutosave )//always load the client unless it's an autosave
  934. {
  935. assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way things work
  936. gclient_t GClient;
  937. EvaluateFields(savefields_gClient, (byte *)&GClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qfalse);
  938. level.clients[0] = GClient; // struct copy
  939. ReadLevelLocals(); // level_locals_t level
  940. }
  941. OBJ_LoadObjectiveData();//loads mission objectives AND tactical info
  942. }
  943. FX_Read();
  944. /////////////
  945. ReadGEntities(qbAutosave);
  946. Quake3Game()->VariableLoad();
  947. G_LoadSave_ReadMiscData();
  948. extern void CG_ReadTheEvilCGHackStuff(void);
  949. CG_ReadTheEvilCGHackStuff();
  950. // (Do NOT put any read-code below this line)
  951. //
  952. // check that the whole file content was loaded by specifically requesting an end-marker...
  953. //
  954. static int iDONE = 1234;
  955. gi.ReadFromSaveGame('DONE', &iDONE, sizeof(iDONE));
  956. }
  957. extern int killPlayerTimer;
  958. qboolean GameAllowedToSaveHere(void)
  959. {
  960. return (!in_camera&&!killPlayerTimer);
  961. }
  962. //////////////////// eof /////////////////////
  963. #if 0
  964. // !!!!!!!!!!!!!!!!!! loadsave affecting structure !!!!!!!!!!!!!!!!!!!!!!!
  965. struct Vehicle_t
  966. {
  967. // The entity who pilots/drives this vehicle.
  968. // NOTE: This is redundant (since m_pParentEntity->owner _should_ be the pilot). This makes things clearer though.
  969. gentity_t *m_pPilot;
  970. int m_iPilotTime; //if spawnflag to die without pilot and this < level.time then die.
  971. qboolean m_bHasHadPilot; //qtrue once the vehicle gets its first pilot
  972. // The passengers of this vehicle.
  973. gentity_t **m_ppPassengers;
  974. // The number of passengers currently in this vehicle.
  975. int m_iNumPassengers;
  976. //the droid unit NPC for this vehicle, if any
  977. gentity_t *m_pDroidUnit;
  978. // The entity from which this NPC comes from.
  979. gentity_t *m_pParentEntity;
  980. // If not zero, how long to wait before we can do anything with the vehicle (we're getting on still).
  981. // -1 = board from left, -2 = board from right, -3 = jump/quick board. -4 & -5 = throw off existing pilot
  982. int m_iBoarding;
  983. // Used to check if we've just started the boarding process
  984. bool m_bWasBoarding;
  985. // The speed the vehicle maintains while boarding occurs (often zero)
  986. vec3_t m_vBoardingVelocity;
  987. // Time modifier (must only be used in ProcessMoveCommands() and ProcessOrientCommands() and is updated in Update()).
  988. float m_fTimeModifier;
  989. // Ghoul2 Animation info.
  990. // NOTE: Since each vehicle has their own model instance, these bolts must be local to each vehicle as well.
  991. int m_iLeftWingBone;
  992. int m_iRightWingBone;
  993. //int m_iDriverTag;
  994. int m_iExhaustTag[MAX_VEHICLE_EXHAUSTS];
  995. int m_iMuzzleTag[MAX_VEHICLE_MUZZLES];
  996. int m_iDroidUnitTag;
  997. int m_iGunnerViewTag[MAX_VEHICLE_TURRETS];//Where to put the view origin of the gunner (index)
  998. // This vehicles weapon muzzles.
  999. Muzzle m_Muzzles[MAX_VEHICLE_MUZZLES];
  1000. // The user commands structure.
  1001. usercmd_t m_ucmd;
  1002. // The direction an entity will eject from the vehicle towards.
  1003. int m_EjectDir;
  1004. // Flags that describe the vehicles behavior.
  1005. unsigned long m_ulFlags;
  1006. // NOTE: Vehicle Type ID, Orientation, and Armor MUST be transmitted over the net.
  1007. // Current angles of this vehicle.
  1008. vec3_t m_vOrientation;
  1009. // How long you have strafed left or right (increments every frame that you strafe to right, decrements every frame you strafe left)
  1010. int m_fStrafeTime;
  1011. // Previous angles of this vehicle.
  1012. vec3_t m_vPrevOrientation;
  1013. // When control is lost on a speeder, current angular velocity is stored here and applied until landing
  1014. float m_vAngularVelocity;
  1015. vec3_t m_vFullAngleVelocity;
  1016. // Current armor and shields of your vehicle (explodes if armor to 0).
  1017. int m_iArmor; //hull strength - STAT_HEALTH on NPC
  1018. int m_iShields; //energy shielding - STAT_ARMOR on NPC
  1019. // Timer for all cgame-FX...? ex: exhaust?
  1020. int m_iLastFXTime;
  1021. // When to die.
  1022. int m_iDieTime;
  1023. // This pointer is to a valid VehicleInfo (which could be an animal, speeder, fighter, whatever). This
  1024. // contains the functions actually used to do things to this specific kind of vehicle as well as shared
  1025. // information (max speed, type, etc...).
  1026. vehicleInfo_t *m_pVehicleInfo;
  1027. // This trace tells us if we're within landing height.
  1028. trace_t m_LandTrace;
  1029. //bitflag of surfaces that have broken off
  1030. int m_iRemovedSurfaces;
  1031. // the last time this vehicle fired a turbo burst
  1032. int m_iTurboTime;
  1033. //how long it should drop like a rock for after freed from SUSPEND
  1034. int m_iDropTime;
  1035. int m_iSoundDebounceTimer;
  1036. //last time we incremented the shields
  1037. int lastShieldInc;
  1038. //so we don't hold it down and toggle it back and forth
  1039. qboolean linkWeaponToggleHeld;
  1040. //info about our weapons (linked, ammo, etc.)
  1041. vehWeaponStatus_t weaponStatus[MAX_VEHICLE_WEAPONS];
  1042. vehTurretStatus_t turretStatus[MAX_VEHICLE_TURRETS];
  1043. //the guy who was previously the pilot
  1044. gentity_t* m_pOldPilot;
  1045. // don't need these in mp
  1046. int m_safeJumpMountTime;
  1047. float m_safeJumpMountRightDot;
  1048. };
  1049. #endif