select a random monster type, with adjusted difficulty */
| 1656 | |
| 1657 | /* select a random monster type, with adjusted difficulty */ |
| 1658 | struct permonst * |
| 1659 | rndmonst_adj(int minadj, int maxadj) |
| 1660 | { |
| 1661 | struct permonst *ptr; |
| 1662 | int mndx; |
| 1663 | int weight, totalweight, selected_mndx, zlevel, minmlev, maxmlev; |
| 1664 | boolean elemlevel, upper; |
| 1665 | |
| 1666 | if (u.uz.dnum == quest_dnum && rn2(7) && (ptr = qt_montype()) != 0) |
| 1667 | return ptr; |
| 1668 | |
| 1669 | zlevel = level_difficulty(); |
| 1670 | minmlev = monmin_difficulty(zlevel) + minadj; |
| 1671 | maxmlev = monmax_difficulty(zlevel) + maxadj; |
| 1672 | upper = Is_rogue_level(&u.uz); /* prefer uppercase only on rogue level */ |
| 1673 | elemlevel = In_endgame(&u.uz) && !Is_astralevel(&u.uz); /* elmntl plane */ |
| 1674 | |
| 1675 | /* amount processed so far */ |
| 1676 | totalweight = 0; |
| 1677 | selected_mndx = NON_PM; |
| 1678 | |
| 1679 | for (mndx = LOW_PM; mndx < SPECIAL_PM; ++mndx) { |
| 1680 | ptr = &mons[mndx]; |
| 1681 | |
| 1682 | if (montooweak(mndx, minmlev) || montoostrong(mndx, maxmlev)) |
| 1683 | continue; |
| 1684 | if (upper && !isupper(monsym(ptr))) |
| 1685 | continue; |
| 1686 | if (elemlevel && wrong_elem_type(ptr)) |
| 1687 | continue; |
| 1688 | if (uncommon(mndx)) |
| 1689 | continue; |
| 1690 | if (Inhell && (ptr->geno & G_NOHELL)) |
| 1691 | continue; |
| 1692 | |
| 1693 | /* |
| 1694 | * Weighted reservoir sampling: select ptr with a |
| 1695 | * (ptr weight)/(total of all weights so far including ptr's) |
| 1696 | * probability. For example, if the previous total is 10, and |
| 1697 | * this is now looking at acid blobs with a frequency of 2, it |
| 1698 | * has a 2/12 chance of abandoning ptr's previous value in favor |
| 1699 | * of acid blobs, and 10/12 chance of keeping whatever it was. |
| 1700 | * |
| 1701 | * This does not bias results towards either the earlier or the |
| 1702 | * later monsters: the smaller pool and better odds from being |
| 1703 | * earlier are exactly canceled out by having more monsters to |
| 1704 | * potentially steal its spot. |
| 1705 | */ |
| 1706 | weight = (int) (ptr->geno & G_FREQ) + align_shift(ptr); |
| 1707 | weight += temperature_shift(ptr); |
| 1708 | if (weight < 0 || weight > 127) { |
| 1709 | impossible("bad weight in rndmonst for mndx %d", mndx); |
| 1710 | weight = 0; |
| 1711 | } |
| 1712 | /* was unconditional, but if weight==0, rn2() < 0 will always fail; |
| 1713 | also need to avoid rn2(0) if totalweight is still 0 so far */ |
| 1714 | if (weight > 0) { |
| 1715 | totalweight += weight; /* totalweight now guaranteed to be > 0 */ |
no test coverage detected