dungeon.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556
  1. /* =============================================================================
  2. * PROGRAM: ularn
  3. * FILENAME: dungeon.c
  4. *
  5. * DESCRIPTION:
  6. * Dungeon levels module.
  7. * This module provides functions to create, load, save etc dungeon levels.
  8. *
  9. * =============================================================================
  10. * EXPORTED VARIABLES
  11. *
  12. * item : The item at each location on the current level
  13. * know : What the player beleives is at each location
  14. * moved : The monster moved status for each dungeon location
  15. * stealth : The monster stealth status for each dungeon location
  16. * hitp : The monster hit points for each dungeon location
  17. * iarg : The item arg for each dungeon location
  18. * screen : Screen data used in moving monsters
  19. * mitem : The monster and items it has stolen for each dungeon location
  20. * beenhere : Which dungeon levels have been visited
  21. * level : The current dungeon level
  22. * levelname : The name of each dungeon level
  23. *
  24. * =============================================================================
  25. * EXPORTED FUNCTIONS
  26. *
  27. * init_cells : Allocate dungeon storage
  28. * free_cells : Free dungeon storage
  29. * cgood : Check if a cell is empty (monster and/or item)
  30. * dropgold : Drop gold around the player
  31. * fillmonst : Attempt to put a monster into the dungeon
  32. * eat : Eat a maze in a level filled with walls
  33. * savelevel : Save the current dungeon level into storage
  34. * getlevel : Get the current level from storage.
  35. * AnalyseWalls : Calculate wall tiles based on adjacent walls.
  36. * newcavelevel : Function to go to a different cave level, creating if reqd
  37. * verifyxy : Verify x and y coordinates are on the map, adjusting if reqd
  38. * createitem : Create an item
  39. * something : Create a random item
  40. * newobject : Return a randomly selected item
  41. * write_levels : Write dungeon levels to the save file
  42. * read_levels : Read dungeon levels from the save file
  43. *
  44. * =============================================================================
  45. */
  46. #include <stdio.h>
  47. #include "dungeon.h"
  48. #include "header.h"
  49. #include "itm.h"
  50. #include "monster.h"
  51. #include "player.h"
  52. #include "potion.h"
  53. #include "saveutils.h"
  54. #include "scores.h"
  55. #include "scroll.h"
  56. #include "ularn_game.h"
  57. #include "ularn_win.h"
  58. /* =============================================================================
  59. * Exported variables
  60. */
  61. char item[MAXX][MAXY]; /* objects in maze if any */
  62. char know[MAXX][MAXY]; /* 1 or 0 if here before */
  63. char moved[MAXX][MAXY]; /* monster movement flags */
  64. char stealth[MAXX][MAXY]; /* See Stealth flags */
  65. short hitp[MAXX][MAXY]; /* monster hp on level */
  66. short iarg[MAXX][MAXY]; /* arg for the item array */
  67. short screen[MAXX][MAXY]; /* The screen as the player knows it */
  68. struct_mitem mitem[MAXX][MAXY]; /* Items stolen by monstes array */
  69. char beenhere[NLEVELS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  70. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  71. int level = 0; /* cavelevel player is on = c[CAVELEVEL]*/
  72. char *levelname[] = {" H", " 1", " 2", " 3", " 4", " 5", " 6",
  73. " 7", " 8", " 9", "10", "11", "12", "13",
  74. "14", "15", "V1", "V2", "V3", "V4", "V5"};
  75. /* =============================================================================
  76. * Local variables
  77. */
  78. /*
  79. * Data and macros for finding the number of +s for items.
  80. */
  81. #define NUM_LEATHER_PTS 15
  82. #define NUM_H_LEATHER_PTS 12
  83. static char nlpts[NUM_LEATHER_PTS] = {0, 0, 0, 0, 0, 1, 1, 2,
  84. 2, 3, 3, 4, 5, 6, 7};
  85. #define NUM_CHAIN_PTS 10
  86. static char nch[NUM_CHAIN_PTS] = {0, 0, 0, 1, 1, 1, 2, 2, 3, 4};
  87. #define NUM_PLATE_PTS 10
  88. #define NUM_H_PLATE_PTS 3
  89. static char nplt[NUM_PLATE_PTS] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 4};
  90. #define NUM_DAGGER_PTS 13
  91. static char ndgg[NUM_DAGGER_PTS] = {0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5};
  92. #define NUM_SWORD_PTS 13
  93. #define NUM_H_SWORD_PTS 6
  94. static char nsw[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3};
  95. /* return the + points on created leather armor */
  96. #define newleather() \
  97. (nlpts[rund(c[HARDGAME] ? (NUM_H_LEATHER_PTS) : (NUM_LEATHER_PTS))])
  98. /* return the + points on chain armor */
  99. #define newchain() (nch[rund(NUM_CHAIN_PTS)])
  100. /* return + points on plate armor */
  101. #define newplate() \
  102. (nplt[rund(c[HARDGAME] ? (NUM_H_PLATE_PTS) : (NUM_PLATE_PTS))])
  103. /* return + points on new daggers */
  104. #define newdagger() (ndgg[rund(NUM_DAGGER_PTS)])
  105. /* return + points on new swords */
  106. #define newsword() \
  107. (nsw[rund(c[HARDGAME] ? (NUM_H_SWORD_PTS) : (NUM_SWORD_PTS))])
  108. typedef char Char_Ary[MAXX][MAXY];
  109. typedef short Short_Ary[MAXX][MAXY];
  110. typedef long Long_Ary[MAXX][MAXY];
  111. typedef struct_mitem Mitem_Ary[MAXX][MAXY];
  112. /* this is the structure that holds the entire dungeon specifications */
  113. typedef struct save_lev_str {
  114. Short_Ary hitp;
  115. Mitem_Ary mitem;
  116. Char_Ary item;
  117. Short_Ary iarg; /* must be long for goldpiles */
  118. Char_Ary know;
  119. } Saved_Level;
  120. static Saved_Level *saved_levels[NLEVELS] = {
  121. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  122. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  123. static unsigned int level_sums[NLEVELS];
  124. /* =============================================================================
  125. * Local functions
  126. */
  127. /* =============================================================================
  128. * FUNCTION: cannedlevel
  129. *
  130. * DESCRIPTION:
  131. * Function to read in a maze from a data file
  132. *
  133. * Only read in a maze 50% of time.
  134. *
  135. * Format of maze data file:
  136. * Must contain 21 mazes
  137. * For each maze:
  138. * 18 lines (1st 17 used)
  139. * 67 characters per line
  140. *
  141. * Line seperating maps must be single newline character
  142. *
  143. * Special characters in maze data file:
  144. *
  145. * # wall D door
  146. * . random monster ~ eye of larn
  147. * ! cure dianthroritis - random object
  148. *
  149. * PARAMETERS:
  150. *
  151. * lev : The dungeon level being read.
  152. *
  153. * RETURN VALUE:
  154. *
  155. * 1 for success
  156. * -1 for error/use random maze
  157. */
  158. static int cannedlevel(int lev) {
  159. int i, j, k;
  160. int it, arg, marg;
  161. FILE *fp;
  162. char *row, buf[128];
  163. MonsterIdType Monst;
  164. if ((lev != DBOTTOM) && (lev != VBOTTOM))
  165. /*
  166. * The bottom levels are always read from the file.
  167. * Only read a maze from file around half the time for regular levels.
  168. */
  169. if (rnd(100) < 50)
  170. return -1;
  171. fp = fopen(larnlevels, "r");
  172. if (fp == (FILE *)NULL)
  173. return -1;
  174. /*
  175. * Umap format
  176. * - lines must be MAXX characters long
  177. * - must be MAXY characters per map
  178. * - each map must be seperated by 1 blank line
  179. * (a single newline character)
  180. */
  181. /*
  182. * Decide which map to use and move to the location of the map in the
  183. * levels file.
  184. * A direct seek is a little non-portable as different operating systems
  185. * use different EOL (CR/LF vs CR or LF).
  186. * Also, be a bit more forgiving of white space after the map line.
  187. */
  188. i = rund(20);
  189. for (j = 0; j < i; j++) {
  190. /*
  191. ** Skip a level + the blank line
  192. */
  193. for (k = 0; k < (MAXY + 1); k++) {
  194. row = fgets(buf, 128, fp);
  195. if (row == (char *)NULL) {
  196. perror("fgets");
  197. fclose(fp);
  198. return -1;
  199. }
  200. }
  201. }
  202. /*
  203. * Read the level from the file
  204. */
  205. for (i = 0; i < MAXY; i++) {
  206. row = fgets(buf, 128, fp);
  207. if (row == (char *)NULL) {
  208. perror("fgets");
  209. fclose(fp);
  210. return -1;
  211. }
  212. for (j = 0; j < MAXX; j++) {
  213. it = ONOTHING;
  214. Monst = MONST_NONE;
  215. arg = 0;
  216. marg = 0;
  217. switch (*row++) {
  218. case '#':
  219. it = OWALL;
  220. break;
  221. case 'D':
  222. it = OCLOSEDDOOR;
  223. arg = rnd(30);
  224. break;
  225. case '~':
  226. if (lev != DBOTTOM)
  227. break;
  228. it = OLARNEYE;
  229. Monst = DEMONPRINCE;
  230. marg = monster[Monst].hitpoints;
  231. break;
  232. case '!':
  233. if (lev != VBOTTOM)
  234. break;
  235. it = OPOTION;
  236. arg = 21;
  237. Monst = LUCIFER;
  238. marg = monster[Monst].hitpoints;
  239. break;
  240. case '.':
  241. if (lev <= DBOTTOM - 5)
  242. break;
  243. Monst = makemonst(lev + 1);
  244. marg = monster[Monst].hitpoints;
  245. break;
  246. case '-':
  247. it = newobject(lev + 1, &arg);
  248. break;
  249. }
  250. item[j][i] = (char)it;
  251. iarg[j][i] = (short)arg;
  252. mitem[j][i].mon = (char)Monst;
  253. hitp[j][i] = (short)marg;
  254. know[j][i] = (char)((wizard) ? item[j][i] : OUNKNOWN);
  255. }
  256. }
  257. fclose(fp);
  258. return 1;
  259. }
  260. /* =============================================================================
  261. * FUNCTION: troom
  262. *
  263. * DESCRIPTION:
  264. * Function to create a treasure room of any size at a given location.
  265. * The room is filled with objects and monsters
  266. * The coordinate given is that of the upper left corner of the room.
  267. *
  268. * PARAMETERS:
  269. *
  270. * lv : The dungeon level for the treasure room
  271. *
  272. * xsize : The x size of the room
  273. *
  274. * ysize : The y size of the room
  275. *
  276. * tx : The Leftmost x position of the room
  277. *
  278. * ty : The Topmost y position og the room
  279. *
  280. * glyph : The door object to use.
  281. *
  282. * RETURN VALUE:
  283. *
  284. * None.
  285. */
  286. static void troom(int lv, int xsize, int ysize, int tx, int ty, int glyph) {
  287. int i, j;
  288. int bupx, bupy;
  289. /* clear out space for room */
  290. for (j = (ty - 1); j <= (ty + ysize); j++)
  291. for (i = (tx - 1); i <= (tx + xsize); i++)
  292. item[i][j] = ONOTHING;
  293. /* now put in the walls */
  294. for (j = ty; j < (ty + ysize); j++) {
  295. for (i = tx; i < (tx + xsize); i++) {
  296. item[i][j] = OWALL;
  297. mitem[i][j].mon = MONST_NONE;
  298. }
  299. }
  300. /* now clear out interior */
  301. for (j = (ty + 1); j < (ty + ysize - 1); j++)
  302. for (i = (tx + 1); i < (tx + xsize - 1); i++)
  303. item[i][j] = ONOTHING;
  304. /* locate the door on the treasure room */
  305. switch (rnd(2)) {
  306. case 1:
  307. i = tx + rund(xsize);
  308. j = ty + (ysize - 1) * rund(2);
  309. item[i][j] = OCLOSEDDOOR;
  310. iarg[i][j] = (short)glyph; /* on horizontal walls */
  311. break;
  312. case 2:
  313. i = tx + (xsize - 1) * rund(2);
  314. j = ty + rund(ysize);
  315. item[i][j] = OCLOSEDDOOR;
  316. iarg[i][j] = (short)glyph; /* on vertical walls */
  317. break;
  318. }
  319. /*
  320. * must save and use playerx, playery because that's what
  321. * createmonster() uses
  322. */
  323. bupx = playerx;
  324. bupy = playery;
  325. playery = (char)(ty + (ysize >> 1));
  326. if (c[HARDGAME] < 3) {
  327. for (playerx = (char)(tx + 1); playerx <= (char)(tx + xsize - 2);
  328. playerx += (char)2) {
  329. j = rnd(6);
  330. for (i = 0; i <= j; i++) {
  331. something(playerx, playery, lv + 2);
  332. createmonster(makemonst(lv + 2));
  333. }
  334. }
  335. } else {
  336. for (playerx = (char)(tx + 1); playerx <= (char)(tx + xsize - 2);
  337. playerx += (char)2) {
  338. j = rnd(4);
  339. for (i = 0; i <= j; i++) {
  340. something(playerx, playery, lv + 2);
  341. createmonster(makemonst(lv + 4));
  342. }
  343. }
  344. }
  345. playerx = bupx;
  346. playery = bupy;
  347. }
  348. /* =============================================================================
  349. * FUNCTION: treasureroom
  350. *
  351. * DESCRIPTION:
  352. * Make a treasure room on a level
  353. * - level 10's treasure room has the eye in it and demon lords
  354. * - level V5 has potion of cure dianthroritis and demon prince
  355. *
  356. * PARAMETERS:
  357. *
  358. * lv : The dungeon level containing the room
  359. *
  360. * RETURN VALUE:
  361. *
  362. * None.
  363. */
  364. static void treasureroom(int lv) {
  365. int tx, ty, xsize, ysize;
  366. for (tx = 1 + rnd(10); tx < MAXX - 10; tx += 10) {
  367. if ((lv == DBOTTOM) || (lv == VBOTTOM) || (rnd(10) <= 2)) {
  368. /* 20% chance */
  369. xsize = rnd(6) + 3;
  370. ysize = rnd(3) + 3;
  371. ty = rnd(MAXY - 9) + 1; /* upper left corner of room */
  372. if ((lv == DBOTTOM) || (lv == VBOTTOM))
  373. troom(lv, xsize, ysize, (tx = tx + rnd(MAXX - 24)), ty, rnd(3) + 6);
  374. else
  375. troom(lv, xsize, ysize, tx, ty, rnd(9));
  376. }
  377. }
  378. }
  379. /* =============================================================================
  380. * FUNCTION: fillroom
  381. *
  382. * DESCRIPTION:
  383. * Function to put an object into an empty room.
  384. * Uses a random walk to find an empty room.
  385. *
  386. * PARAMETERS:
  387. *
  388. * what : The item to create
  389. *
  390. * arg : The item's argument.
  391. *
  392. * RETURN VALUE:
  393. *
  394. * None.
  395. */
  396. static void fillroom(int what, int arg) {
  397. int x, y;
  398. x = rnd(MAXX - 2);
  399. y = rnd(MAXY - 2);
  400. while (item[x][y] != ONOTHING) {
  401. x += rnd(3) - 2;
  402. y += rnd(3) - 2;
  403. if (x > MAXX - 2)
  404. x = 1;
  405. if (x < 1)
  406. x = MAXX - 2;
  407. if (y > MAXY - 2)
  408. y = 1;
  409. if (y < 1)
  410. y = MAXY - 2;
  411. }
  412. item[x][y] = (char)what;
  413. iarg[x][y] = (short)arg;
  414. }
  415. /* =============================================================================
  416. * FUNCTION: fillmroom
  417. *
  418. * DESCRIPTION:
  419. * Function to fill in a number of objects of the same kind
  420. *
  421. * PARAMETERS:
  422. *
  423. * n : The number of items to fill
  424. *
  425. * what : The type of item
  426. *
  427. * arg : The item argument
  428. *
  429. * RETURN VALUE:
  430. *
  431. * None.
  432. */
  433. static void fillmroom(int n, int what, int arg) {
  434. int i;
  435. for (i = 0; i < n; i++)
  436. fillroom(what, arg);
  437. }
  438. /* =============================================================================
  439. * FUNCTION: froom
  440. *
  441. * DESCRIPTION:
  442. * Fill a room with an item with a certain probability.
  443. *
  444. * PARAMETERS:
  445. *
  446. * n : The chance in 151 of the item being created
  447. *
  448. * itm : The item to be filled
  449. *
  450. * arg : The item argument.
  451. *
  452. * RETURN VALUE:
  453. *
  454. * None.
  455. */
  456. static void froom(int n, int itm, int arg) {
  457. if (rnd(151) < n)
  458. fillroom(itm, arg);
  459. }
  460. /*
  461. * Data for the creation of unique items in the game.
  462. */
  463. #define UNIQUE_1_COUNT 10
  464. #define UNIQUE_COUNT 16
  465. /*
  466. * A list of unique items in the game
  467. * The items in the set from which only one can be created per dungeon level
  468. * must be specified first.
  469. */
  470. static int UniqueItem[UNIQUE_COUNT] = {
  471. OBRASSLAMP, OWWAND, OORBOFDRAGON, OSPIRITSCARAB,
  472. OCUBEofUNDEAD, ONOTHEFT, OSPHTALISMAN, OHANDofFEAR,
  473. OORB, OELVENCHAIN, OSWORDofSLASHING, OHAMMER,
  474. OSLAYER, OVORPAL, OPSTAFF, OLIFEPRESERVER};
  475. /* The character flags associated with the creation of each unique item */
  476. static AttributeType UniqueFlag[UNIQUE_COUNT] = {
  477. LAMP, WAND, DRAGSLAY, NEGATE, CUBEUNDEAD, DEVICE,
  478. TALISMAN, HAND, ORB, ELVEN, SLASH, BESSMANN,
  479. SLAY, VORPAL, STAFF, LIFE_PRESERVER};
  480. /* The minimum dungeon level for this item to occur */
  481. static int UniqueMinLevel[UNIQUE_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0,
  482. 0, 0, 0, 0, 10, 0, 8, 5};
  483. /* The die to roll for determining if this item is created */
  484. static int UniqueRoll[UNIQUE_COUNT] = {120, 120, 120, 120, 120, 120, 120, 120,
  485. 120, 120, 120, 120, 100, 120, 100, 100};
  486. /* The max roll for item creation */
  487. static int UniqueProb[UNIQUE_COUNT] = {8, 8, 8, 8, 8, 8, 8, 8,
  488. 8, 8, 8, 8, 15, 8, 15, 15};
  489. /* The increase in probability for each level in the dungeon above the minimum
  490. * required for the item
  491. */
  492. static int UniqueProbLevelMod[UNIQUE_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0,
  493. 0, 0, 0, 0, 1, 0, 1, 0};
  494. /* =============================================================================
  495. * FUNCTION: makeobject
  496. *
  497. * DESCRIPTION:
  498. * Create the objects in a dungeon level.
  499. *
  500. * PARAMETERS:
  501. *
  502. * j : The dungeon level.
  503. *
  504. * RETURN VALUE:
  505. *
  506. * None.
  507. */
  508. static void makeobject(int j) {
  509. int i;
  510. int MadeUnique;
  511. int Flag;
  512. int Item;
  513. int Idx;
  514. int Prob;
  515. if (j == 0) {
  516. /* The town level */
  517. fillroom(OENTRANCE, 0); /* entrance to dungeon*/
  518. fillroom(ODNDSTORE, 0); /* the DND STORE */
  519. fillroom(OSCHOOL, 0); /* college of Larn */
  520. fillroom(OBANK, 0); /* 1st national bank of larn*/
  521. fillroom(OVOLDOWN, 0); /* volcano shaft to temple*/
  522. fillroom(OHOME, 0); /* the players home & family*/
  523. fillroom(OTRADEPOST, 0); /* the trading post */
  524. fillroom(OLRS, 0); /* the larn revenue service */
  525. return;
  526. }
  527. if (j == DBOTTOM + 1) { /* V1 */
  528. fillroom(OVOLUP, 0); /* volcano shaft up from the temple */
  529. }
  530. /* make the fixed object in the maze STAIRS and
  531. random object ELEVATORS */
  532. /* stairs down only on V1 and V2 */
  533. if ((j > 0) && (j != DBOTTOM) && (j < VBOTTOM - 2))
  534. fillroom(OSTAIRSDOWN, 0);
  535. if ((j > 1) && (j != DBOTTOM))
  536. fillroom(OSTAIRSUP, 0);
  537. /* > 3, not on V1 or V5 or 15 */
  538. if ((j > 3) && (j != DBOTTOM + 1) && (j != VBOTTOM) && (j != DBOTTOM)) {
  539. if (c[ELVUP] == 0) {
  540. if (rnd(100) > 85) {
  541. fillroom(OELEVATORUP, 0);
  542. c[ELVUP]++;
  543. }
  544. }
  545. }
  546. /* < lev 10, or 15 or V5 */
  547. if ((j > 0) && (j <= DBOTTOM - 5 || j == DBOTTOM || j == VBOTTOM)) {
  548. if (c[ELVDOWN] == 0) {
  549. if (rnd(100) > 85) {
  550. fillroom(OELEVATORDOWN, 0);
  551. c[ELVDOWN]++;
  552. }
  553. }
  554. }
  555. /* make the random objects in the maze */
  556. fillmroom(rund(3), OBOOK, j);
  557. fillmroom(rund(3), OCOOKIE, 0);
  558. fillmroom(rund(3), OALTAR, 0);
  559. fillmroom(rund(3), OSTATUE, 0);
  560. fillmroom(rund(3), OFOUNTAIN, 0);
  561. fillmroom(rund(2), OTHRONE, 0);
  562. fillmroom(rund(2), OMIRROR, 0);
  563. /* be sure to have pits on V3, V4, and V5 */
  564. /* because there are no stairs on those levels */
  565. if (j >= VBOTTOM - 2)
  566. fillroom(OPIT, 0);
  567. fillmroom(rund(3), OPIT, 0);
  568. /* be sure to have trapdoors on V3, V4, and V5 */
  569. if (j >= VBOTTOM - 2)
  570. fillroom(OIVTRAPDOOR, 0);
  571. fillmroom(rund(2), OIVTRAPDOOR, 0);
  572. fillmroom(rund(2), OTRAPARROWIV, 0);
  573. fillmroom(rnd(3) - 2, OIVTELETRAP, 0);
  574. fillmroom(rnd(3) - 2, OIVDARTRAP, 0);
  575. if (j == 1)
  576. fillmroom(1, OCHEST, j);
  577. else
  578. fillmroom(rund(2), OCHEST, j);
  579. if (j <= DBOTTOM) {
  580. fillmroom(rund(2), ODIAMOND, rnd(10 * j + 1) + 10);
  581. fillmroom(rund(2), ORUBY, rnd(6 * j + 1) + 6);
  582. fillmroom(rund(2), OEMERALD, rnd(4 * j + 1) + 4);
  583. fillmroom(rund(2), OSAPPHIRE, rnd(3 * j + 1) + 2);
  584. }
  585. Prob = rnd(4) + 3;
  586. for (i = 0; i < Prob; i++) {
  587. fillroom(OPOTION, newpotion()); /* make a POTION */
  588. }
  589. Prob = rnd(5) + 3;
  590. for (i = 0; i < Prob; i++) {
  591. fillroom(OSCROLL, newscroll()); /* make a SCROLL */
  592. }
  593. Prob = rnd(12) + 11;
  594. for (i = 0; i < Prob; i++) {
  595. fillroom(OGOLDPILE, 12 * rnd(j + 1) + (j << 3) + 10); /* make GOLD */
  596. }
  597. if (j == 8) {
  598. fillroom(OBANK2, 0); /* branch office of the bank */
  599. }
  600. if ((c[PAD] == 0) && (j >= 4)) {
  601. if (rnd(100) > 75)
  602. // fillroom(OPAD, 0); /* Dealer McDope's Pad */
  603. c[PAD]++;
  604. }
  605. froom(2, ORING, 0); /* a ring mail */
  606. froom(1, OSTUDLEATHER, 0); /* a studded leather */
  607. froom(3, OSPLINT, 0); /* a splint mail*/
  608. froom(5, OSHIELD, rund(3)); /* a shield */
  609. froom(2, OBATTLEAXE, rund(3)); /* a battle axe */
  610. froom(5, OLONGSWORD, rund(3)); /* a long sword */
  611. froom(5, OFLAIL, rund(3)); /* a flail */
  612. froom(7, OSPEAR, rnd(5)); /* a spear */
  613. froom(4, OREGENRING, rund(3)); /* ring of regeneration */
  614. froom(1, OPROTRING, rund(3)); /* ring of protection */
  615. froom(2, OSTRRING, rund(5)); /* ring of strength */
  616. froom(2, ORINGOFEXTRA, 0); /* ring of extra regen */
  617. /*
  618. ** Unique items.
  619. ** Only one of the following items can be created on a level.
  620. */
  621. /*
  622. ** Check if this level contains an item from the 1 of per level set
  623. */
  624. MadeUnique = 0;
  625. for (Idx = 0; Idx < UNIQUE_1_COUNT && !MadeUnique; Idx++) {
  626. Flag = UniqueFlag[Idx];
  627. Item = UniqueItem[Idx];
  628. if (c[Flag] == 0) {
  629. if (j >= UniqueMinLevel[Idx]) {
  630. Prob = UniqueProb[Idx] +
  631. UniqueProbLevelMod[Idx] * (j - UniqueMinLevel[Idx]);
  632. if (rnd(UniqueRoll[Idx]) < Prob) {
  633. fillroom(Item, 0);
  634. c[Flag]++;
  635. MadeUnique = 1;
  636. }
  637. }
  638. }
  639. }
  640. /*
  641. ** Check for creation of other unique items
  642. */
  643. for (Idx = UNIQUE_1_COUNT; Idx < UNIQUE_COUNT; Idx++) {
  644. Flag = UniqueFlag[Idx];
  645. Item = UniqueItem[Idx];
  646. if (c[Flag] == 0) {
  647. if (j >= UniqueMinLevel[Idx]) {
  648. Prob = UniqueProb[Idx] +
  649. UniqueProbLevelMod[Idx] * (j - UniqueMinLevel[Idx]);
  650. if (rnd(UniqueRoll[Idx]) < Prob) {
  651. fillroom(Item, 0);
  652. c[Flag]++;
  653. }
  654. }
  655. }
  656. }
  657. /*
  658. ** we don't get these if the difficulty level
  659. ** is >= 3
  660. */
  661. if (c[HARDGAME] < 3 || (rnd(4) == 3)) {
  662. if (j > 3) {
  663. /* only on levels 3 or below */
  664. froom(3, OSWORD, rund(6)); /* sunsword */
  665. froom(5, O2SWORD, rnd(6)); /* a two handed sword */
  666. froom(3, OBELT, rund(7)); /* belt of striking */
  667. froom(3, OENERGYRING, rund(6)); /* energy ring */
  668. froom(4, OPLATE, rund(8)); /* platemail */
  669. }
  670. }
  671. }
  672. /* =============================================================================
  673. * FUNCTION: sethp
  674. *
  675. * DESCRIPTION:
  676. * Creates an entire set of monsters for a level.
  677. * Must be done when entering a new level.
  678. *
  679. * PARAMETERS:
  680. *
  681. * flg : true if this is the first time on this level
  682. * false if this is a revisit to the level,.
  683. *
  684. * RETURN VALUE:
  685. *
  686. * None.
  687. */
  688. static void sethp(int flg) {
  689. int i, j;
  690. if (flg) {
  691. /* All initial monsters are unseen and asleep */
  692. for (i = 0; i < MAXY; i++)
  693. for (j = 0; j < MAXX; j++)
  694. stealth[j][i] = 0;
  695. }
  696. if (level == 0)
  697. /* Don't spawn extra onsters on the home level */
  698. return;
  699. if (flg)
  700. /* Get the initial numb er of monsters for this level */
  701. j = rnd(12) + 2 + (level >> 1);
  702. else
  703. /* Calculate the number of new monsters to create on revisit */
  704. j = (level >> 1) + 1;
  705. for (i = 0; i < j; i++)
  706. fillmonst(makemonst(level));
  707. if (flg) {
  708. /*
  709. * Only spawn demonlords on first visit to a level otherwise things can
  710. * get out of hand rather rapidly.
  711. */
  712. /*
  713. * level 11 gets 1 demon lord
  714. * level 12 gets 2 demon lords
  715. * level 13 gets 3 demon lords
  716. * level 14 gets 4 demon lords
  717. * level 15 gets 5 demon lords
  718. */
  719. if ((level >= (DBOTTOM - 4)) && (level <= DBOTTOM)) {
  720. i = level - 10;
  721. for (j = 1; j <= i; j++)
  722. while (fillmonst(DEMONLORD + rund(7)) == -1)
  723. ;
  724. }
  725. /*
  726. * level V1 gets 1 demon prince
  727. * level V2 gets 2 demon princes
  728. * level V3 gets 3 demon princes
  729. * level V4 gets 4 demon princes
  730. * level V5 gets 5 demon princes
  731. */
  732. if (level > DBOTTOM) {
  733. i = level - DBOTTOM;
  734. for (j = 1; j <= i; j++)
  735. /* Keep trying until the demon prince has been placed */
  736. while (fillmonst(DEMONPRINCE) == -1)
  737. ;
  738. }
  739. }
  740. }
  741. /* =============================================================================
  742. * FUNCTION: checkgen
  743. *
  744. * DESCRIPTION:
  745. * Function to destroy all genocided monsters on the present level.
  746. *
  747. * PARAMETERS:
  748. *
  749. * None.
  750. *
  751. * RETURN VALUE:
  752. *
  753. * None.
  754. */
  755. static void checkgen(void) {
  756. int x, y;
  757. for (y = 0; y < MAXY; y++) {
  758. for (x = 0; x < MAXX; x++) {
  759. if ((monster[(int)mitem[x][y].mon].flags & FL_GENOCIDED) != 0) {
  760. mitem[x][y].mon = 0; /* no more monster */
  761. }
  762. }
  763. }
  764. }
  765. /* =============================================================================
  766. * FUNCTION: makemaze
  767. *
  768. * DESCRIPTION:
  769. * Function to make the caverns for a given level.
  770. * Only walls are made (except for canned levels).
  771. *
  772. * PARAMETERS:
  773. *
  774. * lev : The dungeon level to be made.
  775. *
  776. * RETURN VALUE:
  777. *
  778. * None.
  779. */
  780. static void makemaze(int lev) {
  781. int mx, mxl, mxh;
  782. int my, myl, myh;
  783. int tmp2;
  784. int i, j;
  785. int tmp;
  786. MonsterIdType Monst;
  787. if (lev > 0) {
  788. /* read maze from data file */
  789. if (cannedlevel(lev) == 1)
  790. return;
  791. }
  792. if (lev == 0)
  793. tmp = ONOTHING;
  794. else
  795. tmp = OWALL;
  796. /* fill up maze */
  797. for (i = 0; i < MAXY; i++)
  798. for (j = 0; j < MAXX; j++)
  799. item[j][i] = (char)tmp;
  800. /* don't need to do anymore for level 0 */
  801. if (lev == 0)
  802. return;
  803. eat(1, 1);
  804. /* now for open spaces -- not on level 15 or V5 */
  805. if ((lev != DBOTTOM) && (lev != VBOTTOM)) {
  806. tmp2 = rnd(3) + 3;
  807. for (tmp = 0; tmp < tmp2; tmp++) {
  808. my = rnd(11) + 2;
  809. myl = my - rnd(2);
  810. myh = my + rnd(2);
  811. if (lev <= DBOTTOM) {
  812. /* in dungeon */
  813. mx = rnd(44) + 5;
  814. mxl = mx - rnd(4);
  815. mxh = mx + rnd(12) + 3;
  816. Monst = 0;
  817. } else {
  818. /* in volcano */
  819. mx = rnd(60) + 3;
  820. mxl = mx - rnd(2);
  821. mxh = mx + rnd(2);
  822. Monst = makemonst(lev);
  823. }
  824. for (i = mxl; i < mxh; i++) {
  825. for (j = myl; j < myh; j++) {
  826. item[i][j] = ONOTHING;
  827. if (Monst != MONST_NONE) {
  828. mitem[i][j].mon = (char)Monst;
  829. hitp[i][j] = monster[Monst].hitpoints;
  830. }
  831. }
  832. }
  833. }
  834. }
  835. if (lev != DBOTTOM && lev != VBOTTOM) {
  836. my = rnd(MAXY - 2);
  837. for (i = 1; i < MAXX - 1; i++)
  838. item[i][my] = ONOTHING;
  839. }
  840. /* no treasure rooms above level 5 */
  841. if (lev > 4)
  842. treasureroom(lev);
  843. }
  844. /* =============================================================================
  845. * Exported functions
  846. */
  847. /* =============================================================================
  848. * FUNCTION: init_cells
  849. */
  850. void init_cells(void) {
  851. int i;
  852. for (i = 0; i < NLEVELS; i++) {
  853. if ((saved_levels[i] = (Saved_Level *)malloc(sizeof(Saved_Level))) ==
  854. (Saved_Level *)NULL)
  855. died(DIED_MALLOC_FAILURE, 0);
  856. }
  857. }
  858. /* =============================================================================
  859. * FUNCTION: free_cells
  860. */
  861. void free_cells(void) {
  862. int i;
  863. for (i = 0; i < NLEVELS; i++)
  864. if (saved_levels[i] != (Saved_Level *)NULL)
  865. free(saved_levels[i]);
  866. }
  867. /* =============================================================================
  868. * FUNCTION: cgood
  869. */
  870. int cgood(int x, int y, int chkitm, int chkmonst) {
  871. int good = 0;
  872. if ((y >= 0) && (y <= MAXY - 1) && (x >= 0) &&
  873. (x <= MAXX - 1)) { /* within bounds? */
  874. if ((level == 1) && (x == 33) && (y == MAXY - 1))
  875. /* exit to level 1 is never good */
  876. return 0;
  877. if ((item[x][y] == OWALL) || (item[x][y] == OCLOSEDDOOR))
  878. /* can't make on walls or closed doors */
  879. return 0;
  880. /* Location is OK so far */
  881. good = 1;
  882. if (chkitm && (item[x][y] != ONOTHING))
  883. /* checking items and it is not free of items */
  884. good = 0;
  885. if (chkmonst && (mitem[x][y].mon != MONST_NONE))
  886. /* checking for monsters and not free of monsters */
  887. good = 0;
  888. }
  889. return good;
  890. }
  891. /* =============================================================================
  892. * FUNCTION: dropgold
  893. */
  894. void dropgold(int amount) {
  895. if (amount > 250)
  896. createitem(playerx, playery, OMAXGOLD, (long)amount);
  897. else
  898. createitem(playerx, playery, OGOLDPILE, (long)amount);
  899. }
  900. /* =============================================================================
  901. * FUNCTION: fillmonst
  902. */
  903. int fillmonst(int what) {
  904. int x, y, trys;
  905. /* max # of creation attempts */
  906. for (trys = 10; trys > 0; --trys) {
  907. x = rnd(MAXX - 2);
  908. y = rnd(MAXY - 2);
  909. if ((item[x][y] == ONOTHING) && (mitem[x][y].mon == MONST_NONE) &&
  910. ((playerx != x) || (playery != y))) {
  911. mitem[x][y].mon = (char)what;
  912. stealth[x][y] = 0;
  913. hitp[x][y] = monster[what].hitpoints;
  914. return 0;
  915. }
  916. }
  917. return -1; /* creation failure */
  918. }
  919. /* =============================================================================
  920. * FUNCTION: eat
  921. */
  922. void eat(int xx, int yy) {
  923. int dir;
  924. int attempt;
  925. dir = rnd(4);
  926. attempt = 2;
  927. while (attempt) {
  928. switch (dir) {
  929. case 1:
  930. if (xx <= 2)
  931. break; /* west */
  932. if ((item[xx - 1][yy] != OWALL) || (item[xx - 2][yy] != OWALL))
  933. break;
  934. item[xx - 1][yy] = ONOTHING;
  935. item[xx - 2][yy] = ONOTHING;
  936. eat(xx - 2, yy);
  937. break;
  938. case 2:
  939. if (xx >= MAXX - 3)
  940. break; /* east */
  941. if ((item[xx + 1][yy] != OWALL) || (item[xx + 2][yy] != OWALL))
  942. break;
  943. item[xx + 1][yy] = ONOTHING;
  944. item[xx + 2][yy] = ONOTHING;
  945. eat(xx + 2, yy);
  946. break;
  947. case 3:
  948. if (yy <= 2)
  949. break; /* south */
  950. if ((item[xx][yy - 1] != OWALL) || (item[xx][yy - 2] != OWALL))
  951. break;
  952. item[xx][yy - 1] = ONOTHING;
  953. item[xx][yy - 2] = ONOTHING;
  954. eat(xx, yy - 2);
  955. break;
  956. case 4:
  957. if (yy >= MAXY - 3)
  958. break; /*north */
  959. if ((item[xx][yy + 1] != OWALL) || (item[xx][yy + 2] != OWALL))
  960. break;
  961. item[xx][yy + 1] = ONOTHING;
  962. item[xx][yy + 2] = ONOTHING;
  963. eat(xx, yy + 2);
  964. break;
  965. }
  966. if (++dir > 4) {
  967. dir = 1;
  968. --attempt;
  969. }
  970. }
  971. }
  972. /* =============================================================================
  973. * FUNCTION: savelevel
  974. */
  975. void savelevel(void) {
  976. Saved_Level *storage = saved_levels[level];
  977. memcpy((char *)storage->hitp, (char *)hitp, sizeof(Short_Ary));
  978. memcpy((char *)storage->mitem, (char *)mitem, sizeof(Mitem_Ary));
  979. memcpy((char *)storage->item, (char *)item, sizeof(Char_Ary));
  980. memcpy((char *)storage->iarg, (char *)iarg, sizeof(Short_Ary));
  981. memcpy((char *)storage->know, (char *)know, sizeof(Char_Ary));
  982. level_sums[level] = sum((unsigned char *)storage, sizeof(Saved_Level));
  983. }
  984. /* =============================================================================
  985. * FUNCTION: getlevel
  986. */
  987. void getlevel(void) {
  988. unsigned int i;
  989. Saved_Level *storage = saved_levels[level];
  990. memcpy((char *)hitp, (char *)storage->hitp, sizeof(Short_Ary));
  991. memcpy((char *)mitem, (char *)storage->mitem, sizeof(Mitem_Ary));
  992. memcpy((char *)item, (char *)storage->item, sizeof(Char_Ary));
  993. memcpy((char *)iarg, (char *)storage->iarg, sizeof(Short_Ary));
  994. memcpy((char *)know, (char *)storage->know, sizeof(Char_Ary));
  995. if (level_sums[level] > 0) {
  996. if ((i = sum((unsigned char *)storage, sizeof(Saved_Level))) !=
  997. level_sums[level]) {
  998. Printf("\nOH NO!!!! INTERNAL MEMORY CORRUPTION!!!!\n");
  999. Printf("(sum %u of level %d does not match saved sum %u)\n", i, level,
  1000. level_sums[level]);
  1001. UlarnBeep();
  1002. nap(5000);
  1003. died(DIED_INTERNAL_COMPLICATIONS, 0);
  1004. }
  1005. } else
  1006. level_sums[level] = sum((unsigned char *)storage, sizeof(Saved_Level));
  1007. }
  1008. /* =============================================================================
  1009. * FUNCTION: AnalyseWalls
  1010. */
  1011. void AnalyseWalls(int x1, int y1, int x2, int y2) {
  1012. int WallArg;
  1013. int x, y;
  1014. int sx, sy;
  1015. int ex, ey;
  1016. /* Limit area to the valid map area */
  1017. sx = (x1 < 0) ? 0 : (x1);
  1018. sy = (y1 < 0) ? 0 : (y1);
  1019. ex = (x2 >= MAXX) ? (MAXX - 1) : (x2);
  1020. ey = (y2 >= MAXY) ? (MAXY - 1) : (y2);
  1021. for (x = sx; x <= ex; x++) {
  1022. for (y = sy; y <= ey; y++) {
  1023. if (item[x][y] == OWALL) {
  1024. /* There is a wall here, so analyse connectivity with other walls */
  1025. WallArg = 0;
  1026. if (x > 0) {
  1027. if ((item[x - 1][y] == OWALL) || (item[x - 1][y] == OOPENDOOR) ||
  1028. (item[x - 1][y] == OCLOSEDDOOR))
  1029. WallArg += 1;
  1030. }
  1031. if (y < (MAXY - 1)) {
  1032. if ((item[x][y + 1] == OWALL) || (item[x][y + 1] == OOPENDOOR) ||
  1033. (item[x][y + 1] == OCLOSEDDOOR))
  1034. WallArg += 2;
  1035. }
  1036. if (x < (MAXX - 1)) {
  1037. if ((item[x + 1][y] == OWALL) || (item[x + 1][y] == OOPENDOOR) ||
  1038. (item[x + 1][y] == OCLOSEDDOOR))
  1039. WallArg += 4;
  1040. }
  1041. if (y > 0) {
  1042. if ((item[x][y - 1] == OWALL) || (item[x][y - 1] == OOPENDOOR) ||
  1043. (item[x][y - 1] == OCLOSEDDOOR))
  1044. WallArg += 8;
  1045. }
  1046. iarg[x][y] = (short)WallArg;
  1047. } /* if a wall is here */
  1048. }
  1049. }
  1050. }
  1051. /* =============================================================================
  1052. * FUNCTION: newcavelevel
  1053. */
  1054. void newcavelevel(int x) {
  1055. int i, j;
  1056. if (beenhere[level]) {
  1057. savelevel(); /* put the level back into storage */
  1058. }
  1059. if (level == 0)
  1060. /* if teleported and found the home level then know level we are on */
  1061. c[TELEFLAG] = 0;
  1062. /*
  1063. * Forget which monster was last hit by the player as it is no longer
  1064. * on this level.
  1065. */
  1066. last_monst_hx = -1;
  1067. last_monst_hy = -1;
  1068. level = (char)x;
  1069. c[CAVELEVEL] = level;
  1070. if (beenhere[x]) {
  1071. /* get the new level and put in working storage */
  1072. getlevel();
  1073. /* spawn new monsters */
  1074. sethp(0);
  1075. /* remove any genocided monsters */
  1076. checkgen();
  1077. /* Position the player on the map */
  1078. positionplayer();
  1079. } else {
  1080. /* never been here before, so don't know anything, and no monsters */
  1081. for (i = 0; i < MAXY; i++) {
  1082. for (j = 0; j < MAXX; j++) {
  1083. know[j][i] = OUNKNOWN;
  1084. mitem[j][i].mon = MONST_NONE;
  1085. }
  1086. }
  1087. makemaze(x);
  1088. /* if this is level 1 */
  1089. if (x == 1)
  1090. /* exit from dungeon */
  1091. item[33][MAXY - 1] = ONOTHING;
  1092. AnalyseWalls(0, 0, MAXX - 1, MAXY - 1);
  1093. makeobject(x);
  1094. beenhere[x] = 1;
  1095. /* create monsters for this level */
  1096. sethp(1);
  1097. if (wizard || x == 0) {
  1098. for (j = 0; j < MAXY; j++) {
  1099. for (i = 0; i < MAXX; i++) {
  1100. know[i][j] = item[i][j];
  1101. stealth[i][j] |= STEALTH_SEEN;
  1102. }
  1103. }
  1104. }
  1105. /* wipe out any genocided monsters */
  1106. checkgen();
  1107. /* Position the player on the map */
  1108. positionplayer();
  1109. }
  1110. }
  1111. /* =============================================================================
  1112. * FUNCTION: verifyxy
  1113. */
  1114. int verifyxy(int *x, int *y) {
  1115. int flag = 0;
  1116. if (*x < 0) {
  1117. *x = 0;
  1118. flag++;
  1119. }
  1120. if (*y < 0) {
  1121. *y = 0;
  1122. flag++;
  1123. }
  1124. if (*x >= MAXX) {
  1125. *x = MAXX - 1;
  1126. flag++;
  1127. }
  1128. if (*y >= MAXY) {
  1129. *y = MAXY - 1;
  1130. flag++;
  1131. }
  1132. return flag;
  1133. }
  1134. /* =============================================================================
  1135. * FUNCTION: checkxy
  1136. */
  1137. int checkxy(int x, int y) {
  1138. return (x >= 0) && (x < MAXX) && (y >= 0) && (y < MAXY);
  1139. }
  1140. /* =============================================================================
  1141. * FUNCTION: createitem
  1142. */
  1143. void createitem(int x, int y, int it, int arg) {
  1144. int i;
  1145. int dir, dir_try;
  1146. int ox, oy;
  1147. if (it >= OCOUNT)
  1148. return; /* no such object */
  1149. /* Select the initial direction to try at random */
  1150. dir = rnd(8);
  1151. for (dir_try = 0; dir_try < 8; dir_try++) {
  1152. /* choose direction, try all */
  1153. if (dir > 8)
  1154. dir = 1; /* wraparound the diroff arrays */
  1155. ox = x + diroffx[dir];
  1156. oy = y + diroffy[dir];
  1157. if ((it != OKGOLD) && (it != OMAXGOLD) && (it != ODGOLD) &&
  1158. (it != OGOLDPILE)) {
  1159. if (cgood(ox, oy, 1, 0)) {
  1160. /* if we can create an item here */
  1161. item[ox][oy] = (char)it;
  1162. iarg[ox][oy] = (short)arg;
  1163. return;
  1164. }
  1165. } else {
  1166. /* arg contains the number of GP to drop */
  1167. switch (item[ox][oy]) {
  1168. case OGOLDPILE:
  1169. if ((iarg[ox][oy] + arg) < 32767) {
  1170. iarg[ox][oy] += (short)arg;
  1171. return;
  1172. }
  1173. case ODGOLD:
  1174. if ((10L * iarg[ox][oy] + arg) < 327670L) {
  1175. i = iarg[ox][oy];
  1176. iarg[ox][oy] = (short)((10L * i + arg) / 10);
  1177. item[ox][oy] = ODGOLD;
  1178. return;
  1179. }
  1180. case OMAXGOLD:
  1181. if ((100L * iarg[ox][oy] + arg) < 3276700L) {
  1182. i = (int)((100L * iarg[ox][oy]) + arg);
  1183. iarg[ox][oy] = (short)(i / 100);
  1184. item[ox][oy] = OMAXGOLD;
  1185. return;
  1186. }
  1187. case OKGOLD:
  1188. if ((1000L * iarg[ox][oy] + arg) <= 32767000L) {
  1189. i = iarg[ox][oy];
  1190. iarg[ox][oy] = (short)((1000L * i + arg) / 1000);
  1191. item[ox][oy] = OKGOLD;
  1192. return;
  1193. } else
  1194. iarg[ox][oy] = 32767;
  1195. return;
  1196. default:
  1197. if (cgood(ox, oy, 1, 0)) {
  1198. item[ox][oy] = (char)it;
  1199. if (it == OMAXGOLD)
  1200. iarg[ox][oy] = (short)(arg / 100);
  1201. else
  1202. iarg[ox][oy] = (short)arg;
  1203. return;
  1204. }
  1205. break;
  1206. } /* end switch */
  1207. } /* end else */
  1208. /* try the next direction */
  1209. dir++;
  1210. } /* end for */
  1211. }
  1212. /* =============================================================================
  1213. * FUNCTION: something
  1214. */
  1215. void something(int x, int y, int lev) {
  1216. int item_id, item_arg = NULL;
  1217. /* correct level? */
  1218. if (lev < 0 || lev > VBOTTOM)
  1219. return;
  1220. /* possibly more than one item */
  1221. do {
  1222. item_id = newobject(lev, &item_arg);
  1223. createitem(x, y, item_id, (long)item_arg);
  1224. } while (rnd(101) < 8);
  1225. }
  1226. /* =============================================================================
  1227. * FUNCTION: newobject
  1228. */
  1229. #define LEV_0to3_LAST 32
  1230. #define LEV_4to6_LAST 35
  1231. #define LEV_6plus_LAST 37
  1232. static char nobjtab[] = {
  1233. 0, OSCROLL, OSCROLL, OSCROLL, OSCROLL, OPOTION,
  1234. OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE,
  1235. OGOLDPILE, OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER,
  1236. ODAGGER, ODAGGER, OLEATHER, OLEATHER, OLEATHER, OREGENRING,
  1237. OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR, OBELT,
  1238. ORING, OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD,
  1239. OPLATE, OLONGSWORD}; /* 38 */
  1240. int newobject(int lev, int *i) {
  1241. int LastObj;
  1242. int ObjType;
  1243. /* correct level? */
  1244. if (level < 0 || level > VBOTTOM)
  1245. return 0;
  1246. /* Decide what types of objects can be created based on the current level */
  1247. if (lev <= 3)
  1248. LastObj = LEV_0to3_LAST;
  1249. else if (lev <= 6)
  1250. LastObj = LEV_4to6_LAST;
  1251. else
  1252. LastObj = LEV_6plus_LAST;
  1253. /* select the object type */
  1254. ObjType = nobjtab[rnd(LastObj)];
  1255. switch (ObjType) {
  1256. case OSCROLL:
  1257. *i = newscroll();
  1258. break;
  1259. case OPOTION:
  1260. *i = newpotion();
  1261. break;
  1262. case OGOLDPILE:
  1263. *i = rnd((lev + 1) * 10) + lev * 10 + 10;
  1264. break;
  1265. case OBOOK:
  1266. *i = lev;
  1267. break;
  1268. case ODAGGER:
  1269. *i = newdagger();
  1270. break;
  1271. case OLEATHER:
  1272. *i = newleather();
  1273. break;
  1274. case OREGENRING:
  1275. case OSHIELD:
  1276. case O2SWORD:
  1277. *i = rund(lev / 3 + 1);
  1278. break;
  1279. case OPROTRING:
  1280. case ODEXRING:
  1281. *i = rnd(lev / 4 + 1);
  1282. break;
  1283. case OENERGYRING:
  1284. *i = rund(lev / 4 + 1);
  1285. break;
  1286. case OSTRRING:
  1287. *i = rnd(lev / 2 + 1);
  1288. break;
  1289. case OSPEAR:
  1290. *i = rund(lev / 3 + 1);
  1291. break;
  1292. case OBELT:
  1293. case OSTUDLEATHER:
  1294. *i = rund(lev / 2 + 1);
  1295. break;
  1296. case ORING:
  1297. case OFLAIL:
  1298. *i = rund(lev / 2 + 1);
  1299. break;
  1300. case OCHAIN:
  1301. *i = newchain();
  1302. break;
  1303. case OPLATE:
  1304. *i = newplate();
  1305. break;
  1306. case OLONGSWORD:
  1307. *i = newsword();
  1308. break;
  1309. default:
  1310. break;
  1311. }
  1312. return ObjType;
  1313. }
  1314. /* =============================================================================
  1315. * FUNCTION: write_levels
  1316. */
  1317. int write_levels(FILE *fp) {
  1318. int i;
  1319. Saved_Level *storage;
  1320. /*
  1321. * Put the current level into storage
  1322. */
  1323. savelevel();
  1324. /*
  1325. * save which level the player is currently on
  1326. */
  1327. bwrite(fp, (char *)&level, sizeof(int));
  1328. /*
  1329. * Save which levels have been visited by the player
  1330. */
  1331. bwrite(fp, (char *)beenhere, sizeof(char) * NLEVELS);
  1332. /*
  1333. * Save each of the visited levels
  1334. */
  1335. for (i = 0; i < NLEVELS; i++) {
  1336. if (beenhere[i]) {
  1337. storage = saved_levels[i];
  1338. bwrite(fp, (char *)storage, sizeof(Saved_Level));
  1339. }
  1340. }
  1341. return 0;
  1342. }
  1343. /* =============================================================================
  1344. * FUNCTION: read_levels
  1345. */
  1346. int read_levels(FILE *fp) {
  1347. int i;
  1348. Saved_Level *storage;
  1349. /*
  1350. * Read which level the player is currently on
  1351. */
  1352. bread(fp, (char *)&level, sizeof(int));
  1353. /*
  1354. * Read which levels have been visited by the player
  1355. */
  1356. bread(fp, (char *)beenhere, sizeof(char) * NLEVELS);
  1357. /*
  1358. * Read each of the visited levels
  1359. */
  1360. for (i = 0; i < NLEVELS; i++) {
  1361. if (beenhere[i]) {
  1362. storage = saved_levels[i];
  1363. bread(fp, (char *)storage, sizeof(Saved_Level));
  1364. }
  1365. }
  1366. return 0;
  1367. }