New: colour.cc, coord.cc, coordit.cc, random.cc, rng.cc.
LUSG5HYFRMFNS3RACRCUJNQXJNXPL4SYKHHOIEG5RBQG2DKQXPDAC
7FIX6VVO7QUIPJVX7K5LOSD7MON3KY6GJH3USKOT566ZWACVJMZAC
DXBPUEUNPDXUWFR5ZK5LYFDZJFNKGNCPOGEQNO6TTFSBHOFH6H6QC
EIWZGID56VJJUOTCZH3OBLXMS7GWCBFOKRL2QIZ2JRLXPEEBAUIAC
QPM2SLQPKICB7SP6PIPEWPD2SMFF3NUSDLMCWSWWSJJWQCPBKWOAC
PQYSVXOLM6L4OGWQNXUHXXNUXJ33TTS36TIVHRPKMYQHQY42EBNQC
DKYR3HEORWRCTEUA525ZBPUAWS5B6VFV5CCIGGVDH5NG6YA4D3ZAC
SDGK6QEAHVCMRJVWSHZUECXXC5ZSJ2PQYTZWN3KX5UQFGAWI4Q3AC
P5HXZFSDGCYC5L7FY7VATY74WFLGYL4WAERPGTO2P64EURULMV4QC
CLO5METZJ4WBV3KWGW3WJ4WY5NYWCOHCGEIMJU4NYWKECWQ536QAC
QAD5QRQDRHBP2SKJXPYAHIJOUUBXQTJEAMJUU274I3UY2WW7FEXQC
XHKAHAVDZIGGXNA442YKWKCTSSIRFTXOIOFYLYEJAR36H7DLD2ZQC
NT5SNG44MU2JRBQA55TR27YDMA6SMKAP2ANDCROS3T2IL7ATLFUAC
KHIL64HDOAMK3KGECPUPQFUOZ76G2J7M5BSQR2YUBYCHB4DZ6V3QC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
SQKPN77WI7ZTJPVBVGLFGVH6OPDMOKLI6A4PEW6ULHFETJLFJNGAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
BR6HF3PWCXUG24OBIWTCZ64DDVBA2G6BQBDJ5V5WMARRQBG2CLGQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC
NLQNXH3SVJ52CWXEV35FSSZP32VHC4QFGN3HINF4KO5GZHZMOBKQC
HQTS3VQ6PNUZKHNVEWMML7JNAAAKL4DSW3KFSRCCSLGYTDHZFCCAC
7NDXS36TE7QVXTXJWMYSVG5UHCCLPIO4VL6NXFGTDK3ZNKE3A2IAC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
IAAPG4VMQN6O4CZYNR5QA7MXWVII5USVV2HRX2MDAF2GLDGRUZGAC
TFZ4TER7O2Z4FOGF2RCPEPYIHBTUA4LG3ECXLR7XGLCC6GO6OOTAC
BBQWA33DPXWEDYOOPO45VAYD4JQDZQVMZSEJ4RUI5LLC733IMIIQC
Q3B3UVMYEVC4YJUPYVSNTR4DJH4E6J4JJDHZNT5LNOCHCPPMEMXAC
F7X6HVUKHZXYURABYAZJHRYBV7UZTIPOWJMGCMDK26FQ66WGKFZAC
QEEJFAETO6B2J4IWDIDCJ5UNIFNNHHG22IWF2CUJRTJJBNE47CWQC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
6BYKOHEMLXXUKTH56UHJ6YQ6VWQCBWSSTCXFDT33RNID4G4ZUIKQC
FIYBXLWALQINNQTHG2KNDUUTAQAZRDDLXW2XOVSKDKBADJ3XCJ4AC
OVYFNBS6TZ7DGYA3TYM7N244T4M6JE6ISAPOZKOMRRAQEEIVPXBQC
UADYVV3UD5ERJTZZJGY4EUQ4NJ2JSBG7YYUJ75ZRBIXRQXQKOJPAC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
22YVHM74WBJNJE4PA5CBEUTDWM6FAGGGILI26A4LXAURX55TNRKAC
QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC
5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC
JK3HFJG76OOQHJMXJUSZRTR5CX5ZMS52LRVBLOR7E2NBI6PRSHHAC
KZWOHH536QBWAPWROR32EOXEK5LRY6I5VHVL7HHI7GOFKCMQTCSQC
5XNQ3SSNBFXFNWA6DPM74W6FH65NX665P3DMH6YCWVFOPZTJSYCQC
VJDLV4PF2ZJ46NERO4LZUX5JE2CD5XBOBQCYYPTFWTHLUEYDUOYAC
GF5VGZLKKWIATLVLTUJR4LVEQZAKR7CWMLNFMJXA67WLHP7JNUUAC
MV5USMLTBKVRWBAD67UFJ2BS4Y5HEOMYASRSB44DS24BBMRP75RQC
RIW55YSFKKTJLBTOJRVUBC7JOFUBOK7OBMISW4PBSVLYJHAAKPPQC
AXRXY7RSEN3QHQRK6SFEH2OZAAYJRR5RBBBFF4YJF756V2FPFJ3AC
LUH6GAJODIQXNPBEHMSUTKH3KA3DYVRCKZ6GJJ4HHNHOIMMUEP6QC
VQZEJTCSRZ5RVLCCKUCIS3IVZPFYRC26I74X4WIJAPEY7NYID2UQC
YTIPWYSKK63WIUKVYLCD2WQUYIBW4R57653MOCJWIKNIFCNHA2DQC
TADKPTKH3CWXZRGVDWOY3CMAQ6CQISITDYB4F27YU53U5XEB6NVAC
GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
OMAUFQNBWGX4FDABHQCVPGDYRVKMDASGQJVRH7AOPPEMHAP2LQSQC
B7DNCNY7SXL5WAW5B3XZP5KIQSBWOJ3N2YW46WOUQKTRBRRZ7YOQC
YKVVFNKT2M5WG2KBURRTOJG23BJVI6WUBP5JOGYPHQBS4RNGFGWQC
TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC
KZNUAHJQUBM6MEVUSSWG734AXZ3NZYMRJ2XFQLRGXJ3MSTBV7ELQC
4OKEEU32EGHIDAJ75GH3USSQHQPZBDZVC7TOP7ALMHZRUFPE5WEQC
X7TRUBJTRDVUI53BROBYHF4UDC4I5SUYWBUOGQMZNN2WEZAFVGVQC
WQLOHSNCA3VOMDJF6IINJYKSYVYZEBPJJWBB33QSNE4RP5HEXPMAC
UKN6HTZXDUUOWKNWNKWPHKGUGL474JIAQN5JU3DM3DU26WGMNP4AC
CCRQESB4ADT4WA7FGLNZZXAJ6G5QMCTYCZIWORBN45P6ZPILC34AC
SOCJXX6MMOXLBEWBID4QN5FW2YNYULNNN7K3IRL7RSWK5EUNAZLQC
BAQ5ZQ3XMXTITZIDAGMES65SE6Y7VQYASNMTYPL3OOJEG4YMGVPAC
L6YPJVODN32IYLEZQQZE2ENH3XDAZ63IQIDX3PB4CJEK3A4NUNSAC
Y56C5OMUQ5XF2G6DKDV4R5MED44UOIUPTBBQVWQBUHYIXYA5MOZAC
7JMN4TTOB7J56UAHT47USGLXARDHDEB7SYIHA5QTGMDX3AZ6ZCSQC
J7GPW2YXLT6FGSKJ24FGQ24GTRZ6A2BDYM6CIXV4R6YBEHP6BGPAC
MPMVK6J5UQUFJ75SNRSPIBBSRTH67ZPDZKPZUF3RZRFKSERS62AAC
IHV7JHD4E67NEGLZEO3FPQGJPJF3IAV6QV5A63FPG4SU2VRFV47QC
BMXIXQKM2247TENYZSOULFAT6VSZJNGGFBQ3SN7IOM4ROQRVTHZAC
HBABF6EDHS4K7QKQU6NM3L3FDIZN3N345MN4KFGHY7XGTX34TPIQC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
5KTPCJG42MF2B34CEH6VXAJIOZR6QOS2BWYNW7DXM3WA7N3GH4HQC
SFWCESFCUEVKJ6ZQQX3Y5YTIQD5BC6MCVSLVZFRGRTU46BFLKKWAC
S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC
TQXNC2YQVJZXBPSLDEANMM2EDGHTH4DSN74OJIRMUF7D46SESHZAC
UIVESOFZ4C262RYTFHSTFZIYTPTWSRJCFJAOZX7O2PQ35DFRDDEAC
JZ4YC57SR2WQJIEIZSO3ZECA2FNMQUB7JYFKID4SIQ3RQ5NYXIVAC
C7MS2OSFVKCD7M7H5WKFAX3WXAWK4O3JULA56WPSXFXE22XB4QSQC
4C6O4H7IO3LDZPBDGRST3QUFKMNQRB4Y6JXUV3NKIJVVPLAA2AWQC
4J2ILW7DGFLSRYX2TF4OYWN3WNJSQXC647MQGGIOBC63MPF4TXKAC
UANJI74DZW4MVGWK53MAZ667HAARWAURFOHKFBPSW4OFZ4C6LPCQC
XKL3ATYU6YNHKOGQCVJVQR7YG2I6KPYGWUNICZ7NSDKLNM4UGK3AC
YTRHJZ4YBCNEI4UY4AGEIVKY66C7IJZ7ESFLXTULTSWV4KF5DG3QC
VS246W2SVNBUAI5SZE3RS5WPQWLEYXHHJHFXP45BZO76CB56NI6QC
4HATGRJJE7Q6LXHJ3ZGYTNBLG542KAUEK6ERKARIYRKRWY6VTDKQC
5T2S4AV7WKL22RUZBMQMOSDQ5JRXPA74SMNQEZWXYMLPI7PB7R7QC
YVQMLXJPDEBW7VXLTVXRUHSR66233VUWCXIYLUTERUBBMBMPSIIQC
4VK7VHWRVRO66BRSGTBPSYJGGXLRF6AG6G74UDTPHTPXR7ZRNINQC
ZP2KE7A2LE7Z2S7AC45WE4CXDSEVDTWIMV2EM4IBUKXYJIDU6R7QC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
FG6S2SNKFZWJK7PYHASHXU32ORYBOLGFL5RWQVDJ47MFVS4VMQHQC
IVVTHLTTLOP5TSULXJWUSSXHOKYWVU3OWKYVK45A7RIB6V34MYQAC
RWH6IAVXQD3Q7ITNN5WOOUHBDBYURLXFEURA7QFHS4ZED2CG7MOQC
OE3TD4J5FSIFAM37J2UPEV7QQNXLSZM6GDUMPI66LC5LW2OM2J4AC
6ZZO2QBB46RZM6OXVS7OIKC5M3SEAULSSJFXW5PJG556JDKKUHWAC
5FHWTG7M6FW4B3I33YI7QSM3OZIB6ZGC6TI6JISSLY5Y43HI56VAC
3ZNI2YMHYXRVEONY5CGWXSRMFSLOATZMKU7H6HRY3CC2W6OZAM7QC
IPPPBA4G2LODBP3EJIYGUAAOMHKLNBXHBD7KVX2JVDTA4DETHO4AC
VDWXI5MMXZLJXWWPZPXJZ2YZIR2OMPQO3VIJO2HMTF4TPYJB2MDQC
YFIVTYI7PMVAXV23DUPXPAQNEY3YSFIXQGSN32I3WVHMMD5XS5DQC
SNH6UWOYVWP4A6B4NC6YZ6KRYPYCGGNYCW5TILTALPH552H2EUFQC
POP6UTTHSJGDU5NU7ENQJOZVFUHYM63HJ6HLPXDDLK7XFIP4XEIQC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
ENI6P5WUO7DS4Y7EUDCYB4PSNT7CXH2L5JIB5BLZHNMWN4QDXMWQC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
Q43X3MHS6IVLGSIIUJMTZT6NO6S4BDAUAJE4UJBXN4KWRFPLYZEAC
P2YNOE2TUTZFAOBTHJOIVD6TCV7J7D2UKUX67LHZUL6QY44ZMENQC
PO3IATZV4JX3I3522UAGF53ZLZ4FW7C2J32Z23PEWQVHGGEUO7SAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
475LL4U4ND6PTNV4XKC7WQAOJC7RF2VCCVX3DRILP2PKIBFYWE6QC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
RCYCFKHI7HUB46VKURMSKGGV2PCMXOCAJQMYHI5AJNGZEEKMIPFQC
ZEFGFQHN6J2S6EIPX7EPDG22C5YXTI6DMKQHHRCLWN5MQC44KY3AC
2TFYJ7D72JY4DYQW3GSPEONA2WYIVHAJXTIQ2QRDIWF65XN2QFGAC
QBAHRGJ2RVSMWKXY2B4FVR5VX75GILH6HSRYGF44PBPNINST2NIAC
U3UHWTM2LW64BR5DEBMMZUIGXGS2H3IYSGTWYI5ZU6LD4WWYKRPQC
G7CTMQ3VNTAB73ZI3LNZHKTAJ5LEQEGG772MVFQQ5XXLCMJVORTQC
S7KC3IFKCUNBO3XO4TV3KEQEIDZWSRJSKXY65DPONKMG54VHU3UQC
BIZDHHK5LIO57S5AKHEPJFLWV5DAFKZIKYBGOUNGICSWTX7DCXKAC
5UC5TI7B6NWGIGN74QRBZKDBYUMHLM2ZO5ATXEZ6TZOGOLF3JX5QC
IIN7AVA6JYRBXH6ZYRR7BY7TV6PW7ANAQ2A3PD55FKBKKQFEEF2AC
NMRKYZUPI6EOC4KONJKB2RHSCC6ONYJUOXQJ7PYJ7V4OBWPRO7AQC
6EJRFPJJRSIISDNDZWODH5A7U4PVIWH4YUCHEPB4V2GLGFG4DLBAC
QFIV4YISNBTC5QXN7JYHEL3FBFWIQ2HKJ4YBDCZYTQ3PMPFE653AC
WNQLH6VJ5DIPNQJUSUQBEKGNOZYCVWU5BYP4W6WQZBRMSR7GLUUQC
VEHHZZFWDG5M4IXTCXXMKH3S2FSXTZ4CD23J6AYVFEPY7PBZ7GWQC
YQ5IYBHW2ICYKOC2M6CI5BNOZKST3DIMMZRQN72LUQCHDAPVYQCQC
KCHX2F3JFEWOZT3WMJVZAAQUU2QSZ5Q7RDCD7WUJ7VE65J52JFUQC
LE5U6CTXEIETQN5GOVYF2K2VCISRXR3ULORXDKIKWYDVBG5GS3WAC
KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC
JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC
DCZMEKDHQWSQCQYQD6ZXB3XOMWLVLPSPVSBVVMPXMSZF7GO3BVCAC
DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
C25ULNTKMNOXT72ERWSFQZQW5E2OIM3TOGAAA33Z7EZQMZHRS2MAC
COLMJH3UIQFF4R5AV642OJK4HHGUIIPLNP5WGKLWWYNJV7ZGPI7AC
ACZYEIX7WMPIIODKCATBCUE626AJ4ZGGBOMVC6BGXM27EQU2RECAC
RGO2JV5HFKZFXO7KJWDXGDMNBR6NIAOMJW34NHRTLLVN2N7XGW7QC
WNC5SY6P2PBCU62Q2DB5J2M4HPDS5EJY76ZEPHRGGCLJ4BSLBSSQC
LPTP6ZL7U4OVXLZ56TJKJ6HENDHE7ITFMFBXC5BKEBVXEGXPW44AC
3A5FX3Y4RPKWQEHKKXZKXZJ7RKV6RKWT7GTR4WFE5UBWKV2HT4RQC
T7CCGLOZ25B7BQKKGR6IA6LWBRKUWTXLTIRXUQ4YKQRVAA7AHZKQC
XP6MR3Q24DQOWNEGMSHJX54ZAISKOIF65IR65M4EOR45KR2OSFVQC
RXYHE3C7R3EGCRZEJT2ZO4ALLRDR3HF66VHZZNF7TT3DFWZ6BJCQC
XPIE6FG6SYZXNQFBRWUBJ3NR5Q6MOMRXAFW3WTKMSLMKKA55ZWCQC
IGUSSYANPKGMX5YDQC7AI5ZWZLEQPIXA4KG3RZHNPMERL554HQWQC
754PQVFHYQER7P7NEHYNLQVOEALF6I23IQDNGNCOK5IV7OLAEXRQC
RJIGO3YE7LKSLASPVA7K6CNWJAPKXD7ENJDURI5GXBGIEXFBBINAC
ZLQAAP55CJ77XIJN3DZVPT4GTTVLIBFJLIJJKI6L5UBSHX7VUK6AC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
UBQTNLYGD3SNWMUNGWUPX7EXEGQXOXCFCPWIVWBFE7ID7DJLPFWAC
CJKLBIIM2ZTWTLGISXEZOGK2JANEYUSLOKG3BBOAYAY7AFG33ELQC
JTVUAALTZP6FW3D3QJUSOUGMEDNZB4F4HGUMYFHWGEJV2ETRBIBQC
D6A2MLKI7UQPZ4A4D6QSM6STFVDY77IY5APXCBT3LNH6CDVKT67QC
U6OTXM3JN7SGPVIGQ5F6NR2I7J5V7KOWFQ7AVNNRQQDNLBEDMYFQC
2ESKXYN266CEMLSL6DNCKG4REDO34FXL4ODVGMWDJTNJRKMXWCRQC
VM7ZJXYXF3XTGYLWW5RXTEFGG46FOOWWEATC6S565BGHBGM3CXUAC
HSRRNAU5UAYC6B6IQWGJPFROMZBTJICPCH6DJVZDHDTAGOQ6IOYAC
SBJWTFK2LCN7IIFREIZWTWV3U3LSZA2IPEOVXTN2ZZYHVEOHWBWQC
YATODO2EN3AW7IXW5PL25HHK34YHF6Y32QBMOUZXEATZZ4YQQWZQC
TPO6FNMPNUSWH4NCKO3VLYNAADEPSAXLUITCCACLZZSY53PKA62QC
43ZTEB57FU7KE5EVMYWZONNVJBZCGF3JEAJZIY25LC4LGE65PG5QC
DGB7DKTR6OEQEMOOF3MAHDT4PAPKZ54Y33MWYVD7XIOESPFAXHQQC
IXWJ54CASZWYHSTDOU3TRQS2DSF4MKBRPO4VZYLE72JL5RD22O2AC
O6ZMFKDI3XO2SWPNEYHIPYFDWJR4TVDP5BAATK6LVCVETQID6E7AC
ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC
OFH2B2UZBK43QLFQBZ54FOCFLFNE54BZVDNCEUGDTBCUGNVZULIQC
K2MLPJIAXXZRWEWZCNSGICCBNIU2WAAPT7SPIMOH7FLLTOB4QFRAC
O3QBT2ISABMEWTNSYEJKAJG6LZMON7U6RQZDSLY2KQHSMILUYQFQC
AMSENYIGRJWHHGHLKIZQGZZQTWCZBTS2Y3WKPVTZZRI7ZMTATBCAC
57E4T664CXRFPVW2BZBYI33UIHFS4PSEZURZYPSYSZK5DRLJJ5CQC
QKGDOYIYKE6B36ION5O2DRW65DWWPZMYNWJVH7LJJ7FPGGM2MYAQC
HBHQQDULNVWISJ75XIL6R6BFEDYRNY22NX3ZTFVNP5ZWJGJSKOEQC
OXHOOJE4XEQKGI3JKURNSITG6CRQFAOFQ2EKKG6M5DCLN7LS4GUAC
OYYZVCE3QHBVJM6IEKK5HTJRG5YOVQNCBRMSJENTHOI2WPJLNCFAC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
FFERAWJ5ZXJW3N63T4PENDNVV7HOJ6IUH7QD2RXX7723MKZSP4BQC
XJRP5MAESWFGYS4CBM7K2ENA3UBPL6N6MDNAHJBH2WRMZ73E5JGQC
4XGOVPFCU6KZIYHKWCHUTZY6G5S326DKBG3UREPR34Q4TSDD3TAAC
GVCGKTH5IJ4VSQEIN4CRC7ZFVZW26JPIYNCPTO7GY66CSZZEW3ZQC
HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC
OONYLF4DAPLIYLBNNRW74IVT5BBTWI4XHQBXSNSPVRX3FTKJBTRAC
GQQ6ASWTYODIHG7X32JNUUHP5NMOVZJIHWGS3F3MKRYZGAHP6NVQC
ATDAT2AONG2BDLZFBJZB4WVNRUFQAU7RDIVUBAZ6STAV62NX5R4AC
LW4N5EHKL776DURXZMAM6JEW3JPWWX5BSNP7TCZHTLCDOQTTGFCAC
DKRSOHZXL6EPSLKOKHF7GJXSZEJVY7CXGACSHWLM5B5FTRETWWCAC
2P3IJKK547AOEFWKXEAL73QFKW423GGAZEZHW6OZ6QB7YUSDNC3AC
KR655YT3I3U5DMN5NS3FPUGMDNT4BI56K3SFF2FNJ77C45NFKL5AC
ZHH4MGCGXMAKIZ4GVA6Q4MS3IWJTGNMWLPSAG2MWLQS2G3WU5YCAC
ZIFFVCQ72K35WGIUMZYN3KOXIUXF2CNXWKG6ZWEZ6LT3NSF3XOQAC
J44YLLLSMPKEY3IXV3CPOM257PQZW45A4QWSSBYVFXS5T5XGQQWAC
KNO4TZR76DMOYJCF24PSVQW7FUZOTMOJTL7I7J74SM4IHOGDX6TAC
Y5GWVQ5SM7DJEAPFOBPMMJH4D3NXBB2MPONSJUMG3KIQMBVGEE6AC
7X5YDPAU34LOFKEGJYE6GC7EOEDKGT3O6CUGZBYJI45L3FQOAKHQC
FC7M3JHVRPOLZP7YWOJN4O6YJV7KRJUMPLTI2Q4ANCO7GD23YKWQC
FLAGBNUNSIQNFDN53CDWABJRTTFWDL4PG34AI474ZKPXDEPYHOAQC
7YUGK5Q64KG5O7GJGTUBRRLHAHBCJ5YOE23YUPT6UBKUSB67CYAQC
PI5BATR2SER3RFE76IUGHM2AGXVFOUM3PLU7WC2K2Q2BA5K2E73QC
PHBACPMH3F34GODHVDKNCMXWU373RJQGVTDLBFCCDLLWDXVYOLTAC
EJKHYV2Z6UPRVYUAL4WRW33GBNHYBFPMPA57HMBX2LQKXHIUO5VQC
46MRRHVYJ3BS74R2BEVUWEWJCI4FCRBSLZ3NWMQCE6FUCNE5P73QC
PKXXBHS3LWLPZI2QVRX22MSQ4R2626IXRSNHFFYHXYTLJJQU54LQC
FSJKED4U2SOUP64DTHF2NEGAYY7EUMSIDKC2SATEXAXEVOCNL3CAC
T72EIKU4IJF3G3FBUDWMLMAFFUEF3ZNMKJFB5G3PZLFWH7W3H44AC
// various elemental colour schemes... used for abstracting random
// short lists. When adding colours, please also add their names in
// initfile.cc (str_to_colour)!
enum element_type
{
ETC_FIRE = 32, // fiery colours (must be first and > highest colour)
ETC_ICE, // icy colours
ETC_EARTH, // earthy colours
ETC_ELECTRICITY, // electrical side of air
ETC_AIR, // non-electric and general air magic
ETC_POISON, // used only for venom mage and stalker stuff
ETC_WATER, // used only for the elemental
ETC_MAGIC, // general magical effect
ETC_MUTAGENIC, // transmute, poly, radiation effects
ETC_WARP, // teleportation and anything similar
ETC_ENCHANT, // magical enhancements
ETC_HEAL, // holy healing (not necromantic stuff)
ETC_HOLY, // general "good" god effects
ETC_DARK, // darkness
ETC_DEATH, // currently only assassin (and equal to ETC_NECRO)
ETC_NECRO, // necromancy stuff
ETC_UNHOLY, // demonology stuff
ETC_VEHUMET, // vehumet's oddball colours
ETC_BEOGH, // Beogh altar colours
ETC_CRYSTAL, // colours of crystal
ETC_BLOOD, // colours of blood
ETC_SMOKE, // colours of smoke
ETC_SLIME, // colours of slime
ETC_JEWEL, // colourful
ETC_ELVEN, // used for colouring elf fabric items
ETC_DWARVEN, // used for colouring dwarf fabric items
ETC_ORCISH, // used for colouring orc fabric items
ETC_GILA, // gila monster colours
ETC_FLOOR, // colour of the area's floor
ETC_ROCK, // colour of the area's rock
ETC_STONE, // colour of the area's stone
ETC_MIST, // colour of mist
ETC_SHIMMER_BLUE, // shimmering colours of blue.
ETC_DECAY, // colour of decay/swamp
ETC_SILVER, // colour of silver
ETC_GOLD, // colour of gold
ETC_IRON, // colour of iron
ETC_BONE, // colour of bone
ETC_RANDOM // any colour (except BLACK)
};
void seed_rng();
void seed_rng(long seed);
void push_rng_state();
void pop_rng_state();
void cf_setseed();
bool coinflip();
int div_rand_round( int num, int den );
int div_round_up( int num, int den );
bool one_chance_in(int a_million);
bool x_chance_in_y(int x, int y);
int random2(int max);
int maybe_random2(int x, bool random_factor);
int random_range(int low, int high);
int random_range(int low, int high, int nrolls);
const char* random_choose_string(const char* first, ...);
int random_choose(int first, ...);
int random_choose_weighted(int weight, int first, ...);
unsigned long random_int();
int random2avg(int max, int rolls);
int bestroll(int max, int rolls);
int roll_dice(int num, int size);
void scale_dice(dice_def &dice, int threshold = 24);
int binomial_generator(unsigned n_trials, unsigned trial_prob);
// Various ways to iterate over things.
};
class rectangle_iterator :
public std::iterator<std::forward_iterator_tag, coord_def>
{
public:
rectangle_iterator( const coord_def& corner1, const coord_def& corner2 );
explicit rectangle_iterator( int x_border_dist, int y_border_dist = -1 );
operator bool() const;
coord_def operator *() const;
const coord_def* operator->() const;
rectangle_iterator& operator ++ ();
rectangle_iterator operator ++ (int);
private:
coord_def current, topleft, bottomright;
class radius_iterator : public std::iterator<std::bidirectional_iterator_tag,
coord_def>
{
public:
radius_iterator( const coord_def& center, int radius,
bool roguelike_metric = true,
bool require_los = true,
bool exclude_center = false,
const env_show_grid* losgrid = NULL );
bool done() const;
void reset();
operator bool() const { return !done(); }
coord_def operator *() const;
const coord_def* operator->() const;
const radius_iterator& operator ++ ();
const radius_iterator& operator -- ();
radius_iterator operator ++ (int);
radius_iterator operator -- (int);
private:
void step();
void step_back();
bool on_valid_square() const;
coord_def location, center;
int radius;
bool roguelike_metric, require_los, exclude_center;
const env_show_grid* losgrid;
bool iter_done;
};
class adjacent_iterator : public radius_iterator
{
public:
explicit adjacent_iterator( const coord_def& pos = you.pos(),
bool _exclude_center = true ) :
radius_iterator(pos, 1, true, false, _exclude_center) {}
};
int random2limit(int max, int limit);
bool in_bounds_x(int x);
bool in_bounds_y(int y);
bool in_bounds(int x, int y);
bool map_bounds_x(int x);
bool map_bounds_y(int y);
bool map_bounds(int x, int y);
coord_def random_in_bounds();
inline bool in_bounds(const coord_def &p)
{
return in_bounds(p.x, p.y);
}
inline bool map_bounds(const coord_def &p)
{
return map_bounds(p.x, p.y);
}
// Determines if the coordinate is within bounds of an LOS array.
inline bool show_bounds(const coord_def &p)
{
return (p.x >= 0 && p.x < ENV_SHOW_DIAMETER
&& p.y >= 0 && p.y < ENV_SHOW_DIAMETER);
}
int grid_distance( const coord_def& p1, const coord_def& p2 );
int grid_distance( int x, int y, int x2, int y2 );
int distance( const coord_def& p1, const coord_def& p2 );
int distance( int x, int y, int x2, int y2);
bool adjacent( const coord_def& p1, const coord_def& p2 );
unsigned char random_colour();
unsigned char random_uncommon_colour();
unsigned char make_low_colour(unsigned char colour);
unsigned char make_high_colour(unsigned char colour);
bool is_element_colour( int col );
int element_colour( int element, bool no_random = false );
class rng_save_excursion
{
public:
rng_save_excursion(long seed) { push_rng_state(); seed_rng(seed); }
rng_save_excursion() { push_rng_state(); }
~rng_save_excursion() { pop_rng_state(); }
};
template<typename Iterator>
int choose_random_weighted(Iterator beg, const Iterator end)
{
ASSERT(beg < end);
#ifdef DEBUG
int times_set = 0;
#endif
int totalweight = 0;
int count = 0, result = 0;
while (beg != end)
{
totalweight += *beg;
if (random2(totalweight) < *beg)
{
result = count;
#ifdef DEBUG
times_set++;
#endif
}
++count;
++beg;
}
#ifdef DEBUG
ASSERT(times_set > 0);
#endif
return result;
}
#endif
#ifdef MORE_HARDENED_PRNG
#include "sha256.h"
#endif
}
rectangle_iterator::rectangle_iterator( const coord_def& corner1,
const coord_def& corner2 )
{
topleft.x = std::min(corner1.x, corner2.x);
topleft.y = std::min(corner1.y, corner2.y); // not really necessary
bottomright.x = std::max(corner1.x, corner2.x);
bottomright.y = std::max(corner1.y, corner2.y);
current = topleft;
}
rectangle_iterator::rectangle_iterator( int x_border_dist, int y_border_dist )
{
if (y_border_dist < 0)
y_border_dist = x_border_dist;
topleft.set(x_border_dist, y_border_dist);
bottomright.set(GXM - x_border_dist - 1, GYM - y_border_dist - 1);
current = topleft;
rectangle_iterator::operator bool() const
{
return (current.y <= bottomright.y);
}
coord_def rectangle_iterator::operator *() const
{
return current;
}
const coord_def* rectangle_iterator::operator->() const
{
return ¤t;
}
rectangle_iterator& rectangle_iterator::operator ++()
{
if (current.x == bottomright.x)
{
current.x = topleft.x;
current.y++;
}
else
{
current.x++;
}
return *this;
}
rectangle_iterator rectangle_iterator::operator++( int dummy )
{
const rectangle_iterator copy = *this;
++(*this);
return (copy);
}
radius_iterator::radius_iterator(const coord_def& _center, int _radius,
bool _roguelike_metric, bool _require_los,
bool _exclude_center,
const env_show_grid* _losgrid)
: center(_center), radius(_radius), roguelike_metric(_roguelike_metric),
require_los(_require_los), exclude_center(_exclude_center),
losgrid(_losgrid), iter_done(false)
{
reset();
}
void radius_iterator::reset()
{
iter_done = false;
location.x = center.x - radius;
location.y = center.y - radius;
if ( !this->on_valid_square() )
++(*this);
}
bool radius_iterator::done() const
{
return iter_done;
}
coord_def radius_iterator::operator *() const
{
return location;
}
const coord_def* radius_iterator::operator->() const
{
return &location;
}
void radius_iterator::step()
{
const int minx = std::max(X_BOUND_1+1, center.x - radius);
const int maxx = std::min(X_BOUND_2-1, center.x + radius);
const int maxy = std::min(Y_BOUND_2-1, center.y + radius);
// Sweep L-R, U-D
location.x++;
if (location.x > maxx)
{
location.x = minx;
location.y++;
if (location.y > maxy)
iter_done = true;
}
}
void radius_iterator::step_back()
{
const int minx = std::max(X_BOUND_1+1, center.x - radius);
const int maxx = std::min(X_BOUND_2-1, center.x + radius);
const int miny = std::max(Y_BOUND_1+1, center.y - radius);
location.x--;
if (location.x < minx)
{
location.x = maxx;
location.y--;
if (location.y < miny)
iter_done = true;
}
}
bool radius_iterator::on_valid_square() const
{
if (!in_bounds(location))
return (false);
if (!roguelike_metric && (location - center).abs() > radius*radius)
return (false);
if (require_los)
{
if (!losgrid && !see_cell(location))
return (false);
if (losgrid && !see_cell(*losgrid, center, location))
return (false);
}
if (exclude_center && location == center)
return (false);
return (true);
}
const radius_iterator& radius_iterator::operator++()
{
do
this->step();
while (!this->done() && !this->on_valid_square());
return (*this);
}
const radius_iterator& radius_iterator::operator--()
{
do
this->step_back();
while (!this->done() && !this->on_valid_square());
return (*this);
}
radius_iterator radius_iterator::operator++(int dummy)
{
const radius_iterator copy = *this;
++(*this);
return (copy);
}
radius_iterator radius_iterator::operator--(int dummy)
{
const radius_iterator copy = *this;
--(*this);
return (copy);
}
void seed_rng(long seed)
{
// MT19937 -- see mt19937ar.cc for details/licence
init_genrand(seed);
}
void seed_rng()
{
unsigned long seed = time( NULL );
#ifdef USE_MORE_SECURE_SEED
/* (at least) 256-bit wide seed */
unsigned long seed_key[8];
struct tms buf;
seed += times( &buf ) + getpid();
seed_key[0] = seed;
/* Try opening from various system provided (hopefully) CSPRNGs */
FILE* seed_f = fopen("/dev/urandom", "rb");
if (!seed_f)
seed_f = fopen("/dev/random", "rb");
if (!seed_f)
seed_f = fopen("/dev/srandom", "rb");
if (!seed_f)
seed_f = fopen("/dev/arandom", "rb");
if (seed_f)
{
fread(&seed_key[1], sizeof(unsigned long), 7, seed_f);
fclose(seed_f);
}
seed_rng(seed_key, 8);
#else
seed_rng(seed);
#endif
}
// MT19937 -- see mt19937ar.cc for details
unsigned long random_int( void )
{
#ifndef MORE_HARDENED_PRNG
return (genrand_int32());
#else
return (sha256_genrand());
#endif
}
int random_range(int low, int high)
{
ASSERT(low <= high);
return (low + random2(high - low + 1));
}
int random_range(int low, int high, int nrolls)
{
ASSERT(nrolls > 0);
int sum = 0;
for (int i = 0; i < nrolls; ++i)
sum += random_range(low, high);
return (sum / nrolls);
}
// Chooses one of the numbers passed in at random. The list of numbers
// must be terminated with -1.
int random_choose(int first, ...)
{
va_list args;
va_start(args, first);
int chosen = first, count = 1, nargs = 100;
while (nargs-- > 0)
{
const int pick = va_arg(args, int);
if (pick == -1)
break;
if (one_chance_in(++count))
chosen = pick;
}
ASSERT(nargs > 0);
va_end(args);
return (chosen);
}
// Chooses one of the strings passed in at random. The list of strings
// must be terminated with NULL.
const char* random_choose_string(const char* first, ...)
{
va_list args;
va_start(args, first);
const char* chosen = first;
int count = 1, nargs = 100;
while (nargs-- > 0)
{
char* pick = va_arg(args, char*);
if (pick == NULL)
break;
if (one_chance_in(++count))
chosen = pick;
}
ASSERT(nargs > 0);
va_end(args);
return (chosen);
}
int random_choose_weighted(int weight, int first, ...)
{
va_list args;
va_start(args, first);
int chosen = first, cweight = weight, nargs = 100;
while (nargs-- > 0)
{
const int nweight = va_arg(args, int);
if (!nweight)
break;
const int choice = va_arg(args, int);
if (random2(cweight += nweight) < nweight)
chosen = choice;
}
ASSERT(nargs > 0);
va_end(args);
return (chosen);
}
int random2(int max)
{
if (max <= 1)
return (0);
#ifdef MORE_HARDENED_PRNG
return (static_cast<int>(sha256_genrand() / (0xFFFFFFFFUL / max + 1)));
#else
return (static_cast<int>(genrand_int32() / (0xFFFFFFFFUL / max + 1)));
#endif
}
bool coinflip(void)
{
return (static_cast<bool>(random2(2)));
}
// Returns random2(x) if random_factor is true, otherwise the mean.
int maybe_random2(int x, bool random_factor)
{
if (random_factor)
return (random2(x));
else
return (x / 2);
}
void push_rng_state()
{
push_mt_state();
}
void pop_rng_state()
{
pop_mt_state();
}
// Attempts to make missile weapons nicer to the player by reducing the
// extreme variance in damage done.
void scale_dice(dice_def &dice, int threshold)
{
while (dice.size > threshold)
{
dice.num *= 2;
// If it's an odd number, lose one; this is more than
// compensated by the increase in number of dice.
dice.size /= 2;
}
}
int bestroll(int max, int rolls)
{
int best = 0;
for (int i = 0; i < rolls; i++)
{
int curr = random2(max);
if (curr > best)
best = curr;
}
return (best);
}
// random2avg() returns same mean value as random2() but with a lower variance
// never use with rolls < 2 as that would be silly - use random2() instead {dlb}
int random2avg(int max, int rolls)
{
int sum = random2(max);
for (int i = 0; i < (rolls - 1); i++)
sum += random2(max + 1);
return (sum / rolls);
}
int roll_dice(int num, int size)
{
int ret = 0;
int i;
// If num <= 0 or size <= 0, then we'll just return the default
// value of zero. This is good behaviour in that it will be
// appropriate for calculated values that might be passed in.
if (num > 0 && size > 0)
{
ret += num; // since random2() is zero based
for (i = 0; i < num; i++)
ret += random2(size);
}
return (ret);
}
// originally designed to randomise evasion -
// values are slightly lowered near (max) and
// approach an upper limit somewhere near (limit/2)
int random2limit(int max, int limit)
{
int i;
int sum = 0;
if (max < 1)
return (0);
for (i = 0; i < max; i++)
if (random2(limit) >= i)
sum++;
return (sum);
}
// Generate samples from a binomial distribution with n_trials and trial_prob
// probability of success per trial. trial_prob is a integer less than 100
// representing the % chancee of success.
// This just evaluates all n trials, there is probably an efficient way of
// doing this but I'm not much of a statistician. -CAO
int binomial_generator(unsigned n_trials, unsigned trial_prob)
{
int count = 0;
for (unsigned i = 0; i < n_trials; ++i)
if (::x_chance_in_y(trial_prob, 100))
count++;
return count;
}
}
// Calculates num/den and randomly adds one based on the remainder.
int div_rand_round(int num, int den)
{
return (num / den + (random2(den) < num % den));
}
bool one_chance_in(int a_million)
{
return (random2(a_million) == 0);
}
bool x_chance_in_y(int x, int y)
{
if (x <= 0)
return (false);
if (x >= y)
return (true);
return (random2(y) < x);
int grid_distance( const coord_def& p1, const coord_def& p2 )
{
return grid_distance(p1.x, p1.y, p2.x, p2.y);
}
// More accurate than distance() given the actual movement geometry -- bwr
int grid_distance( int x, int y, int x2, int y2 )
{
const int dx = abs( x - x2 );
const int dy = abs( y - y2 );
// returns distance in terms of moves:
return ((dx > dy) ? dx : dy);
}
int distance( const coord_def& p1, const coord_def& p2 )
{
return distance(p1.x, p1.y, p2.x, p2.y);
}
int distance( int x, int y, int x2, int y2 )
{
//jmf: now accurate, but remember to only compare vs. pre-squared distances
// thus, next to == (distance(m1.x,m1.y, m2.x,m2.y) <= 2)
const int dx = x - x2;
const int dy = y - y2;
return ((dx * dx) + (dy * dy));
}
bool adjacent( const coord_def& p1, const coord_def& p2 )
{
return grid_distance(p1, p2) <= 1;
}
}
bool in_bounds_x(int x)
{
return (x > X_BOUND_1 && x < X_BOUND_2);
}
bool in_bounds_y(int y)
{
return (y > Y_BOUND_1 && y < Y_BOUND_2);
}
// Returns true if inside the area the player can move and dig (ie exclusive).
bool in_bounds(int x, int y)
{
return (in_bounds_x(x) && in_bounds_y(y));
}
bool map_bounds_x(int x)
{
return (x >= X_BOUND_1 && x <= X_BOUND_2);
}
bool map_bounds_y(int y)
{
return (y >= Y_BOUND_1 && y <= Y_BOUND_2);
}
// Returns true if inside the area the player can map (ie inclusive).
// Note that terrain features should be in_bounds() leaving an outer
// ring of rock to frame the level.
bool map_bounds(int x, int y)
{
return (map_bounds_x(x) && map_bounds_y(y));
}
coord_def random_in_bounds()
{
if (crawl_state.arena)
{
const coord_def &ul = crawl_view.glos1; // Upper left
const coord_def &lr = crawl_view.glos2; // Lower right
return coord_def(random_range(ul.x, lr.x - 1),
random_range(ul.y, lr.y - 1));
}
else
return coord_def(random_range(MAPGEN_BORDER, GXM - MAPGEN_BORDER - 1),
random_range(MAPGEN_BORDER, GYM - MAPGEN_BORDER - 1));
}
unsigned char random_colour(void)
{
return (1 + random2(15));
}
unsigned char random_uncommon_colour()
{
unsigned char result;
do
result = random_colour();
while (result == LIGHTCYAN || result == CYAN || result == BROWN);
return (result);
}
unsigned char make_low_colour(unsigned char colour)
{
if (colour >= 8 && colour <= 15)
return (colour - 8);
return (colour);
}
unsigned char make_high_colour(unsigned char colour)
{
if (colour <= 7)
return (colour + 8);
return (colour);
}
// returns if a colour is one of the special element colours (ie not regular)
bool is_element_colour( int col )
{
// stripping any COLFLAGS (just in case)
return ((col & 0x007f) >= ETC_FIRE);
}
int element_colour( int element, bool no_random )
{
// Doing this so that we don't have to do recursion here at all
// (these were the only cases which had possible double evaluation):
if (element == ETC_FLOOR)
element = env.floor_colour;
else if (element == ETC_ROCK)
element = env.rock_colour;
// pass regular colours through for safety.
if (!is_element_colour( element ))
return (element);
int ret = BLACK;
// Setting no_random to true will get the first colour in the cases
// below. This is potentially useful for calls to this function
// which might want a consistent result.
int tmp_rand = (no_random ? 0 : random2(120));
switch (element & 0x007f) // strip COLFLAGs just in case
{
case ETC_FIRE:
ret = (tmp_rand < 40) ? RED :
(tmp_rand < 80) ? YELLOW
: LIGHTRED;
break;
case ETC_ICE:
ret = (tmp_rand < 40) ? LIGHTBLUE :
(tmp_rand < 80) ? BLUE
: WHITE;
break;
case ETC_EARTH:
ret = (tmp_rand < 60) ? BROWN : LIGHTRED;
break;
case ETC_AIR:
ret = (tmp_rand < 60) ? LIGHTGREY : WHITE;
break;
case ETC_ELECTRICITY:
ret = (tmp_rand < 40) ? LIGHTCYAN :
(tmp_rand < 80) ? LIGHTBLUE
: CYAN;
break;
case ETC_POISON:
ret = (tmp_rand < 60) ? LIGHTGREEN : GREEN;
break;
case ETC_WATER:
ret = (tmp_rand < 60) ? BLUE : CYAN;
break;
case ETC_MAGIC:
ret = (tmp_rand < 30) ? LIGHTMAGENTA :
(tmp_rand < 60) ? LIGHTBLUE :
(tmp_rand < 90) ? MAGENTA
: BLUE;
break;
case ETC_MUTAGENIC:
case ETC_WARP:
ret = (tmp_rand < 60) ? LIGHTMAGENTA : MAGENTA;
break;
case ETC_ENCHANT:
ret = (tmp_rand < 60) ? LIGHTBLUE : BLUE;
break;
case ETC_HEAL:
ret = (tmp_rand < 60) ? LIGHTBLUE : YELLOW;
break;
case ETC_BLOOD:
ret = (tmp_rand < 60) ? RED : DARKGREY;
break;
case ETC_DEATH: // assassin
case ETC_NECRO: // necromancer
ret = (tmp_rand < 80) ? DARKGREY : MAGENTA;
break;
case ETC_UNHOLY: // ie demonology
ret = (tmp_rand < 80) ? DARKGREY : RED;
break;
case ETC_DARK:
ret = (tmp_rand < 80) ? DARKGREY : LIGHTGREY;
break;
case ETC_HOLY:
ret = (tmp_rand < 60) ? YELLOW : WHITE;
break;
case ETC_VEHUMET:
ret = (tmp_rand < 40) ? LIGHTRED :
(tmp_rand < 80) ? LIGHTMAGENTA
: LIGHTBLUE;
break;
case ETC_BEOGH:
ret = (tmp_rand < 60) ? LIGHTRED // plain Orc colour
: BROWN; // Orcish mines wall/idol colour
break;
case ETC_CRYSTAL:
ret = (tmp_rand < 40) ? LIGHTGREY :
(tmp_rand < 80) ? GREEN
: LIGHTRED;
break;
case ETC_SLIME:
ret = (tmp_rand < 40) ? GREEN :
(tmp_rand < 80) ? BROWN
: LIGHTGREEN;
break;
case ETC_SMOKE:
ret = (tmp_rand < 30) ? LIGHTGREY :
(tmp_rand < 60) ? DARKGREY :
(tmp_rand < 90) ? LIGHTBLUE
: MAGENTA;
break;
case ETC_JEWEL:
ret = (tmp_rand < 12) ? WHITE :
(tmp_rand < 24) ? YELLOW :
(tmp_rand < 36) ? LIGHTMAGENTA :
(tmp_rand < 48) ? LIGHTRED :
(tmp_rand < 60) ? LIGHTGREEN :
(tmp_rand < 72) ? LIGHTBLUE :
(tmp_rand < 84) ? MAGENTA :
(tmp_rand < 96) ? RED :
(tmp_rand < 108) ? GREEN
: BLUE;
break;
case ETC_ELVEN:
ret = (tmp_rand < 40) ? LIGHTGREEN :
(tmp_rand < 80) ? GREEN :
(tmp_rand < 100) ? LIGHTBLUE
: BLUE;
break;
case ETC_DWARVEN:
ret = (tmp_rand < 40) ? BROWN :
(tmp_rand < 80) ? LIGHTRED :
(tmp_rand < 100) ? LIGHTGREY
: CYAN;
break;
case ETC_ORCISH:
ret = (tmp_rand < 40) ? DARKGREY :
(tmp_rand < 80) ? RED :
(tmp_rand < 100) ? BROWN
: MAGENTA;
break;
case ETC_GILA:
ret = (tmp_rand < 30) ? LIGHTMAGENTA :
(tmp_rand < 60) ? MAGENTA :
(tmp_rand < 90) ? YELLOW :
(tmp_rand < 105) ? LIGHTRED
: RED;
break;
case ETC_STONE:
if (player_in_branch( BRANCH_HALL_OF_ZOT ))
ret = env.rock_colour;
else
ret = LIGHTGREY;
break;
case ETC_MIST:
ret = tmp_rand < 100? CYAN : BLUE;
break;
case ETC_SHIMMER_BLUE:
ret = random_choose_weighted(80, BLUE, 20, LIGHTBLUE, 5, CYAN, 0);
break;
case ETC_DECAY:
ret = (tmp_rand < 60) ? BROWN : GREEN;
break;
case ETC_SILVER:
ret = (tmp_rand < 90) ? LIGHTGREY : WHITE;
break;
case ETC_GOLD:
ret = (tmp_rand < 60) ? YELLOW : BROWN;
break;
case ETC_IRON:
ret = (tmp_rand < 40) ? CYAN :
(tmp_rand < 80) ? LIGHTGREY :
DARKGREY;
break;
case ETC_BONE:
ret = (tmp_rand < 90) ? WHITE : LIGHTGREY;
break;
case ETC_RANDOM:
ret = 1 + random2(15); // always random
break;
case ETC_FLOOR: // should already be handled
case ETC_ROCK: // should already be handled
default:
break;
}
ASSERT( !is_element_colour( ret ) );
return ((ret == BLACK) ? GREEN : ret);
}
int fuzz_value(int val, int lowfuzz, int highfuzz, int naverage)
{
const int lfuzz = lowfuzz * val / 100,
hfuzz = highfuzz * val / 100;
return val + random2avg(lfuzz + hfuzz + 1, naverage) - lfuzz;
//////////////////////////////////////////////////////////////////////////
// coord_def
int coord_def::distance_from(const coord_def &other) const
{
return (grid_distance(*this, other));
}
#ifndef RNG_H
#define RNG_H
void seed_rng();
void seed_rng(long seed);
void push_rng_state();
void pop_rng_state();
void cf_setseed();
unsigned long random_int();
#endif
/*
* File: rng.cc
* Summary: Random number generator wrapping.
*/
#include "AppHdr.h"
#include "rng.h"
#include "mt19937ar.h"
#ifdef USE_MORE_SECURE_SEED
// for times()
#include <sys/times.h>
// for getpid()
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef MORE_HARDENED_PRNG
#include "sha256.h"
#endif
void seed_rng(unsigned long* seed_key, size_t num_keys)
{
// MT19937 -- see mt19937ar.cc for details/licence
init_by_array(seed_key, num_keys);
}
void seed_rng(long seed)
{
// MT19937 -- see mt19937ar.cc for details/licence
init_genrand(seed);
}
void seed_rng()
{
unsigned long seed = time( NULL );
#ifdef USE_MORE_SECURE_SEED
/* (at least) 256-bit wide seed */
unsigned long seed_key[8];
struct tms buf;
seed += times( &buf ) + getpid();
seed_key[0] = seed;
/* Try opening from various system provided (hopefully) CSPRNGs */
FILE* seed_f = fopen("/dev/urandom", "rb");
if (!seed_f)
seed_f = fopen("/dev/random", "rb");
if (!seed_f)
seed_f = fopen("/dev/srandom", "rb");
if (!seed_f)
seed_f = fopen("/dev/arandom", "rb");
if (seed_f)
{
fread(&seed_key[1], sizeof(unsigned long), 7, seed_f);
fclose(seed_f);
}
seed_rng(seed_key, 8);
#else
seed_rng(seed);
#endif
}
// MT19937 -- see mt19937ar.cc for details
unsigned long random_int( void )
{
#ifndef MORE_HARDENED_PRNG
return (genrand_int32());
#else
return (sha256_genrand());
#endif
}
void push_rng_state()
{
push_mt_state();
}
void pop_rng_state()
{
pop_mt_state();
}
#ifndef RANDOM_H
#define RANDOM_H
#include "rng.h"
bool coinflip();
int div_rand_round( int num, int den );
int div_round_up( int num, int den );
bool one_chance_in(int a_million);
bool x_chance_in_y(int x, int y);
int random2(int max);
int maybe_random2(int x, bool random_factor);
int random_range(int low, int high);
int random_range(int low, int high, int nrolls);
const char* random_choose_string(const char* first, ...);
int random_choose(int first, ...);
int random_choose_weighted(int weight, int first, ...);
int random2avg(int max, int rolls);
int bestroll(int max, int rolls);
int random2limit(int max, int limit);
int binomial_generator(unsigned n_trials, unsigned trial_prob);
int fuzz_value(int val, int lowfuzz, int highfuzz, int naverage = 2);
int roll_dice(int num, int size);
struct dice_def
{
int num;
int size;
dice_def(int n = 0, int s = 0) : num(n), size(s) {}
int roll() const;
};
dice_def calc_dice(int num_dice, int max_damage);
void scale_dice(dice_def &dice, int threshold = 24);
class rng_save_excursion
{
public:
rng_save_excursion(long seed) { push_rng_state(); seed_rng(seed); }
rng_save_excursion() { push_rng_state(); }
~rng_save_excursion() { pop_rng_state(); }
};
template<typename Iterator>
int choose_random_weighted(Iterator beg, const Iterator end)
{
ASSERT(beg < end);
#ifdef DEBUG
int times_set = 0;
#endif
int totalweight = 0;
int count = 0, result = 0;
while (beg != end)
{
totalweight += *beg;
if (random2(totalweight) < *beg)
{
result = count;
#ifdef DEBUG
times_set++;
#endif
}
++count;
++beg;
}
#ifdef DEBUG
ASSERT(times_set > 0);
#endif
return result;
}
#endif
#include "AppHdr.h"
#include "random.h"
int random_range(int low, int high)
{
ASSERT(low <= high);
return (low + random2(high - low + 1));
}
int random_range(int low, int high, int nrolls)
{
ASSERT(nrolls > 0);
int sum = 0;
for (int i = 0; i < nrolls; ++i)
sum += random_range(low, high);
return (sum / nrolls);
}
// Chooses one of the numbers passed in at random. The list of numbers
// must be terminated with -1.
int random_choose(int first, ...)
{
va_list args;
va_start(args, first);
int chosen = first, count = 1, nargs = 100;
while (nargs-- > 0)
{
const int pick = va_arg(args, int);
if (pick == -1)
break;
if (one_chance_in(++count))
chosen = pick;
}
ASSERT(nargs > 0);
va_end(args);
return (chosen);
}
// Chooses one of the strings passed in at random. The list of strings
// must be terminated with NULL.
const char* random_choose_string(const char* first, ...)
{
va_list args;
va_start(args, first);
const char* chosen = first;
int count = 1, nargs = 100;
while (nargs-- > 0)
{
char* pick = va_arg(args, char*);
if (pick == NULL)
break;
if (one_chance_in(++count))
chosen = pick;
}
ASSERT(nargs > 0);
va_end(args);
return (chosen);
}
int random_choose_weighted(int weight, int first, ...)
{
va_list args;
va_start(args, first);
int chosen = first, cweight = weight, nargs = 100;
while (nargs-- > 0)
{
const int nweight = va_arg(args, int);
if (!nweight)
break;
const int choice = va_arg(args, int);
if (random2(cweight += nweight) < nweight)
chosen = choice;
}
ASSERT(nargs > 0);
va_end(args);
return (chosen);
}
int random2(int max)
{
if (max <= 1)
return (0);
return (static_cast<int>(random_int() / (0xFFFFFFFFUL / max + 1)));
}
bool coinflip(void)
{
return (static_cast<bool>(random2(2)));
}
// Returns random2(x) if random_factor is true, otherwise the mean.
int maybe_random2(int x, bool random_factor)
{
if (random_factor)
return (random2(x));
else
return (x / 2);
}
int roll_dice(int num, int size)
{
int ret = 0;
int i;
// If num <= 0 or size <= 0, then we'll just return the default
// value of zero. This is good behaviour in that it will be
// appropriate for calculated values that might be passed in.
if (num > 0 && size > 0)
{
ret += num; // since random2() is zero based
for (i = 0; i < num; i++)
ret += random2(size);
}
return (ret);
}
int dice_def::roll() const
{
return roll_dice(this->num, this->size);
}
dice_def calc_dice(int num_dice, int max_damage)
{
dice_def ret(num_dice, 0);
if (num_dice <= 1)
{
ret.num = 1;
ret.size = max_damage;
}
else if (max_damage <= num_dice)
{
ret.num = max_damage;
ret.size = 1;
}
else
{
// Divide the damage among the dice, and add one
// occasionally to make up for the fractions. -- bwr
ret.size = max_damage / num_dice;
ret.size += x_chance_in_y(max_damage % num_dice, num_dice);
}
return (ret);
}
// Attempts to make missile weapons nicer to the player by reducing the
// extreme variance in damage done.
void scale_dice(dice_def &dice, int threshold)
{
while (dice.size > threshold)
{
dice.num *= 2;
// If it's an odd number, lose one; this is more than
// compensated by the increase in number of dice.
dice.size /= 2;
}
}
// Calculates num/den and randomly adds one based on the remainder.
int div_rand_round(int num, int den)
{
return (num / den + (random2(den) < num % den));
}
int bestroll(int max, int rolls)
{
int best = 0;
for (int i = 0; i < rolls; i++)
{
int curr = random2(max);
if (curr > best)
best = curr;
}
return (best);
}
// random2avg() returns same mean value as random2() but with a lower variance
// never use with rolls < 2 as that would be silly - use random2() instead {dlb}
int random2avg(int max, int rolls)
{
int sum = random2(max);
for (int i = 0; i < (rolls - 1); i++)
sum += random2(max + 1);
return (sum / rolls);
}
// originally designed to randomise evasion -
// values are slightly lowered near (max) and
// approach an upper limit somewhere near (limit/2)
int random2limit(int max, int limit)
{
int i;
int sum = 0;
if (max < 1)
return (0);
for (i = 0; i < max; i++)
if (random2(limit) >= i)
sum++;
return (sum);
}
// Generate samples from a binomial distribution with n_trials and trial_prob
// probability of success per trial. trial_prob is a integer less than 100
// representing the % chancee of success.
// This just evaluates all n trials, there is probably an efficient way of
// doing this but I'm not much of a statistician. -CAO
int binomial_generator(unsigned n_trials, unsigned trial_prob)
{
int count = 0;
for (unsigned i = 0; i < n_trials; ++i)
if (::x_chance_in_y(trial_prob, 100))
count++;
return count;
}
bool one_chance_in(int a_million)
{
return (random2(a_million) == 0);
}
bool x_chance_in_y(int x, int y)
{
if (x <= 0)
return (false);
if (x >= y)
return (true);
return (random2(y) < x);
}
int fuzz_value(int val, int lowfuzz, int highfuzz, int naverage)
{
const int lfuzz = lowfuzz * val / 100,
hfuzz = highfuzz * val / 100;
return val + random2avg(lfuzz + hfuzz + 1, naverage) - lfuzz;
}
#ifdef USE_TILE
static std::string tile_cols[24] =
{
"black", "darkgrey", "grey", "lightgrey", "white",
"blue", "lightblue", "darkblue",
"green", "lightgreen", "darkgreen",
"cyan", "lightcyan", "darkcyan",
"red", "lightred", "darkred",
"magenta", "lightmagenta", "darkmagenta",
"yellow", "lightyellow", "darkyellow", "brown"
};
static unsigned int _str_to_tile_colour(std::string colour)
{
if (colour.empty())
return (0);
lowercase(colour);
if (colour == "darkgray")
colour = "darkgrey";
else if (colour == "gray")
colour = "grey";
else if (colour == "lightgray")
colour = "lightgrey";
for (unsigned int i = 0; i < 24; i++)
{
if (tile_cols[i] == colour)
return (i);
}
return (0);
}
#endif
const std::string cols[16] =
{
"black", "blue", "green", "cyan", "red", "magenta", "brown",
"lightgrey", "darkgrey", "lightblue", "lightgreen", "lightcyan",
"lightred", "lightmagenta", "yellow", "white"
};
const std::string colour_to_str(unsigned char colour)
{
if ( colour >= 16 )
return "lightgrey";
else
return cols[colour];
}
int str_to_colour( const std::string &str, int default_colour,
bool accept_number )
{
int ret;
static const std::string element_cols[] =
{
"fire", "ice", "earth", "electricity", "air", "poison",
"water", "magic", "mutagenic", "warp", "enchant", "heal",
"holy", "dark", "death", "necro", "unholy", "vehumet",
"beogh", "crystal", "blood", "smoke", "slime", "jewel",
"elven", "dwarven", "orcish", "gila", "floor", "rock",
"stone", "mist", "shimmer_blue", "decay", "silver", "gold",
"iron", "bone", "random"
};
ASSERT(ARRAYSZ(element_cols) == (ETC_RANDOM - ETC_FIRE) + 1);
for (ret = 0; ret < 16; ++ret)
{
if (str == cols[ret])
break;
}
// Check for alternate spellings.
if (ret == 16)
{
if (str == "lightgray")
ret = 7;
else if (str == "darkgray")
ret = 8;
}
if (ret == 16)
{
// Maybe we have an element colour attribute.
for (unsigned i = 0; i < sizeof(element_cols) / sizeof(*element_cols);
++i)
{
if (str == element_cols[i])
{
// Ugh.
ret = element_type(ETC_FIRE + i);
break;
}
}
}
if (ret == 16 && accept_number)
{
// Check if we have a direct colour index.
const char *s = str.c_str();
char *es = NULL;
const int ci = static_cast<int>(strtol(s, &es, 10));
if (s != (const char *) es && es && ci >= 0 && ci < 16)
ret = ci;
}
return ((ret == 16) ? default_colour : ret);
}
// Returns -1 if unmatched else returns 0-15.
struct dice_def
{
int num;
int size;
dice_def( int n = 0, int s = 0 ) : num(n), size(s) {}
int roll() const;
};
#ifndef COORDIT_H
#define COORDIT_H
#include "player.h"
class rectangle_iterator :
public std::iterator<std::forward_iterator_tag, coord_def>
{
public:
rectangle_iterator( const coord_def& corner1, const coord_def& corner2 );
explicit rectangle_iterator( int x_border_dist, int y_border_dist = -1 );
operator bool() const;
coord_def operator *() const;
const coord_def* operator->() const;
rectangle_iterator& operator ++ ();
rectangle_iterator operator ++ (int);
private:
coord_def current, topleft, bottomright;
};
class radius_iterator : public std::iterator<std::bidirectional_iterator_tag,
coord_def>
{
public:
radius_iterator( const coord_def& center, int radius,
bool roguelike_metric = true,
bool require_los = true,
bool exclude_center = false,
const env_show_grid* losgrid = NULL );
bool done() const;
void reset();
operator bool() const { return !done(); }
coord_def operator *() const;
const coord_def* operator->() const;
const radius_iterator& operator ++ ();
const radius_iterator& operator -- ();
radius_iterator operator ++ (int);
radius_iterator operator -- (int);
private:
void step();
void step_back();
bool on_valid_square() const;
coord_def location, center;
int radius;
bool roguelike_metric, require_los, exclude_center;
const env_show_grid* losgrid;
bool iter_done;
};
class adjacent_iterator : public radius_iterator
{
public:
explicit adjacent_iterator( const coord_def& pos = you.pos(),
bool _exclude_center = true ) :
radius_iterator(pos, 1, true, false, _exclude_center) {}
};
#endif
/*
* File: coordit.h
* Summary: Coordinate iterators.
*/
#include "AppHdr.h"
#include "coordit.h"
#include "coord.h"
#include "los.h"
rectangle_iterator::rectangle_iterator( const coord_def& corner1,
const coord_def& corner2 )
{
topleft.x = std::min(corner1.x, corner2.x);
topleft.y = std::min(corner1.y, corner2.y); // not really necessary
bottomright.x = std::max(corner1.x, corner2.x);
bottomright.y = std::max(corner1.y, corner2.y);
current = topleft;
}
rectangle_iterator::rectangle_iterator( int x_border_dist, int y_border_dist )
{
if (y_border_dist < 0)
y_border_dist = x_border_dist;
topleft.set(x_border_dist, y_border_dist);
bottomright.set(GXM - x_border_dist - 1, GYM - y_border_dist - 1);
current = topleft;
}
rectangle_iterator::operator bool() const
{
return (current.y <= bottomright.y);
}
coord_def rectangle_iterator::operator *() const
{
return current;
}
const coord_def* rectangle_iterator::operator->() const
{
return ¤t;
}
rectangle_iterator& rectangle_iterator::operator ++()
{
if (current.x == bottomright.x)
{
current.x = topleft.x;
current.y++;
}
else
{
current.x++;
}
return *this;
}
rectangle_iterator rectangle_iterator::operator++( int dummy )
{
const rectangle_iterator copy = *this;
++(*this);
return (copy);
}
radius_iterator::radius_iterator(const coord_def& _center, int _radius,
bool _roguelike_metric, bool _require_los,
bool _exclude_center,
const env_show_grid* _losgrid)
: center(_center), radius(_radius), roguelike_metric(_roguelike_metric),
require_los(_require_los), exclude_center(_exclude_center),
losgrid(_losgrid), iter_done(false)
{
reset();
}
void radius_iterator::reset()
{
iter_done = false;
location.x = center.x - radius;
location.y = center.y - radius;
if ( !this->on_valid_square() )
++(*this);
}
bool radius_iterator::done() const
{
return iter_done;
}
coord_def radius_iterator::operator *() const
{
return location;
}
const coord_def* radius_iterator::operator->() const
{
return &location;
}
void radius_iterator::step()
{
const int minx = std::max(X_BOUND_1+1, center.x - radius);
const int maxx = std::min(X_BOUND_2-1, center.x + radius);
const int maxy = std::min(Y_BOUND_2-1, center.y + radius);
// Sweep L-R, U-D
location.x++;
if (location.x > maxx)
{
location.x = minx;
location.y++;
if (location.y > maxy)
iter_done = true;
}
}
void radius_iterator::step_back()
{
const int minx = std::max(X_BOUND_1+1, center.x - radius);
const int maxx = std::min(X_BOUND_2-1, center.x + radius);
const int miny = std::max(Y_BOUND_1+1, center.y - radius);
location.x--;
if (location.x < minx)
{
location.x = maxx;
location.y--;
if (location.y < miny)
iter_done = true;
}
}
bool radius_iterator::on_valid_square() const
{
if (!in_bounds(location))
return (false);
if (!roguelike_metric && (location - center).abs() > radius*radius)
return (false);
if (require_los)
{
if (!losgrid && !see_cell(location))
return (false);
if (losgrid && !see_cell(*losgrid, center, location))
return (false);
}
if (exclude_center && location == center)
return (false);
return (true);
}
const radius_iterator& radius_iterator::operator++()
{
do
this->step();
while (!this->done() && !this->on_valid_square());
return (*this);
}
const radius_iterator& radius_iterator::operator--()
{
do
this->step_back();
while (!this->done() && !this->on_valid_square());
return (*this);
}
radius_iterator radius_iterator::operator++(int dummy)
{
const radius_iterator copy = *this;
++(*this);
return (copy);
}
radius_iterator radius_iterator::operator--(int dummy)
{
const radius_iterator copy = *this;
--(*this);
return (copy);
}
#ifndef COORD_H
#define COORD_H
bool in_bounds_x(int x);
bool in_bounds_y(int y);
bool in_bounds(int x, int y);
bool map_bounds_x(int x);
bool map_bounds_y(int y);
bool map_bounds(int x, int y);
coord_def random_in_bounds();
inline bool in_bounds(const coord_def &p)
{
return in_bounds(p.x, p.y);
}
inline bool map_bounds(const coord_def &p)
{
return map_bounds(p.x, p.y);
}
// Determines if the coordinate is within bounds of an LOS array.
inline bool show_bounds(const coord_def &p)
{
return (p.x >= 0 && p.x < ENV_SHOW_DIAMETER
&& p.y >= 0 && p.y < ENV_SHOW_DIAMETER);
}
int grid_distance( const coord_def& p1, const coord_def& p2 );
int grid_distance( int x, int y, int x2, int y2 );
int distance( const coord_def& p1, const coord_def& p2 );
int distance( int x, int y, int x2, int y2);
bool adjacent( const coord_def& p1, const coord_def& p2 );
#endif
#include "AppHdr.h"
#include "coord.h"
#include "directn.h"
#include "random.h"
#include "state.h"
//////////////////////////////////////////////////////////////////////////
// coord_def
int coord_def::distance_from(const coord_def &other) const
{
return (grid_distance(*this, other));
}
int grid_distance( const coord_def& p1, const coord_def& p2 )
{
return grid_distance(p1.x, p1.y, p2.x, p2.y);
}
// More accurate than distance() given the actual movement geometry -- bwr
int grid_distance( int x, int y, int x2, int y2 )
{
const int dx = abs( x - x2 );
const int dy = abs( y - y2 );
// returns distance in terms of moves:
return ((dx > dy) ? dx : dy);
}
int distance( const coord_def& p1, const coord_def& p2 )
{
return distance(p1.x, p1.y, p2.x, p2.y);
}
int distance( int x, int y, int x2, int y2 )
{
//jmf: now accurate, but remember to only compare vs. pre-squared distances
// thus, next to == (distance(m1.x,m1.y, m2.x,m2.y) <= 2)
const int dx = x - x2;
const int dy = y - y2;
return ((dx * dx) + (dy * dy));
}
bool adjacent( const coord_def& p1, const coord_def& p2 )
{
return grid_distance(p1, p2) <= 1;
}
bool in_bounds_x(int x)
{
return (x > X_BOUND_1 && x < X_BOUND_2);
}
bool in_bounds_y(int y)
{
return (y > Y_BOUND_1 && y < Y_BOUND_2);
}
// Returns true if inside the area the player can move and dig (ie exclusive).
bool in_bounds(int x, int y)
{
return (in_bounds_x(x) && in_bounds_y(y));
}
bool map_bounds_x(int x)
{
return (x >= X_BOUND_1 && x <= X_BOUND_2);
}
bool map_bounds_y(int y)
{
return (y >= Y_BOUND_1 && y <= Y_BOUND_2);
}
// Returns true if inside the area the player can map (ie inclusive).
// Note that terrain features should be in_bounds() leaving an outer
// ring of rock to frame the level.
bool map_bounds(int x, int y)
{
return (map_bounds_x(x) && map_bounds_y(y));
}
coord_def random_in_bounds()
{
if (crawl_state.arena)
{
const coord_def &ul = crawl_view.glos1; // Upper left
const coord_def &lr = crawl_view.glos2; // Lower right
return coord_def(random_range(ul.x, lr.x - 1),
random_range(ul.y, lr.y - 1));
}
else
return coord_def(random_range(MAPGEN_BORDER, GXM - MAPGEN_BORDER - 1),
random_range(MAPGEN_BORDER, GYM - MAPGEN_BORDER - 1));
}
#ifndef COLOUR_H
#define COLOUR_H
// various elemental colour schemes... used for abstracting random
// short lists. When adding colours, please also add their names in
// str_to_colour!
enum element_type
{
ETC_FIRE = 32, // fiery colours (must be first and > highest colour)
ETC_ICE, // icy colours
ETC_EARTH, // earthy colours
ETC_ELECTRICITY, // electrical side of air
ETC_AIR, // non-electric and general air magic
ETC_POISON, // used only for venom mage and stalker stuff
ETC_WATER, // used only for the elemental
ETC_MAGIC, // general magical effect
ETC_MUTAGENIC, // transmute, poly, radiation effects
ETC_WARP, // teleportation and anything similar
ETC_ENCHANT, // magical enhancements
ETC_HEAL, // holy healing (not necromantic stuff)
ETC_HOLY, // general "good" god effects
ETC_DARK, // darkness
ETC_DEATH, // currently only assassin (and equal to ETC_NECRO)
ETC_NECRO, // necromancy stuff
ETC_UNHOLY, // demonology stuff
ETC_VEHUMET, // vehumet's oddball colours
ETC_BEOGH, // Beogh altar colours
ETC_CRYSTAL, // colours of crystal
ETC_BLOOD, // colours of blood
ETC_SMOKE, // colours of smoke
ETC_SLIME, // colours of slime
ETC_JEWEL, // colourful
ETC_ELVEN, // used for colouring elf fabric items
ETC_DWARVEN, // used for colouring dwarf fabric items
ETC_ORCISH, // used for colouring orc fabric items
ETC_GILA, // gila monster colours
ETC_FLOOR, // colour of the area's floor
ETC_ROCK, // colour of the area's rock
ETC_STONE, // colour of the area's stone
ETC_MIST, // colour of mist
ETC_SHIMMER_BLUE, // shimmering colours of blue.
ETC_DECAY, // colour of decay/swamp
ETC_SILVER, // colour of silver
ETC_GOLD, // colour of gold
ETC_IRON, // colour of iron
ETC_BONE, // colour of bone
ETC_RANDOM // any colour (except BLACK)
};
int str_to_colour(const std::string &str, int default_colour = -1,
bool accept_number = true);
const std::string colour_to_str(unsigned char colour);
unsigned int str_to_tile_colour(std::string colour);
unsigned char random_colour();
unsigned char random_uncommon_colour();
unsigned char make_low_colour(unsigned char colour);
unsigned char make_high_colour(unsigned char colour);
bool is_element_colour(int col);
int element_colour(int element, bool no_random = false);
#endif
#include "AppHdr.h"
#include "colour.h"
#include "env.h"
#include "player.h"
#include "random.h"
unsigned char random_colour(void)
{
return (1 + random2(15));
}
unsigned char random_uncommon_colour()
{
unsigned char result;
do
result = random_colour();
while (result == LIGHTCYAN || result == CYAN || result == BROWN);
return (result);
}
unsigned char make_low_colour(unsigned char colour)
{
if (colour >= 8 && colour <= 15)
return (colour - 8);
return (colour);
}
unsigned char make_high_colour(unsigned char colour)
{
if (colour <= 7)
return (colour + 8);
return (colour);
}
// returns if a colour is one of the special element colours (ie not regular)
bool is_element_colour( int col )
{
// stripping any COLFLAGS (just in case)
return ((col & 0x007f) >= ETC_FIRE);
}
int element_colour( int element, bool no_random )
{
// Doing this so that we don't have to do recursion here at all
// (these were the only cases which had possible double evaluation):
if (element == ETC_FLOOR)
element = env.floor_colour;
else if (element == ETC_ROCK)
element = env.rock_colour;
// pass regular colours through for safety.
if (!is_element_colour( element ))
return (element);
int ret = BLACK;
// Setting no_random to true will get the first colour in the cases
// below. This is potentially useful for calls to this function
// which might want a consistent result.
int tmp_rand = (no_random ? 0 : random2(120));
switch (element & 0x007f) // strip COLFLAGs just in case
{
case ETC_FIRE:
ret = (tmp_rand < 40) ? RED :
(tmp_rand < 80) ? YELLOW
: LIGHTRED;
break;
case ETC_ICE:
ret = (tmp_rand < 40) ? LIGHTBLUE :
(tmp_rand < 80) ? BLUE
: WHITE;
break;
case ETC_EARTH:
ret = (tmp_rand < 60) ? BROWN : LIGHTRED;
break;
case ETC_AIR:
ret = (tmp_rand < 60) ? LIGHTGREY : WHITE;
break;
case ETC_ELECTRICITY:
ret = (tmp_rand < 40) ? LIGHTCYAN :
(tmp_rand < 80) ? LIGHTBLUE
: CYAN;
break;
case ETC_POISON:
ret = (tmp_rand < 60) ? LIGHTGREEN : GREEN;
break;
case ETC_WATER:
ret = (tmp_rand < 60) ? BLUE : CYAN;
break;
case ETC_MAGIC:
ret = (tmp_rand < 30) ? LIGHTMAGENTA :
(tmp_rand < 60) ? LIGHTBLUE :
(tmp_rand < 90) ? MAGENTA
: BLUE;
break;
case ETC_MUTAGENIC:
case ETC_WARP:
ret = (tmp_rand < 60) ? LIGHTMAGENTA : MAGENTA;
break;
case ETC_ENCHANT:
ret = (tmp_rand < 60) ? LIGHTBLUE : BLUE;
break;
case ETC_HEAL:
ret = (tmp_rand < 60) ? LIGHTBLUE : YELLOW;
break;
case ETC_BLOOD:
ret = (tmp_rand < 60) ? RED : DARKGREY;
break;
case ETC_DEATH: // assassin
case ETC_NECRO: // necromancer
ret = (tmp_rand < 80) ? DARKGREY : MAGENTA;
break;
case ETC_UNHOLY: // ie demonology
ret = (tmp_rand < 80) ? DARKGREY : RED;
break;
case ETC_DARK:
ret = (tmp_rand < 80) ? DARKGREY : LIGHTGREY;
break;
case ETC_HOLY:
ret = (tmp_rand < 60) ? YELLOW : WHITE;
break;
case ETC_VEHUMET:
ret = (tmp_rand < 40) ? LIGHTRED :
(tmp_rand < 80) ? LIGHTMAGENTA
: LIGHTBLUE;
break;
case ETC_BEOGH:
ret = (tmp_rand < 60) ? LIGHTRED // plain Orc colour
: BROWN; // Orcish mines wall/idol colour
break;
case ETC_CRYSTAL:
ret = (tmp_rand < 40) ? LIGHTGREY :
(tmp_rand < 80) ? GREEN
: LIGHTRED;
break;
case ETC_SLIME:
ret = (tmp_rand < 40) ? GREEN :
(tmp_rand < 80) ? BROWN
: LIGHTGREEN;
break;
case ETC_SMOKE:
ret = (tmp_rand < 30) ? LIGHTGREY :
(tmp_rand < 60) ? DARKGREY :
(tmp_rand < 90) ? LIGHTBLUE
: MAGENTA;
break;
case ETC_JEWEL:
ret = (tmp_rand < 12) ? WHITE :
(tmp_rand < 24) ? YELLOW :
(tmp_rand < 36) ? LIGHTMAGENTA :
(tmp_rand < 48) ? LIGHTRED :
(tmp_rand < 60) ? LIGHTGREEN :
(tmp_rand < 72) ? LIGHTBLUE :
(tmp_rand < 84) ? MAGENTA :
(tmp_rand < 96) ? RED :
(tmp_rand < 108) ? GREEN
: BLUE;
break;
case ETC_ELVEN:
ret = (tmp_rand < 40) ? LIGHTGREEN :
(tmp_rand < 80) ? GREEN :
(tmp_rand < 100) ? LIGHTBLUE
: BLUE;
break;
case ETC_DWARVEN:
ret = (tmp_rand < 40) ? BROWN :
(tmp_rand < 80) ? LIGHTRED :
(tmp_rand < 100) ? LIGHTGREY
: CYAN;
break;
case ETC_ORCISH:
ret = (tmp_rand < 40) ? DARKGREY :
(tmp_rand < 80) ? RED :
(tmp_rand < 100) ? BROWN
: MAGENTA;
break;
case ETC_GILA:
ret = (tmp_rand < 30) ? LIGHTMAGENTA :
(tmp_rand < 60) ? MAGENTA :
(tmp_rand < 90) ? YELLOW :
(tmp_rand < 105) ? LIGHTRED
: RED;
break;
case ETC_STONE:
if (player_in_branch( BRANCH_HALL_OF_ZOT ))
ret = env.rock_colour;
else
ret = LIGHTGREY;
break;
case ETC_MIST:
ret = tmp_rand < 100? CYAN : BLUE;
break;
case ETC_SHIMMER_BLUE:
ret = random_choose_weighted(80, BLUE, 20, LIGHTBLUE, 5, CYAN, 0);
break;
case ETC_DECAY:
ret = (tmp_rand < 60) ? BROWN : GREEN;
break;
case ETC_SILVER:
ret = (tmp_rand < 90) ? LIGHTGREY : WHITE;
break;
case ETC_GOLD:
ret = (tmp_rand < 60) ? YELLOW : BROWN;
break;
case ETC_IRON:
ret = (tmp_rand < 40) ? CYAN :
(tmp_rand < 80) ? LIGHTGREY :
DARKGREY;
break;
case ETC_BONE:
ret = (tmp_rand < 90) ? WHITE : LIGHTGREY;
break;
case ETC_RANDOM:
ret = 1 + random2(15); // always random
break;
case ETC_FLOOR: // should already be handled
case ETC_ROCK: // should already be handled
default:
break;
}
ASSERT( !is_element_colour( ret ) );
return ((ret == BLACK) ? GREEN : ret);
}
#ifdef USE_TILE
static std::string tile_cols[24] =
{
"black", "darkgrey", "grey", "lightgrey", "white",
"blue", "lightblue", "darkblue",
"green", "lightgreen", "darkgreen",
"cyan", "lightcyan", "darkcyan",
"red", "lightred", "darkred",
"magenta", "lightmagenta", "darkmagenta",
"yellow", "lightyellow", "darkyellow", "brown"
};
unsigned int str_to_tile_colour(std::string colour)
{
if (colour.empty())
return (0);
lowercase(colour);
if (colour == "darkgray")
colour = "darkgrey";
else if (colour == "gray")
colour = "grey";
else if (colour == "lightgray")
colour = "lightgrey";
for (unsigned int i = 0; i < 24; i++)
{
if (tile_cols[i] == colour)
return (i);
}
return (0);
}
#endif
const std::string cols[16] =
{
"black", "blue", "green", "cyan", "red", "magenta", "brown",
"lightgrey", "darkgrey", "lightblue", "lightgreen", "lightcyan",
"lightred", "lightmagenta", "yellow", "white"
};
const std::string colour_to_str(unsigned char colour)
{
if ( colour >= 16 )
return "lightgrey";
else
return cols[colour];
}
// Returns -1 if unmatched else returns 0-15.
int str_to_colour( const std::string &str, int default_colour,
bool accept_number )
{
int ret;
static const std::string element_cols[] =
{
"fire", "ice", "earth", "electricity", "air", "poison",
"water", "magic", "mutagenic", "warp", "enchant", "heal",
"holy", "dark", "death", "necro", "unholy", "vehumet",
"beogh", "crystal", "blood", "smoke", "slime", "jewel",
"elven", "dwarven", "orcish", "gila", "floor", "rock",
"stone", "mist", "shimmer_blue", "decay", "silver", "gold",
"iron", "bone", "random"
};
ASSERT(ARRAYSZ(element_cols) == (ETC_RANDOM - ETC_FIRE) + 1);
for (ret = 0; ret < 16; ++ret)
{
if (str == cols[ret])
break;
}
// Check for alternate spellings.
if (ret == 16)
{
if (str == "lightgray")
ret = 7;
else if (str == "darkgray")
ret = 8;
}
if (ret == 16)
{
// Maybe we have an element colour attribute.
for (unsigned i = 0; i < sizeof(element_cols) / sizeof(*element_cols);
++i)
{
if (str == element_cols[i])
{
// Ugh.
ret = element_type(ETC_FIRE + i);
break;
}
}
}
if (ret == 16 && accept_number)
{
// Check if we have a direct colour index.
const char *s = str.c_str();
char *es = NULL;
const int ci = static_cast<int>(strtol(s, &es, 10));
if (s != (const char *) es && es && ci >= 0 && ci < 16)
ret = ci;
}
return ((ret == 16) ? default_colour : ret);
}
}
dice_def calc_dice( int num_dice, int max_damage )
{
dice_def ret( num_dice, 0 );
if (num_dice <= 1)
{
ret.num = 1;
ret.size = max_damage;
}
else if (max_damage <= num_dice)
{
ret.num = max_damage;
ret.size = 1;
}
else
{
// Divide the damage among the dice, and add one
// occasionally to make up for the fractions. -- bwr
ret.size = max_damage / num_dice;
ret.size += x_chance_in_y(max_damage % num_dice, num_dice);
}
return (ret);