Mercurial > hg > early-roguelike
view arogue5/new_level.c @ 313:2f75940cc544
Advanced Rogue 7: fix a string literal overwrite.
pick_spell() attempted to capitalize type by overwriting the first
character, changing it back later. All calls of pick_spell passed a
string literal as type, and string literals should be considered
immutable.
This has been fixed by using a separate variable for the capitalized
first character. XRogue already has a similar fix.
Reported by John Harris of @Play.
author | John "Elwin" Edwards |
---|---|
date | Tue, 19 Oct 2021 20:39:00 -0400 |
parents | 56e748983fa8 |
children |
line wrap: on
line source
/* * 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 void put_things(LEVTYPE ltype); /* ltype designates type of level to create */ void new_level(LEVTYPE ltype) { 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 */ 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, *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 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 = 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; } }