boardmem.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. * Copyright (C) 2002 Gilead Kutnick - exophase@adelphia.net
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22. //Code to find space to store boards, and push and pull them into and out
  23. //of storage. Also deallocates board storage and helps simplify file
  24. //access.
  25. #include "window.h"
  26. #include "meter.h"
  27. #include "roballoc.h"
  28. #include "boardmem.h"
  29. #include "meminter.h"
  30. #include <dir.h>
  31. #include "ems.h"
  32. #include "data.h"
  33. #include "const.h"
  34. #include <stdio.h>
  35. #include "string.h"
  36. #include "error.h"
  37. #include <dos.h>
  38. #include "mod.h"
  39. #define SAVE_INDIVIDUAL
  40. //Normalize an unsigned char far * ptr-
  41. #define normalize(x) {\
  42. x=(unsigned char far *)MK_FP(FP_SEG(x)+(FP_OFF(x)>>4),FP_OFF(x)&15); }
  43. //Find space for board of given size and allocates it to given id. Don't use
  44. //if space is already allocated. If allocated, returns 0. Out of mem returns
  45. //1. This is really rare- Checks for ems, then conventional, then disk.
  46. //Doesn't affect board_sizes[]. If conv_mem_ok is 0, then only ems and disk
  47. //are checked.
  48. char allocate_board_space(long size,unsigned char id,char conv_mem_ok)
  49. {
  50. int t1,ems_pages;
  51. FILE *fp;
  52. //Check for ems first...
  53. //Get number of 16k pages needed
  54. ems_pages=(int)(size>>14);
  55. if(size&16383) ems_pages++;
  56. t1=alloc_EMS(ems_pages);
  57. if(t1)
  58. {
  59. //Got it!
  60. board_where[id]=W_EMS;
  61. board_offsets[id].EMS.handle=t1;
  62. board_offsets[id].EMS.page=0;
  63. board_filenames[id*FILENAME_SIZE]=0;
  64. return 0;
  65. }
  66. //Nope.. try conventional
  67. // SPIDER'S NOTE: WILL NOT USE CONVENTIONAL, DISABLED
  68. if(conv_mem_ok)
  69. {
  70. board_offsets[id].mem=(unsigned char *)farmalloc(size);
  71. if(board_offsets[id].mem)
  72. {
  73. //Got it!
  74. board_where[id]=W_MEMORY;
  75. board_filenames[id*FILENAME_SIZE]=0;
  76. return 0;
  77. }
  78. //Retry after clearing sfx cache
  79. free_sam_cache(1);
  80. board_offsets[id].mem=(unsigned char *)farmalloc(size);
  81. if(board_offsets[id].mem)
  82. {
  83. //Got it!
  84. board_where[id]=W_MEMORY;
  85. board_filenames[id*FILENAME_SIZE]=0;
  86. return 0;
  87. }
  88. }
  89. //Nope.. try disk
  90. //Make temporary filename
  91. str_cpy(&board_filenames[id*FILENAME_SIZE],"~MZTMPXXXXXX");
  92. mktemp(&board_filenames[id*FILENAME_SIZE]);
  93. //Open..
  94. fp=fopen(&board_filenames[id*FILENAME_SIZE],"wb");
  95. if(fp==NULL)
  96. {
  97. //Error
  98. board_filenames[id*FILENAME_SIZE]=0;
  99. return 1;
  100. }
  101. //Try to solidify room
  102. fseek(fp,size-1,SEEK_SET);
  103. fputc(0,fp);
  104. fseek(fp,size,SEEK_SET);
  105. if(ftell(fp)<size)
  106. {
  107. //Not enough room on hard drive
  108. fclose(fp);
  109. unlink(&board_filenames[id*FILENAME_SIZE]);
  110. board_filenames[id*FILENAME_SIZE]=0;
  111. return 2;
  112. }
  113. //Room made!
  114. fclose(fp);
  115. board_where[id]=W_TEMPFILE;
  116. board_offsets[id].offset=0;
  117. return 0;
  118. }
  119. //Deallocates the space allocated to id given. Sets where to W_NOWHERE and
  120. //clears all others except for board_sizes[].
  121. void deallocate_board_space(unsigned char id)
  122. {
  123. //According to type...
  124. switch(board_where[id])
  125. {
  126. case W_EMS:
  127. //EMS- deallocate.
  128. free_EMS(board_offsets[id].EMS.handle);
  129. break;
  130. case W_MEMORY:
  131. //Memory- deallocate.
  132. farfree(board_offsets[id].mem);
  133. break;
  134. case W_TEMPFILE:
  135. //Temp file- delete.
  136. unlink(&board_filenames[id*FILENAME_SIZE]);
  137. break;
  138. }
  139. //Reset variables for id
  140. board_where[id]=W_NOWHERE;
  141. board_offsets[id].offset=0;
  142. board_filenames[id*FILENAME_SIZE]=0;
  143. }
  144. //Returns size array would take up RLE2 encoded, using current x size and
  145. //y size.
  146. unsigned int RLE2_size(unsigned char far *plane)
  147. {
  148. unsigned int size=4;//4 for x/y size
  149. int t1,t2;
  150. int runchar=-1,runsize=-1,chr;
  151. for(t1=0;t1<board_ysiz;t1++)
  152. {
  153. for(t2=0;t2<board_xsiz;t2++)
  154. {
  155. //Get char
  156. chr=plane[t1*max_bxsiz+t2];
  157. //Continue run?
  158. if(chr==runchar)
  159. {
  160. //Yep.
  161. runsize++;
  162. //Run size at max of 127?
  163. if(runsize==127)
  164. {
  165. //Store run and reset it.
  166. size+=2;
  167. runchar=runsize=-1;
  168. }
  169. }
  170. else
  171. {
  172. //Nope- Store current run...
  173. if((runchar<128)&&(runsize==1)) size++;
  174. else if(runchar>-1) size+=2;
  175. //...and set up for a new run.
  176. runchar=chr;
  177. runsize=1;
  178. }
  179. //Loop.
  180. }
  181. }
  182. //Store last run, if any
  183. if((runchar<128)&&(runsize==1)) size++;
  184. else if(runchar>-1) size+=2;
  185. //Done- return size.
  186. return size;
  187. }
  188. //Stores plane in where as RLE2 compressed, using current x/y sizes.
  189. //Returns size.
  190. unsigned int RLE2_store(unsigned char far *where,unsigned char far *plane)
  191. {
  192. unsigned int size=4;//4 for x/y size
  193. int t1,t2;
  194. int runchar=-1,runsize=-1,chr;
  195. //board_xsiz = 100;
  196. //board_ysiz = 50;
  197. where[0]=board_xsiz&255; where[1]=board_xsiz>>8;
  198. where[2]=board_ysiz&255; where[3]=board_ysiz>>8;
  199. for(t1=0;t1<board_ysiz;t1++)
  200. {
  201. for(t2=0;t2<board_xsiz;t2++)
  202. {
  203. //Get char
  204. chr=plane[t1*max_bxsiz+t2];
  205. //Continue run?
  206. if(chr==runchar)
  207. {
  208. //Yep.
  209. runsize++;
  210. //Run size at max of 127?
  211. if(runsize==127)
  212. {
  213. //Store run and reset it.
  214. where[size++]=runsize|128;
  215. where[size++]=runchar;
  216. runchar=runsize=-1;
  217. }
  218. }
  219. else
  220. {
  221. //Nope- Store current run...
  222. if((runchar<128)&&(runsize==1)) where[size++]=runchar;
  223. else if(runchar>-1)
  224. {
  225. where[size++]=runsize|128;
  226. where[size++]=runchar;
  227. }
  228. //...and set up for a new run.
  229. runchar=chr;
  230. runsize=1;
  231. }
  232. //Loop.
  233. }
  234. }
  235. //Store last run, if any
  236. if((runchar<128)&&(runsize==1)) where[size++]=runchar;
  237. else if(runchar>-1)
  238. {
  239. where[size++]=runsize|128;
  240. where[size++]=runchar;
  241. }
  242. //Done.
  243. return size;
  244. }
  245. //Stores plane in file as RLE2 compressed, using current x/y sizes.
  246. void RLE2_save(FILE *fp,unsigned char far *plane)
  247. {
  248. int t1,t2;
  249. int runchar=-1,runsize=-1,chr;
  250. fwrite(&board_xsiz,2,1,fp);
  251. fwrite(&board_ysiz,2,1,fp);
  252. for(t1=0;t1<board_ysiz;t1++)
  253. {
  254. for(t2=0;t2<board_xsiz;t2++)
  255. {
  256. //Get char
  257. chr=plane[t1*max_bxsiz+t2];
  258. //Continue run?
  259. if(chr==runchar)
  260. {
  261. //Yep.
  262. runsize++;
  263. //Run size at max of 127?
  264. if(runsize==127)
  265. {
  266. //Store run and reset it.
  267. fputc(runsize|128,fp);
  268. fputc(runchar,fp);
  269. runchar=runsize=-1;
  270. }
  271. }
  272. else
  273. {
  274. //Nope- Store current run...
  275. if((runchar<128)&&(runsize==1)) fputc(runchar,fp);
  276. else if(runchar>-1)
  277. {
  278. fputc(runsize|128,fp);
  279. fputc(runchar,fp);
  280. }
  281. //...and set up for a new run.
  282. runchar=chr;
  283. runsize=1;
  284. }
  285. //Loop.
  286. }
  287. }
  288. //Store last run, if any
  289. if((runchar<128)&&(runsize==1)) fputc(runchar,fp);
  290. else if(runchar>-1)
  291. {
  292. fputc(runsize|128,fp);
  293. fputc(runchar,fp);
  294. }
  295. //Done.
  296. }
  297. //Reads RLE2-compressed plane from where and puts into plane.
  298. //Also sets board_xsiz and board_ysiz unless specified otherwise.
  299. //Returns byte count of RLE2 read.
  300. unsigned int RLE2_read(unsigned char far *where,unsigned char far *plane,
  301. char change_xysizes)
  302. {
  303. unsigned int pos=4;//2 for x/y size
  304. int t1,t2,t3,xsiz=where[0]+(where[1]<<8),ysiz=where[2]+(where[3]<<8);
  305. int runsize,chr;
  306. if(change_xysizes)
  307. {
  308. board_xsiz=xsiz;
  309. board_ysiz=ysiz;
  310. }
  311. t1=t2=0;//y and x position
  312. do
  313. {
  314. chr=where[pos++];
  315. if(!(chr&128))
  316. {//Regular character
  317. plane[t1*max_bxsiz+t2]=chr;
  318. if((++t2)>=xsiz)
  319. {
  320. t2=0;
  321. if((++t1)>=ysiz) goto done;
  322. }
  323. }
  324. else
  325. {
  326. //A run
  327. runsize=chr&127;
  328. chr=where[pos++];
  329. for(t3=0;t3<runsize;t3++)
  330. {
  331. plane[t1*max_bxsiz+t2]=chr;
  332. if((++t2)>=xsiz)
  333. {
  334. t2=0;
  335. if((++t1)>=ysiz) goto done;
  336. }
  337. }
  338. }
  339. } while(1);
  340. done:
  341. //Done!
  342. return pos;
  343. }
  344. //Reads RLE2-compressed plane from file and puts into plane.
  345. //Also sets board_xsiz and board_ysiz unless specified otherwise.
  346. void RLE2_load(FILE *fp,unsigned char far *plane,char change_xysizes)
  347. {
  348. int t1,t2,t3,xsiz,ysiz;
  349. int runsize,chr;
  350. fread(&xsiz,2,1,fp);
  351. fread(&ysiz,2,1,fp);
  352. //xsiz = 100;
  353. //ysiz = 50;
  354. if(change_xysizes)
  355. {
  356. board_xsiz=xsiz;
  357. board_ysiz=ysiz;
  358. }
  359. t1=t2=0;//y and x position
  360. do
  361. {
  362. chr=fgetc(fp);
  363. if(!(chr&128))
  364. {//Regular character
  365. plane[t1*max_bxsiz+t2]=chr;
  366. if((++t2)>=xsiz)
  367. {
  368. t2=0;
  369. if((++t1)>=ysiz) goto done;
  370. }
  371. }
  372. else
  373. {
  374. //A run
  375. runsize=chr&127;
  376. chr=fgetc(fp);
  377. for(t3=0;t3<runsize;t3++)
  378. {
  379. plane[t1*max_bxsiz+t2]=chr;
  380. if((++t2)>=xsiz)
  381. {
  382. t2=0;
  383. if((++t1)>=ysiz) goto done;
  384. }
  385. }
  386. }
  387. } while(1);
  388. done:
  389. //Done!
  390. }
  391. //Gets size current board would take up, were it stored.
  392. long size_of_current_board(void)
  393. {
  394. long size=224;//Size of info other than board and robots/etc
  395. int t1,count=0;
  396. //Count robots
  397. for(t1=1;t1<NUM_ROBOTS;t1++)
  398. if(robots[t1].used) count=t1;
  399. //Add room for robots and all their programs plus the count itself
  400. size+=sizeof(Robot)*count;
  401. if(count)
  402. for(t1=0;t1<count;t1++)
  403. size+=robots[t1+1].program_length;
  404. //Count scrolls
  405. count=0;
  406. for(t1=1;t1<NUM_SCROLLS;t1++)
  407. if(scrolls[t1].used) count=t1;
  408. //Add room for scrolls and all their texts plus the count itself
  409. size+=sizeof(Scroll)*count;
  410. if(count)
  411. for(t1=0;t1<count;t1++)
  412. size+=scrolls[t1+1].mesg_size;
  413. //Count sensors
  414. count=0;
  415. for(t1=1;t1<NUM_SENSORS;t1++)
  416. if(sensors[t1].used) count=t1;
  417. //Add room for sensors plus the count itself
  418. size+=sizeof(Sensor)*count;
  419. //If overlay on, add room for 2 bytes (one for overlay mode, one
  420. //for indicator bit) and RLE2 of both planes
  421. if(overlay_mode)
  422. {
  423. size+=2;
  424. size+=RLE2_size(overlay);
  425. size+=RLE2_size(overlay_color);
  426. }
  427. //Finally, add room for all six planes, RLE2 encoded, and return
  428. size+=RLE2_size(level_id);
  429. size+=RLE2_size(level_color);
  430. size+=RLE2_size(level_param);
  431. size+=RLE2_size(level_under_id);
  432. size+=RLE2_size(level_under_color);
  433. return(size+RLE2_size(level_under_param));
  434. }
  435. //Stores current board in slot given. Space must already be allocated.
  436. //board_sizes and other board variables MUST be accurate. Returns non-0
  437. //if out of room in memory and on disk for working, or for misc. errors.
  438. //Does not affect and is not affected by a current object or global robot.
  439. char store_current(unsigned char id)
  440. {
  441. unsigned char far *ptr;//Where to store for mem/ems
  442. unsigned char far *old_ptr;//Saves old ems allocated ptr
  443. FILE *fp;//Where to store for tempfile (or ems if pressed for space)
  444. int t1,count,tcpy;
  445. long copied;
  446. //Space of proper size already assumed to be allocated. This function
  447. //has two major parts- The code for memory/ems, and the code for temp
  448. //files.
  449. //Switch according to storage type.
  450. switch(board_where[id])
  451. {
  452. case W_MEMORY:
  453. case W_EMS:
  454. //If EMS, allocate a temporary area to allow storage in conventional
  455. //memory for now, then copy to EMS later. If not possible, we use a
  456. //temp file and then copy THAT to EMS later. If no room for a temp
  457. //file... return error.
  458. if(board_where[id]==W_EMS)
  459. {
  460. //Allocate a temporary area
  461. ptr=(unsigned char far *)farmalloc(board_sizes[id]);
  462. if(ptr==NULL)
  463. {
  464. //No room in mem- try a temp file
  465. //Make temporary filename
  466. str_cpy(&board_filenames[id*FILENAME_SIZE],"~MZTMPXXXXXX");
  467. mktemp(&board_filenames[id*FILENAME_SIZE]);
  468. //Open..
  469. fp=fopen(&board_filenames[id*FILENAME_SIZE],"wb+");
  470. if(fp==NULL)
  471. {
  472. //Error
  473. board_filenames[id*FILENAME_SIZE]=0;
  474. return 1;
  475. }
  476. //Try to make room
  477. fseek(fp,board_sizes[id],SEEK_SET);
  478. if(ftell(fp)!=(board_sizes[id]))
  479. {
  480. //Not enough room on hard drive
  481. fclose(fp);
  482. unlink(&board_filenames[id*FILENAME_SIZE]);
  483. board_filenames[id*FILENAME_SIZE]=0;
  484. return 2;
  485. }
  486. //Room made! Solidify.
  487. fseek(fp,-1,SEEK_CUR);
  488. fputc(0,fp);
  489. fclose(fp);
  490. //Go to tempfile storage
  491. goto store_tempfile;
  492. }
  493. else old_ptr=ptr;
  494. }
  495. else ptr=(unsigned char far *)board_offsets[id].mem;
  496. *(ptr++)=max_bsiz_mode;
  497. //Store RLE2 stuff
  498. if(overlay_mode)
  499. {
  500. *(ptr++)=0;
  501. *(ptr++)=overlay_mode;
  502. ptr+=RLE2_store((unsigned char far*)ptr,overlay);
  503. normalize(ptr);
  504. ptr+=RLE2_store((unsigned char far*)ptr,overlay_color);
  505. normalize(ptr);
  506. }
  507. ptr+=RLE2_store((unsigned char far *)ptr,level_id);
  508. normalize(ptr);
  509. ptr+=RLE2_store((unsigned char far *)ptr,level_color);
  510. normalize(ptr);
  511. ptr+=RLE2_store((unsigned char far *)ptr,level_param);
  512. normalize(ptr);
  513. ptr+=RLE2_store((unsigned char far *)ptr,level_under_id);
  514. normalize(ptr);
  515. ptr+=RLE2_store((unsigned char far *)ptr,level_under_color);
  516. normalize(ptr);
  517. ptr+=RLE2_store((unsigned char far *)ptr,level_under_param);
  518. normalize(ptr);
  519. //Store variables- Due to the way they are stored in DATA.ASM,
  520. //they can all be stored as a series of 210 bytes starting at
  521. //mod_playing. Appropriate code to save each individually is
  522. //also included in case this ever fails. To use the individual
  523. //code, define the symbol SAVE_INDIVIDUAL.
  524. #ifndef SAVE_INDIVIDUAL
  525. mem_cpy((char far *)ptr,mod_playing,207+FILENAME_SIZE);
  526. ptr+=207+FILENAME_SIZE;
  527. #else
  528. mem_cpy((char far *)ptr,mod_playing,FILENAME_SIZE);
  529. ptr+=FILENAME_SIZE;
  530. *(ptr++)=viewport_x;
  531. *(ptr++)=viewport_y;
  532. *(ptr++)=viewport_xsiz;
  533. *(ptr++)=viewport_ysiz;
  534. *(ptr++)=can_shoot;
  535. *(ptr++)=can_bomb;
  536. *(ptr++)=fire_burn_brown;
  537. *(ptr++)=fire_burn_space;
  538. *(ptr++)=fire_burn_fakes;
  539. *(ptr++)=fire_burn_trees;
  540. *(ptr++)=explosions_leave;
  541. *(ptr++)=save_mode;
  542. *(ptr++)=forest_becomes;
  543. *(ptr++)=collect_bombs;
  544. *(ptr++)=fire_burns;
  545. mem_cpy((char far *)ptr,(char far *)board_dir,4);
  546. ptr+=4;
  547. *(ptr++)=restart_if_zapped;
  548. mem_cpy((char far *)ptr,(char far *)&time_limit,2);
  549. ptr+=2;
  550. *(ptr++)=last_key;
  551. mem_cpy((char far *)ptr,(char far *)&num_input,2);
  552. ptr+=2;
  553. *(ptr++)=input_size;
  554. mem_cpy((char far *)ptr,input_string,81);
  555. ptr+=81;
  556. *(ptr++)=player_last_dir;
  557. mem_cpy((char far *)ptr,bottom_mesg,81);
  558. ptr+=81;
  559. *(ptr++)=b_mesg_timer;
  560. *(ptr++)=lazwall_start;
  561. *(ptr++)=b_mesg_row;
  562. *(ptr++)=b_mesg_col;
  563. mem_cpy((char far *)ptr,(char far *)&scroll_x,2);
  564. ptr+=2;
  565. mem_cpy((char far *)ptr,(char far *)&scroll_y,2);
  566. ptr+=2;
  567. mem_cpy((char far *)ptr,(char far *)&locked_x,2);
  568. ptr+=2;
  569. mem_cpy((char far *)ptr,(char far *)&locked_y,2);
  570. ptr+=2;
  571. *(ptr++)=player_ns_locked;
  572. *(ptr++)=player_ew_locked;
  573. *(ptr++)=player_attack_locked;
  574. *(ptr++)=volume;
  575. *(ptr++)=volume_inc;
  576. *(ptr++)=volume_target;
  577. #endif
  578. //Robot count
  579. count=0;
  580. for(t1=1;t1<NUM_ROBOTS;t1++)
  581. if(robots[t1].used) count=t1;
  582. *(ptr++)=count;
  583. //Robots themselves
  584. prepare_robot_mem();
  585. if(count)
  586. {
  587. for(t1=1;t1<=count;t1++)
  588. {
  589. //Copy robot t1
  590. mem_cpy((char far *)ptr,(char far *)&robots[t1],sizeof(Robot));
  591. ptr+=sizeof(Robot);
  592. normalize(ptr);
  593. mem_cpy((char far *)ptr,
  594. (char far *)&robot_mem[robots[t1].program_location],
  595. robots[t1].program_length);
  596. ptr+=robots[t1].program_length;
  597. }
  598. }
  599. //Scroll count
  600. count=0;
  601. for(t1=1;t1<NUM_SCROLLS;t1++)
  602. if(scrolls[t1].used) count=t1;
  603. *(ptr++)=count;
  604. //Scrolls themselves
  605. if(count)
  606. {
  607. for(t1=1;t1<=count;t1++)
  608. {
  609. //Copy scroll t1
  610. mem_cpy((char far *)ptr,(char far *)&scrolls[t1],sizeof(Scroll));
  611. ptr+=sizeof(Scroll);
  612. normalize(ptr);
  613. mem_cpy((char far *)ptr,
  614. (char far *)&robot_mem[scrolls[t1].mesg_location],
  615. scrolls[t1].mesg_size);
  616. ptr+=scrolls[t1].mesg_size;
  617. }
  618. }
  619. //Sensor count
  620. count=0;
  621. for(t1=1;t1<NUM_SENSORS;t1++)
  622. if(sensors[t1].used) count=t1;
  623. *(ptr++)=count;
  624. //Sensors themselves
  625. if(count)
  626. {
  627. for(t1=1;t1<=count;t1++)
  628. {
  629. //Copy sensor t1
  630. mem_cpy((char far *)ptr,(char far *)&sensors[t1],sizeof(Sensor));
  631. ptr+=sizeof(Sensor);
  632. }
  633. }
  634. //All copied! Return if memory...
  635. if(board_where[id]==W_MEMORY) return 0;
  636. //...otherwise copy to EMS.
  637. //Copy a page at a time...
  638. t1=board_offsets[id].EMS.page;//Current page
  639. copied=0;//Copied nothing so far.
  640. ptr=old_ptr;//Use original pointer
  641. do
  642. {
  643. //Map page
  644. map_page_EMS(board_offsets[id].EMS.handle,0,t1);
  645. //Copy a page, or part of a page if that's all that's left.
  646. tcpy=16384;
  647. if((copied+tcpy)>board_sizes[id]) //Too much...
  648. tcpy=(int)(board_sizes[id]-(unsigned long)copied);
  649. //Now copy it...
  650. mem_cpy(page_frame_EMS,(char far *)ptr,tcpy);
  651. //...increment status...
  652. copied+=tcpy;
  653. ptr+=tcpy;
  654. normalize(ptr);
  655. t1++;//Page
  656. //...loop.
  657. } while(copied<board_sizes[id]);
  658. //All copied! Free memory and exit
  659. farfree(old_ptr);
  660. return 0;
  661. case W_TEMPFILE:
  662. store_tempfile:
  663. //This is storage in a tempfile, sometimes a subfuction of storage
  664. //in EMS.
  665. //Open file...
  666. fp=fopen(&board_filenames[id*FILENAME_SIZE],"rb+");
  667. if(fp==NULL)
  668. {
  669. if(board_where[id]==W_EMS) board_filenames[id*FILENAME_SIZE]=0;
  670. return 1;//Error...
  671. }
  672. //...and begin output!
  673. fputc(max_bsiz_mode,fp);
  674. //Store RLE2 stuff
  675. if(overlay_mode)
  676. {
  677. fputc(0,fp);
  678. fputc(overlay_mode,fp);
  679. RLE2_save(fp,overlay);
  680. RLE2_save(fp,overlay_color);
  681. }
  682. RLE2_save(fp,level_id);
  683. RLE2_save(fp,level_color);
  684. RLE2_save(fp,level_param);
  685. RLE2_save(fp,level_under_id);
  686. RLE2_save(fp,level_under_color);
  687. RLE2_save(fp,level_under_param);
  688. //Store variables- Due to the way they are stored in DATA.ASM,
  689. //they can all be stored as a series of 210 bytes starting at
  690. //mod_playing. Appropriate code to save each individually is
  691. //also included in case this ever fails. To use the individual
  692. //code, define the symbol SAVE_INDIVIDUAL.
  693. #ifndef SAVE_INDIVIDUAL
  694. fwrite(mod_playing,1,207+FILENAME_SIZE,fp);
  695. #else
  696. fwrite(mod_playing,1,FILENAME_SIZE,fp);
  697. fputc(viewport_x,fp);
  698. fputc(viewport_y,fp);
  699. fputc(viewport_xsiz,fp);
  700. fputc(viewport_ysiz,fp);
  701. fputc(can_shoot,fp);
  702. fputc(can_bomb,fp);
  703. fputc(fire_burn_brown,fp);
  704. fputc(fire_burn_space,fp);
  705. fputc(fire_burn_fakes,fp);
  706. fputc(fire_burn_trees,fp);
  707. fputc(explosions_leave,fp);
  708. fputc(save_mode,fp);
  709. fputc(forest_becomes,fp);
  710. fputc(collect_bombs,fp);
  711. fputc(fire_burns,fp);
  712. fwrite(board_dir,1,4,fp);
  713. fputc(restart_if_zapped,fp);
  714. fwrite(&time_limit,2,1,fp);
  715. fputc(last_key,fp);
  716. fwrite(&num_input,2,1,fp);
  717. fputc(input_size,fp);
  718. fwrite(input_string,1,81,fp);
  719. fputc(player_last_dir,fp);
  720. fwrite(bottom_mesg,1,81,fp);
  721. fputc(b_mesg_timer,fp);
  722. fputc(lazwall_start,fp);
  723. fputc(b_mesg_row,fp);
  724. fputc(b_mesg_col,fp);
  725. fwrite(&scroll_x,2,1,fp);
  726. fwrite(&scroll_y,2,1,fp);
  727. fwrite(&locked_x,2,1,fp);
  728. fwrite(&locked_y,2,1,fp);
  729. fputc(player_ns_locked,fp);
  730. fputc(player_ew_locked,fp);
  731. fputc(player_attack_locked,fp);
  732. fputc(volume,fp);
  733. fputc(volume_inc,fp);
  734. fputc(volume_target,fp);
  735. #endif
  736. //Robot count
  737. count=0;
  738. for(t1=1;t1<NUM_ROBOTS;t1++)
  739. if(robots[t1].used) count=t1;
  740. fputc(count,fp);
  741. //Robots themselves
  742. prepare_robot_mem();
  743. if(count)
  744. {
  745. for(t1=1;t1<=count;t1++)
  746. {
  747. //Copy robot t1
  748. fwrite(&robots[t1],sizeof(Robot),1,fp);
  749. fwrite(&robot_mem[robots[t1].program_location],1,
  750. robots[t1].program_length,fp);
  751. }
  752. }
  753. //Scroll count
  754. count=0;
  755. for(t1=1;t1<NUM_SCROLLS;t1++)
  756. if(scrolls[t1].used) count=t1;
  757. fputc(count,fp);
  758. //Scrolls themselves
  759. if(count)
  760. {
  761. for(t1=1;t1<=count;t1++)
  762. {
  763. //Copy scroll t1
  764. fwrite(&scrolls[t1],sizeof(Scroll),1,fp);
  765. fwrite(&robot_mem[scrolls[t1].mesg_location],1,
  766. scrolls[t1].mesg_size,fp);
  767. }
  768. }
  769. //Sensor count
  770. count=0;
  771. for(t1=1;t1<NUM_SENSORS;t1++)
  772. if(sensors[t1].used) count=t1;
  773. fputc(count,fp);
  774. //Sensors themselves
  775. if(count)
  776. {
  777. for(t1=1;t1<=count;t1++) //Copy sensor t1
  778. fwrite(&sensors[t1],sizeof(Sensor),1,fp);
  779. }
  780. //All saved! Return if tempfile...
  781. if(board_where[id]==W_TEMPFILE)
  782. {
  783. fclose(fp);
  784. return 0;
  785. }
  786. //...otherwise copy to EMS.
  787. //Copy a page at a time...
  788. t1=board_offsets[id].EMS.page;//Current page
  789. copied=0;//Copied nothing so far.
  790. fseek(fp,0,SEEK_SET);//Return to start of file
  791. do
  792. {
  793. //Map page
  794. map_page_EMS(board_offsets[id].EMS.handle,0,t1);
  795. //Copy a page, or part of a page if that's all that's left.
  796. tcpy=16384;
  797. if((copied+tcpy)>board_sizes[id]) //Too much...
  798. tcpy=(int)(board_sizes[id]-(unsigned long)copied);
  799. //Now copy it...
  800. fread(page_frame_EMS,tcpy,1,fp);
  801. //...increment status...
  802. copied+=tcpy;
  803. t1++;//Page
  804. //...loop.
  805. } while(copied<board_sizes[id]);
  806. //All copied! Clear file and exit
  807. fclose(fp);
  808. unlink(&board_filenames[id*FILENAME_SIZE]);
  809. board_filenames[id*FILENAME_SIZE]=0;
  810. return 0;
  811. }
  812. return 3;
  813. }
  814. //Loads current board from slot given. Space must already be filled.
  815. //board_sizes and other board variables MUST be accurate. Returns non-0
  816. //if out of room in memory and on disk for working, or for misc. errors.
  817. //Returns 4 if out of robot memory. (This is usually due to a large current
  818. //robot/scroll or a large global robot) Does not affect current object or
  819. //global robot.
  820. char grab_current(unsigned char id)
  821. {
  822. unsigned char far *ptr;//Where to grab from for mem/ems
  823. unsigned char far *old_ptr;//Saves old ems allocated ptr
  824. FILE *fp;//Where to grab from for tempfile (or ems if pressed for space)
  825. int t1,count,tcpy;
  826. unsigned int oldsize,newsize,oldloc;//For robot/scroll allocation
  827. long copied;
  828. //Space of proper size already assumed to be allocated. This function
  829. //has two major parts- The code for memory/ems, and the code for temp
  830. //files.
  831. //Switch according to storage type.
  832. switch(board_where[id])
  833. {
  834. case W_EMS:
  835. //If EMS, allocate a temporary area to allow storage in conventional
  836. //memory for now, then copy to robots/etc. later. If not possible,
  837. //we use a temp file and then copy THAT to mem. later. If no room
  838. //for a temp file... return error.
  839. //Allocate a temporary area
  840. ptr=(unsigned char far *)farmalloc(board_sizes[id]);
  841. if(ptr==NULL)
  842. {
  843. //No room in mem- try a temp file
  844. //Make temporary filename
  845. str_cpy(&board_filenames[id*FILENAME_SIZE],"~MZTMPXXXXXX");
  846. mktemp(&board_filenames[id*FILENAME_SIZE]);
  847. //Open..
  848. fp=fopen(&board_filenames[id*FILENAME_SIZE],"wb+");
  849. if(fp==NULL)
  850. {
  851. //Error
  852. board_filenames[id*FILENAME_SIZE]=0;
  853. return 1;
  854. }
  855. //Try to make room
  856. fseek(fp,board_sizes[id],SEEK_SET);
  857. if(ftell(fp)!=(board_sizes[id]))
  858. {
  859. //Not enough room on hard drive
  860. fclose(fp);
  861. unlink(&board_filenames[id*FILENAME_SIZE]);
  862. board_filenames[id*FILENAME_SIZE]=0;
  863. return 2;
  864. }
  865. //Room made! Solidify.
  866. fseek(fp,-1,SEEK_CUR);
  867. fputc(0,fp);
  868. //Load from EMS
  869. //Copy a page at a time...
  870. t1=board_offsets[id].EMS.page;//Current page
  871. copied=0;//Copied nothing so far.
  872. fseek(fp,0,SEEK_SET);//Return to start of file
  873. do
  874. {
  875. //Map page
  876. map_page_EMS(board_offsets[id].EMS.handle,0,t1);
  877. //Copy a page, or part of a page if that's all that's left.
  878. tcpy=16384;
  879. if((copied+tcpy)>board_sizes[id]) //Too much...
  880. tcpy=(int)(board_sizes[id]-(unsigned long)copied);
  881. //Now copy it...
  882. fwrite(page_frame_EMS,tcpy,1,fp);
  883. //...increment status...
  884. copied+=tcpy;
  885. t1++;//Page
  886. //...loop.
  887. } while(copied<board_sizes[id]);
  888. //All copied! Close file and jump to tempfile code
  889. fclose(fp);
  890. goto grab_tempfile;
  891. }
  892. //Allocated. Copy from EMS to memory first...
  893. old_ptr=ptr;
  894. //Copy a page at a time...
  895. t1=board_offsets[id].EMS.page;//Current page
  896. copied=0;//Copied nothing so far.
  897. do
  898. {
  899. //Map page
  900. map_page_EMS(board_offsets[id].EMS.handle,0,t1);
  901. //Copy a page, or part of a page if that's all that's left.
  902. tcpy=16384;
  903. if((copied+tcpy)>board_sizes[id]) //Too much...
  904. tcpy=(int)(board_sizes[id]-(unsigned long)copied);
  905. //Now copy it...
  906. mem_cpy((char far *)ptr,page_frame_EMS,tcpy);
  907. //...increment status...
  908. copied+=tcpy;
  909. ptr+=tcpy;
  910. normalize(ptr);
  911. t1++;//Page
  912. //...loop.
  913. } while(copied<board_sizes[id]);
  914. //All copied! Now do regular memory code.
  915. ptr=old_ptr;//Restore pointer
  916. goto grab_memory;
  917. case W_MEMORY:
  918. ptr=(unsigned char far *)board_offsets[id].mem;
  919. grab_memory:
  920. //Clear overlay
  921. overlay_mode=0;
  922. for(t1=0;t1<10000;t1++)
  923. {
  924. level_id[t1]=level_under_id[t1]=level_param[t1]=level_under_param[t1]=0;
  925. level_color[t1]=level_under_color[t1]=overlay_color[t1]=7;
  926. overlay[t1]=32;
  927. }
  928. max_bsiz_mode=*(ptr++);
  929. convert_max_bsiz_mode();
  930. //Load RLE2 stuff
  931. // Oh Greg NO. According to the board specs, the first byte being 0 here
  932. // means that there's no overlay. Otherwise, this byte is the first byte of
  933. // the board width for the level stuff. But what Greg didn't realize is that
  934. // the first byte can be 0 for a board without overlay if the width is 256.
  935. // So if the width is 256, it will try to load an overlay that's not there and
  936. // totally eat the game. Solution? Um... well you can't just check the entire
  937. // word because the latter 8bits won't necessarily be 0. So 0 1 bytes mean
  938. // either 256 width no overlay, or overlay mode 1, you can't tell the
  939. // difference. You can guess by looking at the word following this one to see
  940. // if it's less than 26 (which it must be for the board to be 256 wide) but
  941. // this value in overlay mode may be less than 256.
  942. if(*ptr == 0)
  943. {
  944. //Overlay
  945. ptr++;
  946. overlay_mode=*(ptr++);
  947. ptr+=RLE2_read((unsigned char far *)ptr,overlay);
  948. normalize(ptr);
  949. ptr+=RLE2_read((unsigned char far *)ptr,overlay_color);
  950. normalize(ptr);
  951. }
  952. ptr+=RLE2_read((unsigned char far *)ptr,level_id);
  953. normalize(ptr);
  954. ptr+=RLE2_read((unsigned char far *)ptr,level_color);
  955. normalize(ptr);
  956. ptr+=RLE2_read((unsigned char far *)ptr,level_param);
  957. normalize(ptr);
  958. ptr+=RLE2_read((unsigned char far *)ptr,level_under_id);
  959. normalize(ptr);
  960. ptr+=RLE2_read((unsigned char far *)ptr,level_under_color);
  961. normalize(ptr);
  962. ptr+=RLE2_read((unsigned char far *)ptr,level_under_param);
  963. normalize(ptr);
  964. //Read variables- Due to the way they are stored in DATA.ASM,
  965. //they can all be read as a series of 210 bytes starting at
  966. //mod_playing. Appropriate code to read each individually is
  967. //also included in case this ever fails. To use the individual
  968. //code, define the symbol SAVE_INDIVIDUAL.
  969. #ifndef SAVE_INDIVIDUAL
  970. mem_cpy(mod_playing,(char far *)ptr,207+FILENAME_SIZE);
  971. ptr+=207+FILENAME_SIZE;
  972. #else
  973. mem_cpy(mod_playing,(char far *)ptr,FILENAME_SIZE);
  974. ptr+=FILENAME_SIZE;
  975. viewport_x=*(ptr++);
  976. viewport_y=*(ptr++);
  977. viewport_xsiz=*(ptr++);
  978. viewport_ysiz=*(ptr++);
  979. can_shoot=*(ptr++);
  980. can_bomb=*(ptr++);
  981. fire_burn_brown=*(ptr++);
  982. fire_burn_space=*(ptr++);
  983. fire_burn_fakes=*(ptr++);
  984. fire_burn_trees=*(ptr++);
  985. explosions_leave=*(ptr++);
  986. save_mode=*(ptr++);
  987. forest_becomes=*(ptr++);
  988. collect_bombs=*(ptr++);
  989. fire_burns=*(ptr++);
  990. mem_cpy((char far *)board_dir,(char far *)ptr,4);
  991. ptr+=4;
  992. restart_if_zapped=*(ptr++);
  993. mem_cpy((char far *)&time_limit,(char far *)ptr,2);
  994. ptr+=2;
  995. last_key=*(ptr++);
  996. mem_cpy((char far *)&num_input,(char far *)ptr,2);
  997. ptr+=2;
  998. input_size=*(ptr++);
  999. mem_cpy(input_string,(char far *)ptr,81);
  1000. ptr+=81;
  1001. player_last_dir=*(ptr++);
  1002. mem_cpy(bottom_mesg,(char far *)ptr,81);
  1003. ptr+=81;
  1004. b_mesg_timer=*(ptr++);
  1005. lazwall_start=*(ptr++);
  1006. b_mesg_row=*(ptr++);
  1007. b_mesg_col=*(ptr++);
  1008. mem_cpy((char far *)&scroll_x,(char far *)ptr,2);
  1009. ptr+=2;
  1010. mem_cpy((char far *)&scroll_y,(char far *)ptr,2);
  1011. ptr+=2;
  1012. mem_cpy((char far *)&locked_x,(char far *)ptr,2);
  1013. ptr+=2;
  1014. mem_cpy((char far *)&locked_y,(char far *)ptr,2);
  1015. ptr+=2;
  1016. player_ns_locked=*(ptr++);
  1017. player_ew_locked=*(ptr++);
  1018. player_attack_locked=*(ptr++);
  1019. volume=*(ptr++);
  1020. volume_inc=*(ptr++);
  1021. volume_target=*(ptr++);
  1022. #endif
  1023. //Before doing robots/scrolls, make sure all but #0 and global
  1024. //are allocated to the minimum. Also clear all sensors.
  1025. prepare_robot_mem();
  1026. for(t1=1;t1<NUM_ROBOTS;t1++)
  1027. clear_robot(t1);
  1028. for(t1=1;t1<NUM_SCROLLS;t1++)
  1029. clear_scroll(t1);
  1030. for(t1=1;t1<NUM_SENSORS;t1++)
  1031. clear_sensor(t1);
  1032. //Robots- get count, then load 'em up. All must be allocated
  1033. //first. A mis-allocation frees any ems memory and returns error
  1034. //code #4.
  1035. count=*(ptr++);
  1036. if(count)
  1037. {
  1038. for(t1=1;t1<=count;t1++)
  1039. {
  1040. //Read robot t1
  1041. oldsize=robots[t1].program_length;
  1042. oldloc=robots[t1].program_location;
  1043. mem_cpy((char far *)&robots[t1],(char far *)ptr,sizeof(Robot));
  1044. ptr+=sizeof(Robot);
  1045. normalize(ptr);
  1046. newsize=robots[t1].program_length;
  1047. robots[t1].program_length=oldsize;
  1048. robots[t1].program_location=oldloc;
  1049. if(reallocate_robot_mem(T_ROBOT,t1,newsize))
  1050. {
  1051. //Error in allocation.
  1052. //EMS- delete temp area
  1053. if(board_where[id]==W_EMS) farfree(ptr);
  1054. return 4;
  1055. }
  1056. //Load in robot
  1057. mem_cpy((char far *)&robot_mem[robots[t1].program_location],
  1058. (char far *)ptr,robots[t1].program_length);
  1059. ptr+=robots[t1].program_length;
  1060. }
  1061. }
  1062. //Scroll count
  1063. count=*(ptr++);
  1064. if(count)
  1065. {
  1066. for(t1=1;t1<=count;t1++)
  1067. {
  1068. //Read scroll t1
  1069. oldsize=scrolls[t1].mesg_size;
  1070. oldloc=scrolls[t1].mesg_location;
  1071. mem_cpy((char far *)&scrolls[t1],(char far *)ptr,sizeof(Scroll));
  1072. ptr+=sizeof(Scroll);
  1073. normalize(ptr);
  1074. newsize=scrolls[t1].mesg_size;
  1075. scrolls[t1].mesg_size=oldsize;
  1076. scrolls[t1].mesg_location=oldloc;
  1077. if(reallocate_robot_mem(T_SCROLL,t1,newsize))
  1078. {
  1079. //Error in allocation.
  1080. //EMS- delete temp area
  1081. if(board_where[id]==W_EMS) farfree(ptr);
  1082. return 4;
  1083. }
  1084. mem_cpy((char far *)&robot_mem[scrolls[t1].mesg_location],
  1085. (char far *)ptr,scrolls[t1].mesg_size);
  1086. ptr+=scrolls[t1].mesg_size;
  1087. }
  1088. }
  1089. //Sensor count
  1090. count=*(ptr++);
  1091. if(count)
  1092. {
  1093. for(t1=1;t1<=count;t1++)
  1094. {
  1095. //Read sensor t1
  1096. mem_cpy((char far *)&sensors[t1],(char far *)ptr,sizeof(Sensor));
  1097. ptr+=sizeof(Sensor);
  1098. }
  1099. }
  1100. //All grabbed! Return if memory...
  1101. if(board_where[id]==W_MEMORY) return 0;
  1102. //...otherwise free EMS temp memory.
  1103. farfree(old_ptr);
  1104. return 0;
  1105. case W_TEMPFILE:
  1106. grab_tempfile:
  1107. //This is loading from a tempfile, sometimes a subfuction of loading
  1108. //from EMS.
  1109. //Open file...
  1110. fp=fopen(&board_filenames[id*FILENAME_SIZE],"rb");
  1111. if(fp==NULL)
  1112. {
  1113. if(board_where[id]==W_EMS) board_filenames[id*FILENAME_SIZE]=0;
  1114. return 1;//Error...
  1115. }
  1116. //...and begin input!
  1117. //Clear overlay
  1118. overlay_mode=0;
  1119. for(t1=0;t1<10000;t1++)
  1120. {
  1121. level_id[t1]=level_under_id[t1]=level_param[t1]=level_under_param[t1]=0;
  1122. level_color[t1]=level_under_color[t1]=overlay_color[t1]=7;
  1123. overlay[t1]=32;
  1124. }
  1125. max_bsiz_mode=fgetc(fp);
  1126. convert_max_bsiz_mode();
  1127. //Overlay
  1128. if(fgetc(fp)==0)
  1129. {
  1130. overlay_mode=fgetc(fp);
  1131. RLE2_load(fp,overlay);
  1132. RLE2_load(fp,overlay_color);
  1133. }
  1134. else fseek(fp,-1,SEEK_CUR);
  1135. //load RLE2 stuff
  1136. RLE2_load(fp,level_id);
  1137. RLE2_load(fp,level_color);
  1138. RLE2_load(fp,level_param);
  1139. RLE2_load(fp,level_under_id);
  1140. RLE2_load(fp,level_under_color);
  1141. RLE2_load(fp,level_under_param);
  1142. //Load variables- Due to the way they are stored in DATA.ASM,
  1143. //they can all be loaded as a series of 210 bytes starting at
  1144. //mod_playing. Appropriate code to load each individually is
  1145. //also included in case this ever fails. To use the individual
  1146. //code, define the symbol SAVE_INDIVIDUAL.
  1147. #ifndef SAVE_INDIVIDUAL
  1148. fread(mod_playing,1,207+FILENAME_SIZE,fp);
  1149. #else
  1150. fread(mod_playing,1,FILENAME_SIZE,fp);
  1151. viewport_x=fgetc(fp);
  1152. viewport_y=fgetc(fp);
  1153. viewport_xsiz=fgetc(fp);
  1154. viewport_ysiz=fgetc(fp);
  1155. can_shoot=fgetc(fp);
  1156. can_bomb=fgetc(fp);
  1157. fire_burn_brown=fgetc(fp);
  1158. fire_burn_space=fgetc(fp);
  1159. fire_burn_fakes=fgetc(fp);
  1160. fire_burn_trees=fgetc(fp);
  1161. explosions_leave=fgetc(fp);
  1162. save_mode=fgetc(fp);
  1163. forest_becomes=fgetc(fp);
  1164. collect_bombs=fgetc(fp);
  1165. fire_burns=fgetc(fp);
  1166. fread(board_dir,1,4,fp);
  1167. restart_if_zapped=fgetc(fp);
  1168. fread(&time_limit,2,1,fp);
  1169. last_key=fgetc(fp);
  1170. fread(&num_input,2,1,fp);
  1171. input_size=fgetc(fp);
  1172. fread(input_string,1,81,fp);
  1173. player_last_dir=fgetc(fp);
  1174. fread(bottom_mesg,1,81,fp);
  1175. b_mesg_timer=fgetc(fp);
  1176. lazwall_start=fgetc(fp);
  1177. b_mesg_row=fgetc(fp);
  1178. b_mesg_col=fgetc(fp);
  1179. fread(&scroll_x,2,1,fp);
  1180. fread(&scroll_y,2,1,fp);
  1181. fread(&locked_x,2,1,fp);
  1182. fread(&locked_y,2,1,fp);
  1183. player_ns_locked=fgetc(fp);
  1184. player_ew_locked=fgetc(fp);
  1185. player_attack_locked=fgetc(fp);
  1186. volume=fgetc(fp);
  1187. volume_inc=fgetc(fp);
  1188. volume_target=fgetc(fp);
  1189. #endif
  1190. //Before doing robots/scrolls, make sure all but #0 and global
  1191. //are allocated to the minimum. Also clear all sensors.
  1192. prepare_robot_mem();
  1193. for(t1=1;t1<NUM_ROBOTS;t1++)
  1194. clear_robot(t1);
  1195. for(t1=1;t1<NUM_SCROLLS;t1++)
  1196. clear_scroll(t1);
  1197. for(t1=1;t1<NUM_SENSORS;t1++)
  1198. clear_sensor(t1);
  1199. //Robots- get count, then load 'em up. All must be allocated
  1200. //first. A mis-allocation frees any ems memory and returns error
  1201. //code #4.
  1202. count=fgetc(fp);
  1203. if(count)
  1204. {
  1205. for(t1=1;t1<=count;t1++)
  1206. {
  1207. //Read robot t1
  1208. oldsize=robots[t1].program_length;
  1209. oldloc=robots[t1].program_location;
  1210. fread(&robots[t1],sizeof(Robot),1,fp);
  1211. newsize=robots[t1].program_length;
  1212. robots[t1].program_length=oldsize;
  1213. robots[t1].program_location=oldloc;
  1214. if(reallocate_robot_mem(T_ROBOT,t1,newsize))
  1215. {
  1216. //Error in allocation.
  1217. fclose(fp);
  1218. //EMS- delete temp file
  1219. if(board_where[id]==W_EMS)
  1220. {
  1221. unlink(&board_filenames[id*FILENAME_SIZE]);
  1222. board_filenames[id*FILENAME_SIZE]=0;
  1223. }
  1224. return 4;
  1225. }
  1226. //Load in robot
  1227. fread(&robot_mem[robots[t1].program_location],1,
  1228. robots[t1].program_length,fp);
  1229. }
  1230. }
  1231. //Scroll count
  1232. count=fgetc(fp);
  1233. if(count)
  1234. {
  1235. for(t1=1;t1<=count;t1++)
  1236. {
  1237. //Read scroll t1
  1238. oldsize=scrolls[t1].mesg_size;
  1239. oldloc=scrolls[t1].mesg_location;
  1240. fread(&scrolls[t1],sizeof(Scroll),1,fp);
  1241. newsize=scrolls[t1].mesg_size;
  1242. scrolls[t1].mesg_size=oldsize;
  1243. scrolls[t1].mesg_location=oldloc;
  1244. if(reallocate_robot_mem(T_SCROLL,t1,newsize))
  1245. {
  1246. //Error in allocation.
  1247. fclose(fp);
  1248. //EMS- delete temp file
  1249. if(board_where[id]==W_EMS)
  1250. {
  1251. unlink(&board_filenames[id*FILENAME_SIZE]);
  1252. board_filenames[id*FILENAME_SIZE]=0;
  1253. }
  1254. return 4;
  1255. }
  1256. fread(&robot_mem[scrolls[t1].mesg_location],1,
  1257. scrolls[t1].mesg_size,fp);
  1258. }
  1259. }
  1260. //Sensor count
  1261. count=fgetc(fp);
  1262. if(count)
  1263. {
  1264. for(t1=1;t1<=count;t1++) //Read sensor t1
  1265. fread(&sensors[t1],sizeof(Sensor),1,fp);
  1266. }
  1267. //All loaded! Return if tempfile...
  1268. fclose(fp);
  1269. if(board_where[id]==W_TEMPFILE) return 0;
  1270. //...otherwise erase EMS file.
  1271. unlink(&board_filenames[id*FILENAME_SIZE]);
  1272. board_filenames[id*FILENAME_SIZE]=0;
  1273. return 0;
  1274. }
  1275. return 3;
  1276. }
  1277. //Loads OR saves board of given id to/from an already open file. Space
  1278. //must already be allocated and board_sizes, etc must be set properly.
  1279. //All read characters are xor'd with xor_with, although not if it is 0,
  1280. //to save time for the same result. Returns non-0 for misc. errors.
  1281. //Set loading to non-0 to load FROM file, 0 to save TO file.
  1282. char disk_board(unsigned char id,FILE *fp,char loading,
  1283. unsigned char xor_with)
  1284. {
  1285. unsigned int siz,cpg1,buffsize;
  1286. long copied=0,tmp;
  1287. char far *ptr;
  1288. FILE *destfp;
  1289. //Switch according to storage type.
  1290. switch(board_where[id])
  1291. {
  1292. case W_MEMORY:
  1293. //Simply do a fread then a mem_xor. Must be read in chunks in case
  1294. //size is larger than an unsigned int.
  1295. ptr=(char far *)board_offsets[id].mem;
  1296. do
  1297. {
  1298. siz=(unsigned int)(board_sizes[id]-copied);
  1299. if((board_sizes[id]-copied)>32768U) siz=32768U;
  1300. if(!loading)//If saving, must xor first, but later xor again
  1301. //to restore memory copy to normal.
  1302. if(xor_with) mem_xor(ptr,siz,xor_with);
  1303. if(loading) fread(ptr,siz,1,fp);//LOAD
  1304. else fwrite(ptr,siz,1,fp);//SAVE
  1305. if(xor_with) mem_xor(ptr,siz,xor_with);
  1306. copied+=siz;
  1307. ptr+=siz;
  1308. } while(copied<board_sizes[id]);
  1309. //Done!
  1310. return 0;
  1311. case W_EMS:
  1312. //Simply do a fread then a mem_xor. Read in chunks of one page.
  1313. cpg1=board_offsets[id].EMS.page;
  1314. do
  1315. {
  1316. map_page_EMS(board_offsets[id].EMS.handle,0,cpg1);
  1317. siz=(unsigned int)(board_sizes[id]-copied);
  1318. if((board_sizes[id]-copied)>16384) siz=16384;
  1319. if(!loading)//If saving, must xor first, but later xor again
  1320. //to restore memory copy to normal.
  1321. if(xor_with) mem_xor(page_frame_EMS,siz,xor_with);
  1322. if(loading) fread(page_frame_EMS,siz,1,fp);//LOAD
  1323. else fwrite(page_frame_EMS,siz,1,fp);//SAVE
  1324. if(xor_with) mem_xor(page_frame_EMS,siz,xor_with);
  1325. copied+=siz;
  1326. cpg1++;
  1327. } while(copied<board_sizes[id]);
  1328. //Done!
  1329. return 0;
  1330. case W_TEMPFILE:
  1331. //First, verify file can be opened...
  1332. destfp=fopen(&board_filenames[id*FILENAME_SIZE],"rb+");
  1333. if(destfp==NULL) return 1;
  1334. //This one is easier to program but slower. Allocates a buffer
  1335. //in conventional memory as large as possible (up to 32k) then
  1336. //buffers from fp to dest file, xor'ing if required. If buffer
  1337. //cannot be allocated, does it directly. (IE one byte at a time)
  1338. copied=farcoreleft();
  1339. if(copied>32768U) buffsize=32768U;
  1340. else buffsize=(unsigned int)copied;
  1341. if(buffsize>=128)
  1342. {
  1343. //Allocate buffer
  1344. ptr=(char far *)farmalloc(buffsize);
  1345. if(ptr==NULL) //Huh? Ok we'll do singles..
  1346. goto transfer_bytewise;
  1347. //Do transferring
  1348. copied=0;
  1349. do
  1350. {
  1351. //Pick size
  1352. siz=((unsigned int)(board_sizes[id]-copied));
  1353. if(board_sizes[id]>buffsize) siz=buffsize;
  1354. //Read
  1355. if(loading) fread(ptr,siz,1,fp);
  1356. else fread(ptr,siz,1,destfp);
  1357. //XOR
  1358. if(xor_with) mem_xor(ptr,siz,xor_with);
  1359. //Write
  1360. if(loading) fwrite(ptr,siz,1,destfp);
  1361. else fwrite(ptr,siz,1,fp);
  1362. //Update variables
  1363. copied+=siz;
  1364. } while(copied<board_sizes[id]);
  1365. //Done! Close file and deallocate buffer.
  1366. farfree(ptr);
  1367. fclose(destfp);
  1368. return 0;
  1369. }
  1370. transfer_bytewise:
  1371. //Couldn't allocate memory buffer. Do transfer byte by byte...
  1372. tmp=board_sizes[id];
  1373. if(xor_with)
  1374. {
  1375. for(;copied<tmp;copied++)
  1376. {//Read, XOR, and write
  1377. if(loading) fputc(fgetc(fp)^xor_with,destfp);
  1378. else fputc(fgetc(destfp)^xor_with,fp);
  1379. }
  1380. }
  1381. else
  1382. {
  1383. for(;copied<tmp;copied++)
  1384. {//Read, XOR, and write
  1385. if(loading) fputc(fgetc(fp),destfp);
  1386. else fputc(fgetc(destfp),fp);
  1387. }
  1388. }
  1389. //Done! Close file.
  1390. fclose(destfp);
  1391. return 0;
  1392. }
  1393. //Misc. error
  1394. return 2;
  1395. }
  1396. //Attempts to clear up conventional memory by moving all boards in
  1397. //conventional memory to either EMS or disk. If there is no more room on
  1398. //disk/EMS, then boards are no longer moved. Runs a meter.
  1399. void free_up_board_memory(void)
  1400. {
  1401. int t1,t2,nmb=0,nb_done=0;
  1402. unsigned char far *tmp_ptr;
  1403. unsigned char far *ptr;
  1404. long copied;
  1405. unsigned int tcpy;
  1406. char temp=curr_rmem_status;
  1407. FILE *fp;
  1408. //Count boards
  1409. for(t1=0;t1<NUM_BOARDS;t1++)
  1410. {
  1411. if(board_where[t1]==W_MEMORY) nmb++;
  1412. }
  1413. if(nmb==0) return;//None to swap!
  1414. save_screen(current_pg_seg);
  1415. meter("Swapping boards to disk/EMS...",current_pg_seg,nb_done,nmb);
  1416. //Go through the boards, picking out those in conventional memory...
  1417. for(t1=0;t1<NUM_BOARDS;t1++)
  1418. {
  1419. if(board_where[t1]==W_MEMORY)
  1420. {
  1421. //Ok, board #t1 is in conventional memory. Now we need to try to
  1422. //allocate a new area for it in anything BUT conventional memory.
  1423. //First, since the allocate function destroys the allocation
  1424. //variables, we need to save board_offset. (board_where is obvious
  1425. //and board_sizes/board_filenames are not affected)
  1426. tmp_ptr=board_offsets[t1].mem;
  1427. if(allocate_board_space(board_sizes[t1],t1,0))
  1428. {
  1429. //No room. Restore variables and return.
  1430. board_offsets[t1].mem=tmp_ptr;
  1431. board_where[t1]=W_MEMORY;
  1432. restore_screen(current_pg_seg);
  1433. return;
  1434. }
  1435. //Aha, new area allocated. Switch for EMS or disk.
  1436. switch(board_where[t1])
  1437. {
  1438. case W_EMS:
  1439. //Copy to EMS from tmp_ptr for board_sizes[t1] bytes.
  1440. //Copy a page at a time...
  1441. t2=board_offsets[t1].EMS.page;//Current page
  1442. copied=0;//Copied nothing so far.
  1443. ptr=tmp_ptr;//Use a copy of the ptr so we save it
  1444. do
  1445. {
  1446. //Map page
  1447. map_page_EMS(board_offsets[t1].EMS.handle,0,t2);
  1448. //Copy a page, or part of a page if that's all that's left.
  1449. tcpy=16384;
  1450. if((copied+tcpy)>board_sizes[t1]) //Too much...
  1451. tcpy=(int)(board_sizes[t1]-(unsigned long)copied);
  1452. //Now copy it...
  1453. mem_cpy(page_frame_EMS,(char far *)ptr,tcpy);
  1454. //...increment status...
  1455. copied+=tcpy;
  1456. ptr+=tcpy;
  1457. t2++;//Page
  1458. //...loop.
  1459. } while(copied<board_sizes[t1]);
  1460. //All copied! Free old memory for board and we're done.
  1461. farfree(tmp_ptr);
  1462. break;
  1463. case W_TEMPFILE:
  1464. //We're saving memory to a disk file. REAL simple.
  1465. fp=fopen(&board_filenames[t1*FILENAME_SIZE],"rb+");
  1466. if(fp==NULL)
  1467. {
  1468. //Not gonna work.
  1469. board_offsets[t1].mem=tmp_ptr;
  1470. board_where[t1]=W_MEMORY;
  1471. board_filenames[t1*FILENAME_SIZE]=0;
  1472. break;
  1473. }
  1474. //Do in chunks of 32768 bytes.
  1475. ptr=tmp_ptr;
  1476. copied=0;
  1477. do
  1478. {
  1479. tcpy=(unsigned int)board_sizes[t1];
  1480. if(board_sizes[t1]>32768U) tcpy=32768U;
  1481. fwrite(ptr,tcpy,1,fp);//SAVE
  1482. copied+=tcpy;
  1483. ptr+=tcpy;
  1484. } while(copied<board_sizes[t1]);
  1485. //Done. Close file and free memory.
  1486. fclose(fp);
  1487. farfree(tmp_ptr);
  1488. break;
  1489. default:
  1490. //Error.
  1491. restore_screen(current_pg_seg);
  1492. error("Error accessing boards",2,20,current_pg_seg,0x0701);
  1493. }
  1494. //All done with THIS board.
  1495. meter_interior(current_pg_seg,++nb_done,nmb);
  1496. }
  1497. //Loop to next board.
  1498. }
  1499. restore_screen(current_pg_seg);
  1500. //All done totally.
  1501. prepare_robot_mem(temp);
  1502. }
  1503. void convert_max_bsiz_mode(void)
  1504. {
  1505. switch(max_bsiz_mode)
  1506. {
  1507. case 0:
  1508. max_bxsiz=60;
  1509. max_bysiz=166;
  1510. break;
  1511. case 1:
  1512. max_bxsiz=80;
  1513. max_bysiz=125;
  1514. break;
  1515. default:
  1516. max_bxsiz=100;
  1517. max_bysiz=100;
  1518. break;
  1519. case 3:
  1520. max_bxsiz=200;
  1521. max_bysiz=50;
  1522. break;
  1523. case 4:
  1524. max_bxsiz=400;
  1525. max_bysiz=25;
  1526. break;
  1527. }
  1528. }