comparison arogue7/new_level.c @ 125:adfa37e67084

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