Annotation of early-roguelike/xrogue/n_level.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: n_level.c - Dig and draw a new level
3:
4: XRogue: Expeditions into the Dungeons of Doom
5: Copyright (C) 1991 Robert Pietkivitch
6: All rights reserved.
7:
8: Based on "Advanced Rogue"
9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
10: All rights reserved.
11:
12: Based on "Rogue: Exploring the Dungeons of Doom"
13: Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14: All rights reserved.
15:
16: See the file LICENSE.TXT for full copyright and licensing information.
17: */
18:
19: #include <curses.h>
20: #include "rogue.h"
21: #define TERRASAVE 3
22:
23: void put_things(LEVTYPE ltype);
24:
25: /*
26: * new_level:
27: * Dig and draw a new level
28: * ltype: designates type of level to create
29: */
30:
31: void
32: new_level(LEVTYPE ltype)
33: {
34: register int rm = 0, i, cnt;
35: register unsigned char ch;
36: register struct linked_list *item;
37: register struct thing *tp;
38: register struct object *obj;
39: int waslit = 0; /* Was the previous outside level lit? */
40: int starty = 0, startx = 0, deltay = 0, deltax = 0;
41: bool fresh=TRUE, vert = 0, top;
42: struct room *rp;
43: struct linked_list *nitem, *savmonst=NULL, *savitems=NULL;
44: coord stairs = {0,0};
45:
46: if (wizard) {
47: msg("Turns: %ld", turns); /* Number of turns for last level */
48: mpos = 0;
49: }
50:
51: /* Start player off right */
52: turn_off(player, ISHELD);
53: turn_off(player, ISFLEE);
54: extinguish(suffocate);
55: hold_count = 0;
56: trap_tries = 0;
57:
58: /* Are we just entering a dungeon? If so, how big is it? */
59: if (ltype != OUTSIDE && nfloors < 0) nfloors = HARDER+20 + rnd(51);
60:
61: if (level > max_level)
62: max_level = level;
63:
64: /* Are we starting a new outside level? */
65: if (ltype == OUTSIDE) {
66: register int i, j;
67:
68: /* Save some information prior to clearing the screen */
69: if (level == -1 || mvinch(hero.y, hero.x) == HORZWALL) vert = TRUE;
70: else vert = FALSE;
71:
72: if (level < 1) {
73: fresh = TRUE;
74: starty = 2;
75: startx = 1;
76: deltay = deltax = 1;
77: level = max_level; /* Restore level to deepest attempt */
78: prev_max = level; /* reset for boundary crossings below */
79: }
80: else if (level >= 1 && prev_max == 1000) {
81: fresh = TRUE;
82: starty = 2;
83: startx = 1;
84: deltay = deltax = 1;
85: prev_max = level; /* reset for boundary crossings below */
86: }
87: else { /* Copy several lines of the terrain to the other end */
88:
89: unsigned char cch; /* Copy character */
90:
91: if (wizard) msg("Crossing sector boundary ");
92:
93: /* Was the area dark (not magically lit)? */
94: if (!(rooms[0].r_flags & ISDARK)) waslit = 1;
95:
96: fresh = FALSE;
97: if ((vert && hero.y == 1) || (!vert && hero.x == 0)) top = TRUE;
98: else top = FALSE;
99: for (i=0; i<TERRASAVE; i++) {
100: if (vert)
101: for (j=1; j<cols-1; j++) {
102: if (top) {
103: cch = mvinch(i+2, j);
104: mvaddch(lines-6+i, j, cch);
105: }
106: else {
107: cch = mvinch(lines-4-i, j);
108: mvaddch(4-i, j, cch);
109: }
110: }
111: else
112: for (j=2; j<lines-3; j++) {
113: if (top) {
114: cch = mvinch(j, i+1);
115: mvaddch(j, cols-4+i, cch);
116: }
117: else {
118: cch = mvinch(j, cols-2-i);
119: mvaddch(j, 3-i, cch);
120: }
121: }
122: }
123:
124: if (vert) {
125: startx = deltax = 1;
126: if (top) {
127: starty = lines-4-TERRASAVE;
128: deltay = -1;
129: }
130: else {
131: starty = TERRASAVE + 2;
132: deltay = 1;
133: }
134: }
135: else {
136: starty = 2;
137: deltay = 1;
138: if (top) {
139: startx = cols-2-TERRASAVE;
140: deltax = -1;
141: }
142: else {
143: deltax = 1;
144: startx = TERRASAVE + 1;
145: }
146: }
147:
148: /* Check if any monsters should be saved */
149: for (item = mlist; item != NULL; item = nitem) {
150: nitem = next(item);
151: tp = THINGPTR(item);
152: if (vert) {
153: if (top) {
154: if (tp->t_pos.y < TERRASAVE + 2)
155: tp->t_pos.y += lines - 5 - TERRASAVE;
156: else continue;
157: }
158: else {
159: if (tp->t_pos.y > lines - 4 - TERRASAVE)
160: tp->t_pos.y += 5 + TERRASAVE - lines;
161: else continue;
162: }
163: }
164: else {
165: if (top) {
166: if (tp->t_pos.x < TERRASAVE + 1)
167: tp->t_pos.x += cols - 2 - TERRASAVE;
168: else continue;
169: }
170: else {
171: if (tp->t_pos.x > cols - 2 - TERRASAVE)
172: tp->t_pos.x += 2 + TERRASAVE - cols;
173: else continue;
174: }
175: }
176:
177: /*
178: * If the monster is busy chasing another monster, don't save
179: * it
180: */
181: if (tp->t_dest && tp->t_dest != &hero) continue;
182:
183: /* Outside has plenty of monsters, don't need these.
184: * detach(mlist, item);
185: * attach(savmonst, item);
186: */
187: }
188:
189: /* Check if any treasure should be saved */
190: for (item = lvl_obj; item != NULL; item = nitem) {
191: nitem = next(item);
192: obj = OBJPTR(item);
193: if (vert) {
194: if (top) {
195: if (obj->o_pos.y < TERRASAVE + 2)
196: obj->o_pos.y += lines - 5 - TERRASAVE;
197: else continue;
198: }
199: else {
200: if (obj->o_pos.y > lines - 4 - TERRASAVE)
201: obj->o_pos.y += 5 + TERRASAVE - lines;
202: else continue;
203: }
204: }
205: else {
206: if (top) {
207: if (obj->o_pos.x < TERRASAVE + 1)
208: obj->o_pos.x += cols - 2 - TERRASAVE;
209: else continue;
210: }
211: else {
212: if (obj->o_pos.x > cols - 2 - TERRASAVE)
213: obj->o_pos.x += 2 + TERRASAVE - cols;
214: else continue;
215: }
216: }
217: detach(lvl_obj, item);
218: attach(savitems, item);
219: }
220: }
221: }
222:
223: wclear(cw);
224: wclear(mw);
225: if (fresh || levtype != OUTSIDE) clear();
226: /*
227: * check to see if he missed a UNIQUE, If he did then put it back
228: * in the monster table for next time
229: */
230: for (item = mlist; item != NULL; item = next(item)) {
231: tp = THINGPTR(item);
232: if (on(*tp, ISUNIQUE))
233: monsters[tp->t_index].m_normal = TRUE;
234: }
235: /*
236: * Free up the monsters on the last level
237: */
238: t_free_list(mlist);
239: o_free_list(lvl_obj); /* Free up previous objects (if any) */
240: for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
241: r_free_list(rp->r_exit); /* Free up the exit lists */
242:
243: levtype = ltype;
244: foods_this_level = 0; /* food for hero this level */
245:
246: /* What kind of level are we on? */
247: if (ltype == POSTLEV || ltype == STARTLEV) {
248: if (ltype == POSTLEV)
249: do_post(FALSE); /* Trading post */
250: else
251: do_post(TRUE); /* Equipage */
252:
253: levtype = ltype = POSTLEV;
254: }
255: else if (ltype == MAZELEV) {
256: do_maze();
257: no_food++;
258: put_things(ltype); /* Place objects (if any) */
259: }
260: else if (ltype == OUTSIDE) {
261: /* Move the cursor back onto the hero */
262: wmove(cw, hero.y, hero.x);
263: init_terrain();
264: do_terrain(starty, startx, deltay, deltax, (bool) (fresh || !vert));
265: no_food++;
266: put_things(ltype);
267:
268: /* Should we magically light this area? */
269: if (waslit) rooms[0].r_flags &= ~ISDARK;
270: }
271: else {
272: do_rooms(); /* Draw rooms */
273: do_passages(); /* Draw passages */
274: no_food++;
275: put_things(ltype); /* Place objects (if any) */
276: }
277: /*
278: * Place the staircase down. Only a small chance for an outside stairway.
279: */
280: if (ltype != OUTSIDE || roll(1, 5) == 5) {
281: cnt = 0;
282: do {
283: rm = rnd_room();
284: rnd_pos(&rooms[rm], &stairs);
285: } until (mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 2500);
286: addch(STAIRS);
287: }
288: /*
289: * maybe add a trading post
290: */
291: if (level > 5 && rnd(10) == 7 && ltype == NORMLEV) {
292: cnt = 0;
293: do {
294: rm = rnd_room();
295: if (rooms[rm].r_flags & ISTREAS)
296: continue;
297: rnd_pos(&rooms[rm], &stairs);
298: } until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 2500);
299: addch(POST);
300: }
301: if (ltype != POSTLEV) { /* Add monsters that fell through */
302: nitem = tlist;
303: while (nitem != NULL) {
304: item = nitem;
305: nitem = next(item); /* because detach and attach mess up ptrs */
306: tp = THINGPTR(item);
307: cnt = 0;
308: do {
309: rm = rnd_room();
310: rnd_pos(&rooms[rm], &tp->t_pos);
311: } until (cnt++ > 2500 || winat(tp->t_pos.y, tp->t_pos.x) == FLOOR);
312: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
313: tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x);
314:
315: /*
316: * If it has a fire, mark it
317: */
318: if (on(*tp, HASFIRE)) {
319: register struct linked_list *fire_item;
320:
321: fire_item = creat_item();
322: ldata(fire_item) = (char *) tp;
323: attach(rooms[rm].r_fires, fire_item);
324: rooms[rm].r_flags |= HASFIRE;
325: }
326:
327: detach(tlist, item);
328: turn_off(*tp,ISELSEWHERE);
329: attach(mlist, item);
330: }
331: }
332:
333: /* Restore any saved monsters */
334: for (item = savmonst; item != NULL; item = nitem) {
335: nitem = next(item);
336: tp = THINGPTR(item);
337: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
338: tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x);
339:
340: /*
341: * If it has a fire, mark it
342: */
343: if (on(*tp, HASFIRE)) {
344: register struct linked_list *fire_item;
345:
346: fire_item = creat_item();
347: ldata(fire_item) = (char *) tp;
348: attach(rooms[rm].r_fires, fire_item);
349: rooms[rm].r_flags |= HASFIRE;
350: }
351:
352: detach(savmonst, item);
353: attach(mlist, item);
354: }
355:
356: /* Restore any saved objects */
357: for(item = savitems; item != NULL; item = nitem) {
358: nitem = next(item);
359: obj = OBJPTR(item);
360: mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type);
361: detach(savitems, item);
362: attach(lvl_obj, item);
363: }
364:
365: /*
366: * Place the traps (except for trading post)
367: */
368: ntraps = 0; /* No traps yet */
369: if (levtype == NORMLEV) {
370: if (rnd(10) < vlevel) {
371: ntraps = rnd(vlevel/4)+2;
372: if (ntraps > MAXTRAPS)
373: ntraps = MAXTRAPS;
374: i = ntraps;
375: while (i--)
376: {
377: cnt = 0;
378: do {
379: rm = rnd_room();
380: if (rooms[rm].r_flags & ISTREAS)
381: continue;
382: rnd_pos(&rooms[rm], &stairs);
383: } until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 2500);
384:
385: traps[i].tr_flags = 0;
386:
387: /* If we are at the bottom, we can't set a trap door */
388: if (level >= nfloors) ch = (unsigned char) rnd(8) + 1;
389: else ch = (unsigned char) rnd(9);
390:
391: switch((int) ch) {
392: case 0: ch = TRAPDOOR;
393: when 1: ch = BEARTRAP;
394: when 2: ch = SLEEPTRAP;
395: when 3: ch = ARROWTRAP;
396: when 4: ch = TELTRAP;
397: when 5: ch = DARTTRAP;
398: when 6: ch = POOL;
399: traps[i].tr_flags = ISFOUND;
400: when 7: ch = MAZETRAP;
401: when 8: ch = WORMHOLE;
402: }
403: addch(ch);
404: traps[i].tr_type = ch;
405: traps[i].tr_show = FLOOR;
406: traps[i].tr_pos = stairs;
407: }
408: }
409: }
410: if (fresh) { /* A whole new picture */
411: /*
412: * try to find a room for the hero. The objective here is to:
413: * --> don't put him in a treasure room
414: * --> don't put him on an object
415: * --> try not to put him next to the stairs
416: */
417: cnt = 2500;
418: do {
419: if (ltype != OUTSIDE) rm = rnd_room();
420: else continue;
421:
422: if (rooms[rm].r_flags & ISTREAS)
423: continue;
424:
425: rnd_pos(&rooms[rm], &hero);
426: } until( cnt-- == 0 ||
427: (winat(hero.y, hero.x) == FLOOR &&
428: DISTANCE(hero.y, hero.x, stairs.y, stairs.x) > cnt/10));
429: }
430: else { /* We're extending into an adjacent outside plane */
431: rm = 0;
432: if (vert) {
433: if (hero.y == 1) hero.y = lines - 3 - TERRASAVE; /* Top to bottom */
434: else hero.y = TERRASAVE + 1; /* Bottom to top */
435: }
436: else {
437: if (hero.x == 0) hero.x = cols - 1 - TERRASAVE; /* Right to left */
438: else hero.x = TERRASAVE; /* Left to right */
439: }
440: }
441: oldrp = &rooms[rm]; /* Set the current room */
442: player.t_oldpos = player.t_pos; /* Set the current position */
443:
444: if (ISWEARING(R_AGGR) ||
445: (cur_misc[WEAR_JEWEL] != NULL &&
446: cur_misc[WEAR_JEWEL]->o_which == MM_JEWEL))
447: aggravate(TRUE, TRUE); /* affect all charactors */
448:
449: /*
450: * If player is moving up or above his deepest point, wake up any
451: * non-uniques
452: */
453: else if (level < cur_max) {
454: aggravate(FALSE, FALSE);
455: }
456:
457: light(&hero);
458: wmove(cw, hero.y, hero.x);
459: waddch(cw, PLAYER);
460:
461: if (level > cur_max)
462: cur_max = level;
463:
464: draw(cw);
465:
466: status(TRUE);
467:
468: /* Do we sense any food on this level? */
469: if (cur_relic[SURTUR_RING])
470: quaff(P_FFIND, 0, 0, FALSE);
471: }
472:
473: /*
474: * Pick a room that is really there
475: */
476:
477: int
478: rnd_room(void)
479: {
480: register int rm;
481:
482: if (levtype != NORMLEV)
483: rm = 0;
484: else do
485: {
486: rm = rnd(MAXROOMS);
487: } while (rooms[rm].r_flags & ISGONE);
488: return rm;
489: }
490:
491: /*
492: * put_things:
493: * put potions and scrolls on this level
494: * ltype: designates type of level to create
495: */
496:
497: void
498: put_things(LEVTYPE ltype)
499: {
500: register int i, rm, cnt;
501: register struct object *cur;
502: register struct linked_list *item, *nextitem, *exitptr;
503: int length, width;
504: int ITEMS = 0; /* number of items to place */
505: coord tp, *exit;
506:
507: /*
508: * The only way to get new stuff is to go down into the dungeon.
509: */
510: if (level < cur_max) {
511: if (ltype == NORMLEV)
512: return;
513: }
514:
515: if (ltype == OUTSIDE) goto jmp_here; /* a jump for outside */
516:
517: /*
518: * There is a chance that there is a Treasure Room on this level
519: */
520: if (ltype == NORMLEV && rnd(150) < level) {
521: register int j;
522: register struct room *rp;
523:
524: /* Count the number of free spaces */
525: i = 0; /* 0 tries */
526: do {
527: rp = &rooms[rnd_room()];
528: width = rp->r_max.y - 2;
529: length = rp->r_max.x - 2;
530: } until ((width*length >= MAXTREAS) || (i++ > MAXROOMS*4));
531:
532: /* Mark the room as a treasure room */
533: rp->r_flags |= ISTREAS;
534:
535: /* Make all the doors secret doors */
536: for (exitptr = rp->r_exit; exitptr; exitptr = next(exitptr)) {
537: exit = DOORPTR(exitptr);
538: move(exit->y, exit->x);
539: addch(SECRETDOOR);
540: }
541:
542: /*
543: * check to see if there are any monsters in room already
544: */
545: for (item = mlist; item != NULL; item = nextitem) {
546: register struct thing *tp;
547:
548: tp = THINGPTR(item);
549: nextitem = next(item);
550: if (rp == roomin(&tp->t_pos)) {
551: /*
552: * Don't let nice creatures be generated in a treasure
553: * room.
554: */
555: if ((player.t_ctype==C_PALADIN || player.t_ctype==C_RANGER ||
556: player.t_ctype==C_MONK) && off(*tp, ISMEAN)) {
557: int index;
558:
559: if (on(*tp, ISUNIQUE)) index = tp->t_index;
560: else index = -1;
561:
562: /* Get rid of the monster */
563: killed(item, FALSE, FALSE, FALSE);
564:
565: /* Restore uniques back in the table */
566: if (index != -1) monsters[index].m_normal = TRUE;
567:
568: continue;
569: }
570: turn_on(*tp, ISMEAN);
571: turn_on(*tp, ISGUARDIAN);
572: }
573: }
574:
575: /* Put in the monsters and treasures */
576: for (j=1; j<rp->r_max.y-1; j++)
577: for (i=1; i<rp->r_max.x-1; i++) {
578: coord trp;
579:
580: trp.y = rp->r_pos.y+j;
581: trp.x = rp->r_pos.x+i;
582:
583: /* Monsters */
584: if ((rnd(100) < (MAXTREAS*100)/(width*length)) &&
585: (mvwinch(mw, rp->r_pos.y+j, rp->r_pos.x+i) == ' ')) {
586: register struct thing *tp;
587:
588: /*
589: * Put it there and leave it asleep. Wake the monsters
590: * when the player enters the room. Hopefully, all bases
591: * are covered as far as the ways to get in. This way
592: * cpu time is not wasted on the awake monsters that
593: * can't get to the player anyway.
594: * try not to put any UNIQUEs in a treasure room.
595: * note that they may have put put in already by the
596: * non-treasure room code.
597: * also, try not to put ISMEAN monsters in a treasure
598: * room as these are supposed to be non-hostile until
599: * attacked. It also makes life simpler for the ranger,
600: * paladin, and monk.
601: */
602: for(;;) {
603: item = new_item(sizeof *tp); /* Make a monster */
604: tp = THINGPTR(item);
605: new_monster(item,randmonster(FALSE, TRUE),&trp,TRUE);
606: if (on(*tp, HASFIRE)) {
607: register struct linked_list *fire_item;
608:
609: fire_item = creat_item();
610: ldata(fire_item) = (char *) tp;
611: attach(rp->r_fires, fire_item);
612: rp->r_flags |= HASFIRE;
613: }
614: /*
615: * only picky for these classes
616: */
617: if (player.t_ctype != C_RANGER &&
618: player.t_ctype != C_PALADIN &&
619: player.t_ctype != C_MONK)
620: break;
621: if (on(*tp, ISMEAN))
622: break;
623: killed (item, FALSE, FALSE, FALSE);
624: }
625: if (on(*tp, ISUNIQUE)) { /* just in case */
626: carry_obj(tp, monsters[tp->t_index].m_carry);
627: tp->t_no_move = movement(tp);
628: }
629: turn_on(*tp, ISGUARDIAN);
630:
631: }
632:
633: /* Treasures */
634: if ((rnd(100) < (MAXTREAS*100)/(width*length)) &&
635: (mvinch(rp->r_pos.y+j, rp->r_pos.x+i) == FLOOR)) {
636: item = new_thing(ALL, TRUE);
637: attach(lvl_obj, item);
638: cur = OBJPTR(item);
639:
640: mvaddch(trp.y, trp.x, cur->o_type);
641: cur->o_pos = trp;
642: }
643: }
644: }
645:
646: jmp_here: /* outside jumper for equippage */
647:
648: /*
649: * Do ITEMS attempts to put things in dungeon, maze, or outside
650: */
651:
652: if (ltype == OUTSIDE) ITEMS = rnd(15)+1;
653: else if (ltype == MAZELEV) ITEMS = rnd(20)+1;
654: else ITEMS = MAXOBJ + rnd(4);
655:
656: for (i = 0; i < ITEMS; i++)
657: if (rnd(100) < 65) {
658: /*
659: * Pick a new object and link it in the list
660: */
661: item = new_thing(ALL, TRUE);
662: attach(lvl_obj, item);
663: cur = OBJPTR(item);
664: /*
665: * Put it somewhere
666: */
667: cnt = 0;
668: do {
669: if (ltype == OUTSIDE) rm = 0;
670: else rm = rnd_room();
671: rnd_pos(&rooms[rm], &tp);
672: } until (winat(tp.y, tp.x) == FLOOR || cnt++ > 2500);
673: mvaddch(tp.y, tp.x, cur->o_type);
674: cur->o_pos = tp;
675: }
676: }
677:
CVSweb