Annotation of early-roguelike/arogue7/new_level.c, Revision 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