Mercurial > hg > early-roguelike
view xrogue/n_level.c @ 265:7fcb2f9f57e6
Mention UltraRogue in the top-level README.
author | John "Elwin" Edwards |
---|---|
date | Sun, 19 Feb 2017 19:54:17 -0500 |
parents | f54901b9c39b |
children | e52a8a7ad4c5 |
line wrap: on
line source
/* n_level.c - Dig and draw a new level XRogue: Expeditions into the Dungeons of Doom Copyright (C) 1991 Robert Pietkivitch All rights reserved. Based on "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 void put_things(LEVTYPE ltype); /* * new_level: * Dig and draw a new level * ltype: designates type of level to create */ void new_level(LEVTYPE ltype) { register int rm = 0, i, cnt; register unsigned 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: %ld", 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+20 + rnd(51); 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) == HORZWALL) vert = TRUE; else vert = FALSE; if (level < 1) { fresh = TRUE; starty = 2; startx = 1; deltay = deltax = 1; level = max_level; /* Restore level to deepest attempt */ prev_max = level; /* reset for boundary crossings below */ } else if (level >= 1 && prev_max == 1000) { fresh = TRUE; starty = 2; startx = 1; deltay = deltax = 1; prev_max = level; /* reset for boundary crossings below */ } else { /* Copy several lines of the terrain to the other end */ unsigned char cch; /* Copy character */ if (wizard) msg("Crossing sector boundary "); /* 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 = mvinch(i+2, j); mvaddch(lines-6+i, j, cch); } else { cch = mvinch(lines-4-i, j); mvaddch(4-i, j, cch); } } else for (j=2; j<lines-3; j++) { if (top) { cch = mvinch(j, i+1); mvaddch(j, cols-4+i, cch); } else { cch = 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; } } /* * If the monster is busy chasing another monster, don't save * it */ if (tp->t_dest && tp->t_dest != &hero) continue; /* Outside has plenty of monsters, don't need these. * 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 || levtype != OUTSIDE) 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(mlist); o_free_list(lvl_obj); /* Free up previous objects (if any) */ for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) r_free_list(rp->r_exit); /* Free up the exit lists */ levtype = ltype; foods_this_level = 0; /* food for hero this level */ /* What kind of level are we on? */ if (ltype == POSTLEV || ltype == STARTLEV) { if (ltype == POSTLEV) do_post(FALSE); /* Trading post */ else do_post(TRUE); /* Equipage */ levtype = ltype = POSTLEV; } else if (ltype == MAZELEV) { do_maze(); no_food++; put_things(ltype); /* Place objects (if any) */ } else if (ltype == OUTSIDE) { /* Move the cursor back onto the hero */ wmove(cw, hero.y, hero.x); 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, 5) == 5) { cnt = 0; do { rm = rnd_room(); rnd_pos(&rooms[rm], &stairs); } until (mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 2500); addch(STAIRS); } /* * maybe add a trading post */ if (level > 5 && rnd(10) == 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++ > 2500); 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++ > 2500 || 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 = 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(tlist, item); turn_off(*tp,ISELSEWHERE); 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 = 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)+2; 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++ > 2500); traps[i].tr_flags = 0; /* If we are at the bottom, we can't set a trap door */ if (level >= nfloors) ch = (unsigned char) rnd(8) + 1; else ch = (unsigned char) rnd(9); 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; when 8: ch = WORMHOLE; } addch(ch); traps[i].tr_type = ch; traps[i].tr_show = FLOOR; traps[i].tr_pos = stairs; } } } if (fresh) { /* A whole new picture */ /* * try to find a room for the hero. The objective here is to: * --> don't put him in a treasure room * --> don't put him on an object * --> try not to put him next to the stairs */ cnt = 2500; do { if (ltype != OUTSIDE) rm = rnd_room(); else continue; if (rooms[rm].r_flags & ISTREAS) continue; rnd_pos(&rooms[rm], &hero); } until( cnt-- == 0 || (winat(hero.y, hero.x) == FLOOR && DISTANCE(hero.y, hero.x, stairs.y, stairs.x) > cnt/10)); } 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(TRUE, TRUE); /* affect all charactors */ /* * If player is moving up or above his deepest point, wake up any * non-uniques */ else if (level < cur_max) { aggravate(FALSE, FALSE); } light(&hero); wmove(cw, hero.y, hero.x); waddch(cw, PLAYER); if (level > cur_max) cur_max = level; draw(cw); status(TRUE); /* Do we sense any food on this level? */ if (cur_relic[SURTUR_RING]) quaff(P_FFIND, 0, 0, FALSE); } /* * Pick a room that is really there */ int rnd_room(void) { 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 * ltype: designates type of level to create */ void put_things(LEVTYPE ltype) { register int i, rm, cnt; register struct object *cur; register struct linked_list *item, *nextitem, *exitptr; int length, width; int ITEMS = 0; /* number of items to place */ coord tp, *exit; /* * The only way to get new stuff is to go down into the dungeon. */ if (level < cur_max) { if (ltype == NORMLEV) return; } if (ltype == OUTSIDE) goto jmp_here; /* a jump for outside */ /* * There is a chance that there is a Treasure Room on this level */ if (ltype == NORMLEV && rnd(150) < level) { register int 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 = nextitem) { register struct thing *tp; tp = THINGPTR(item); nextitem = next(item); if (rp == roomin(&tp->t_pos)) { /* * Don't let nice creatures be generated in a treasure * room. */ if ((player.t_ctype==C_PALADIN || player.t_ctype==C_RANGER || player.t_ctype==C_MONK) && off(*tp, ISMEAN)) { int index; if (on(*tp, ISUNIQUE)) index = tp->t_index; else index = -1; /* Get rid of the monster */ killed(item, FALSE, FALSE, FALSE); /* Restore uniques back in the table */ if (index != -1) monsters[index].m_normal = TRUE; continue; } turn_on(*tp, ISMEAN); turn_on(*tp, ISGUARDIAN); } } /* 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; /* * Put it there and leave it asleep. Wake the monsters * when the player enters the room. Hopefully, all bases * are covered as far as the ways to get in. This way * cpu time is not wasted on the awake monsters that * can't get to the player anyway. * try not to put any UNIQUEs in a treasure room. * note that they may have put put in already by the * non-treasure room code. * also, try not to put ISMEAN monsters in a treasure * room as these are supposed to be non-hostile until * attacked. It also makes life simpler for the ranger, * paladin, and monk. */ for(;;) { item = new_item(sizeof *tp); /* Make a monster */ tp = THINGPTR(item); new_monster(item,randmonster(FALSE, TRUE),&trp,TRUE); 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; } /* * only picky for these classes */ if (player.t_ctype != C_RANGER && player.t_ctype != C_PALADIN && player.t_ctype != C_MONK) break; if (on(*tp, ISMEAN)) break; killed (item, FALSE, FALSE, FALSE); } if (on(*tp, ISUNIQUE)) { /* just in case */ carry_obj(tp, monsters[tp->t_index].m_carry); tp->t_no_move = movement(tp); } turn_on(*tp, ISGUARDIAN); } /* Treasures */ if ((rnd(100) < (MAXTREAS*100)/(width*length)) && (mvinch(rp->r_pos.y+j, rp->r_pos.x+i) == FLOOR)) { item = new_thing(ALL, TRUE); attach(lvl_obj, item); cur = OBJPTR(item); mvaddch(trp.y, trp.x, cur->o_type); cur->o_pos = trp; } } } jmp_here: /* outside jumper for equippage */ /* * Do ITEMS attempts to put things in dungeon, maze, or outside */ if (ltype == OUTSIDE) ITEMS = rnd(15)+1; else if (ltype == MAZELEV) ITEMS = rnd(20)+1; else ITEMS = MAXOBJ + rnd(4); for (i = 0; i < ITEMS; i++) if (rnd(100) < 65) { /* * Pick a new object and link it in the list */ item = new_thing(ALL, TRUE); attach(lvl_obj, item); cur = OBJPTR(item); /* * Put it somewhere */ cnt = 0; do { if (ltype == OUTSIDE) rm = 0; else rm = rnd_room(); rnd_pos(&rooms[rm], &tp); } until (winat(tp.y, tp.x) == FLOOR || cnt++ > 2500); mvaddch(tp.y, tp.x, cur->o_type); cur->o_pos = tp; } }