Mercurial > hg > early-roguelike
diff arogue5/new_level.c @ 63:0ed67132cf10
Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author | elwin |
---|---|
date | Thu, 09 Aug 2012 22:58:48 +0000 |
parents | |
children | 56e748983fa8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue5/new_level.c Thu Aug 09 22:58:48 2012 +0000 @@ -0,0 +1,579 @@ +/* + * new_level: Dig and draw a new level + * + * Advanced Rogue + * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include "rogue.h" +#define TERRASAVE 3 + +new_level(ltype) +LEVTYPE ltype; /* designates type of level to create */ +{ + register int rm = 0, i, cnt; + register char ch; + register struct linked_list *item; + register struct thing *tp; + register struct object *obj; + int waslit = 0; /* Was the previous outside level lit? */ + int starty = 0, startx = 0, deltay = 0, deltax = 0; + bool fresh=TRUE, vert = 0, top; + struct room *rp; + struct linked_list *nitem, *savmonst=NULL, *savitems=NULL; + coord stairs = { 0, 0 }; + + if (wizard) { + msg("Turns: %d", turns); /* Number of turns for last level */ + mpos = 0; + } + + /* Start player off right */ + turn_off(player, ISHELD); + turn_off(player, ISFLEE); + extinguish(suffocate); + hold_count = 0; + trap_tries = 0; + + /* Are we just entering a dungeon? If so, how big is it? */ + if (ltype != OUTSIDE && nfloors < 0) nfloors = HARDER+10 + rnd(11); + + if (level > max_level) + max_level = level; + + /* Are we starting a new outside level? */ + if (ltype == OUTSIDE) { + register int i, j; + + /* Save some information prior to clearing the screen */ + if (level == -1 || mvinch(hero.y, hero.x) == '-') vert = TRUE; + else vert = FALSE; + + if (level == -1) { + fresh = TRUE; + starty = 2; + startx = 1; + deltay = deltax = 1; + level = 0; /* Restore the level */ + } + else { /* Copy several lines of the terrain to the other end */ + char cch; /* Copy character */ + + /* Was the area dark (not magically lit)? */ + if (!(rooms[0].r_flags & ISDARK)) waslit = 1; + + fresh = FALSE; + if ((vert && hero.y == 1) || (!vert && hero.x == 0)) top = TRUE; + else top = FALSE; + for (i=0; i<TERRASAVE; i++) { + if (vert) + for (j=1; j<COLS-1; j++) { + if (top) { + cch = CCHAR( mvinch(i+2, j) ); + mvaddch(LINES-6+i, j, cch); + } + else { + cch = CCHAR( mvinch(LINES-4-i, j) ); + mvaddch(4-i, j, cch); + } + } + else + for (j=2; j<LINES-3; j++) { + if (top) { + cch = CCHAR( mvinch(j, i+1) ); + mvaddch(j, COLS-4+i, cch); + } + else { + cch = CCHAR( mvinch(j, COLS-2-i) ); + mvaddch(j, 3-i, cch); + } + } + } + + if (vert) { + startx = deltax = 1; + if (top) { + starty = LINES-4-TERRASAVE; + deltay = -1; + } + else { + starty = TERRASAVE + 2; + deltay = 1; + } + } + else { + starty = 2; + deltay = 1; + if (top) { + startx = COLS-2-TERRASAVE; + deltax = -1; + } + else { + deltax = 1; + startx = TERRASAVE + 1; + } + } + + /* Check if any monsters should be saved */ + for (item = mlist; item != NULL; item = nitem) { + nitem = next(item); + tp = THINGPTR(item); + if (vert) { + if (top) { + if (tp->t_pos.y < TERRASAVE + 2) + tp->t_pos.y += LINES - 5 - TERRASAVE; + else continue; + } + else { + if (tp->t_pos.y > LINES - 4 - TERRASAVE) + tp->t_pos.y += 5 + TERRASAVE - LINES; + else continue; + } + } + else { + if (top) { + if (tp->t_pos.x < TERRASAVE + 1) + tp->t_pos.x += COLS - 2 - TERRASAVE; + else continue; + } + else { + if (tp->t_pos.x > COLS - 2 - TERRASAVE) + tp->t_pos.x += 2 + TERRASAVE - COLS; + else continue; + } + } + detach(mlist, item); + attach(savmonst, item); + } + + /* Check if any treasure should be saved */ + for (item = lvl_obj; item != NULL; item = nitem) { + nitem = next(item); + obj = OBJPTR(item); + if (vert) { + if (top) { + if (obj->o_pos.y < TERRASAVE + 2) + obj->o_pos.y += LINES - 5 - TERRASAVE; + else continue; + } + else { + if (obj->o_pos.y > LINES - 4 - TERRASAVE) + obj->o_pos.y += 5 + TERRASAVE - LINES; + else continue; + } + } + else { + if (top) { + if (obj->o_pos.x < TERRASAVE + 1) + obj->o_pos.x += COLS - 2 - TERRASAVE; + else continue; + } + else { + if (obj->o_pos.x > COLS - 2 - TERRASAVE) + obj->o_pos.x += 2 + TERRASAVE - COLS; + else continue; + } + } + detach(lvl_obj, item); + attach(savitems, item); + } + } + } + + + wclear(cw); + wclear(mw); + if (fresh) clear(); + /* + * check to see if he missed a UNIQUE, If he did then put it back + * in the monster table for next time + */ + for (item = mlist; item != NULL; item = next(item)) { + tp = THINGPTR(item); + if (on(*tp, ISUNIQUE)) + monsters[tp->t_index].m_normal = TRUE; + } + /* + * Free up the monsters on the last level + */ + t_free_list(monst_dead); + t_free_list(mlist); + o_free_list(lvl_obj); /* Free up previous objects (if any) */ + for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) + t_free_list(rp->r_exit); /* Free up the exit lists */ + + levtype = ltype; + foods_this_level = 0; /* food for hero this level */ + if (ltype == POSTLEV) { + do_post(); /* do post stuff */ + } + else if (ltype == MAZELEV) { + do_maze(); + no_food++; + put_things(ltype); /* Place objects (if any) */ + } + else if (ltype == OUTSIDE) { + init_terrain(); + do_terrain(starty, startx, deltay, deltax, (bool) (fresh || !vert)); + no_food++; + put_things(ltype); + + /* Should we magically light this area? */ + if (waslit) rooms[0].r_flags &= ~ISDARK; + } + else { + do_rooms(); /* Draw rooms */ + do_passages(); /* Draw passages */ + no_food++; + put_things(ltype); /* Place objects (if any) */ + } + /* + * Place the staircase down. Only a small chance for an outside stairway. + */ + if (ltype != OUTSIDE || roll(1, 4) == 4) { + cnt = 0; + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &stairs); + } until (mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000); + addch(STAIRS); + } + /* + * maybe add a trading post + */ + if (level > 5 && rnd(11) == 7 && ltype == NORMLEV) { + cnt = 0; + do { + rm = rnd_room(); + if (rooms[rm].r_flags & ISTREAS) + continue; + rnd_pos(&rooms[rm], &stairs); + } until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 5000); + addch(POST); + } + if (ltype != POSTLEV) { /* Add monsters that fell through */ + nitem = tlist; + while (nitem != NULL) { + item = nitem; + nitem = next(item); /* because detach and attach mess up ptrs */ + tp = THINGPTR(item); + cnt = 0; + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &tp->t_pos); + } until (cnt++ > 5000 || winat(tp->t_pos.y, tp->t_pos.x) == FLOOR); + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type); + tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) ); + + /* + * If it has a fire, mark it + */ + if (on(*tp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rooms[rm].r_fires, fire_item); + rooms[rm].r_flags |= HASFIRE; + } + turn_off(*tp, ISELSEWHERE); + detach(tlist, item); + attach(mlist, item); + } + } + + /* Restore any saved monsters */ + for (item = savmonst; item != NULL; item = nitem) { + nitem = next(item); + tp = THINGPTR(item); + mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type); + tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) ); + + /* + * If it has a fire, mark it + */ + if (on(*tp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rooms[rm].r_fires, fire_item); + rooms[rm].r_flags |= HASFIRE; + } + + detach(savmonst, item); + attach(mlist, item); + } + + /* Restore any saved objects */ + for(item = savitems; item != NULL; item = nitem) { + nitem = next(item); + obj = OBJPTR(item); + mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type); + detach(savitems, item); + attach(lvl_obj, item); + } + + + /* + * Place the traps (except for trading post) + */ + ntraps = 0; /* No traps yet */ + if (levtype == NORMLEV) { + if (rnd(10) < vlevel) { + ntraps = rnd(vlevel/4)+1; + if (ntraps > MAXTRAPS) + ntraps = MAXTRAPS; + i = ntraps; + while (i--) + { + cnt = 0; + do { + rm = rnd_room(); + if (rooms[rm].r_flags & ISTREAS) + continue; + rnd_pos(&rooms[rm], &stairs); + } until (winat(stairs.y, stairs.x) == FLOOR || cnt++ > 5000); + + traps[i].tr_flags = 0; + + /* If we are at the bottom, we can't set a trap door */ + if (level >= nfloors) ch = (char) rnd(7) + 1; + else ch = (char) rnd(8); + + switch((int) ch) { + case 0: ch = TRAPDOOR; + when 1: ch = BEARTRAP; + when 2: ch = SLEEPTRAP; + when 3: ch = ARROWTRAP; + when 4: ch = TELTRAP; + when 5: ch = DARTTRAP; + when 6: ch = POOL; + traps[i].tr_flags = ISFOUND; + when 7: ch = MAZETRAP; + } + addch(ch); + traps[i].tr_type = ch; + traps[i].tr_show = FLOOR; + traps[i].tr_pos = stairs; + } + } + } + if (fresh) { /* A whole new picture */ + cnt = 0; + do { + rm = rnd_room(); + if (rooms[rm].r_flags & ISTREAS) + continue; + rnd_pos(&rooms[rm], &hero); + } until( cnt++ > 5000 || + (winat(hero.y, hero.x) == FLOOR && + DISTANCE(hero.y, hero.x, stairs.y, stairs.x) > 16)); + } + else { /* We're extending into an adjacent outside plane */ + rm = 0; + if (vert) { + if (hero.y == 1) hero.y = LINES - 3 - TERRASAVE; /* Top to bottom */ + else hero.y = TERRASAVE + 1; /* Bottom to top */ + } + else { + if (hero.x == 0) hero.x = COLS - 1 - TERRASAVE; /* Right to left */ + else hero.x = TERRASAVE; /* Left to right */ + } + } + oldrp = &rooms[rm]; /* Set the current room */ + player.t_oldpos = player.t_pos; /* Set the current position */ + if (ISWEARING(R_AGGR) || + (cur_misc[WEAR_JEWEL] != NULL && + cur_misc[WEAR_JEWEL]->o_which == MM_JEWEL)) + aggravate(); + light(&hero); + wmove(cw, hero.y, hero.x); + waddch(cw, PLAYER); + + if (level > cur_max) + cur_max = level; + + status(TRUE); +} + +/* + * Pick a room that is really there + */ + +rnd_room() +{ + register int rm; + + if (levtype != NORMLEV) + rm = 0; + else do + { + rm = rnd(MAXROOMS); + } while (rooms[rm].r_flags & ISGONE); + return rm; +} + +/* + * put_things: + * put potions and scrolls on this level + */ + +put_things(ltype) +LEVTYPE ltype; /* designates type of level to create */ +{ + register int i, rm, cnt; + register struct object *cur; + register struct linked_list *item, *exitptr; + bool got_unique = FALSE; + int length, width; + coord tp, *exit; + + /* + * The only way to get new stuff is to go down into the dungeon. + */ + if (level <= cur_max) + return; + + /* + * There is a chance that there is a treasure room on this level + * Increasing chance after level 9 + */ + if (ltype != MAZELEV && rnd(HARDER) < level - 8) { + register j; + register struct room *rp; + + /* Count the number of free spaces */ + i = 0; /* 0 tries */ + do { + rp = &rooms[rnd_room()]; + width = rp->r_max.y - 2; + length = rp->r_max.x - 2; + } until ((width*length >= MAXTREAS) || (i++ > MAXROOMS*4)); + + /* Mark the room as a treasure room */ + rp->r_flags |= ISTREAS; + + /* Make all the doors secret doors */ + for (exitptr = rp->r_exit; exitptr; exitptr = next(exitptr)) { + exit = DOORPTR(exitptr); + move(exit->y, exit->x); + addch(SECRETDOOR); + } + + /* + * check to see if there are any monsters in room already + */ + for (item = mlist; item != NULL; item = next(item)) { + register struct thing *tp; + + tp = THINGPTR(item); + if (rp == roomin(&tp->t_pos)) { + turn_on(*tp, ISMEAN); + if (off(*tp, CANINWALL)) { + tp->t_dest = &hero; + turn_on(*tp, ISRUN); + } + if (on(*tp, ISUNIQUE)) + got_unique = TRUE; + + /* If it is a mimic, undisguise it */ + if (on(*tp, ISDISGUISE)) + turn_off(*tp, ISDISGUISE); + } + } + + + /* Put in the monsters and treasures */ + for (j=1; j<rp->r_max.y-1; j++) + for (i=1; i<rp->r_max.x-1; i++) { + coord trp; + + trp.y = rp->r_pos.y+j; + trp.x = rp->r_pos.x+i; + + /* Monsters */ + if ((rnd(100) < (MAXTREAS*100)/(width*length)) && + (mvwinch(mw, rp->r_pos.y+j, rp->r_pos.x+i) == ' ')) { + register struct thing *tp; + + /* Make a monster */ + item = new_item(sizeof *tp); + tp = THINGPTR(item); + + /* + * Put it there and aggravate it (unless it can escape) + * only put one UNIQUE per treasure room at most + */ + if (got_unique) + new_monster(item,randmonster(FALSE, TRUE),&trp,TRUE); + else + new_monster(item,randmonster(FALSE, FALSE),&trp,TRUE); + if (on(*tp, ISUNIQUE)) { + got_unique = TRUE; + carry_obj(tp, monsters[tp->t_index].m_carry); + } + turn_on(*tp, ISMEAN); + if (off(*tp, CANINWALL)) { + tp->t_dest = &hero; + turn_on(*tp, ISRUN); + } + + /* If it is a mimic, undisguise it */ + if (on(*tp, ISDISGUISE)) + turn_off(*tp, ISDISGUISE); + + if (on(*tp, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) tp; + attach(rp->r_fires, fire_item); + rp->r_flags |= HASFIRE; + } + } + + /* Treasures */ + if ((rnd(100) < (MAXTREAS*100)/(width*length)) && + (mvinch(rp->r_pos.y+j, rp->r_pos.x+i) == FLOOR)) { + item = new_thing(ALL); + attach(lvl_obj, item); + cur = OBJPTR(item); + + mvaddch(trp.y, trp.x, cur->o_type); + cur->o_pos = trp; + } + } + } + + /* + * Do MAXOBJ attempts to put things on a level + */ + for (i = 0; i < MAXOBJ; i++) + if (rnd(100) < 45) { + /* + * Pick a new object and link it in the list + */ + item = new_thing(ALL); + attach(lvl_obj, item); + cur = OBJPTR(item); + /* + * Put it somewhere + */ + cnt = 0; + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &tp); + } until (winat(tp.y, tp.x) == FLOOR || cnt++ > 500); + mvaddch(tp.y, tp.x, cur->o_type); + cur->o_pos = tp; + } +}