1 | /* SCCS Id: @(#)mkroom.c 3.3 97/05/25 */ 2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3 | /* NetHack may be freely redistributed. See license for details. */ 4 | 5 | /* 6 | * Entry points: 7 | * mkroom() -- make and stock a room of a given type 8 | * nexttodoor() -- return TRUE if adjacent to a door 9 | * has_dnstairs() -- return TRUE if given room has a down staircase 10 | * has_upstairs() -- return TRUE if given room has an up staircase 11 | * courtmon() -- generate a court monster 12 | * save_rooms() -- save rooms into file fd 13 | * rest_rooms() -- restore rooms from file fd 14 | */ 15 | 16 | #include "hack.h" 17 | 18 | #ifdef OVLB 19 | STATIC_DCL boolean FDECL(isbig, (struct mkroom *)); 20 | STATIC_DCL struct mkroom * FDECL(pick_room,(BOOLEAN_P)); 21 | STATIC_DCL void NDECL(mkshop), FDECL(mkzoo,(int)), NDECL(mkswamp); 22 | STATIC_DCL void NDECL(mktemple); 23 | STATIC_DCL coord * FDECL(shrine_pos, (int)); 24 | STATIC_DCL struct permonst * NDECL(morguemon); 25 | STATIC_DCL struct permonst * NDECL(antholemon); 26 | STATIC_DCL struct permonst * NDECL(squadmon); 27 | STATIC_DCL void FDECL(save_room, (int,struct mkroom *)); 28 | STATIC_DCL void FDECL(rest_room, (int,struct mkroom *)); 29 | #endif /* OVLB */ 30 | 31 | #define sq(x) ((x)*(x)) 32 | 33 | extern const struct shclass shtypes[]; /* defined in shknam.c */ 34 | 35 | #ifdef OVLB 36 | 37 | STATIC_OVL boolean 38 | isbig(sroom) 39 | register struct mkroom *sroom; 40 | { 41 | register int area = (sroom->hx - sroom->lx + 1) 42 | * (sroom->hy - sroom->ly + 1); 43 | return((boolean)( area > 20 )); 44 | } 45 | 46 | void 47 | mkroom(roomtype) 48 | /* make and stock a room of a given type */ 49 | int roomtype; 50 | { 51 | if (roomtype >= SHOPBASE) 52 | mkshop(); /* someday, we should be able to specify shop type */ 53 | else switch(roomtype) { 54 | case COURT: mkzoo(COURT); break; 55 | case ZOO: mkzoo(ZOO); break; 56 | case BEEHIVE: mkzoo(BEEHIVE); break; 57 | case MORGUE: mkzoo(MORGUE); break; 58 | case BARRACKS: mkzoo(BARRACKS); break; 59 | case SWAMP: mkswamp(); break; 60 | case TEMPLE: mktemple(); break; 61 | case LEPREHALL: mkzoo(LEPREHALL); break; 62 | case COCKNEST: mkzoo(COCKNEST); break; 63 | case ANTHOLE: mkzoo(ANTHOLE); break; 64 | default: impossible("Tried to make a room of type %d.", roomtype); 65 | } 66 | } 67 | 68 | STATIC_OVL void 69 | mkshop() 70 | { 71 | register struct mkroom *sroom; 72 | int i = -1; 73 | #ifdef WIZARD 74 | char *ep = (char *)0; /* (init == lint suppression) */ 75 | 76 | /* first determine shoptype */ 77 | if(wizard){ 78 | #ifndef MAC 79 | ep = nh_getenv("SHOPTYPE"); 80 | if(ep){ 81 | if(*ep == 'z' || *ep == 'Z'){ 82 | mkzoo(ZOO); 83 | return; 84 | } 85 | if(*ep == 'm' || *ep == 'M'){ 86 | mkzoo(MORGUE); 87 | return; 88 | } 89 | if(*ep == 'b' || *ep == 'B'){ 90 | mkzoo(BEEHIVE); 91 | return; 92 | } 93 | if(*ep == 't' || *ep == 'T' || *ep == '\\'){ 94 | mkzoo(COURT); 95 | return; 96 | } 97 | if(*ep == 's' || *ep == 'S'){ 98 | mkzoo(BARRACKS); 99 | return; 100 | } 101 | if(*ep == 'a' || *ep == 'A'){ 102 | mkzoo(ANTHOLE); 103 | return; 104 | } 105 | if(*ep == 'c' || *ep == 'C'){ 106 | mkzoo(COCKNEST); 107 | return; 108 | } 109 | if(*ep == 'l' || *ep == 'L'){ 110 | mkzoo(LEPREHALL); 111 | return; 112 | } 113 | if(*ep == '_'){ 114 | mktemple(); 115 | return; 116 | } 117 | if(*ep == '}'){ 118 | mkswamp(); 119 | return; 120 | } 121 | for(i=0; shtypes[i].name; i++) 122 | if(*ep == def_oc_syms[(int)shtypes[i].symb]) 123 | goto gottype; 124 | if(*ep == 'g' || *ep == 'G') 125 | i = 0; 126 | else 127 | i = -1; 128 | } 129 | #endif 130 | } 131 | gottype: 132 | #endif 133 | for(sroom = &rooms[0]; ; sroom++){ 134 | if(sroom->hx < 0) return; 135 | if(sroom - rooms >= nroom) { 136 | pline("rooms not closed by -1?"); 137 | return; 138 | } 139 | if(sroom->rtype != OROOM) continue; 140 | if(has_dnstairs(sroom) || has_upstairs(sroom)) 141 | continue; 142 | if( 143 | #ifdef WIZARD 144 | (wizard && ep && sroom->doorct != 0) || 145 | #endif 146 | sroom->doorct == 1) break; 147 | } 148 | if (!sroom->rlit) { 149 | int x, y; 150 | 151 | for(x = sroom->lx - 1; x <= sroom->hx + 1; x++) 152 | for(y = sroom->ly - 1; y <= sroom->hy + 1; y++) 153 | levl[x][y].lit = 1; 154 | sroom->rlit = 1; 155 | } 156 | 157 | if(i < 0) { /* shoptype not yet determined */ 158 | register int j; 159 | 160 | /* pick a shop type at random */ 161 | for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++) 162 | continue; 163 | 164 | /* big rooms cannot be wand or book shops, 165 | * - so make them general stores 166 | */ 167 | if(isbig(sroom) && (shtypes[i].symb == WAND_CLASS 168 | || shtypes[i].symb == SPBOOK_CLASS)) i = 0; 169 | } 170 | sroom->rtype = SHOPBASE + i; 171 | 172 | /* set room bits before stocking the shop */ 173 | #ifdef SPECIALIZATION 174 | topologize(sroom, FALSE); /* doesn't matter - this is a special room */ 175 | #else 176 | topologize(sroom); 177 | #endif 178 | 179 | /* stock the room with a shopkeeper and artifacts */ 180 | stock_room(i, sroom); 181 | } 182 | 183 | STATIC_OVL struct mkroom * 184 | pick_room(strict) 185 | register boolean strict; 186 | /* pick an unused room, preferably with only one door */ 187 | { 188 | register struct mkroom *sroom; 189 | register int i = nroom; 190 | 191 | for(sroom = &rooms[rn2(nroom)]; i--; sroom++) { 192 | if(sroom == &rooms[nroom]) 193 | sroom = &rooms[0]; 194 | if(sroom->hx < 0) 195 | return (struct mkroom *)0; 196 | if(sroom->rtype != OROOM) continue; 197 | if(!strict) { 198 | if(has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3))) 199 | continue; 200 | } else if(has_upstairs(sroom) || has_dnstairs(sroom)) 201 | continue; 202 | if(sroom->doorct == 1 || !rn2(5) 203 | #ifdef WIZARD 204 | || wizard 205 | #endif 206 | ) 207 | return sroom; 208 | } 209 | return (struct mkroom *)0; 210 | } 211 | 212 | STATIC_OVL void 213 | mkzoo(type) 214 | int type; 215 | { 216 | register struct mkroom *sroom; 217 | 218 | if ((sroom = pick_room(FALSE)) != 0) { 219 | sroom->rtype = type; 220 | fill_zoo(sroom); 221 | } 222 | } 223 | 224 | void 225 | fill_zoo(sroom) 226 | struct mkroom *sroom; 227 | { 228 | struct monst *mon; 229 | register int sx,sy,i; 230 | int sh, tx, ty, goldlim, type = sroom->rtype; 231 | int rmno = (sroom - rooms) + ROOMOFFSET; 232 | coord mm; 233 | 234 | #ifdef GCC_WARN 235 | tx = ty = goldlim = 0; 236 | #endif 237 | 238 | sh = sroom->fdoor; 239 | switch(type) { 240 | case COURT: 241 | if(level.flags.is_maze_lev) { 242 | for(tx = sroom->lx; tx <= sroom->hx; tx++) 243 | for(ty = sroom->ly; ty <= sroom->hy; ty++) 244 | if(IS_THRONE(levl[tx][ty].typ)) 245 | goto throne_placed; 246 | } 247 | i = 100; 248 | do { /* don't place throne on top of stairs */ 249 | (void) somexy(sroom, &mm); 250 | tx = mm.x; ty = mm.y; 251 | } while (occupied((xchar)tx, (xchar)ty) && --i > 0); 252 | throne_placed: 253 | /* TODO: try to ensure the enthroned monster is an M2_PRINCE */ 254 | break; 255 | case BEEHIVE: 256 | tx = sroom->lx + (sroom->hx - sroom->lx + 1)/2; 257 | ty = sroom->ly + (sroom->hy - sroom->ly + 1)/2; 258 | if(sroom->irregular) { 259 | /* center might not be valid, so put queen elsewhere */ 260 | if ((int) levl[tx][ty].roomno != rmno || 261 | levl[tx][ty].edge) { 262 | (void) somexy(sroom, &mm); 263 | tx = mm.x; ty = mm.y; 264 | } 265 | } 266 | break; 267 | case ZOO: 268 | case LEPREHALL: 269 | goldlim = 500 * level_difficulty(); 270 | break; 271 | } 272 | for(sx = sroom->lx; sx <= sroom->hx; sx++) 273 | for(sy = sroom->ly; sy <= sroom->hy; sy++) { 274 | if(sroom->irregular) { 275 | if ((int) levl[sx][sy].roomno != rmno || 276 | levl[sx][sy].edge || 277 | (sroom->doorct && 278 | distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)) 279 | continue; 280 | } else if(!SPACE_POS(levl[sx][sy].typ) || 281 | (sroom->doorct && 282 | ((sx == sroom->lx && doors[sh].x == sx-1) || 283 | (sx == sroom->hx && doors[sh].x == sx+1) || 284 | (sy == sroom->ly && doors[sh].y == sy-1) || 285 | (sy == sroom->hy && doors[sh].y == sy+1)))) 286 | continue; 287 | /* don't place monster on explicitly placed throne */ 288 | if(type == COURT && IS_THRONE(levl[sx][sy].typ)) 289 | continue; 290 | mon = makemon( 291 | (type == COURT) ? courtmon() : 292 | (type == BARRACKS) ? squadmon() : 293 | (type == MORGUE) ? morguemon() : 294 | (type == BEEHIVE) ? 295 | (sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] : 296 | &mons[PM_KILLER_BEE]) : 297 | (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] : 298 | (type == COCKNEST) ? &mons[PM_COCKATRICE] : 299 | (type == ANTHOLE) ? antholemon() : 300 | (struct permonst *) 0, 301 | sx, sy, NO_MM_FLAGS); 302 | if(mon) { 303 | mon->msleeping = 1; 304 | if (type==COURT && mon->mpeaceful) { 305 | mon->mpeaceful = 0; 306 | set_malign(mon); 307 | } 308 | } 309 | switch(type) { 310 | case ZOO: 311 | case LEPREHALL: 312 | if(sroom->doorct) 313 | { 314 | int distval = dist2(sx,sy,doors[sh].x,doors[sh].y); 315 | i = sq(distval); 316 | } 317 | else 318 | i = goldlim; 319 | if(i >= goldlim) i = 5*level_difficulty(); 320 | goldlim -= i; 321 | (void) mkgold((long) rn1(i, 10), sx, sy); 322 | break; 323 | case MORGUE: 324 | if(!rn2(5)) 325 | (void) mk_tt_object(CORPSE, sx, sy); 326 | if(!rn2(10)) /* lots of treasure buried with dead */ 327 | (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, 328 | sx, sy, TRUE); 329 | if (!rn2(5)) 330 | make_grave(sx, sy, (char *)0); 331 | break; 332 | case BEEHIVE: 333 | if(!rn2(3)) 334 | (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE); 335 | break; 336 | case BARRACKS: 337 | if(!rn2(20)) /* the payroll and some loot */ 338 | (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, 339 | sx, sy, TRUE); 340 | break; 341 | case COCKNEST: 342 | if(!rn2(3)) { 343 | struct obj *sobj = mk_tt_object(STATUE, sx, sy); 344 | 345 | if (sobj) 346 | for (i = rn2(5); i; i--) 347 | add_to_container(sobj, mkobj(RANDOM_CLASS, FALSE)); 348 | } 349 | break; 350 | case ANTHOLE: 351 | if(!rn2(3)) 352 | (void) mkobj_at(FOOD_CLASS, sx, sy, TRUE); 353 | break; 354 | } 355 | } 356 | switch (type) { 357 | case COURT: 358 | { 359 | struct obj *chest; 360 | levl[tx][ty].typ = THRONE; 361 | (void) somexy(sroom, &mm); 362 | (void) mkgold((long) rn1(50 * level_difficulty(),10), mm.x, mm.y); 363 | chest = mksobj_at(CHEST, mm.x, mm.y, TRUE); /* the royal coffers */ 364 | chest->spe = 2; /* so it can be found later */ 365 | level.flags.has_court = 1; 366 | break; 367 | } 368 | case BARRACKS: 369 | level.flags.has_barracks = 1; 370 | break; 371 | case ZOO: 372 | level.flags.has_zoo = 1; 373 | break; 374 | case MORGUE: 375 | level.flags.has_morgue = 1; 376 | break; 377 | case SWAMP: 378 | level.flags.has_swamp = 1; 379 | break; 380 | case BEEHIVE: 381 | level.flags.has_beehive = 1; 382 | break; 383 | } 384 | } 385 | 386 | /* make a swarm of undead around mm */ 387 | void 388 | mkundead(mm, revive_corpses, mm_flags) 389 | coord *mm; 390 | boolean revive_corpses; 391 | int mm_flags; 392 | { 393 | int cnt = (level_difficulty() + 1)/10 + rnd(5); 394 | struct permonst *mdat; 395 | struct obj *otmp; 396 | coord cc; 397 | 398 | while (cnt--) { 399 | mdat = morguemon(); 400 | if (enexto(&cc, mm->x, mm->y, mdat) && 401 | (!revive_corpses || 402 | !(otmp = sobj_at(CORPSE, cc.x, cc.y)) || 403 | !revive(otmp))) 404 | (void) makemon(mdat, cc.x, cc.y, mm_flags); 405 | } 406 | level.flags.graveyard = TRUE; /* reduced chance for undead corpse */ 407 | } 408 | 409 | STATIC_OVL struct permonst * 410 | morguemon() 411 | { 412 | register int i = rn2(100), hd = rn2(level_difficulty()); 413 | 414 | if(hd > 10 && i < 10) 415 | return((Inhell || In_endgame(&u.uz)) ? mkclass(S_DEMON,0) : 416 | &mons[ndemon(A_NONE)]); 417 | if(hd > 8 && i > 85) 418 | return(mkclass(S_VAMPIRE,0)); 419 | 420 | return((i < 20) ? &mons[PM_GHOST] 421 | : (i < 40) ? &mons[PM_WRAITH] : mkclass(S_ZOMBIE,0)); 422 | } 423 | 424 | STATIC_OVL struct permonst * 425 | antholemon() 426 | { 427 | int mtyp; 428 | 429 | /* Same monsters within a level, different ones between levels */ 430 | switch ((level_difficulty() + ((long)u.ubirthday)) % 3) { 431 | default: mtyp = PM_GIANT_ANT; break; 432 | case 0: mtyp = PM_SOLDIER_ANT; break; 433 | case 1: mtyp = PM_FIRE_ANT; break; 434 | } 435 | return ((mvitals[mtyp].mvflags & G_GONE) ? 436 | (struct permonst *)0 : &mons[mtyp]); 437 | } 438 | 439 | STATIC_OVL void 440 | mkswamp() /* Michiel Huisjes & Fred de Wilde */ 441 | { 442 | register struct mkroom *sroom; 443 | register int sx,sy,i,eelct = 0; 444 | 445 | for(i=0; i<5; i++) { /* turn up to 5 rooms swampy */ 446 | sroom = &rooms[rn2(nroom)]; 447 | if(sroom->hx < 0 || sroom->rtype != OROOM || 448 | has_upstairs(sroom) || has_dnstairs(sroom)) 449 | continue; 450 | 451 | /* satisfied; make a swamp */ 452 | sroom->rtype = SWAMP; 453 | for(sx = sroom->lx; sx <= sroom->hx; sx++) 454 | for(sy = sroom->ly; sy <= sroom->hy; sy++) 455 | if(!OBJ_AT(sx, sy) && 456 | !MON_AT(sx, sy) && !t_at(sx,sy) && !nexttodoor(sx,sy)) { 457 | if((sx+sy)%2) { 458 | levl[sx][sy].typ = POOL; 459 | if(!eelct || !rn2(4)) { 460 | /* mkclass() won't do, as we might get kraken */ 461 | (void) makemon(rn2(5) ? &mons[PM_GIANT_EEL] 462 | : rn2(2) ? &mons[PM_PIRANHA] 463 | : &mons[PM_ELECTRIC_EEL], 464 | sx, sy, NO_MM_FLAGS); 465 | eelct++; 466 | } 467 | } else 468 | if(!rn2(4)) /* swamps tend to be moldy */ 469 | (void) makemon(mkclass(S_FUNGUS,0), 470 | sx, sy, NO_MM_FLAGS); 471 | } 472 | level.flags.has_swamp = 1; 473 | } 474 | } 475 | 476 | STATIC_OVL coord * 477 | shrine_pos(roomno) 478 | int roomno; 479 | { 480 | static coord buf; 481 | struct mkroom *troom = &rooms[roomno - ROOMOFFSET]; 482 | 483 | buf.x = troom->lx + ((troom->hx - troom->lx) / 2); 484 | buf.y = troom->ly + ((troom->hy - troom->ly) / 2); 485 | return(&buf); 486 | } 487 | 488 | STATIC_OVL void 489 | mktemple() 490 | { 491 | register struct mkroom *sroom; 492 | coord *shrine_spot; 493 | register struct rm *lev; 494 | 495 | if(!(sroom = pick_room(TRUE))) return; 496 | 497 | /* set up Priest and shrine */ 498 | sroom->rtype = TEMPLE; 499 | /* 500 | * In temples, shrines are blessed altars 501 | * located in the center of the room 502 | */ 503 | shrine_spot = shrine_pos((sroom - rooms) + ROOMOFFSET); 504 | lev = &levl[shrine_spot->x][shrine_spot->y]; 505 | lev->typ = ALTAR; 506 | lev->altarmask = induced_align(80); 507 | priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE); 508 | lev->altarmask |= AM_SHRINE; 509 | level.flags.has_temple = 1; 510 | } 511 | 512 | boolean 513 | nexttodoor(sx,sy) 514 | register int sx, sy; 515 | { 516 | register int dx, dy; 517 | register struct rm *lev; 518 | for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) { 519 | if(!isok(sx+dx, sy+dy)) continue; 520 | if(IS_DOOR((lev = &levl[sx+dx][sy+dy])->typ) || 521 | lev->typ == SDOOR) 522 | return(TRUE); 523 | } 524 | return(FALSE); 525 | } 526 | 527 | boolean 528 | has_dnstairs(sroom) 529 | register struct mkroom *sroom; 530 | { 531 | if (sroom == dnstairs_room) 532 | return TRUE; 533 | if (sstairs.sx && !sstairs.up) 534 | return((boolean)(sroom == sstairs_room)); 535 | return FALSE; 536 | } 537 | 538 | boolean 539 | has_upstairs(sroom) 540 | register struct mkroom *sroom; 541 | { 542 | if (sroom == upstairs_room) 543 | return TRUE; 544 | if (sstairs.sx && sstairs.up) 545 | return((boolean)(sroom == sstairs_room)); 546 | return FALSE; 547 | } 548 | 549 | #endif /* OVLB */ 550 | #ifdef OVL0 551 | 552 | int 553 | somex(croom) 554 | register struct mkroom *croom; 555 | { 556 | return rn2(croom->hx-croom->lx+1) + croom->lx; 557 | } 558 | 559 | int 560 | somey(croom) 561 | register struct mkroom *croom; 562 | { 563 | return rn2(croom->hy-croom->ly+1) + croom->ly; 564 | } 565 | 566 | boolean 567 | inside_room(croom, x, y) 568 | struct mkroom *croom; 569 | xchar x, y; 570 | { 571 | return((boolean)(x >= croom->lx-1 && x <= croom->hx+1 && 572 | y >= croom->ly-1 && y <= croom->hy+1)); 573 | } 574 | 575 | boolean 576 | somexy(croom, c) 577 | struct mkroom *croom; 578 | coord *c; 579 | { 580 | int try_cnt = 0; 581 | int i; 582 | 583 | if (croom->irregular) { 584 | i = (croom - rooms) + ROOMOFFSET; 585 | 586 | while(try_cnt++ < 100) { 587 | c->x = somex(croom); 588 | c->y = somey(croom); 589 | if (!levl[c->x][c->y].edge && 590 | (int) levl[c->x][c->y].roomno == i) 591 | return TRUE; 592 | } 593 | /* try harder; exhaustively search until one is found */ 594 | for(c->x = croom->lx; c->x <= croom->hx; c->x++) 595 | for(c->y = croom->ly; c->y <= croom->hy; c->y++) 596 | if (!levl[c->x][c->y].edge && 597 | (int) levl[c->x][c->y].roomno == i) 598 | return TRUE; 599 | return FALSE; 600 | } 601 | 602 | if (!croom->nsubrooms) { 603 | c->x = somex(croom); 604 | c->y = somey(croom); 605 | return TRUE; 606 | } 607 | 608 | /* Check that coords doesn't fall into a subroom or into a wall */ 609 | 610 | while(try_cnt++ < 100) { 611 | c->x = somex(croom); 612 | c->y = somey(croom); 613 | if (IS_WALL(levl[c->x][c->y].typ)) 614 | continue; 615 | for(i=0 ; i<croom->nsubrooms;i++) 616 | if(inside_room(croom->sbrooms[i], c->x, c->y)) 617 | goto you_lose; 618 | break; 619 | you_lose: ; 620 | } 621 | if (try_cnt >= 100) 622 | return FALSE; 623 | return TRUE; 624 | } 625 | 626 | /* 627 | * Search for a special room given its type (zoo, court, etc...) 628 | * Special values : 629 | * - ANY_SHOP 630 | * - ANY_TYPE 631 | */ 632 | 633 | struct mkroom * 634 | search_special(type) 635 | schar type; 636 | { 637 | register struct mkroom *croom; 638 | 639 | for(croom = &rooms[0]; croom->hx >= 0; croom++) 640 | if((type == ANY_TYPE && croom->rtype != OROOM) || 641 | (type == ANY_SHOP && croom->rtype >= SHOPBASE) || 642 | croom->rtype == type) 643 | return croom; 644 | for(croom = &subrooms[0]; croom->hx >= 0; croom++) 645 | if((type == ANY_TYPE && croom->rtype != OROOM) || 646 | (type == ANY_SHOP && croom->rtype >= SHOPBASE) || 647 | croom->rtype == type) 648 | return croom; 649 | return (struct mkroom *) 0; 650 | } 651 | 652 | #endif /* OVL0 */ 653 | #ifdef OVLB 654 | 655 | struct permonst * 656 | courtmon() 657 | { 658 | int i = rn2(60) + rn2(3*level_difficulty()); 659 | if (i > 100) return(mkclass(S_DRAGON,0)); 660 | else if (i > 95) return(mkclass(S_GIANT,0)); 661 | else if (i > 85) return(mkclass(S_TROLL,0)); 662 | else if (i > 75) return(mkclass(S_CENTAUR,0)); 663 | else if (i > 60) return(mkclass(S_ORC,0)); 664 | else if (i > 45) return(&mons[PM_BUGBEAR]); 665 | else if (i > 30) return(&mons[PM_HOBGOBLIN]); 666 | else if (i > 15) return(mkclass(S_GNOME,0)); 667 | else return(mkclass(S_KOBOLD,0)); 668 | } 669 | 670 | #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1) 671 | 672 | static struct { 673 | unsigned pm; 674 | unsigned prob; 675 | } squadprob[NSTYPES] = { 676 | {PM_SOLDIER, 80}, {PM_SERGEANT, 15}, {PM_LIEUTENANT, 4}, {PM_CAPTAIN, 1} 677 | }; 678 | 679 | STATIC_OVL struct permonst * 680 | squadmon() /* return soldier types. */ 681 | { 682 | int sel_prob, i, cpro, mndx; 683 | 684 | sel_prob = rnd(80+level_difficulty()); 685 | 686 | cpro = 0; 687 | for (i = 0; i < NSTYPES; i++) { 688 | cpro += squadprob[i].prob; 689 | if (cpro > sel_prob) { 690 | mndx = squadprob[i].pm; 691 | goto gotone; 692 | } 693 | } 694 | mndx = squadprob[rn2(NSTYPES)].pm; 695 | gotone: 696 | if (!(mvitals[mndx].mvflags & G_GONE)) return(&mons[mndx]); 697 | else return((struct permonst *) 0); 698 | } 699 | 700 | /* 701 | * save_room : A recursive function that saves a room and its subrooms 702 | * (if any). 703 | */ 704 | 705 | STATIC_OVL void 706 | save_room(fd, r) 707 | int fd; 708 | struct mkroom *r; 709 | { 710 | short i; 711 | /* 712 | * Well, I really should write only useful information instead 713 | * of writing the whole structure. That is I should not write 714 | * the subrooms pointers, but who cares ? 715 | */ 716 | bwrite(fd, (genericptr_t) r, sizeof(struct mkroom)); 717 | for(i=0; i<r->nsubrooms; i++) 718 | save_room(fd, r->sbrooms[i]); 719 | } 720 | 721 | /* 722 | * save_rooms : Save all the rooms on disk! 723 | */ 724 | 725 | void 726 | save_rooms(fd) 727 | int fd; 728 | { 729 | short i; 730 | 731 | /* First, write the number of rooms */ 732 | bwrite(fd, (genericptr_t) &nroom, sizeof(nroom)); 733 | for(i=0; i<nroom; i++) 734 | save_room(fd, &rooms[i]); 735 | } 736 | 737 | STATIC_OVL void 738 | rest_room(fd, r) 739 | int fd; 740 | struct mkroom *r; 741 | { 742 | short i; 743 | 744 | mread(fd, (genericptr_t) r, sizeof(struct mkroom)); 745 | for(i=0; i<r->nsubrooms; i++) { 746 | r->sbrooms[i] = &subrooms[nsubroom]; 747 | rest_room(fd, &subrooms[nsubroom]); 748 | subrooms[nsubroom++].resident = (struct monst *)0; 749 | } 750 | } 751 | 752 | /* 753 | * rest_rooms : That's for restoring rooms. Read the rooms structure from 754 | * the disk. 755 | */ 756 | 757 | void 758 | rest_rooms(fd) 759 | int fd; 760 | { 761 | short i; 762 | 763 | mread(fd, (genericptr_t) &nroom, sizeof(nroom)); 764 | nsubroom = 0; 765 | for(i = 0; i<nroom; i++) { 766 | rest_room(fd, &rooms[i]); 767 | rooms[i].resident = (struct monst *)0; 768 | } 769 | rooms[nroom].hx = -1; /* restore ending flags */ 770 | subrooms[nsubroom].hx = -1; 771 | } 772 | #endif /* OVLB */ 773 | 774 | /*mkroom.c*/