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