comparison xrogue/n_level.c @ 133:e6179860cb76

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