git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@6550 c06c8d41-db1a-0410-9941-cceddc491573
Q3B3UVMYEVC4YJUPYVSNTR4DJH4E6J4JJDHZNT5LNOCHCPPMEMXAC
MN4TJZVTK27PM5ETQBJBUMF64CXJRN75IVCS2MWGTIVCFPRR7LOAC
I2G7DP3TJL4RDMYKNXAA67P3VRSO3RF7FHZWA5CYINSEWEQE2YSQC
MWS346AS2OCQYDQ64HRT3U47NJCRGEYBLMT5K7DWSWT7ULMA4WLAC
BWPT5FA3JZJCSFPPRDLJF76ZKAG4WGUHNIWQFAYZ4DAZLFIIMZ7AC
KHY3KA2VB4VVMKYNR7ETQQBT2NO2LTEQQPBRQ7TA6O4BNH7OLVYQC
XWJFLTFZL3MPBNI6Q3VEKRY45PVTHGTQUNLVFMP2FVI7LBZJQ2XQC
66KRMFZAWM65VI75Z6O4CIVCKB3Z2YQCQSGE44OAP6ESTEFUWYOQC
BGPUXHZ2FDUKA6LAFNBDQJOT3XQGTZQDYBPU7Z6H5HTXZK2EG2BAC
MZFGNRIWJAKU2LX5S2C76IRT4ORXSBXBNP24EUSFEZYHUVIS3A5QC
RLKCTCTFWIGLVMMXGD4IXXA7HCKLOJ3KILVWQUMWVT2CNI5ZMRPAC
325MMZ56C7O4XJSIVKTRHWL2Z5FUVVXATBE7PEHXZGX4XXR2NOJQC
OYPZUHLG34Y64LSNG3G4GTCOZJWV2JOLKWFDUMVRAVFXKXUERPEQC
3YAYJNECJUGIKFNE4F5QJ2X3PRIEIACYXUQL45EHVLROMK6NJOOQC
I4M3O5UA4UOV35WFD435G3GP6RT3EZ5NPRZ645X22A2Z7CR2E2AAC
KVPISK262B2GBNOFBAA3GL3QUNAJJGKVS326YYQZTP7QF3YKFX4QC
5JMTXGN7S5VCLCXRYJAOV32MPPW4IECFJ2NCSFLDVRNFPINHPDTQC
KDSO4JU27HHHNK4PMAFCE2GULZ5X4J2R5SYMTXC4I6YALWYBB4UAC
T6IYM4SLLV3G55XKSFPK3QAY2KF6MXYXXHLFHGLEQEZABTCJU6UAC
2KZ65CC2GFWTSCYVXFSKNRW3CJBBYPSWE2F7XFFI2OXH4I2YOA4AC
EQNA77UM24FFYQ2N44FG53KQGLS43ZGEX7XS5UWR6MM2HE3JBKAAC
AMSENYIGRJWHHGHLKIZQGZZQTWCZBTS2Y3WKPVTZZRI7ZMTATBCAC
AEPGJLX47SNMG4B25UWQXXIQTN4N7TCIVSENYVYAJEQFPTT2OP6AC
55OQMLV7ONCBKOS4KW6W4D3X7JZZTI3PGIVUVHCWCLWCPGKTEE4AC
OHOFJZ6S5AJUO5EFVGG7HJHRPSXJSTJD2DDXAERT4LNVWDK23K6AC
72YQQHCY6DYHOVZ6P5C7APPDA7D4UUPJTBJCLRSK7RIKLBP5JS4AC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
AXAM3TX4CUCIPL6ILEJLGJ4D4SMCJYDXGLIB256PBQXXKBIKZ4QAC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
LDBTCT5WIPLJPZWXS2RUQ26QKISCUUTLO77M464WOE6VSYSNPKYAC
D5EMJEEIJSSULF236DUM26QHHNDLH7FXAOBHFDAYI65KCKTDTDYQC
IHOKNI4O7EEW4UBMKHP6XOZNEIQSW4AYOT4O3JXUIXNNR553IQAQC
5DTGRF4G4T2CAUCZHTPNM6FF2XJHUYMWF74MATNVJC5QYSOPNOPQC
5B5DP5S6A6LQMKZYVLQAEMHQZWFWYDHPCKQGRNSCNNYIBQYZ6BIQC
S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC
MZLB3Q7G4EC2BR3OFMG55WPHXPFJGQSLWAIHHFJEAEATPUTYR7EAC
S6Z5DI4LGLFHRSOVGGC7PW5CPP34GR5TJXPSJ2XMBFR5YU6VNF4QC
YBNWH7EXICXYJXYSLYSVMVZCVR7MWMVJ24CAUZ4ELPZUYTJ4CE5AC
BLZC4APKXT76IVDHJ7UHBZQJJVW4FOLLDEDAKAGNLF6LZYMWOWOAC
XR2332MJV6ZC6GWBRRWV4IZAYXMK7WLXGSNLGZHHAKN65HS26IVAC
M5JRISNFA35UTUE6EZKABYLNFLD5Y2CM3CEASFEWM4QRNYC3UK3QC
HRAL36C7UUL7V6TFXQ76FZ3VVVFEJYF7YWOP2EXYXP6C27XME2PAC
LJNAKLI5N7MDAOOM6RSRUOJ6OOKRAM7NHA3G562KYAVN6H4Y3R4QC
5FA5IEAXTMXYS2VUBVDKBKHPKAIOY4GN5SXYJORBYWQIGHVW3FFQC
H5CCPXNHFSQ3SBRGB72XZTFD2U77DP7ZMW2SXXKD7DD3EO732QDQC
C4WXQRJTDW53PYFWQ4LOINSCI2IWMIQTH5WDSI7QUP72PKDBYHZAC
ANOEQTM6IGCBTESKKQ5PCBSDTZ7VGRCMDIOAFEH4R7DJHKWKDFAAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
PL6I2CMSTHY5ZHWVMIQE5YTM5S5VPKBNZM6QJVHZSSKOJGIJ5W4AC
D27U7RT2C77NEUBP6JCSQJ2DRCJVHOXUO2PFZ45VFYMEVMKI4TSAC
L57WEZMVIHTFRLWVIPWOIOWHCF2I53TVUVYJ2V6IZ64R56FVTZZAC
NG53L53MSFQZAIVKHG54IEMXNJ33AYVPF2OZM4MMJFDKEJCGPBSAC
AUXVWXWIFSTWFA6VZXN2FMG7FQEKRZVV6MD32VQQ7J2RKCXHAVGAC
4VK7VHWRVRO66BRSGTBPSYJGGXLRF6AG6G74UDTPHTPXR7ZRNINQC
E7DV36ZR6TOGBD75BHGARCMIQQS6MSV7V3A7M7V4LOFHEC5NF6CQC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
75M6AVUSS3G5EJECJJRB67V5UYDOIV26FZNB2FFCMBZ33EK7FVIQC
Z7SNXEH74EM5YJW3KVPVDQAQZB425M62AYB5GODBNVYMBRVJ4LSQC
XHNJ2W4AQHIF32P2ENIMMDLWAIFWP442KJIZC6RKS4HBJNZIHHBAC
HKMVHUQLTDIDM3HGXCTLPHHT5YJHV5UMQPEVX5ZL4G7OLEICIOXQC
WHY6LRRJ5T2NSBE3IUCR4X3TOAH7TTK5NPUPUIFT7TPNJ6J4HBDAC
4HATGRJJE7Q6LXHJ3ZGYTNBLG542KAUEK6ERKARIYRKRWY6VTDKQC
CQ24AVAI6SW3AHTIDMLPSTRRBEU6FHRF5I5FD6G5QIYE6PO4BQMQC
TPZWAV3USKO7RX4IGHLZKVPRN36K33PJPSZYL6FZMX4XBHTYOQYAC
2TECJQA3PK7OYSSTOWZSQFWMTATJRHHA6JV3IGRHFGS3R7U27RZAC
7NDXS36TE7QVXTXJWMYSVG5UHCCLPIO4VL6NXFGTDK3ZNKE3A2IAC
ESWIM76FGJL4QFLSHU6AC4D74PT7OPLQ7ZCJYWLZS5UCBAJDXYHAC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
HQTS3VQ6PNUZKHNVEWMML7JNAAAKL4DSW3KFSRCCSLGYTDHZFCCAC
7HA2754QW3SBCAJ5K6KUXNXXXIZB5BIBCFPLXADCXHH6EREKXHSAC
TOOHYAX73C5KPSWGHPCBWCUN62WMMO3BI5CWEEMGV3WBFZ5RIH5AC
W54GZBNFKPOF6DTOVK73PVASTQI5DXG42WQ6CXFDPXHFZOHUVVSQC
NK2TBKWOQBD2ZRGAO4Z3HMZPIN7UX3HNUS2YHEIJUUINUTRMPODQC
LS5XCCGKQHSJQGWLWLGTP2F5OYWK4ND5AQQAGRN6H2HVBSXNCCZAC
5HF63O5IRRERI2V3SZEDHUNFHUF2B4RSVWQR6C6DR5JF5UYSROWAC
QXD3HX6QQ37PW6HVKIIKGFLO2ACROLUGKK66KFX7ED6SO4FDXB2AC
RS2Q66UPKG2NLNBE6UMX273UEVNGTNLVEITB2PCRVHZWTS2WXTAQC
OYYZVCE3QHBVJM6IEKK5HTJRG5YOVQNCBRMSJENTHOI2WPJLNCFAC
GWGKGHFGBLVPDSSDWYFORHZHMWOR3SFC5PJNF732V7FEKWWJKPOAC
O6ZMFKDI3XO2SWPNEYHIPYFDWJR4TVDP5BAATK6LVCVETQID6E7AC
KZIHM6RUX43HHKXG6HGJHVEEYUPVVNBFIWMT4SKPD2GAH5ZMA3KAC
3SK2OEKJBQUGGYU2PJ7BWBGMKS53K2JH6HKL65AWTFN6JVZRG2PAC
44LY6TB272RWWFLON2XOUIXWFPUXM5OMX6KLX66HH37BNURVT4DQC
4SUUJM2DQUEWHDG3UKJUDZABLHFVF2CFUX5GVAWKT7BBBGR2ISTQC
U6ILMKBXTQZYT62IGD2CALYNU4VQGRSTHN6QBFBU7BVUBHWYOEQQC
HUMRQOA7Y32XBXQNR5LUIWM2ZB57XDW4ZQHMZ4RDGDZATY6K73SQC
CSRWDG2SUGS4YR4PAFI574EGEXW65P6JDT4ZHWDICS2G2GZIGEUQC
D7EPLNYHJH6C4CTMHCOUUODKGHCJRE4CGKNVSCHCSABN6ZOD2ZBAC
J3M6J3UPL4AUJDXINY7UKH2JZQVQLKGH7AMOKI6L3QI7Y2F33O5QC
LP5EK64IEM7AHNYQID4GGKOQJQNZLKY4DCCZN47SIUZ6IXAXH5UAC
CKY7MRFWMNHXIPJD5ZUAJN5T2YHUIEAYBNYYV5GN74LBZJRDJMEQC
HODV46TCH5AGI42Z5JKVDX4VCRVQCNREJUL6W3TUJK6S77SXQNLQC
RB4PNFZOBEPUJM6PH4J4IPKF2WYYSQ2DINHZHOGDPA4ZN6E4RJAAC
E3X5HVN5UN75OMTJA6JFQBNZ54P37NDZLZZF7EFBZZC45KR73YGAC
Q3XHNSHW6FI4JCXSEABATRFBJPMCF7PXNG2K6ZQTRRPVMIZFHUBQC
3FRPKD2JSN7RA2HKWAO3XV7MMKCIAMWIMU6JNJ452VZEUSXM6PWQC
FOQJ5S5WR7P7YMEWQ5Q4O7LTGLQ7LFVM4I2SG2Q7MIVC4PB2JHTQC
OEISFRW2B7E4YRJSWXNXBH2IAJO4O3LHNYFPFD3MBY57LYVRHMZQC
MQOL2SN2EYBCAVVJ7NPCXEV6C4NPBNMC6QD2AOTZPIAZB243JQ7QC
JXAB5WYRDGBLKOBEQJLZKIE7YHQ2ZI6LKWEFSNF2TGAHPNUI3SBQC
ZNUMGZOGREVG6RNSM4RGHG2Y6NYL7O2U642V6F3HJAXMTC5JXJHAC
ZWVXM43CBKDWRFNZ432Z6G6J7DBA2GKRRGCSZQCRQS2M4YX53ETQC
ZBHENBGH5RNIC4L2NP45RJWYB3256NAM2JU2E3CD2RF6FEV4Z4FAC
HBHQQDULNVWISJ75XIL6R6BFEDYRNY22NX3ZTFVNP5ZWJGJSKOEQC
RNRDGY5JBFBHF7IDQ6LDV2GULR4ILNJ7UHYNGIWZIPLN6IJYX2PQC
CD4GR4YLJMAMP5XZ3IR7MZ6SDLQJL6YSPWMH74VV5Z56TZAZDM2QC
TZLAHS2FQGDWDAO6OQFZIZALQCCRTCRBJZBNZFNQ4G7D5UYAIFQAC
QON6K747RDVN55UTIJWNGIIGSDS7IHKB24JMHWSIMAQ572D7C3NAC
3ICSXUKO2RWAARVKXTV3MGIB6G7UQHIHN5I4JNBLXIFEQA4H462QC
PDOFPXD2X6VI23AHKCGQ5RVDBG74CNP2E3YOHKXLOARHHBXEK3HQC
TUF6IG4NNHW5YD5AVRYE7GILPSFJLUV6442F5LSP436MFEIIGVUAC
3ZWALZFSTSIVYXY4BAY6ANGINTDACZC6RSSJTEMQSTSUIE66YOBQC
TFHMBVXTRA2LXBHE7L7OEWK37JQN5DWZ3HOACMN7PRWVJNCS4TYQC
OTVV4KBC5LVECK5B2Y7ORMRV7K4OXRZMYPCAMWJCUGZCQIBVRTXQC
GJIMGW6UJFIEZEOOHUVR6647W2C3L6MFRKIE5AKQIPZ5LIOWZWMAC
STQDS62PD6PCLYBAB7LPYTG47WMBJP3FIJL55UHC3XFDPGERC3UQC
ND3T5LCZATC63EVQ6SLI7XXMSUL7XICJDNLH3UCYUDEFWTA3N5MQC
PSCYVKJ7DGXAL3V5U4O6AJTRV6Q3N3SHQWAZ73VIPRTE4W64F2XAC
4VV5V2ZLRNS6TDMQR7ZAE5INGFZAGNLJ5GXFMMX5JJWZEJSLFS7QC
SH6NU4H5TG4O7CRXRHZ7MDHABZLWWXQ77NJDBHI7KCVHXHQYK46QC
SQV4OUWNCYWQTAVHXNK4AENJAEOU2YZOJNJTRWVDZZHOEG6OVAFAC
7G4KWTOOBRLHOZZGFGAXGTUCDF3FGSZOXVHUZZ3V2KVWYSFE7EKAC
EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC
KEANRIMF5CGFVZ2XJYNFPOAKLXOSOJUOVA73IWBWOG576265ERHAC
3VWSZUGYL36SO5AOZRASGK3VHFCFZUGGCGRT3R7BZB36IZPN7OSQC
36SHRKVELEOW7PUDHUS2ONWI6OEHUTP6NBFGOT4GR6ZS3QZRTK5AC
CNTJFUFA4A3L53QEITFZEWL4R4AXOXP4L3K4X5NSKFHBAFSREIQAC
LAMIVDKY7LO5ONX5Z273ZCCEA5UBENOJD5VWNE4AK2EXGFED6BFQC
2GV6OW7P54FXZ5OD2NUMX7MLXH424LYAFMOAUQ2UGSOLKLYDBJGAC
SXQ32Z7ZILMUYSDTK3WE6OOEBYZURCJIUDHT3PXVPV44CBZTPGJQC
L2BH25YQXSIQ7B66SXO7Q3IWUFVX7HTERRJZ5ZJJZS54ZETVFP6AC
AYYQVALBAAKFK5U52WGHWE2N7LCVZM3BGRADPVJQWOFLS2TXK6QAC
YOZHWGKGPWZGHQYNMMBHNGDO2UEVIHPOR6UF3SEZPIYWVMBGWBOAC
JJCHVUDSWKDHVKOYATOUV7RLXAMVMTL6FFFVR7OBW57OCD7MW3PQC
ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC
542UIZKI65UDRNEMGFFDBWYD5XC7AYLTZ3JZQRR2GHYJALD3YY6QC
DGB7DKTR6OEQEMOOF3MAHDT4PAPKZ54Y33MWYVD7XIOESPFAXHQQC
QCUMH3C7GXV7ZW444WT5SFAXQOJKJSE2YCQCEHMRYXCWF4QI7UMAC
XI7U6RL6MFTH6SZQMLO4XFWGXGIFJBCRT6ZFCJFR2B2MGRSKDDCAC
OXHOOJE4XEQKGI3JKURNSITG6CRQFAOFQ2EKKG6M5DCLN7LS4GUAC
FRLPNEJJAGFWOJ5KJAE4PUQZN3EA4UAFKKUNN2UL5CRWKJRLMMJQC
PBRFKFYILME3A2YLLVGRWJ2C7PCE2GONSINX65P4EG22ZGCW6JWAC
YMC3RKF4Z7DOHZNGG7INC343SXCTWOPK7ISD42I3WA3AZZNVBGIAC
TM35IHKZZNBCMR3ERBS4EYHGUK5IVCPUT2JUITMT74AYAIUZSYFQC
RX6575DZOHRUXQUZH34YZGPZJF4STUPLBQDIVTINA2L6LVCKRIGQC
ZVJPCEGKZ3MMRTTN563KQOSA7LFVFMMUDVARW2W5YQG6XZB6U7UAC
CYAVI4PYWMMKTPYT5N2B3MI4OSHZFLPKOZFSLFJUXRYAACYXWW3AC
67AF33NTJG4WEAIFQX4R5XZTC5XZ5IBVHSFLYTGOXQJIXCZVXKDQC
V4C7Y3VML7H7IXW5IZYL4ONSBUYDEU6RSRCDCOAZD7SZ4ZC2ONPAC
WSENSWVHRNAW2NZO3HQLRV3HJKULA4JQHKM65M2NINZSD6NRQAMAC
DGHHGJ6RCXFF3I53K2DI2FDB3UW2SUZAWWAQ7T6YW6374WOQASUQC
BFYHDL4EHSPKKC6EPKDRPESHYAA2WFKC6RXQIRRTSSTF3Z2QPVCAC
RQR4PTMGQLTRWLYRU3KXIIDGND7FBORESJWMWFVD3WYU5SISZXAAC
3SBEV2BQOK6TVP7CJHXL7QHQDLYWJXVA6JCV4YCZT6LYXE3IDPHAC
4PAWVDF5IXOGPB5OLYXGTLUNAEZI3KNSW7AKJKQAIOLQGQBFAFBAC
Z5Q3G3R4UCP236KXS4MW4LVRIM3LTEKG4J4XVMGO7ISA3XUWXYMQC
CE6FLTWU5PYFBSGVTIJXQXRMHOIHQ3VJCKHQVIMUUAIFHQ73X7NAC
3GLHLYH34NUBL2C5HSECKNVAO4ZFAAYXCW3Q5VZ2PXDDZ4SDD7LQC
MDAJYB6STTZPNHRQ2X66MMMSONMKXTESLHJSFPGN7H3D3TOVBAVAC
3UHMSNL7FEGVWYDX6AAJD2XQUQQ3HJMMTDR66IORZPYP5MJ2L7AQC
4HLF6Q3OBOOHCCJ76L2BXVIYI6EMJ2G7O4XXZPFTLFP6BQGSUZNAC
UH3CJQMQ3NPICXD34NTCTUZJWOCEF4P5XEGXFLLNDDFLZK7QPUBQC
HSRRNAU5UAYC6B6IQWGJPFROMZBTJICPCH6DJVZDHDTAGOQ6IOYAC
TJRYL3NXPW5IUGEV3YOC7JYWEXCZDBFPLT4AUG4P227WVKVB72ZAC
TPPJRQ2NTCV3GI2VRHEXQJREDERPJODCJWUG5WCOQGN4REPPPAMAC
SPOCLROO64OKT2F6SGUJNAQXH2XZWCK3LE7IRCDQCRYPU6Q6SAFQC
DF5LOTJFSXOT7UBDHLBDLGA22OY4L7ZF6CVFP6H3KL4N5CHB5C5QC
2BTN774TDEFKS7L23YNEDQJSLSUWWKXPC5GA73ZGKLCKDHVEWSJAC
IIN7AVA6JYRBXH6ZYRR7BY7TV6PW7ANAQ2A3PD55FKBKKQFEEF2AC
UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC
Z3RI4XAN7J2GUABAQ5G6YIOQYMBOAEQFFGRBWHMUEB2A2QYXO5MQC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
IQGGFC563RBS7GDOACKCLXK752EE5RC3T6G5L6H446SXTMSA7T2AC
4FQAKUKUO6PCAZ3N4HUR5XL6E4VA5UQUZ3AEDGRBLVY7W2LMWI7QC
6TEISZD7HYSSL24EOKIBNURU66KGSQX7B7SNAHBP4DQSAOTGH2MQC
NCHTJYDWTFLBWRQ3NS47O4ZAPT6RN7P2GNUT7G2PPVNURCLCWW6AC
YHSVOROKPYS33Y4RYZRVZTE3G5LXOFX52HEDNLV6HIXOJYNOKH3QC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
VIFZ6DO6GWJGYMXJZKFZ2JYNPHNE74H3OFAOCPISQG7M7A4LCOHAC
YF2GZWXNV6NVFFEBEOYS67JQJQK2IUS5BZMGJW3XQPYIJYHQJCEQC
5OVWAD2MGK2NT6Q546KW7HZHELVDBBRC2CQX6VZMZF2YVRC7CPVAC
#include "AppHdr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef USE_X11 //Sys dep
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
#include <X11/keysym.h>
#include <X11/keysymdef.h>
#include <X11/Xmd.h>
#endif
#include "cio.h"
#include "enum.h"
#include "externs.h"
#include "guic.h"
#include "libutil.h"
/*
* Tile related stuff
*/
#ifdef USE_TILE
#include "tiles.h"
static Display *display=NULL;
static int screen;
static int x11_keypress(XKeyEvent *xev);
static void x11_check_exposure(XEvent *xev);
extern WinClass *win_main;
void GetNextEvent(int *etype, int *key, bool *shift, bool *ctrl,
{
XEvent xev;
{
XNextEvent(display, &xev);
{
int button = xev.xbutton.button;
*shift = (xev.xkey.state & ShiftMask) ? true : false;
*ctrl = (xev.xkey.state & ControlMask) ? true : false;
*x1 = xev.xbutton.x;
*y1 = xev.xbutton.y;
*key = button;
}
{
*x1 = xev.xbutton.x;
*y1 = xev.xbutton.y;
}
{
int button = xev.xbutton.button;
*x1 = xev.xbutton.x;
*y1 = xev.xbutton.y;
*key = button;
break;
}
char *my_getenv(const char *envname, const char *def)
{
const char *result = getenv(envname);
return (char *)result;
}
int my_getenv_int(const char *envname, int def)
{
const char *rstr = getenv(envname);
return atoi(rstr);
}
extern WinClass *win_main;
extern TextRegionClass *region_tip;
void update_tip_text(const char *tip)
{
return;
{
{
// try to remove inscriptions
{
*ins = 0;
}
else
{
// try to remove state, e.g. "(worn)"
{
*state = 0;
}
else
{
// if nothing else...
}
}
}
}
}
void TileDrawDungeonAux()
{
}
#endif /* USE_TILE */
/* X11 */
int sx, sy, ex, ey;
sx = xev->xexpose.x;
sy = xev->xexpose.y;
win_main->redraw(sx,sy,ex,ey);
}
/* X11 */
// This routine is taken from Angband main-x11.c
int x11_keypress(XKeyEvent *xev)
{
#define IsSpecialKey(keysym) \
((unsigned)(keysym) >= 0xFF00)
{
};
int dir, base;
int n;
bool mc, ms, ma;
unsigned int ks1;
XKeyEvent *ev = (XKeyEvent*)(xev);
KeySym ks;
char buf[256];
n = XLookupString(ev, buf, 125, &ks, NULL);
buf[n] = '\0';
if (IsModifierKey(ks)) return 0;
/* Extract "modifier flags" */
mc = (ev->state & ControlMask) ? true : false;
/* Normal keys */
if (n && !IsSpecialKey(ks))
{
buf[n] = 0;
}
/* Hack -- convert into an unsigned int */
ks1 = (uint)(ks);
/* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
base = dir = 0;
switch (ks1)
//Handle keypad first
if (dir != 0)
{
}
if (base != 0)
{
}
//Hack Special key
{
}
return 0;
}
void libgui_init_sys()
{
GuicInit(&display, &screen);
}
void libgui_shutdown_sys()
{
GuicDeinit();
}
void update_screen()
{
XFlush(display);
}
int kbhit()
{
XEvent xev;
{
XPutBackEvent(display, &xev);
return 1;
}
return 0;
}
void delay( unsigned long time )
{
usleep( time * 1000 );
}
/* Convert value to string */
int itoa(int value, char *strptr, int radix)
{
unsigned int bitmask = 32768;
int ctr = 0;
int startflag = 0;
if (radix == 10)
{
sprintf(strptr, "%i", value);
}
{
while (bitmask)
{
if (value & bitmask)
{
startflag = 1;
sprintf(strptr + ctr, "1");
}
{
}
bitmask = bitmask >> 1;
if (startflag)
ctr++;
}
if (!startflag) /* Special case if value == 0 */
sprintf((strptr + ctr++), "0");
strptr[ctr] = (char) NULL;
}
return (0); /* Me? Fail? Nah. */
}
// Convert string to lowercase.
char *strlwr(char *str)
{
unsigned int i;
for (i = 0; i < strlen(str); i++)
str[i] = tolower(str[i]);
return (str);
}
int stricmp( const char *str1, const char *str2 )
{
return (strcmp(str1, str2));
}
sprintf(strptr + ctr, "0");
else if (startflag)
else if (radix == 2) /* int to "binary string" */
if (XCheckMaskEvent(display, KeyPressMask | ButtonPressMask, &xev))
base = 512 + ks1 - 0xff00;
if (ms) base |= 1024;
if (mc) base |= 2048;
if (ma) base |= 4096;
return base;
if (ks1 >=
0xff00)
if (ms) base |= 1024;
if (mc) base |= 2048;
if (ma) base |= 4096;
return base;
if (ms) result += CK_SHIFT_UP - CK_UP;
if (mc) result += CK_CTRL_UP - CK_UP;
return result;
int result = ck_table[dir-1];
// Keypad
case XK_KP_1:
case XK_KP_End:
dir = 1;
break;
case XK_KP_2:
case XK_KP_Down:
dir = 2;
break;
case XK_KP_3:
case XK_KP_Page_Down:
dir = 3;
break;
case XK_KP_6:
case XK_KP_Right:
dir = 6;
break;
case XK_KP_9:
case XK_KP_Page_Up:
dir = 9;
break;
case XK_KP_8:
case XK_KP_Up:
dir = 8;
break;
case XK_KP_7:
case XK_KP_Home:
dir = 7;
break;
case XK_KP_4:
case XK_KP_Left:
dir = 4;
break;
case XK_KP_5:
dir = 5;
break;
}
// for menus
case XK_Down:
return CK_DOWN;
case XK_Up:
return CK_UP;
case XK_Left:
return CK_LEFT;
case XK_Right:
return CK_RIGHT;
{
case XK_Escape:
base = 0x1b;
break;
case XK_Return:
base = '\r';
break;
case XK_Tab:
base = '\t';
break;
case XK_Delete:
case XK_BackSpace:
base = '\010';
break;
/* Alt + ? */
return 2048|buf[0];
if (!ma)
return buf[0];
// Hack Ctrl + [0-9] etc.
if (mc && ((ks >= '0' && ks <= '9') || buf[0] >= ' '))
return 1024 | ks;
ms = (ev->state & ShiftMask) ? true : false;
ma = (ev->state & Mod1Mask) ? true : false;
CK_END, CK_DOWN, CK_PGDN,
CK_LEFT, CK_INSERT, CK_RIGHT,
CK_HOME, CK_UP, CK_PGUP
const unsigned int ck_table[9] =
if (xev->xany.window != win_main->win)
return;
ey = xev->xexpose.y + (xev->xexpose.height) - 1;
ex = xev->xexpose.x + (xev->xexpose.width) - 1;
void x11_check_exposure(XEvent *xev)
{
if (is_main_screen)
{
region_tip->addstr(this_tip);
region_tip->make_active();
}
else
{
ASSERT(i == 0);
textattr(WHITE);
cprintf("%s", this_tip);
clear_to_end_of_line();
}
cgotoxy(1, get_number_of_lines() + 1);
region_tip->cgotoxy(1, 1 + i);
this_tip[width-1] = '.';
this_tip[width-2] = '.';
this_tip[width] = 0;
char *state = strchr(this_tip, '(');
if (state && state[-1] == ' ')
state--;
if (state && (state - this_tip <= (int)width))
char *ins = strchr(this_tip, '{');
if (ins && ins[-1] == ' ')
ins--;
if (ins && (ins - this_tip <= (int)width))
char *this_tip = next_tip;
// find end of line
char *pc = strchr(next_tip, '\n');
if (pc)
{
*pc = 0;
next_tip = pc + 1;
}
else
next_tip = 0;
if (strlen(this_tip) > width)
char *next_tip = new_tip;
for (unsigned int i = 0; next_tip && i < height; i++)
if (is_main_screen)
region_tip->clear();
const bool is_main_screen = (win_main->active_layer == 0);
const unsigned int height = is_main_screen ? region_tip->my : 1;
const unsigned int width = is_main_screen ? region_tip->mx
: region_crt->mx;
strncpy(new_tip, tip, tip_size);
strncpy(old_tip, new_tip, tip_size);
if (strncmp(old_tip, tip, tip_size) == 0)
const unsigned int tip_size = 512;
static char old_tip[tip_size];
char new_tip[tip_size];
extern TextRegionClass *region_crt;
if (!rstr)
return def;
if (!result)
result = def;
}
}
if (button == 3)
button = 2;
else if (button == 2)
button = 3;
*etype = EV_UNBUTTON;
else if (xev.type == ButtonRelease)
break;
}
else if (xev.type == LeaveNotify)
{
*etype = EV_MOVE;
*x1 = -100;
*y1 = -100;
break;
*etype = EV_MOVE;
else if (xev.type == MotionNotify || xev.type == EnterNotify)
break;
if (button == 3)
button = 2;
else if (button == 2)
button = 3;
*etype = EV_KEYIN;
*key = x11_keypress(&(xev.xkey));
break;
}
else if (xev.type == Expose)
{
x11_check_exposure(&xev);
}
else if (xev.type == ConfigureNotify)
{
win_main->ox = xev.xconfigure.x;
win_main->oy = xev.xconfigure.y;
break;
}
else if (xev.type == ButtonPress)
{
*etype = EV_BUTTON;
if (xev.type == KeyPress)
while (true)
int *x1, int *y1, int *x2, int *y2)
/*
* File: guic-win.cc
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
*/
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <commctrl.h>
// GDT_NONE in commctrl.h conflicts with enum.h
#ifdef GDT_NONE
#undef GDT_NONE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include "AppHdr.h"
#include "cio.h"
#include "externs.h"
#include "guic.h"
#include "itemprop.h"
#include "state.h"
#include "tiles.h"
extern int old_main(int argc, char *argv[]);
extern WinClass *win_main;
extern TileRegionClass *region_tile;
extern img_type TileImg;
extern BYTE pix_transparent;
typedef struct ev_data
{
int type;
int key;
int x1, y1;
bool sh, ct;
}ev_data;
#define EV_MAX 1024
struct ev_data ev_cue[EV_MAX];
static int ev_head = 0;
static int ev_tail = 0;
void ev_push(struct ev_data *e);
static bool skip_key = false;
// Tip text
static TOOLINFO tiTip;
static HWND hTool;
static HWND pWin;
#ifdef USE_TILE
#define PAL_STD 0 //standard palette
#define PAL_BER 1 //berserk palette
#define PAL_SHA 2 //shadow palette
static int palette = PAL_STD;
LPBYTE lpPalettes[3] ;
#endif
#define DF_TOOLTIP_WIDTH 300
ATOM MyRegisterClass( HINSTANCE hInstance );
BOOL InitInstance( HINSTANCE, int );
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
bool libgui_init_sys();
void libgui_shutdown_sys();
void update_tip_text(const char *tip);
void GetNextEvent(int *etype, int *key, bool *shift, bool *ctrl,
void TileInitWin();
void delay(unsigned long ms);
int kbhit();
/***************************/
void TileInitWin()
{
int i;
TileImg->pDib->bmiColors[pix_transparent].rgbRed = 0;
TileImg->pDib->bmiColors[pix_transparent].rgbGreen = 0;
TileImg->pDib->bmiColors[pix_transparent].rgbBlue = 0;
RegionClass::set_std_palette(&TileImg->pDib->bmiColors[0]);
lpPalettes[0] = (LPBYTE) (&TileImg->pDib->bmiColors[0]);
for (i = 0; i < 256; i++)
{
chcol = (TileImg->pDib->bmiColors[i].rgbRed * 30
ptr[2] = (BYTE)chcol;
ptr[0] = (BYTE)( (chcol +1)/6 );
ptr[1] = (BYTE)( (chcol +1)/6 );
ptr[2] = ptr[0] = ptr[1] = (BYTE)chcol;
}
}
void update_tip_text(const char *tip)
{
#define MAXTIP 512
static char oldtip[MAXTIP+1];
strncpy(oldtip, tip, MAXTIP);
tiTip.lpszText = (char *)tip;
SendMessage(hTool, TTM_UPDATETIPTEXT, 0, (LPARAM)&tiTip);
}
bool libgui_init_sys( )
{
}
void libgui_shutdown_sys()
{
DestroyWindow( pWin );
}
void GetNextEvent(int *etype, int *key, bool *sh, bool *ct,
{
MSG msg;
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
struct ev_data *e = &ev_cue[ev_head];
ev_head++;
ev_head = 0;
*etype = e->type;
*key = e->key;
*sh = e->sh;
*ct = e->ct;
*x1 = e->x1;
*y1 = e->y1;
}
void ev_push(struct ev_data *e)
{
ev_cue[ev_tail] = *e;
ev_tail++;
ev_tail = 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
{
MSG msg;
MyRegisterClass( hInstance );
GuicInit(hInstance, nCmdShow);
return msg.wParam;
}
ATOM MyRegisterClass( HINSTANCE hInstance )
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, TEXT("CRAWL_ICON"));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = "CRAWL";
wcex.lpszClassName = "CrawlList";
wcex.hIconSm = NULL;//LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx( &wcex );
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
struct ev_data ev;
static int clix = 0;
static int cliy = 0;
// For keypad
{
};
switch( message )
{
case WM_CREATE:
{
pWin = hWnd;
InitCommonControls();
hTool = CreateWindowEx( 0 , TOOLTIPS_CLASS ,
NULL , TTS_ALWAYSTIP ,
CW_USEDEFAULT , CW_USEDEFAULT ,
CW_USEDEFAULT , CW_USEDEFAULT ,
hWnd , NULL , ((LPCREATESTRUCT)(lParam))->hInstance ,
NULL
);
tiTip.hwnd = hWnd;
tiTip.lpszText = (char *)
SendMessage(hTool, TTM_ADDTOOL , 0 , (LPARAM)&tiTip);
return 0;
}
case WM_RBUTTONDOWN:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
{
ev.x1 = LOWORD(lParam);
ev.y1 = HIWORD(lParam);
ev.key = 1;
if (message == WM_RBUTTONDOWN) ev.key = 2;
if (message == WM_MBUTTONDOWN) ev.key = 3;
return 0;
}
case WM_RBUTTONUP:
ev.x1 = LOWORD(lParam);
ev.y1 = HIWORD(lParam);
ev.key = 1;
if (message == WM_RBUTTONUP) ev.key = 2;
if (message == WM_MBUTTONUP) ev.key = 3;
return 0;
case WM_MOUSEWHEEL:
{
return 0;
}
case WM_MOUSEMOVE:
{
ev.x1 = LOWORD(lParam);
ev.y1 = HIWORD(lParam);
return 0;
}
case WM_KEYDOWN:
{
int result = 0;
{
switch(ch)
{
case VK_LEFT: dir = 4; break;
case VK_RIGHT: dir = 6; break;
case VK_UP: dir = 8; break;
case VK_DOWN: dir = 2; break;
case VK_HOME: dir = 7; break;
case VK_PRIOR: dir = 9; break;
case VK_NEXT: dir = 3; break;
case VK_END: dir = 1; break;
case VK_CLEAR: dir = 5; break;
}
if (dir != 0)
{
if (fc)
if (fs)
ev.key = ch;
return 0;
}
case WM_CHAR:
{
ev.key = (int)wParam;
return 0;
}
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
win_main->redraw();
EndPaint(hWnd, &ps);
return 0;
}
case WM_COMMAND:
{
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch( wmId )
{
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
case WM_CLOSE:
{
if (crawl_state.need_save)
save_game(true);
}
break;
case WM_DESTROY:
{
PostQuitMessage( 0 );
exit(0);
break;
}
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
#ifdef USE_TILE
dib_pack *pBuf = region_tile->backbuf;
if (new_palette != palette)
{
SetDIBColorTable(pBuf->hDC, 0, 256, (RGBQUAD *)lpPalettes[palette]);
}
}
#endif
bool windows_change_font(char *font_name, int *font_size, bool dos)
{
CHOOSEFONT cf;
memset(&cf, 0, sizeof(cf));
cf.lStructSize = sizeof(cf);
cf.iPointSize = *font_size;
cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_NOVERTFONTS
LOGFONT lf;
strcpy(lf.lfFaceName, font_name);
cf.lpLogFont = &lf;
if (ChooseFont(&cf))
{
*font_size = (cf.iPointSize / 10);
strcpy(font_name, lf.lfFaceName);
}
}
void windows_get_winpos(int *x, int *y)
{
WINDOWPLACEMENT wndpl;
// set length
wndpl.length = sizeof( WINDOWPLACEMENT );
{
*x = wndpl.rcNormalPosition.top;
*y = wndpl.rcNormalPosition.left;
}
}
void delay(unsigned long ms)
{
Sleep((DWORD)ms);
}
int kbhit()
{
MSG msg;
if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_NOREMOVE)
return 1;
else
return 0;
}
void update_screen()
{
}
}
|| PeekMessage(&msg, NULL, WM_KEYDOWN, WM_KEYDOWN, PM_NOREMOVE))
{
if (GetWindowPlacement( win_main->hWnd, &wndpl ) != 0)
return (false);
return (true);
lf.lfHeight = 16;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = lf.lfEscapement;
lf.lfWeight = FW_NORMAL;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
lf.lfStrikeOut = FALSE;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = FF_MODERN | FIXED_PITCH;
lf.lfCharSet = (dos)? OEM_CHARSET:ANSI_CHARSET;
| CF_INITTOLOGFONTSTRUCT | CF_LIMITSIZE | CF_FORCEFONTEXIST;
cf.nSizeMin = 8;
cf.nSizeMax = 24;
palette = new_palette;
int new_palette = PAL_STD; // standard
if (you.duration[DUR_BERSERKER])
new_palette = PAL_BER;
// XXX: is this supposed to override Berserk?
if (you.special_wield == SPWLD_SHADOW)
new_palette = PAL_SHA;
void TileDrawDungeonAux()
{
libgui_shutdown();
if (mouse_get_mode() == MOUSE_MODE_COMMAND
|| !crawl_state.need_save )
// XXX: Isn't that always the case?
case WM_MOVE:
{
clix = LOWORD(lParam);
cliy = HIWORD(lParam);
return 0;
}
ev.type = EV_KEYIN;
ev_push(&ev);
if (skip_key)
{
skip_key = false;
return 0;
}
return 0;
if (result)
{
if (fs) result |= 512;
if (fc) result |= 1024;
if (fa) result |= 2048;
ev.key = result;
ev.type = EV_KEYIN;
ev_push(&ev);
}
}
{
}
result = 300 + ch;
else if (ch >= VK_PAUSE
&& (ch < VK_CAPITAL || ch > VK_SPACE)
&& ch != VK_PROCESSKEY
&& ch != VK_NUMLOCK
&& (ch < VK_LSHIFT || ch > VK_RMENU)
&& (ch < 0x30 || ch > 0x39)
&& (ch < 0x41 || ch > 0x5a)
&& (ch < 0xa6 || ch > 0xe4))
ev.type = EV_KEYIN;
ev_push(&ev);
if (fa)
ch |= 2048;
ch += CK_SHIFT_UP - CK_UP;
ch += CK_CTRL_UP - CK_UP;
ch = ck_table[dir-1];
}
if (ch >= VK_NUMPAD1 && ch <= VK_NUMPAD9)
{
skip_key = true;
dir = ch - VK_NUMPAD0;
}
else if (VK_PRIOR <= ch && ch <= VK_DOWN || ch == VK_CLEAR)
int dir = 0;
bool fs = ((GetKeyState(VK_SHIFT) & 0x80) != 0)? true : false;
bool fc = ((GetKeyState(VK_CONTROL)& 0x80) != 0)? true : false;
bool fa = ((GetKeyState(VK_MENU) & 0x80) != 0)? true : false;
int ch = (int) wParam;
ev_push(&ev);
ev.type = EV_MOVE;
int z = (short)HIWORD(wParam);
ev.x1 = LOWORD(lParam) - clix;
ev.y1 = HIWORD(lParam) - cliy;
ev.type = EV_BUTTON;
ev.sh = ((GetKeyState(VK_SHIFT) & 0x80) != 0) ? true : false;
ev.ct = ((GetKeyState(VK_CONTROL) & 0x80) != 0) ? true : false;
ev.key = (z > 0) ? 4 : 5;
ev_push(&ev);
}
ev_push(&ev);
{
ev.type = EV_UNBUTTON;
ev_push(&ev);
ev.sh = ((GetKeyState(VK_SHIFT) & 0x80) != 0)? true : false;
ev.ct = ((GetKeyState(VK_CONTROL) & 0x80) != 0)? true : false;
ev.type = EV_BUTTON;
// Allow line wrap
SendMessage(hTool, TTM_SETMAXTIPWIDTH, 0, DF_TOOLTIP_WIDTH);
"This text will tell you" EOL
" what you are pointing";
tiTip.cbSize = sizeof (TOOLINFO);
tiTip.uFlags = TTF_SUBCLASS;
GetClientRect(hWnd , &tiTip.rect);
// Example taken from
// http://black.sakura.ne.jp/~third/system/winapi/common10.html
CK_END, CK_DOWN, CK_PGDN,
CK_LEFT, CK_INSERT, CK_RIGHT,
CK_HOME, CK_UP, CK_PGUP
const unsigned char ck_table[9] =
// Redirect output to the console
AttachConsole(ATTACH_PARENT_PROCESS);
freopen("CONOUT$", "wb", stdout);
freopen("CONOUT$", "wb", stderr);
// I'll be damned if I have to parse lpCmdLine myself...
int argc;
LPWSTR *wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
char *ptr = args;
for (int i = 0; i < argc; i++)
{
wsprintfA(ptr, "%S", wargv[i]);
argv[i] = ptr;
ptr += strlen(argv[i]) + 1;
}
ASSERT(ptr <= args + args_len);
old_main(argc, argv);
delete args;
delete argv;
FreeConsole();
char **argv = new char*[argc];
int args_len = wcslen(GetCommandLineW()) + argc;
char *args = new char[args_len];
LPSTR lpCmdLine, int nCmdShow )
if (ev_tail == EV_MAX)
if (ev_head == EV_MAX)
if (ev_tail != ev_head)
break;
while ( GetMessage(&msg, NULL, 0, 0) )
int *x1, int *y1, int *x2, int *y2)
GlobalFree(lpPalettes[1]);
GlobalFree(lpPalettes[2]);
return (true);
if (strncmp(oldtip, tip, MAXTIP) == 0)
return;
ptr = lpPalettes[2] + i * sizeof(RGBQUAD);
+ TileImg->pDib->bmiColors[i].rgbGreen * 59
+ TileImg->pDib->bmiColors[i].rgbBlue * 11) / 100;
LPBYTE ptr = lpPalettes[1] + i * sizeof(RGBQUAD);
lpPalettes[1] = (LPBYTE)GlobalAlloc(GPTR, 256 * sizeof(RGBQUAD) );
lpPalettes[2] = (LPBYTE)GlobalAlloc(GPTR, 256 * sizeof(RGBQUAD) );
WORD chcol;
int *x1, int *y1, int *x2, int *y2);
#include "files.h"
#include "debug.h"
#include <fcntl.h>
/*
* File: guic-win.cc
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
*/
#define _WIN32_WINNT 0x0501
#ifdef USE_X11
#include <X11/Xlib.h>
#include <X11/X.h>
bool GuicInit(Display **d, int *s);
void GuicDeinit();
#elif defined(WIN32TILES)
#include <windows.h>
#include <commdlg.h>
bool GuicInit(HINSTANCE h, int nCmdShow);
void GuicDeinit();
#elif defined(SOME_OS)
#include <some-headers.h>
bool GuicInit(some args);
#endif
#include <vector>
/*
* Internal Image types
*/
#ifdef USE_X11
/*********** X11 ********/
typedef XImage *img_type;
#define ImgWidth(img) (img->width)
#define ImgHeight(img) (img->height)
#elif defined(WIN32TILES)
/********** Windows *****/
// struct for DIB info
typedef struct dib_pack
{
} dib_pack;
typedef dib_pack *img_type;
#define ImgWidth(img) (img->Width)
#define ImgHeight(img) (img->Height)
#elif defined(SOME_OS)
typedef sometype *img_type;
#define ImgWidth(img) (img->x)
#define ImgHeight(img) (img->y)
#endif
// Image overlay/copy between internal images,
// implemented in winclass-*.cc
void ImgCopy(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, int copy);
// hilight rim color #010101 to magenta
void ImgCopyH(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, int copy);
// maskout by char array mask
void ImgCopyMasked(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, char *mask);
// maskout+hilight
void ImgCopyMaskedH(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, char *mask);
// create internal buffer (not assosiated to any window)
img_type ImgCreateSimple(int wx, int wy);
// create it from file
img_type ImgLoadFile(const char *name);
// destroy
void ImgDestroy(img_type img);
// clear by transparent color
void ImgClear(img_type img);
// if it is pix_transparent #476c6c
bool ImgIsTransparentAt(img_type img, int x, int y);
void ImgSetTransparentPix(img_type img);
/*
* Windows and internal regions (text, dungeon, map, etc)
*/
class WinClass
{
public:
int ox; //Offset x in dots
int oy; //Offset y in dots
int wx; //width in dots
int wy; //height in dots
std::vector<class RegionClass *> regions;
std::vector<int> layers;
int active_layer;
// Pointer to the window
#ifdef USE_X11
Window win;
#elif defined(WIN32TILES)
HWND hWnd;
#elif defined(SOME_OS)
somewindowtype win;
#endif
WinClass();
void SysInit();
void SysDeinit();
~WinClass();
// fillout with black: Sys dep
void clear();
// create: Sys dep
#ifdef USE_X11
void create(char *name);
#elif defined(WIN32TILES)
BOOL create(const char *name);
#elif defined(SOME_OS)
void create(some args);
#endif
void resize(int wx, int wy);
void resize();
void move(int ox, int oy);
void move();
// place Regions inside it
int pflag,
int margin_bottom = 0, int margin_right = 0);
int x, int y,
int margin_bottom = 0, int margin_right = 0);
// fillout a rectangle
void fillrect(int left, int right, int top, int bottom, int color);
// redraw for exposure, etc
void redraw(int x1, int y1, int x2, int y2);
void redraw();
};
class RegionClass
{
public:
WinClass *win;
int layer;
// Geometry
// <-----------------wx----------------------->
// sx ox ex
// |margin| text/tile area |margin|
int ox; //Offset x in dots
int oy; //Offset y in dots
int dx; //unit width
int dy; //unit height
int mx; //window width in dx
int my; //window height in dy
int wx; //width in dots = dx*mx + margins
int wy; //height in dots = dy*my + margins
int sx; //Left edge pos
int sy; //Top edge pos
int ex; //right edge pos
int ey; //bottom edge pos
bool flag;// use or no
int id; // for general purpose
// pointer to internal backup image buffer
// used for redraw and supplessing flicker
img_type backbuf;
#ifdef WIN32TILES
static void set_std_palette(RGBQUAD *pPal);
static RGBQUAD std_palette[256];
void init_backbuf(RGBQUAD *pPal = NULL, int ncol = 0);
bool dos_char;
#else
void init_backbuf();
#endif
void resize_backbuf();
// font-related
int fx; // font height and width (can differ from dx, dy)
int fy;
#ifdef USE_X11
int asc; //font ascent
#ifdef JP
XFontSet font; //fontset
#else
XFontStruct *font;
#endif
void init_font(const char *name);
#elif defined(WIN32TILES)
HFONT font;
void init_font(const char *name, int height);
void change_font(const char *name, int height);
#elif defined(SOME_OS)
sometype font;
void init_font(some args);
#endif
bool font_copied;
void copy_font(RegionClass *r);
// init/deinit
RegionClass();
virtual ~RegionClass();
// system-dependent init/deinit
void SysInit();
void SysDeinit();
// Sys indep
bool is_active();
void make_active();
//Sys indep
// convert mouse point into logical position
virtual bool mouse_pos(int mouse_x, int mouse_y, int *cx, int *cy);
virtual bool convert_redraw_rect(int x1, int y1, int x2, int y2,
int *rx1, int *ry1, int *rx2, int *ry2);
virtual void redraw(int x1, int y1, int x2, int y2);
virtual void redraw();
void sys_flush();
virtual void fillrect(int left, int right, int top, int bottom, int color);
virtual void framerect(int left, int right, int top, int bottom, int color);
virtual void clear();
};
class TextRegionClass :public RegionClass
{
public:
// init/deinit
TextRegionClass(int x, int y , int cx, int cy);
~TextRegionClass();
// os dependent init/deinit
void SysInit(int x, int y, int cx, int cy);
void SysDeinit();
// where now printing? what color?
static int print_x;
static int print_y;
static int text_col;
// which region now printing?
static class TextRegionClass *text_mode;
// display cursor? where is the cursor now?
static int cursor_flag;
static class TextRegionClass *cursor_region;
static int cursor_x;
static int cursor_y;
// class methods
static int wherex();
static int wherey();
//static int get_number_of_lines(void);
static void _setcursortype(int curstype);
static void textbackground(int bg);
static void textcolor(int col);
// Object's method
void clear_to_end_of_line(void);
void clear_to_end_of_screen(void);
void putch(unsigned char chr);
void writeWChar(unsigned char *ch);
unsigned char *cbuf; //text backup
unsigned char *abuf; //textcolor backup
int cx_ofs; //cursor x offset
int cy_ofs; //cursor y offset
void addstr(char *buffer);
void addstr_aux(char *buffer, int len);
void adjust_region(int *x1, int *x2, int y);
void scroll();
//bool mouse_pos(int mouse_x, int mouse_y, int *cx, int *cy);
//Sys dep
void draw_string(int x, int y, unsigned char *buf, int len, int col);
void draw_cursor(int x, int y, int width);
void draw_cursor(int x, int y);
void erase_cursor();
void clear();
void init_backbuf();
void redraw(int x1, int y1, int x2, int y2);
void resize(int x, int y);
};
class TileRegionClass :public RegionClass
{
public:
bool force_redraw;
void DrawPanel(int left, int top, int width, int height);
void fillrect(int left, int right, int top, int bottom, int color);
void framerect(int left, int right, int top, int bottom, int color);
bool mouse_pos(int mouse_x, int mouse_y, int *cx, int *cy);
virtual bool convert_redraw_rect(int x1, int y1, int x2, int y2,
int *rx1, int *ry1, int *rx2, int *ry2);
void redraw(int x1, int y1, int x2, int y2);
void redraw();
void clear();
//Sys dep
void resize(int x, int y, int dx, int dy);
#ifdef WIN32TILES
void init_backbuf(RGBQUAD *pPal = NULL);
#else
void init_backbuf();
#endif
void resize_backbuf();
TileRegionClass(int mx0, int my0, int dx0, int dy0);
void SysInit(int mx0, int my0, int dx0, int dy0);
void SysDeinit();
~TileRegionClass();
};
{
int mx2;
int my2;
int x_margin;
int y_margin;
unsigned char *mbuf;
bool force_redraw;
bool mouse_pos(int mouse_x, int mouse_y, int *cx, int *cy);
void redraw(int x1, int y1, int x2, int y2);
void redraw();
void clear();
//Sys dep
void init_backbuf();
void resize_backbuf();
void resize(int mx0, int my0, int dx0, int dy0);
void set_col(int col, int x, int y);
int get_col(int x, int y);
void SysInit(int x, int y, int o_x, int o_y);
void SysDeinit();
};
#define PLACE_RIGHT 0
#define PLACE_BOTTOM 1
#define PLACE_FORCE 2
// Graphics Colors
#define PIX_BLACK 0
#define PIX_BLUE 1
#define PIX_GREEN 2
#define PIX_CYAN 3
#define PIX_RED 4
#define PIX_MAGENTA 5
#define PIX_BROWN 6
#define PIX_LIGHTGREY 7
#define PIX_DARKGREY 8
#define PIX_LIGHTBLUE 9
#define PIX_LIGHTGREEN 10
#define PIX_LIGHTCYAN 11
#define PIX_LIGHTRED 12
#define PIX_LIGHTMAGENTA 13
#define PIX_YELLOW 14
#define PIX_WHITE 15
#define MAX_TERM_COL 16
#define MAP_BLACK 0
#define MAP_DKGREY 1
#define MAP_MDGREY 2
#define MAP_LTGREY 3
#define MAP_WHITE 4
#define MAP_BLUE 5
#define MAP_LTBLUE 6
#define MAP_DKBLUE 7
#define MAP_GREEN 8
#define MAP_LTGREEN 9
#define MAP_DKGREEN 10
#define MAP_CYAN 11
#define MAP_LTCYAN 12
#define MAP_DKCYAN 13
#define MAP_RED 14
#define MAP_LTRED 15
#define MAP_DKRED 16
#define MAP_MAGENTA 17
#define MAP_LTMAGENTA 18
#define MAP_DKMAGENTA 19
#define MAP_YELLOW 20
#define MAP_LTYELLOW 21
#define MAP_DKYELLOW 22
#define MAP_BROWN 23
#define MAX_MAP_COL 24
extern const int term_colors[MAX_TERM_COL][3];
extern const int map_colors[MAX_MAP_COL][3];
protected:
int old_mark_x;
int old_mark_y;
MapRegionClass(int x, int y, int o_x, int o_y, int marker_length);
~MapRegionClass();
void draw_data(unsigned char *buf, bool show_mark, int mark_x, int mark_y);
int marker_length;
public:
class MapRegionClass : public RegionClass
static void cgotoxy(int x, int y);
void removeRegion(class RegionClass *r);
int margin_top = 0, int margin_left = 0,
void placeRegion(class RegionClass *r, int layer,
int margin_top = 0, int margin_left = 0,
void placeRegion(class RegionClass *r, int layer,
class RegionClass *neighbor,
LPBITMAPINFO pDib ;
HBITMAP hDib ;
HDC hDC ;
LPBYTE pDibBits ;
LPBYTE pDibZero ;
int Width ;
int Height ;
/*
* File: guic-win.cc
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
*/
*/
#include "guic.h"
#ifdef WIN32TILES
#else
#define dos_char false;
#endif
int TextRegionClass::print_x;
int TextRegionClass::print_y;
TextRegionClass *TextRegionClass::text_mode = NULL;
int TextRegionClass::text_col = 0;
TextRegionClass *TextRegionClass::cursor_region= NULL;
int TextRegionClass::cursor_flag = 0;
int TextRegionClass::cursor_x;
int TextRegionClass::cursor_y;
// more logical color naming
{
{ 0, 0, 0}, // BLACK
{128, 128, 128}, // DKGREY
{160, 160, 160}, // MDGREY
{192, 192, 192}, // LTGREY
{255, 255, 255}, // WHITE
{ 0, 64, 255}, // BLUE (actually cyan-blue)
{128, 128, 255}, // LTBLUE
{ 0, 32, 128}, // DKBLUE (maybe too dark)
{ 0, 255, 0}, // GREEN
{128, 255, 128}, // LTGREEN
{ 0, 128, 0}, // DKGREEN
{ 0, 255, 255}, // CYAN
{ 64, 255, 255}, // LTCYAN (maybe too pale)
{ 0, 128, 128}, // DKCYAN
{255, 0, 0}, // RED
{255, 128, 128}, // LTRED (actually pink)
{128, 0, 0}, // DKRED
{192, 0, 255}, // MAGENTA (actually blue-magenta)
{255, 128, 255}, // LTMAGENTA
{ 96, 0, 128}, // DKMAGENTA
{255, 255, 0}, // YELLOW
{255, 255, 64}, // LTYELLOW (maybe too pale)
{128, 128, 0}, // DKYELLOW
{165, 91, 0}, // BROWN
};
{
{ 0, 0, 0}, // BLACK
{ 0, 82, 255}, // BLUE
{100, 185, 70}, // GREEN
{ 0, 180, 180}, // CYAN
{255, 48, 0}, // RED
{238, 92, 238}, // MAGENTA
{165, 91, 0}, // BROWN
{162, 162, 162}, // LIGHTGREY
{ 82, 82, 82}, // DARKGREY
{ 82, 102, 255}, // LIGHTBLUE
{ 82, 255, 82}, // LIGHTGREEN
{ 82, 255, 255}, // LIGHTCYAN
{255, 82, 82}, // LIGHTRED
{255, 82, 255}, // LIGHTMAGENTA
{255, 255, 82}, // YELLOW
{255, 255, 255} // WHITE
};
WinClass::WinClass()
{
// Minimum;
wx = 10;
wy = 10;
ox = 0;
oy = 0;
SysInit();
}
WinClass::~WinClass()
{
SysDeinit();
regions.clear();
layers.clear();
}
void WinClass::placeRegion(RegionClass *r, int layer0,
int x, int y,
int margin_top, int margin_left,
int margin_bottom, int margin_right)
{
if (r->win == NULL)
{
regions.push_back(r);
layers.push_back(layer0);
}
r->win = this;
r->layer = layer0;
r->flag = true;
r->sx = x;
r->sy = y;
r->ox = r->sx + margin_left;
r->oy = r->sy + margin_top;
r->wx = r->dx * r->mx + margin_left + margin_right;
r->wy = r->dy * r->my + margin_top + margin_bottom;
r->ex = r->sx + r->wx;
r->ey = r->sy + r->wy;
if (r->ex > wx) wx = r->ex;
if (r->ey > wy) wy = r->ey;
}
void WinClass::placeRegion(RegionClass *r, int layer0,
RegionClass *neighbor, int pflag,
int margin_top, int margin_left,
int margin_bottom, int margin_right)
{
int x = 0;
int y = 0;
if (neighbor!=NULL)
{
sx0 = neighbor->sx;
sy0 = neighbor->sy;
ex0 = neighbor->ex;
ey0 = neighbor->ey;
}
if (pflag == PLACE_RIGHT)
{
x = ex0;
y = sy0;
}
else
{
x = sx0;
y = ey0;
}
placeRegion(r, layer0, x, y, margin_top, margin_left,
margin_bottom, margin_right);
}
void WinClass::redraw(int x1, int y1, int x2, int y2)
{
std::vector <RegionClass *>::iterator r;
int cx1, cx2, cy1, cy2;
{
(*r)->redraw(cx1, cy1, cx2, cy2);
}
}
void WinClass::redraw()
{
redraw(0, 0, wx-1, wy-1);
}
void WinClass::move(int ox0, int oy0)
{
ox = ox0;
oy = oy0;
move(); // system dependent
}
void WinClass::resize(int wx0, int wy0)
{
if (wx0>0) wx = wx0;
if (wy0>0) wy = wy0;
resize(); // system dependent
}
RegionClass::RegionClass()
{
flag = false;
win = NULL;
backbuf = NULL;
SysInit();
ox = oy = 0;
dx = dy = 1;
font_copied = false;
id = 0;
}
RegionClass::~RegionClass()
{
SysDeinit();
}
void TextRegionClass::resize(int x, int y)
{
int i;
free(cbuf);
free(abuf);
cbuf = (unsigned char *)malloc(x*y);
abuf = (unsigned char *)malloc(x*y);
{
}
mx = x;
my = y;
}
TextRegionClass::TextRegionClass(int x, int y, int cx, int cy)
{
cbuf = NULL;
abuf = NULL;
resize(x, y);
// Cursor Offset
cx_ofs = cx;
cy_ofs = cy;
SysInit(x, y, cx, cy);
}
TextRegionClass::~TextRegionClass()
{
SysDeinit();
free(cbuf);
free(abuf);
}
TileRegionClass::TileRegionClass(int mx0, int my0, int dx0, int dy0)
{
// Unit size
dx = dx0;
dy = dy0;
mx = mx0;
my = my0;
force_redraw = false;
SysInit(mx0, my0, dx0, dy0);
}
TileRegionClass::~TileRegionClass()
{
SysDeinit();
}
void TileRegionClass::resize(int mx0, int my0, int dx0, int dy0)
{
if (mx0 != 0) mx = mx0;
if (my0 != 0) my = my0;
if (dx0 != 0) dx = dx0;
if (dy0 != 0) dy = dy0;
}
{
int i;
mx2 = x;
my2 = y;
mx = mx2;
my = my2;
mbuf = (unsigned char *)malloc(mx2*my2);
x_margin = o_x;
y_margin = o_y;
force_redraw = false;
SysInit(x, y, o_x, o_y);
}
MapRegionClass::~MapRegionClass()
{
SysDeinit();
free(mbuf);
}
void MapRegionClass::resize(int mx0, int my0, int dx0, int dy0)
{
if (mx0 != 0) mx2 = mx0;
if (my0 != 0) my2 = my0;
if (dx0 != 0) dx = dx0;
if (dy0 != 0) dy = dy0;
if (mx0 != 0 || my0 != 0)
{
int i;
free(mbuf);
mbuf = (unsigned char *)malloc(mx2*my2);
}
}
/*------------------------------------------*/
bool RegionClass::is_active()
{
if (win->active_layer == layer)
}
void RegionClass::make_active()
{
win->active_layer = layer;
void RegionClass::redraw(int x1, int y1, int x2, int y2)
{
}
void RegionClass::redraw()
{
redraw(0, 0, mx-1, my-1);
}
void MapRegionClass::redraw()
{
redraw(0, 0, mx-1, my-1);
}
void TileRegionClass::redraw()
{
redraw(0, 0, mx*dx-1, my*dy-1);
}
void MapRegionClass::set_col(int col, int x, int y)
{
mbuf[x + y * mx2] = col;
}
int MapRegionClass::get_col(int x, int y)
{
return mbuf[x + y * mx2];
}
/*------------------------------------------*/
int *rx1, int *ry1, int *rx2, int *ry2)
{
int cx1 = x1-ox;
int cy1 = y1-oy;
int cx2 = x2-ox;
int cy2 = y2-oy;
cx1 /= dx;
cy1 /= dy;
cx2 /= dx;
cy2 /= dy;
*rx1 = cx1;
*ry1 = cy1;
*rx2 = cx2;
*ry2 = cy2;
}
{
int cx1 = x1-ox;
int cy1 = y1-oy;
int cx2 = x2-ox;
int cy2 = y2-oy;
int wwx = dx*mx;
int wwy = dy*my;
*rx1 = cx1;
*ry1 = cy1;
*rx2 = cx2;
*ry2 = cy2;
}
bool RegionClass::mouse_pos(int mouse_x, int mouse_y, int *cx, int *cy)
{
int x = mouse_x - ox;
int y = mouse_y - oy;
x /= dx;
y /= dy;
*cx = x;
*cy = y;
}
bool MapRegionClass::mouse_pos(int mouse_x, int mouse_y, int *cx, int *cy)
{
x /= dx;
y /= dy;
*cx = x;
*cy = y;
}
bool TileRegionClass::mouse_pos(int mouse_x, int mouse_y, int *cx, int *cy)
{
int x = mouse_x - ox;
int y = mouse_y - oy;
x /= dx;
y /= dy;
*cx = x;
*cy = y;
}
void TextRegionClass::scroll()
{
int idx;
return;
{
cbuf[idx] = cbuf[idx + mx];
abuf[idx] = abuf[idx + mx];
}
{
cbuf[idx] = ' ';
abuf[idx] = 0;
}
redraw(0, 0, mx-1, my-1);
}
void TextRegionClass::adjust_region(int *x1, int *x2, int y)
{
*x2 = *x2 + 1;
}
void TextRegionClass::addstr(char *buffer)
{
int i,j;
char buf2[1024];
int len = strlen(buffer);
{
char c = buffer[i];
{
newline = true;
i++;
}
buf2[j] = c;
j++;
{
if (j-1 != 0)
addstr_aux(buf2, j - 1); // draw it
if (newline)
{
print_x = cx_ofs;
print_y++;
}
}
}
}
void TextRegionClass::addstr_aux(char *buffer, int len)
{
int i;
int x = print_x - cx_ofs;
int y = print_y - cy_ofs;
int adrs = y * mx;
int head = x;
int tail = x + len - 1;
adjust_region(&head, &tail, y);
{
}
draw_string(head, y, &cbuf[adrs+head], tail-head, text_col);
print_x += len;
}
void TextRegionClass::redraw(int x1, int y1, int x2, int y2)
{
int x, y;
{
unsigned char *a = &abuf[y * mx];
unsigned char *c = &cbuf[y * mx];
int head = x1;
int tail = x2;
adjust_region(&head, &tail, y);
int col = a[x];
{
int oldcol = col;
col = -1;
else
col = a[x];
if (oldcol != col)
{
draw_string(head, y, &c[head], x-head, oldcol);
head = x;
}
x++;
}
}
draw_cursor(cursor_x, cursor_y);
sys_flush();
}
void TextRegionClass::clear_to_end_of_line()
{
int i;
int cx = print_x - cx_ofs;
int cy = print_y - cy_ofs;
int col = text_col;
int adrs = cy * mx;
}
redraw(cx, cy, mx-1, cy);
}
void TextRegionClass::clear_to_end_of_screen()
{
int i;
int cy = print_y - cy_ofs;
int col = text_col;
}
redraw(0, cy, mx-1, my-1);
}
void TextRegionClass::putch(unsigned char ch)
{
addstr_aux((char *)&ch, 1);
}
void TextRegionClass::writeWChar(unsigned char *ch)
{
addstr_aux((char *)ch, 2);
}
void TextRegionClass::textcolor(int color)
{
text_col = color;
}
void TextRegionClass::textbackground(int col)
{
textcolor(col*16 + (text_col & 0xf));
}
{
print_x = x-1;
print_y = y-1;
if (cursor_region != NULL && cursor_flag)
{
cursor_region ->erase_cursor();
cursor_region = NULL;
}
if (cursor_flag)
{
text_mode->draw_cursor(print_x, print_y);
cursor_x = print_x;
cursor_y = print_y;
cursor_region = text_mode;
}
}
int TextRegionClass::wherex()
{
return print_x + 1;
}
int TextRegionClass::wherey()
{
return print_y + 1;
}
void TextRegionClass::_setcursortype(int curstype)
{
cursor_flag = curstype;
if (cursor_region != NULL)
if (curstype)
{
text_mode->draw_cursor(print_x, print_y);
cursor_x = print_x;
cursor_y = print_y;
cursor_region = text_mode;
}
}
cursor_region->erase_cursor();
ASSERT(x >= 1);
ASSERT(y >= 1);
void TextRegionClass::cgotoxy(int x, int y)
if (ch == 0)
ch=32;
for (i = cy*mx; i < mx*my; i++)
{
cbuf[i] = ' ';
abuf[i] = col;
if (!flag)
return;
cbuf[adrs+i] = ' ';
abuf[adrs+i] = col;
ASSERT(adrs + mx - 1 < mx * my);
for (i = cx; i < mx; i++)
{
return;
if (!flag)
if (cursor_region == this && cursor_flag == 1)
if (x == tail)
while (x <= tail)
x = head;
for (y = y1; y <= y2; y++)
return;
if (!flag)
cbuf[adrs+x+i] = buffer[i];
abuf[adrs+x+i] = text_col;
for (i = 0; i < len && x + i < mx; i++)
return;
if (!flag)
if (cursor_flag)
cgotoxy(print_x+1, print_y+1);
scroll();
if (print_y - cy_ofs == my)
j = 0;
if (c == 0)
if (buffer[i+1] == '\n' || buffer[i+1] == '\r')
c = 0;
bool newline = false;
if (c == '\n' || c == '\r')
for (i = 0; i < len + 1; i++)
j = 0;
if (!flag)
return;
if (print_y > 0)
print_y -= 1;
if (cursor_y > 0)
cursor_y -= 1;
for (idx = mx*(my-1); idx < mx*my; idx++)
for (idx = 0; idx < mx*(my-1); idx++)
if (!flag)
//
// Text related
//
return (true);
if (!is_active())
return (false);
if (x < 0 || y < 0)
return (false);
if (x >= dx * mx || y >= dy * my)
return (false);
return (true);
if (x >= mx || y >= my)
return (false);
if (!is_active())
return (false);
int x = mouse_x - ox - x_margin;
int y = mouse_y - oy - y_margin;
if (x < 0 || y < 0)
return (false);
return (true);
if (x >= mx || y >= my)
return (false);
if (!is_active())
return (false);
if ( x < 0 || y < 0 )
return (false);
return (true);
if (cx2 >= wwx - 1)
cx2 = wwx - 1;
if (cy2 >= wwy - 1)
cy2 = wwy - 1;
if (cx1 < 0)
cx1 = 0;
if (cy1 < 0)
cy1 = 0;
if (cx2 < 0 || cy2 < 0 || cx1 >= wwx || cy1 >=wwy)
return (false);
bool TileRegionClass::convert_redraw_rect(int x1, int y1, int x2, int y2,
int *rx1, int *ry1,
int *rx2, int *ry2)
return (true);
if (cx2 >= mx - 1)
cx2 = mx - 1;
if (cy2 >= my - 1)
cy2 = my - 1;
if (cx1 < 0)
cx1 = 0;
if (cy1 < 0)
cy1 = 0;
if (cx2 < 0 || cy2 < 0 || cx1 >= dx * mx || cy1 >= dy * my)
return (false);
bool RegionClass::convert_redraw_rect(int x1, int y1, int x2, int y2,
}
if (!flag)
return;
return (true);
else
return (false);
if (!flag)
return (false);
for (i = 0; i < mx2*my2; i++)
mbuf[i] = 0;
marker_length = marker_len;
old_mark_x = old_mark_y = 0;
for (i = 0; i < mx2*my2; i++)
mbuf[i] = 0;
MapRegionClass::MapRegionClass(int x, int y, int o_x, int o_y, int marker_len)
cbuf[i] = ' ';
abuf[i] = 0;
for (i = 0; i < x*y; i++)
if (backbuf != NULL)
ImgDestroy(backbuf);
if (!(*r)->is_active())
continue;
if ( (*r)->convert_redraw_rect(x1, y1, x2, y2, &cx1, &cy1, &cx2, &cy2) )
for (r = regions.begin();r != regions.end();r++)
return;
}
}
}
void WinClass::removeRegion(RegionClass *r)
{
for (unsigned int i = 0; i < regions.size(); i++)
{
if (regions[i] == r)
{
for (unsigned int j = i + 1; j < regions.size(); j++)
{
regions[j-1] = regions[j];
layers[j-1] = layers[j];
}
regions.pop_back();
layers.pop_back();
int sx0 = 0;
int sy0 = 0;
int ex0 = 0;
int ey0 = 0;
const int term_colors[MAX_TERM_COL][3] =
const int map_colors[MAX_MAP_COL][3] =
#include "AppHdr.h"
#include "debug.h"
/*
* File: guic-win.cc
* Summary: 1) Image manipulation routines
* 2) WinClass and RegionClass system independent imprementaions
* see guic-*.cc for system dependent implementations
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
#include <X11/keysym.h>
#include <X11/keysymdef.h>
#include <X11/Xmd.h>
#include "guic.h"
static Display *display;
static int screen;
static GC term_gc[MAX_TERM_COL];
static GC map_gc[MAX_MAP_COL];
static unsigned long term_pix[MAX_TERM_COL];
static unsigned long map_pix[MAX_MAP_COL];
static unsigned long pix_transparent;
static unsigned long pix_hilite;
static unsigned long pix_black;
static unsigned long pix_rimcolor;
static int x11_byte_per_pixel_ximage();
unsigned int blue);
static XImage *read_png(const char *fname);
/*******************************************************/
void WinClass::SysInit()
{
win = (Window)NULL;
}
void WinClass::SysDeinit()
{}
void RegionClass::SysInit()
{
font = NULL;
}
void RegionClass::SysDeinit()
{
if (font != NULL && !font_copied) XFreeFont(display, font);
}
void TextRegionClass::SysInit(int x, int y, int cx, int cy)
{}
void TextRegionClass::SysDeinit()
{}
void TileRegionClass::SysInit(int mx0, int my0, int dx0, int dy0)
{}
void TileRegionClass::SysDeinit()
{}
void MapRegionClass::SysInit(int x, int y, int o_x, int o_y)
{}
void MapRegionClass::SysDeinit()
{}
/*** Large part of this routine was copied from Hengband ***/
int ascent, descent, width;
font = XLoadQueryFont(display, name);
if (!font)
{
fprintf(stderr,"Error! Can't load font %s\n",name);
exit(1);
}
width = font->max_bounds.width;
ascent = font->ascent;
descent = font->descent;
int i;
XSetFont(display, term_gc[i], font->fid);
fx = dx = width;
fy = dy = ascent + descent;
asc = ascent;
font_copied = false;
}
void RegionClass::copy_font(RegionClass *r)
{
fx = r->fx;
fy = r->fy;
dx = r->dx;
dy = r->dy;
asc = r->asc;
font = r->font;
font_copied = true;
}
void RegionClass::sys_flush()
{
XFlush(display);
}
void RegionClass::init_backbuf()
{
}
void TextRegionClass::init_backbuf()
{
}
void TileRegionClass::init_backbuf()
{
int x, y;
backbuf = ImgCreateSimple(mx*dx, my*dy);
for (x = 0; x < mx*dx; x++)
for (y = 0; y < my*dy; y++)
XPutPixel(backbuf, x, y, pix_black);
}
void TileRegionClass::resize_backbuf()
{
if (backbuf != NULL) ImgDestroy(backbuf);
init_backbuf();
}
void RegionClass::resize_backbuf()
{
if (backbuf != NULL) ImgDestroy(backbuf);
init_backbuf();
}
void MapRegionClass::init_backbuf()
{
int x, y;
backbuf = ImgCreateSimple(mx*dx, my*dy);
for (x = 0; x < mx*dx; x++)
for (y = 0; y < my*dy; y++)
XPutPixel(backbuf, x, y, pix_black);
}
void MapRegionClass::resize_backbuf()
{
if (backbuf != NULL)
ImgDestroy(backbuf);
init_backbuf();
}
void TextRegionClass::draw_string(int x, int y, unsigned char *buf,
{
XFillRectangle(display, win->win, term_gc[col>>4],
x*dx+ox, y*dy+oy, dx * len, dy);
XDrawString(display, win->win, term_gc[col&0x0f], x*dx+ox, y*dy+asc+oy,
(char *)&cbuf[y*mx+x], len);
}
void TextRegionClass::draw_cursor(int x, int y)
{
XDrawString(display, win->win, term_gc[0x0f], x*dx+ox, y*dy+asc+oy,
"_", 1);
sys_flush();
}
void TextRegionClass::erase_cursor()
{
WinClass *w = win;
int x0 = cursor_x;
int y0 = cursor_y;
int width = 1;
int adrs = y0 * mx + x0;
int col = abuf[adrs];
int x1 = x0;;
XFillRectangle(display, w->win, term_gc[col>>4],
x1*dx + ox, y0*dy +oy, dx*width, dy);
XDrawString(display, w->win,
term_gc[col&0x0f], x0*dx+ ox, y0*dy+asc+ oy,
(char *)&cbuf[adrs], width );
}
void WinClass::clear()
{
fillrect(0, 0, wx, wy, PIX_BLACK);
XFlush(display);
}
void RegionClass::clear()
{
fillrect(0, 0, wx, wy, PIX_BLACK);
XFlush(display);
}
void TileRegionClass::clear()
{
RegionClass::clear();
}
void MapRegionClass::clear()
{
int i;
RegionClass::clear();
}
void TextRegionClass::clear()
{
int i;
{
}
RegionClass::clear();
}
void WinClass::create(char *name)
{
if (!win)
{
win = XCreateSimpleWindow(display, RootWindow(display,screen),
XMapWindow(display, win);
XSelectInput(display, win, ExposureMask | KeyPressMask
| ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
LeaveWindowMask | EnterWindowMask | StructureNotifyMask );
move(ox, oy);
}
else
resize(0,0);
clear();
}
void WinClass::move()
{
XMoveWindow(display, win, ox, oy);
}
void WinClass::resize()
{
XResizeWindow(display, win, wx, wy);
}
void TileRegionClass::redraw(int x1, int y1, int x2, int y2)
{
int wwx = x2-x1+1;
int wwy = y2-y1+1;
if (x1<0)
{
wwx += x1;
x1 = 0;
}
if (y1<0)
{
wwy += y1;
y1 = 0;
}
if (x2 >= mx*dx)
{
wwx -= x2-mx*dx+1;
}
if (y2 >= my*dy)
{
wwy -= y2-my*dy+1;
}
XPutImage(display, win->win, term_gc[0],
backbuf, x1, y1, x1+ox, y1+oy, wwx, wwy);
}
void MapRegionClass::redraw(int x1, int y1, int x2, int y2)
{
if (!flag)
return;
XPutImage(display, win->win, term_gc[0],
backbuf, x1*dx, y1*dy,
x1*dx+ox, y1*dy+oy,
(x2-x1+1)*dx, (y2-y1+1)*dy);
}
if (!flag)
return;
{
{
{
set_col(col, x, y);
}
}
}
redraw();
XFlush(display);
force_redraw = false;
}
/* XXXXX
* img_type related
*/
bool ImgIsTransparentAt(img_type img, int x, int y)
{
}
void ImgSetTransparentPix(img_type img)
{
pix_transparent = XGetPixel(img, 0, 0);
}
void ImgDestroy(img_type img)
{
}
img_type ImgCreateSimple(int wx, int wy)
{
char *buf = (char *)malloc(x11_byte_per_pixel_ximage()* wx * wy);
return(res);
}
img_type ImgLoadFile(const char *name)
{
return read_png(name);
}
void ImgClear(img_type img)
{
ASSERT(img != NULL);
}
// Copy internal image to another internal image
void ImgCopy(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, int copy)
{
int x, y;
int bpp = src->bytes_per_line / src->width;
int bpl_s = src->bytes_per_line;
int bpl_d = dest->bytes_per_line;
{
char *p_dest = (char *)(dest->data + bpl_d * dy + dx * bpp);
memcpy(p_dest, p_src, wx * bpp);
p_dest += bpl_d;
}
}
{
CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = p_src[x];
}
p_dest += bpl_d;
}
}
{
CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
{
CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
}
// Copy internal image to another internal image
void ImgCopyH(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, int copy)
{
int x, y;
int bpp = src->bytes_per_line / src->width;
int bpl_s = src->bytes_per_line;
int bpl_d = dest->bytes_per_line;
{
char *p_dest = (char *)(dest->data + bpl_d * dy + dx * bpp);
memcpy(p_dest, p_src, wx * bpp);
p_dest += bpl_d;
}
}
{
CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = pix_hilite;
p_dest[x] = p_src[x];
}
p_dest += bpl_d;
}
}
{
CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = pix_hilite;
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
{
CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = pix_hilite;
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
}
// Copy internal image to another internal image
void ImgCopyMasked(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, char *mask)
{
int x, y, count;
int bpp = src->bytes_per_line / src->width;
int bpl_s = src->bytes_per_line;
int bpl_d = dest->bytes_per_line;
count = 0;
{
CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = p_src[x];
}
p_dest += bpl_d;
}
}
{
CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
{
CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
}
// Copy internal image to another internal image
void ImgCopyMaskedH(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, char *mask)
{
int x, y, count;
int bpp = src->bytes_per_line / src->width;
int bpl_s = src->bytes_per_line;
int bpl_d = dest->bytes_per_line;
count = 0;
{
CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = pix_hilite;
p_dest[x] = p_src[x];
}
p_dest += bpl_d;
}
}
{
CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = pix_hilite;
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
{
CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp);
//X11 specific
p_dest[x] = pix_hilite;
p_dest[x] = p_src[x];
}
p_dest += bpl_d/bpp;
}
}
}
void TileRegionClass::DrawPanel(int left, int top, int width, int height)
{
framerect(left, top , left + width, top + height, PIX_WHITE);
framerect(left + 1, top + 1, left + width, top + height, PIX_DARKGREY);
fillrect (left + 1, top + 1, left + width - 1, top + height -1, PIX_LIGHTGREY);
}
void RegionClass::framerect(int left, int top, int right, int bottom,
int color)
{
XDrawRectangle(display, win->win, term_gc[color&0xf],
ox+left, oy+top, right-left, bottom-top);
}
void TileRegionClass::framerect(int left, int top, int right, int bottom,
int color)
{
int x,y;
int pix = term_pix[color];
XPutPixel(backbuf, x, top, pix);
XPutPixel(backbuf, x, bottom, pix);
}
XPutPixel(backbuf, left, y, pix);
XPutPixel(backbuf, right, y, pix);
}
}
void WinClass::fillrect(int left, int top, int right, int bottom,
int color)
{
XFillRectangle(display, win, term_gc[color&0xf],
top, left, right-left+1, bottom-top+1);
}
void RegionClass::fillrect(int left, int top, int right, int bottom,
int color)
{
XFillRectangle(display, win->win, term_gc[color&0xf],
ox+left, oy+top, right-left, bottom-top);
}
void TileRegionClass::fillrect(int left, int top, int right, int bottom,
int color)
{
int x,y;
int pix = term_pix[color];
}
/********************************************/
bool GuicInit(Display **d, int *s)
{
int i;
setlocale(LC_ALL, "");
if (!display)
{
fprintf(stderr,"Cannot open display\n");
}
screen=DefaultScreen(display);
*d = display;
*s = screen;
// for text display
{
const int *c = term_colors[i];
XSetForeground(display,term_gc[i], term_pix[i]);
}
// for text display
{
const int *c = map_colors[i];
XSetForeground(display, map_gc[i], map_pix[i]);
}
// for Image manipulation
pix_rimcolor = create_pixel(1,1,1);
}
void GuicDeinit()
{
int i;
XFreeGC(display,term_gc[i]);
XFreeGC(display,map_gc[i]);
XCloseDisplay(display);
}
static int x11_byte_per_pixel_ximage()
{
int i = 1;
int j = (DefaultDepth(display, screen) - 1) >> 2;
return i;
}
unsigned int blue)
{
Colormap cmap = DefaultColormapOfScreen(DefaultScreenOfDisplay(display));
XColor xcolour;
xcolour.green = green * 256;
xcolour.flags = DoRed | DoGreen | DoBlue;
XAllocColor(display, cmap, &xcolour);
return (xcolour.pixel);
}
/*
Copied from pngtopnm.c and modified by M.Itakura
(mostly omitted and added a few lines)
only color paletted image is handled
*/
/*
** pngtopnm.c -
** read a Portable Network Graphics file and produce a portable anymap
**
** Copyright (C) 1995,1998 by Alexander Lehmann <alex@hal.rhein-main.de>
** and Willem van Schaik <willem@schaik.com>
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
**
** modeled after giftopnm by David Koblas and
** with lots of bits pasted from libpng.txt by Guy Eric Schalnat
*/
#include "png.h"
#define pm_message printf
#define pm_error(x) {fprintf(stderr,x);return NULL;}
# define TRUE 1
# define FALSE 0
# define NONE 0
#define SIG_CHECK_SIZE 4
XImage *read_png (const char *fname)
{
}
/* sBIT handling is very tricky. If we are extracting only the image, we
values agree. If we extract the transparency/alpha mask, sBIT is
irrelevant for trans and valid for alpha. If we mix both, the
multiplication may result in values that require the normal bit depth,
so we will use the sBIT info only for transparency, if we know that only
solid and fully transparent is used */
if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
(info_ptr->sig_bit.red != info_ptr->sig_bit.green ||
for (i = 0 ; i < 256 ; i++)
}
}
fclose(ifp);
return res;
free (png_image);
free (png_ptr);
free (info_ptr);
for (y = 0 ; y < info_ptr->height ; y++)
free (png_image[y]);
for (y = 0; y < info_ptr->height; y++)
{
png_pixel = png_image[y];
for (x = 0; x < info_ptr->width; x++)
{
c = *png_pixel;
png_pixel++;
XPutPixel(res, x, y, pix_table[c]);
}
res = ImgCreateSimple(info_ptr->width, info_ptr->height);
png_read_image (png_ptr, png_image);
png_read_end (png_ptr, info_ptr);
pix_table[i] = create_pixel(i, i, i);
}
info_ptr->palette[i].green, info_ptr->palette[i].blue);
}
else if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
//X11
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
//X11
for (i = 0 ; i < info_ptr->num_palette ; i++)
pix_table[i] = create_pixel(info_ptr->palette[i].red,
info_ptr->sig_bit.red != info_ptr->sig_bit.blue) )
{
"supported");
info_ptr->bit_depth);
}
else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE
&& info_ptr->sig_bit.red < 255)
{
for (i = 0 ; i < info_ptr->num_palette ; i++)
{
}
else if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY
|| info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
&& info_ptr->sig_bit.gray < info_ptr->bit_depth)
{
}
}
png_set_shift (png_ptr, &(info_ptr->sig_bit));
info_ptr->palette[i].red >>= (8 - info_ptr->sig_bit.red);
info_ptr->palette[i].green >>= (8 - info_ptr->sig_bit.green);
info_ptr->palette[i].blue >>= (8 - info_ptr->sig_bit.blue);
}
pm_message ("writing file with %d bit resolution",
pm_message ("different bit depths for color channels not "
if (info_ptr->valid & PNG_INFO_sBIT)
{
can use the sBIT info for greyscale and color images, if the three
if (info_ptr->bit_depth < 8)
png_set_packing (png_ptr);
free (png_image);
free (png_ptr);
free (info_ptr);
pm_error ("couldn't alloc space for image");
}
for (y = 0 ; y < info_ptr->height ; y++)
{
png_image[y] = (png_byte *)malloc (linesize);
if (png_image[y] == NULL)
{
for (x = 0; x < y; x++)
free (png_image[x]);
if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
linesize *= 2;
else if (info_ptr->color_type == PNG_COLOR_TYPE_RGB)
linesize *= 3;
else if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
linesize *= 4;
if (info_ptr->bit_depth == 16)
linesize = 2 * info_ptr->width;
else
linesize = info_ptr->width;
png_image = (png_byte **)malloc (info_ptr->height * sizeof (png_byte*));
if (png_image == NULL)
{
free (png_ptr);
free (info_ptr);
pm_error ("couldn't alloc space for image");
}
png_init_io (png_ptr, ifp);
png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE);
png_read_info (png_ptr, info_ptr);
if (setjmp (png_ptr->jmpbuf))
{
png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
free (png_ptr);
free (info_ptr);
pm_error ("setjmp returns error condition");
}
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL)
{
png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
pm_error ("cannot allocate LIBPNG structures");
}
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
pm_error ("cannot allocate LIBPNG structure");
if (fread (sig_buf, 1, SIG_CHECK_SIZE, ifp) != SIG_CHECK_SIZE)
pm_error ("input file empty or too short");
if (png_sig_cmp ((unsigned char *)sig_buf, (png_size_t) 0,
(png_size_t) SIG_CHECK_SIZE) != 0)
{
pm_error ("input file not a PNG file");
}
if (!ifp)
{
fprintf(stderr, "File not found: %s", fname);
return NULL;
}
FILE *ifp = fopen(fname,"r");
//X11
XImage *res;
unsigned long pix_table[256];
char sig_buf [SIG_CHECK_SIZE];
png_struct *png_ptr;
png_info *info_ptr;
png_byte **png_image;
png_byte *png_pixel;
unsigned int x, y;
int linesize;
png_uint_16 c;
unsigned int i;
xcolour.blue = blue * 256;
xcolour.red = red * 256;
unsigned long create_pixel(unsigned int red, unsigned int green,
while (j >>= 1)
{
i <<= 1;
}
for (i = 0; i < MAX_MAP_COL; i++)
for (i = 0; i < MAX_TERM_COL; i++)
return (true);
pix_black = term_pix[PIX_BLACK] ;
pix_hilite = term_pix[PIX_LIGHTMAGENTA] ;
map_pix[i] = create_pixel(c[0], c[1], c[2]);
map_gc[i] = XCreateGC(display, RootWindow(display,screen), 0, 0);
for (i = 0; i < MAX_MAP_COL; i++)
term_pix[i] = create_pixel(c[0], c[1], c[2]);
term_gc[i] = XCreateGC(display, RootWindow(display,screen), 0, 0);
for (i = 0; i < MAX_TERM_COL; i++)
return (false);
display = XOpenDisplay("");
for (x = left; x <= right; x++)
for (y = top; y <= bottom; y++)
XPutPixel(backbuf, x, y, pix);
ASSERT(left >= 0);
ASSERT(top >= 0);
ASSERT(right < mx*dx);
ASSERT(bottom < my*dy);
for (y = top+1; y < bottom; y++)
{
for (x = left; x <= right; x++)
{
p_src += bpl_s/bpp;
count++;
else if (p_src[x] != pix_transparent && mask[count] == 0)
if (p_src[x] == pix_rimcolor)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 4)
p_src += bpl_s/bpp;
count++;
else if (p_src[x] != pix_transparent && mask[count] == 0)
if (p_src[x] == pix_rimcolor)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 2)
p_src += bpl_s;
count++;
else if (p_src[x] != pix_transparent && mask[count] == 0)
if (p_src[x] == pix_rimcolor)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp);
if (bpp <= 1)
ASSERT(sx >= 0);
ASSERT(sy >= 0);
ASSERT(sx + wx <= src->width);
ASSERT(sy + wy <= src->height);
ASSERT(dx >= 0);
ASSERT(dy >= 0);
ASSERT(dx + wx <= dest->width);
ASSERT(dy + wy <= dest->height);
p_src += bpl_s/bpp;
count++;
if (p_src[x] != pix_transparent && mask[count] == 0)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 4)
p_src += bpl_s/bpp;
count++;
if (p_src[x] != pix_transparent && mask[count] == 0)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 2)
p_src += bpl_s;
count++;
if (p_src[x] != pix_transparent && mask[count] == 0)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp);
if (bpp <= 1)
ASSERT(sx >= 0);
ASSERT(sy >= 0);
ASSERT(sx + wx <= src->width);
ASSERT(sy + wy <= src->height);
ASSERT(dx >= 0);
ASSERT(dy >= 0);
ASSERT(dx + wx <= dest->width);
ASSERT(dy + wy <= dest->height);
p_src += bpl_s/bpp;
else if (p_src[x] != pix_transparent)
if (p_src[x] == pix_rimcolor)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 4)
p_src += bpl_s/bpp;
else if (p_src[x] != pix_transparent)
if (p_src[x] == pix_rimcolor)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 2)
p_src += bpl_s;
else if (p_src[x] != pix_transparent)
if (p_src[x] == pix_rimcolor)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 1)
p_src += bpl_s;
for (y = 0; y < wy; y++)
{
char *p_src = (char *)(src->data + bpl_s * sy + sx * bpp);
if (copy == 1)
ASSERT(sx >= 0);
ASSERT(sy >= 0);
ASSERT(sx + wx <= src->width);
ASSERT(sy + wy <= src->height);
ASSERT(dx >= 0);
ASSERT(dy >= 0);
ASSERT(dx + wx <= dest->width);
ASSERT(dy + wy <= dest->height);
p_src += bpl_s/bpp;
if (p_src[x] != pix_transparent)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 4)
p_src += bpl_s/bpp;
if (p_src[x] != pix_transparent)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 2)
p_src += bpl_s;
if (p_src[x] != pix_transparent)
for (y = 0; y < wy; y++)
{
for (x = 0; x < wx; x++)
{
CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp);
else if (bpp <= 1)
p_src += bpl_s;
for (y = 0; y < wy; y++)
{
char *p_src = (char *)(src->data + bpl_s * sy + sx * bpp);
if (copy == 1)
ASSERT(sx >= 0);
ASSERT(sy >= 0);
ASSERT(sx + wx <= src->width);
ASSERT(sy + wy <= src->height);
ASSERT(dx >= 0);
ASSERT(dy >= 0);
ASSERT(dx + wx <= dest->width);
ASSERT(dy + wy <= dest->height);
for (x = 0; x < img->width; x++)
for (y = 0; y < img->height; y++)
XPutPixel(img, x, y, pix_transparent);
int x, y;
img_type res = XCreateImage(display, DefaultVisual(display, screen),
DefaultDepth(display, screen),
ZPixmap, 0, buf, wx, wy, 8, 0);
if (wx == 0 || wy == 0)
return NULL;
if (img)
XDestroyImage(img);
return (pix_transparent == XGetPixel(img, x, y)) ? true : false;
ASSERT(x >= 0);
ASSERT(y >= 0);
ASSERT(x < img->width);
ASSERT(y < img->height);
if (show_mark)
{
for (int yy = 0; yy < dy * marker_length; yy++)
{
map_pix[MAP_WHITE]);
}
for (int xx = 0; xx < dx * marker_length; xx++)
{
map_pix[MAP_WHITE]);
}
}
XPutPixel(backbuf, xx, old_mark_y*dy+dy/2 + y_margin,
XPutPixel(backbuf, old_mark_x*dx+dx/2 + x_margin, yy,
old_mark_x = mark_x;
old_mark_y = mark_y;
{
XPutPixel(backbuf, x_margin + x*dx+xx,
}
y_margin + y*dy+yy, map_pix[col]);
for (int xx = 0; xx < dx; xx++)
for (int yy = 0; yy < dy; yy++)
if (col != get_col(x, y) || force_redraw
|| x < marker_length || y < marker_length)
int col = ptr[x];
unsigned char *ptr = &buf[y * (mx2 - x_margin)];
for (int x = 0; x < mx - x_margin; x++)
for (int y = 0; y < my - y_margin; y++)
for (int xx = 0; xx < dx * marker_length; xx++)
{
XPutPixel(backbuf, xx, old_mark_y*dy+dy/2 + y_margin,
map_pix[MAP_BLACK]);
}
for (int yy = 0; yy < dy * marker_length; yy++)
{
XPutPixel(backbuf, old_mark_x*dx+dx/2 + x_margin, yy,
map_pix[MAP_BLACK]);
}
{
void MapRegionClass::draw_data(unsigned char *buf, bool show_mark,
int mark_x, int mark_y)
XStoreName(display, win, CRAWL " " VERSION);
10,10, wx, wy, 0,
BlackPixel(display,screen), BlackPixel(display,screen));
cbuf[i] = ' ';
abuf[i] = 0;
for (i = 0; i < mx*my; i++)
for (i = 0; i < mx2*my2; i++)
mbuf[i] = PIX_BLACK;
if (!flag)
return;
if (!flag)
return;
int len, int col)
for (i = 0; i < MAX_TERM_COL; i++)
void RegionClass::init_font(const char *name)
{
static unsigned long create_pixel(unsigned int red, unsigned int green,
#include "version.h"
#include "debug.h"
#include "externs.h"
#include "AppHdr.h"
/*
* File: guic-x11.cc
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
*/
#include <windows.h>
#include <commdlg.h>
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
// WinClass & RegionClass definitions
static HINSTANCE hInst;
static int nCmdShow;
// colors
static COLORREF term_pix[MAX_TERM_COL];
BYTE pix_transparent;
BYTE pix_black;
BYTE pix_white;
BYTE pix_magenta;
BYTE pix_rimcolor;
RGBQUAD RegionClass::std_palette[256];
bool GuicInit(HINSTANCE h, int nCmd)
{
int i;
hInst = h;
nCmdShow = nCmd;
{
}
}
void GuicDeinit()
{
}
void WinClass::SysInit()
{
hWnd = NULL;
}
void WinClass::SysDeinit()
{}
void RegionClass::SysInit()
{
font = NULL;
}
void RegionClass::SysDeinit()
{
if (font != NULL && !font_copied) DeleteObject(font);
}
void RegionClass::sys_flush()
{}
void TextRegionClass::SysInit(int x, int y, int cx, int cy)
{
dos_char = false;
}
void TextRegionClass::SysDeinit()
{}
void TileRegionClass::SysInit(int mx0, int my0, int dx0, int dy0)
{}
void TileRegionClass::SysDeinit()
{}
void MapRegionClass::SysInit(int x, int y, int o_x, int o_y)
{}
void MapRegionClass::SysDeinit()
{}
void RegionClass::init_font(const char *name, int height)
{
int wid, hgt;
LOGFONT lf;
HFONT ftmp;
strcpy(lf.lfFaceName, name);
lf.lfHeight = height;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = lf.lfEscapement;
lf.lfWeight = FW_NORMAL;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
lf.lfStrikeOut = FALSE;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
#ifdef JP
lf.lfCharSet = (dos_char) ? OEM_CHARSET:SHIFTJIS_CHARSET;
lf.lfPitchAndFamily= FF_DONTCARE|FIXED_PITCH;
#else
lf.lfCharSet = (dos_char) ? OEM_CHARSET:ANSI_CHARSET;
lf.lfPitchAndFamily= FF_MODERN|FIXED_PITCH;
#endif
ftmp = CreateFontIndirect( &lf );
if (!ftmp)
{
}
font = ftmp;
wid = lf.lfWidth;
hgt = lf.lfHeight;
/* This part is taken from angband */
/* Hack -- Unknown size */
if (!wid || !hgt)
{
HDC hdcDesktop;
HFONT hfOld;
TEXTMETRIC tm;
/* all this trouble to get the cell size */
hdcDesktop = GetDC(HWND_DESKTOP);
hfOld = (HFONT)SelectObject(hdcDesktop, font);
GetTextMetrics(hdcDesktop, &tm);
SelectObject(hdcDesktop, hfOld);
ReleaseDC(HWND_DESKTOP, hdcDesktop);
/* Font size info */
wid = tm.tmAveCharWidth;
hgt = tm.tmHeight;
}
fx = dx = wid;
fy = dy = hgt;
}
void RegionClass::change_font(const char *name, int height)
{
if (font != NULL) DeleteObject(font);
init_font(name, height);
}
void RegionClass::copy_font(RegionClass *r)
{
fx = r->fx;
fy = r->fy;
dx = r->dx;
dy = r->dy;
font = r->font;
}
void RegionClass::set_std_palette(RGBQUAD *pPal)
{
int i;
{
pix_black = i;
pix_white = i;
pix_magenta = i;
pix_rimcolor = i;
}
std_palette[pix_transparent].rgbRed = 0;
std_palette[pix_transparent].rgbGreen = 0;
std_palette[pix_transparent].rgbBlue = 0;
}
void RegionClass::init_backbuf(RGBQUAD *pPal, int ncolor)
{
int i;
// first time
if (backbuf == NULL)
{
// alloc for misc info
backbuf = (dib_pack *)GlobalAlloc(GPTR, sizeof(dib_pack));
// alloc for header+palette data
backbuf->pDib = (LPBITMAPINFO)GlobalAlloc(GPTR,
(sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)) );
// set header data
// set palette data
for (i = 0; i < ncolor; i++)
{
// copy palette from given palette pPal
backbuf->pDib->bmiColors[i].rgbRed = pPal[i].rgbRed ;
backbuf->pDib->bmiColors[i].rgbGreen = pPal[i].rgbGreen;
backbuf->pDib->bmiColors[i].rgbBlue = pPal[i].rgbBlue ;
}
}
// set dimension
backbuf->pDib->bmiHeader.biWidth = mx*dx;
backbuf->pDib->bmiHeader.biHeight = my*dy;
backbuf->Width = mx * dx;
backbuf->Height= my * dy;
if (win != NULL)
{
// this routine should be called after the window is initialized
if (win->hWnd != NULL)
{
HDC hdc1 = GetDC(0);
HDC hdc2 = GetDC(win->hWnd);
backbuf->hDib = CreateDIBSection(hdc1, backbuf->pDib,
backbuf->hDC = CreateCompatibleDC(hdc2);
SelectObject(backbuf->hDC, backbuf->hDib);
ReleaseDC(win->hWnd, hdc2);
ReleaseDC(0, hdc1);
}
}
}
void RegionClass::resize_backbuf()
{
int i;
// discard it for resize
if (backbuf->hDC != NULL) DeleteDC(backbuf->hDC);
if (backbuf->hDib != NULL) DeleteObject(backbuf->hDib);
// set dimension
HDC hdc1 = GetDC(0);
HDC hdc2 = GetDC(win->hWnd);
// alloc a region of the window
backbuf->hDib = CreateDIBSection(hdc1, backbuf->pDib,
backbuf->hDC = CreateCompatibleDC(hdc2);
SelectObject(backbuf->hDC, backbuf->hDib);
ReleaseDC(win->hWnd, hdc2);
ReleaseDC(0, hdc1);
for (i = 0; i< mx*dx*my*dy; i++)
*(backbuf->pDibBits + i) = pix_black;
}
void MapRegionClass::resize_backbuf()
{
RegionClass::resize_backbuf();
}
void TileRegionClass::resize_backbuf()
{
RegionClass::resize_backbuf();
}
void TextRegionClass::init_backbuf()
{
}
void TileRegionClass::init_backbuf(RGBQUAD *pPal)
{
int i;
if (!pPal)
else
for (i = 0; i< mx*dx*my*dy; i++)
*(backbuf->pDibBits + i) = pix_black;
}
void MapRegionClass::init_backbuf()
{
BYTE black = 0;
RGBQUAD scol[MAX_MAP_COL];
int i;
{
}
// just resize
if (backbuf != NULL)
RegionClass::init_backbuf(NULL, 0);
else
RegionClass::init_backbuf(scol, MAX_MAP_COL);
for (i = 0; i < MAX_MAP_COL; i++)
{
black = i;
}
for (i = 0; i< mx*dx*my*dy; i++)
}
// defined to object, not to class
void TextRegionClass::draw_string(int x, int y, unsigned char *buf,
{
HDC hdc = GetDC(win->hWnd);
RECT rc;
rc.bottom = rc.top + dy;
SelectObject(hdc, font);
SetBkColor(hdc, term_pix[col>>4]);
SetTextColor(hdc, term_pix[col&0x0f]);
ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc,
ReleaseDC(win->hWnd, hdc);
}
void TextRegionClass::draw_cursor(int x, int y)
{
RECT rc;
HDC hdc;
int cx = x - cx_ofs;
int cy = y - cy_ofs;
SelectObject(hdc, font);
rc.bottom = rc.top + dy;
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, term_pix[0x0f]);
ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc,
ReleaseDC(win->hWnd, hdc);
}
int x0 = cursor_x;
int y0 = cursor_y;
int adrs = y0 * mx + x0;
int col = abuf[adrs];
RECT rc;
SelectObject(hdc, font);
//restore previous cursor cell
rc.bottom = rc.top + dy;
unsigned char rchar[3];
SetBkColor(hdc, term_pix[col>>4]);
SetTextColor(hdc, term_pix[col&0x0f]);
rchar[0] = cbuf[adrs];
#ifdef JP
if ( (rchar[0]&0x80) && !dos_char /*_ismbblead( rchar[0])*/ )
{
rchar[1] = cbuf[adrs+1];
rchar[2] = '\0';
ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc,
}
else
#endif
{
rchar[1] = '\0';
ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc,
}
ReleaseDC(win->hWnd, hdc);
}
void WinClass::clear()
{
fillrect(0, 0, wx-1, wy-1, PIX_BLACK);
}
void RegionClass::clear()
{
fillrect(0, 0, wx-1, wy-1, PIX_BLACK);
}
void TileRegionClass::clear()
{
RegionClass::clear();
}
void MapRegionClass::clear()
{
RegionClass::clear();
}
void TextRegionClass::clear()
{
int i;
{
}
RegionClass::clear();
}
BOOL WinClass::create(const char *name)
{
RECT rc;
rc.left = 0;
rc.right = wx;
rc.top = 0;
rc.bottom = wy;
//game_state = STAT_NORMAL;
AdjustWindowRectEx(&rc,
false, 0);
if (hWnd == NULL)
{
hWnd = CreateWindowEx(0, "CrawlList",name,
ShowWindow( hWnd, nCmdShow );
}
clear();
}
void WinClass::move()
{
}
void WinClass::resize()
{
RECT rc;
rc.left = 0;
rc.right = wx;
rc.top = 0;
rc.bottom = wy;
AdjustWindowRectEx(&rc,
false, 0);
SetWindowPos(hWnd, 0, ox, oy,
UpdateWindow( hWnd );
}
void TileRegionClass::redraw(int x1, int y1, int x2, int y2)
{
if (!flag) return;
if (!is_active()) return;
HDC hdc = GetDC(win->hWnd);
BitBlt(hdc, ox, oy, mx*dx, my*dy,
backbuf->hDC, 0, 0, SRCCOPY);
ReleaseDC(win->hWnd, hdc);
}
void MapRegionClass::redraw(int x1, int y1, int x2, int y2)
{
if (!flag) return;
if (!is_active()) return;
BitBlt(hdc, ox, oy, dx*mx, dy*my,
backbuf->hDC, 0, 0, SRCCOPY);
ReleaseDC(win->hWnd, hdc);
}
LPBYTE ppix ,dpix;
int inc_x, inc_y, inc_x0, inc_y0;
int bufx = mx * dx;
int bufy = my * dy;
#define BUF_IDX(x,y, x1, y1) ((x)*dx-(y)*dy*bufx + (x1) - (y1)*bufx)
// upper left corner
LPBYTE pDibBit0 = backbuf->pDibBits + bufx*(bufy-1);
ppix = pDibBit0;
inc_x0 = 1;
{
{
{
dpix = ppix;
{
{
*dpix = col;
dpix += inc_x0;
}
dpix += inc_y0;
}
}
ppix += inc_x;
}
ppix += inc_y;
}
redraw();
force_redraw = false;
}
LPBYTE dib_ref_pixel(dib_pack* dib, int x, int y)
{
int w = ((3 + dib->Width)/4)*4;
LPBYTE ref = dib->pDibBits + x + (dib->Height -1 -y) * w;
}
bool ImgIsTransparentAt(img_type img, int x, int y)
{
}
void ImgSetTransparentPix(img_type img)
{
pix_transparent = (BYTE)*(img->pDibZero);
}
img_type ImgCreateSimple(int wx, int wy)
{
dib_pack *ptr = (dib_pack *)GlobalAlloc(GPTR, sizeof(dib_pack));
ptr->pDibBits = (LPBYTE)GlobalAlloc(GPTR, wx*wy );
ptr->pDibZero = ptr->pDibBits + (wy -1)* wx;
ptr->Width = wx;
ptr->Height = wy;
ptr->pDib = NULL;
ptr->hDib = NULL;
ptr->hDC = NULL;
}
void ImgDestroy(img_type img)
{
GlobalFree(img);
}
img_type ImgLoadFile(const char *name)
{
HANDLE fh;
DWORD dummy;
BITMAPFILEHEADER bmHead;
int BitsSize;
HDC hdc1;
dib_pack *img;
hdc1 = GetDC(0);
if (!ReadFile(fh,&bmHead, sizeof(BITMAPFILEHEADER), &dummy, NULL))
img = (dib_pack *) GlobalAlloc(GPTR, sizeof(dib_pack));
img->pDib = (LPBITMAPINFO)GlobalAlloc(GPTR,
(sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)) );
if (img->pDib == NULL)
{
GlobalFree(img);
return NULL;
}
SetFilePointer(fh, sizeof(BITMAPFILEHEADER), NULL, FILE_BEGIN);
{
GlobalFree(img->pDib);
GlobalFree(img);
return NULL;
}
img->hDib = CreateDIBSection(hdc1, img->pDib, DIB_RGB_COLORS,
(VOID **)&(img->pDibBits), NULL,0);
if (img->hDib == NULL)
{
GlobalFree(img->pDib);
GlobalFree(img);
return NULL;
}
BitsSize = bmHead.bfSize-bmHead.bfOffBits;
SetFilePointer(fh, bmHead.bfOffBits, NULL, FILE_BEGIN);
if (!ReadFile(fh, img->pDibBits, BitsSize, &dummy, NULL))
{
GlobalFree(img->hDib);
GlobalFree(img->pDib);
GlobalFree(img);
return NULL;
}
img->Width = img->pDib->bmiHeader.biWidth ;
img->Height = img->pDib->bmiHeader.biHeight;
img->pDibZero = img->pDibBits + (img->Height - 1) * img->Width;
ReleaseDC(0, hdc1);
return img;
}
void ImgClear(img_type img)
{
int i;
for (i = 0; i< (img->Width * img->Height); i++)
*(img->pDibBits + i) = pix_transparent;
}
// Copy internal image to another internal image
void ImgCopy(img_type src, int sx, int sy, int wx, int wy,
{
int x, y;
BYTE pix;
{
}
else
{
}
}
// Copy internal image to another internal image
void ImgCopyH(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, int copy)
{
int x, y;
BYTE pix;
{
}
else
{
}
}
// Copy internal image to another internal image
void ImgCopyMasked(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, char *mask)
{
int x, y;
BYTE pix;
int count = 0;
}
// Copy internal image to another internal image
void ImgCopyMaskedH(img_type src, int sx, int sy, int wx, int wy,
img_type dest, int dx, int dy, char *mask)
{
int x, y;
BYTE pix;
int count = 0;
}
void WinClass::fillrect(int left, int top, int right, int bottom, int color)
{
HDC hdc = GetDC(hWnd);
HBRUSH curbrush;
HDC curbrushhdc = NULL;
curbrush = CreateSolidBrush(term_pix[color]);
SelectObject(curbrushhdc, curbrush);
FillRect(hdc, &currect, curbrush);
DeleteObject(curbrush);
DeleteDC(curbrushhdc);
ReleaseDC(hWnd, hdc);
}
void TileRegionClass::DrawPanel(int left, int top, int width, int height)
{
framerect(left, top , left + width, top + height, PIX_WHITE);
framerect(left + 1, top + 1, left + width, top + height, PIX_DARKGREY);
fillrect (left + 1, top + 1, left + width - 1, top + height -1, PIX_LIGHTGREY);
}
void RegionClass::framerect(int left, int top, int right, int bottom, int color)
{
HDC hdc = GetDC(win->hWnd);
HBRUSH curbrush;
RECT currect;
curbrush = CreateSolidBrush(term_pix[color]);
SelectObject(curbrushhdc, curbrush);
FrameRect(hdc, &currect, curbrush);
DeleteObject(curbrush);
DeleteDC(curbrushhdc);
ReleaseDC(win->hWnd, hdc);
}
void TileRegionClass::framerect(int left, int top, int right, int bottom,
int color)
{
HDC dhdc = backbuf->hDC;
HBRUSH curbrush;
RECT currect;
curbrush = CreateSolidBrush(term_pix[color]);
SelectObject(curbrushhdc, curbrush);
FrameRect(dhdc, &currect, curbrush);
DeleteObject(curbrush);
DeleteDC(curbrushhdc);
}
void RegionClass::fillrect(int left, int top, int right, int bottom, int color)
{
HDC hdc = GetDC(win->hWnd);
HBRUSH curbrush;
RECT currect;
curbrush = CreateSolidBrush(term_pix[color]);
SelectObject(curbrushhdc, curbrush);
FillRect(hdc, &currect, curbrush);
DeleteObject(curbrush);
DeleteDC(curbrushhdc);
ReleaseDC(win->hWnd, hdc);
}
void TileRegionClass::fillrect(int left, int top, int right, int bottom,
int color)
{
HDC dhdc = backbuf->hDC;
HBRUSH curbrush;
RECT currect;
curbrush = CreateSolidBrush(term_pix[color]);
SelectObject(curbrushhdc, curbrush);
FillRect(dhdc, &currect, curbrush);
DeleteObject(curbrush);
DeleteDC(curbrushhdc);
}
currect.left = left;
currect.right = right;
currect.top = top;
currect.bottom = bottom;
HDC curbrushhdc = NULL;
currect.left = sx + left;
currect.right = sx + right;
currect.top = sy + top;
currect.bottom = sy + bottom;
HDC curbrushhdc = NULL;
currect.left = left;
currect.right = right;
currect.top = top;
currect.bottom = bottom;
HDC curbrushhdc = NULL;
currect.left = sx + left;
currect.right = sx + right;
currect.top = sy + top;
currect.bottom = sy + bottom;
HDC curbrushhdc = NULL;
currect.left = left;
currect.right = right;
currect.top = top;
currect.bottom = bottom;
RECT currect;
for (y = 0; y < wy; y++)
for (x = 0; x < wx; x++)
{
pix = *( dib_ref_pixel(src, sx+x, sy+y) );
if (pix == pix_rimcolor)
pix = pix_magenta;
*( dib_ref_pixel(dest, dx+x, dy+y) ) = pix;
count++;
}
if (mask[count] == 0 && pix != pix_transparent)
for (y = 0; y < wy; y++)
for (x = 0; x < wx; x++)
{
pix = *( dib_ref_pixel(src, sx+x, sy+y) );
*( dib_ref_pixel(dest, dx+x, dy+y) ) = pix;
count++;
}
if (mask[count] == 0 && pix != pix_transparent)
for (x = 0; x < wx; x++)
for (y = 0; y < wy; y++)
{
pix = *( dib_ref_pixel(src, sx+x, sy+y) );
if (pix == pix_rimcolor)
pix = pix_magenta;
if (pix != pix_transparent)
*( dib_ref_pixel(dest, dx+x, dy+y) ) = pix;
}
for (x = 0; x < wx; x++)
for (y = 0; y < wy; y++)
{
pix = *( dib_ref_pixel(src, sx+x, sy+y) );
if (pix == pix_rimcolor) pix = pix_magenta;
*( dib_ref_pixel(dest, dx+x, dy+y) ) = pix;
}
if (copy)
for (x = 0; x < wx; x++)
for (y = 0; y < wy; y++)
{
pix = *( dib_ref_pixel(src, sx+x, sy+y) );
if (pix!=pix_transparent)
*( dib_ref_pixel(dest, dx+x, dy+y) ) = pix;
}
for (x = 0; x < wx; x++)
for (y = 0; y < wy; y++)
{
pix = *( dib_ref_pixel(src, sx+x, sy+y) );
*( dib_ref_pixel(dest, dx+x, dy+y) ) = pix;
}
if (copy)
img_type dest, int dx, int dy, int copy)
CloseHandle(fh);
if (!ReadFile(fh, img->pDib,
sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD),
&dummy, NULL))
if (!img)
return NULL;
return NULL;
SetFilePointer(fh, 0, NULL, FILE_BEGIN);
fh = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE)
return NULL;
if (img->hDC)
DeleteDC(img->hDC);
if (img->hDib)
DeleteObject(img->hDib);
if (img->pDib)
GlobalFree(img->pDib);
if (!img)
return;
return (ptr);
if (wx == 0 || wy == 0)
return NULL;
if (pix_transparent == *( dib_ref_pixel(img, x, y) ))
return (false);
return (true);
return (ref);
//
// img_type related
//
for (int j = 0; j < dx * marker_length; j++)
*(pDibBit0 + BUF_IDX(0, mark_y, j, dy/2 + y_margin)) = MAP_WHITE;
}
old_mark_x = mark_x;
old_mark_y = mark_y;
if (show_mark)
{
// draw new markers
for (int j = 0; j < dy * marker_length; j++)
*(pDibBit0 + BUF_IDX(mark_x, 0, dx/2 + x_margin, j)) = MAP_WHITE;
set_col(col, i, j);
for (int x = 0; x < dx; x++)
for (int y = 0; y < dy; y++)
if ( col != get_col(i,j) || force_redraw
|| i < marker_length || j < marker_length)
int col = (j >= my2 - y_margin || i >= mx2 - x_margin) ?
MAP_BLACK : ptr[i];
unsigned char *ptr = &buf[j * (mx2 - x_margin)];
for (int i = 0; i < mx2; i++)
force_redraw = true;
dpix = ppix;
for (int j = 0; j < my2; j++)
for (int j = 0; j < dx * marker_length; j++)
*(pDibBit0 + BUF_IDX(0, old_mark_y, j, dy/2 + y_margin)) = MAP_BLACK;
// erase old markers
for (int j = 0; j < dy * marker_length; j++)
*(pDibBit0 + BUF_IDX(old_mark_x, 0, dx/2 + x_margin, j)) = MAP_BLACK;
inc_y0 = - dx * inc_x0 + BUF_IDX(0, 0, 0, 1);
inc_y = - mx2 * inc_x + BUF_IDX(0, 1, 0, 0);
inc_x = dx;
bufx = (bufx+3)/4;
bufx *= 4;
if (!flag)
return;
{
void MapRegionClass::draw_data(unsigned char *buf, bool show_mark,
int mark_x, int mark_y)
HDC hdc = GetDC(win->hWnd);
rc.right - rc.left,
rc.bottom - rc.top,
SWP_NOMOVE);
(WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX
| WS_CAPTION | WS_VISIBLE),
SetWindowPos(hWnd, 0, ox, oy, wx, wy, SWP_NOSIZE);
UpdateWindow( hWnd );
return (TRUE);
if (!hWnd)
return (FALSE);
(WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX
| WS_CAPTION | WS_VISIBLE),
ox, oy, //pos
rc.right - rc.left, rc.bottom - rc.top, //size
HWND_DESKTOP, NULL, hInst, NULL);
(WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX
| WS_CAPTION | WS_VISIBLE),
if ( GetSystemMetrics(SM_CYSCREEN) < (oy + wy) )
oy = 0;
if ( GetSystemMetrics(SM_CXSCREEN) < (ox + wx) )
ox = 0;
cbuf[i] = ' ';
abuf[i] = 0;
for (i = 0; i < mx*my; i++)
for (int i = 0; i < mx2*my2; i++)
mbuf[i] = PIX_BLACK;
(char *)&rchar, 1, NULL);
(char *)&rchar, 2, NULL);
rc.left = ox + x0 * dx;
rc.right = rc.left + (2 * dx);
rc.top = oy + y0 * dy;
HDC hdc = GetDC(win->hWnd);
if (!flag)
return;
void TextRegionClass::erase_cursor()
{
"_ ", 2, NULL);
rc.left = ox + cx * dx ;
rc.right = rc.left + (2 * dx);
rc.top = oy + cy * dy;
hdc = GetDC(win->hWnd);
if (!flag)
return;
(char *)buf, len, NULL);
rc.left = ox + x * dx;
rc.right = rc.left + len * dx;
rc.top = oy + y * dy;
int len, int col)
*(backbuf->pDibBits + i) = black;
}
if (backbuf->pDib->bmiColors[i].rgbRed == 0
&& backbuf->pDib->bmiColors[i].rgbGreen == 0
&& backbuf->pDib->bmiColors[i].rgbBlue == 0)
{
scol[i].rgbBlue = map_colors[i][2];
scol[i].rgbGreen = map_colors[i][1];
scol[i].rgbRed = map_colors[i][0];
scol[i].rgbReserved = 0;
for (i = 0; i < MAX_MAP_COL; i++)
RegionClass::init_backbuf(pPal, 256);
RegionClass::init_backbuf(std_palette, 256);
/* not used */
backbuf->pDibZero = (backbuf->pDibBits
+ (backbuf->Height -1) * backbuf->Width);
DIB_RGB_COLORS, (VOID **)&(backbuf->pDibBits), NULL, 0);
backbuf->pDib->bmiHeader.biWidth = mx*dx;
backbuf->pDib->bmiHeader.biHeight = my*dy;
backbuf->Width = mx * dx;
backbuf->Height = my * dy;
backbuf->pDibZero = (backbuf->pDibBits
+ (backbuf->Height -1) * backbuf->Width);
DIB_RGB_COLORS, (VOID **)&(backbuf->pDibBits), NULL, 0);
// alloc a region of the window
backbuf->pDib->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
backbuf->pDib->bmiHeader.biPlanes = 1;
backbuf->pDib->bmiHeader.biBitCount = 8;
backbuf->pDib->bmiHeader.biCompression = BI_RGB;
backbuf->pDib->bmiHeader.biSizeImage = 0;
backbuf->pDib->bmiHeader.biXPelsPerMeter = 0;
backbuf->pDib->bmiHeader.biYPelsPerMeter = 0;
backbuf->pDib->bmiHeader.biClrUsed = 0;
backbuf->pDib->bmiHeader.biClrImportant = 0;
}
if (pPal[i].rgbRed == 1
&& pPal[i].rgbGreen == 1
&& pPal[i].rgbBlue == 1)
{
}
if (pPal[i].rgbRed == 255
&& pPal[i].rgbGreen == 0
&& pPal[i].rgbBlue == 255)
{
}
if (pPal[i].rgbRed == 255
&& pPal[i].rgbGreen == 255
&& pPal[i].rgbBlue == 255)
{
}
if (pPal[i].rgbRed == 0
&& pPal[i].rgbGreen == 0
&& pPal[i].rgbBlue == 0)
{
std_palette[i].rgbRed = pPal[i].rgbRed ;
std_palette[i].rgbGreen = pPal[i].rgbGreen;
std_palette[i].rgbBlue = pPal[i].rgbBlue ;
for (i = 0; i < 256; i++)
if (font) return;
exit(1);
return (true);
term_pix[i] = PALETTERGB( c[0], c[1], c[2] );
int *c = (int *)&term_colors[i];
for (i = 0; i < MAX_TERM_COL; i++)
/*
* File: guic-win.cc
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
*/
#include "AppHdr.h"
#include "debug.h"
#include "externs.h"
#include "guic.h"
}
#ifdef USE_TILE
static void _update_minimap(int x, int y)
{
int object = env.map[x][y].object;
map_feature f = (object >= DNGN_START_OF_MONSTERS) ? MF_MONS_HOSTILE :
Feature[object].minimap;
if (f == MF_SKIP)
f = Feature[grd[x][y]].minimap;
ASSERT(f < MF_MAX);
tiles.update_minimap(x, y, f);
// Highlight item. XXX: Doesn't work, unfortunately.
const coord_def ep = grid2view(coord_def(item.x, item.y));
tile_place_cursor(ep.x-1,ep.y-1,true);
const coord_def gc = coord_def(item.x, item.y);
tiles.place_cursor(CURSOR_TUTORIAL, gc);
tiles.add_text_tag(TAG_TUTORIAL, item.name(DESC_CAP_A), gc);
/*
* File: tiletex.h
* Summary: PNG and texture loading functionality
* Written by: Enne Walker
*/
#ifndef TILETEX_H
#define TILETEX_H
enum TextureID
{
TEX_DUNGEON,
TEX_DEFAULT,
TEX_DOLL,
TEX_TITLE,
TEX_MAX
};
class GenericTexture
{
public:
GenericTexture();
virtual ~GenericTexture();
enum MipMapOptions
{
MIPMAP_CREATE,
MIPMAP_NONE,
MIPMAP_MAX
};
// Arbitrary post-load texture processing
typedef bool(*tex_proc_func)(unsigned char *pixels, unsigned int w,
unsigned int h);
bool load_texture(const char *filename, MipMapOptions mip_opt,
tex_proc_func proc = NULL);
bool load_texture(unsigned char *pixels, unsigned int w, unsigned int h,
MipMapOptions mip_opt);
void unload_texture();
unsigned int width() const { return m_width; }
unsigned int height() const { return m_height; }
void bind();
protected:
unsigned int m_handle;
unsigned int m_width;
unsigned int m_height;
};
class TilesTexture : public GenericTexture
{
public:
void get_texcoord(int idx, float &x, float &y, float &wx, float &wy);
void get_texcoord_doll(int part, int idx, int ymax, float &x, float &y, float &wx, float &wy, int &wx_pix, int &wy_pix, int &ox, int &oy);
};
#endif
#include "AppHdr.h"
#include "tiles.h"
#include "tiletex.h"
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_image.h>
GenericTexture::GenericTexture() :
m_handle(0),
m_width(0),
m_height(0)
{
}
GenericTexture::~GenericTexture()
{
unload_texture();
}
void GenericTexture::unload_texture()
{
glDeleteTextures(1, (GLuint*)&m_handle);
}
bool GenericTexture::load_texture(const char *filename,
GenericTexture::MipMapOptions mip_opt,
tex_proc_func proc)
{
char acBuffer[512];
// TODO enne - use Crawl's helper functions to find images...
strcpy(acBuffer, "dat/tiles/");
strcat(acBuffer, filename);
SDL_Surface *img = IMG_Load(acBuffer);
if (!img)
{
printf("Warning: couldn't load file '%s'.\n", acBuffer);
return false;
}
unsigned int bpp = img->format->BytesPerPixel;
glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
// Determine texture format
unsigned char *pixels = (unsigned char*)img->pixels;
int new_width = img->w;
int new_height = img->h;
GLenum texture_format;
if (bpp == 4)
{
if (img->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
}
else if (bpp == 3)
{
if (img->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
}
else if (bpp == 1)
{
// need to depalettize
SDL_LockSurface(img);
// Prefer power-of-two textures to avoid texture bleeding from
// floating point error.
// TODO enne - convert non-palettized to power-of-2 as well?
new_width = 1;
while (new_width < img->w)
new_width *= 2;
new_height = 1;
while (new_height < img->h)
new_height *= 2;
pixels = new unsigned char[4 * new_width * new_height];
SDL_Palette* pal = img->format->palette;
ASSERT(pal);
ASSERT(pal->colors);
// Find transparent colour
// TODO enne - this should probably be removed from rltiles
// TODO enne - is there more than one transparent color??
int trans_index = -1;
for (int p = 0; p < pal->ncolors ; p++)
{
if (pal->colors[p].r == 71 &&
pal->colors[p].g == 108 &&
pal->colors[p].b == 108)
{
trans_index = p;
break;
}
}
int src = 0;
int dest = 0;
for (int y = 0; y < img->h; y++)
{
int x;
for (x = 0; x < img->w; x++)
{
int index = ((unsigned char*)img->pixels)[src++];
pixels[dest*4 ] = pal->colors[index].r;
pixels[dest*4 + 1] = pal->colors[index].g;
pixels[dest*4 + 2] = pal->colors[index].b;
pixels[dest*4 + 3] = (index == trans_index) ? 0 : 255;
dest++;
}
while (x++ < new_width)
{
// Extend to the right with transparent pixels
pixels[dest*4 ] = 0;
pixels[dest*4 + 1] = 0;
pixels[dest*4 + 2] = 0;
pixels[dest*4 + 3] = 0;
dest++;
}
}
while (dest < new_width * new_height)
{
// Extend down with transparent pixels
pixels[dest*4 ] = 0;
pixels[dest*4 + 1] = 0;
pixels[dest*4 + 2] = 0;
pixels[dest*4 + 3] = 0;
dest++;
}
SDL_UnlockSurface(img);
bpp = 4;
texture_format = GL_RGBA;
}
else
{
printf("Warning: unsupported format, bpp = %d for '%s'\n",
bpp, acBuffer);
return false;
}
bool success = false;
if (!proc || proc(pixels, new_width, new_height))
{
success |= load_texture(pixels, new_width, new_height, mip_opt);
}
// If conversion has occurred, delete converted data.
if (pixels != img->pixels)
delete pixels;
SDL_FreeSurface(img);
return success;
}
bool GenericTexture::load_texture(unsigned char *pixels, unsigned int new_width,
unsigned int new_height,
GenericTexture::MipMapOptions mip_opt)
{
if (!pixels || !new_width || !new_height)
return false;
// Assumptions...
const unsigned int bpp = 4;
const GLenum texture_format = GL_RGBA;
const GLenum format = GL_UNSIGNED_BYTE;
m_width = new_width;
m_height = new_height;
glGenTextures(1, (GLuint*)&m_handle);
glBindTexture(GL_TEXTURE_2D, m_handle);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
if (mip_opt == MIPMAP_CREATE)
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, bpp, m_width, m_height,
texture_format, format, pixels);
}
else
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, bpp, m_width, m_height, 0,
texture_format, format, pixels);
}
return true;
}
void GenericTexture::bind()
{
ASSERT(m_handle);
glBindTexture(GL_TEXTURE_2D, m_handle);
}
void TilesTexture::get_texcoord_doll(int part, int idx, int ymax, float &x, float &y, float &wx, float &wy, int &wx_pix, int &wy_pix, int &ox, int &oy)
{
int tile_idx = tilep_parts_start[part];
int nx = tilep_parts_nx[part];
int ny = tilep_parts_ny[part];
ox = tilep_parts_ox[part];
oy = tilep_parts_oy[part];
wx_pix = TILE_X / nx;
wy_pix = TILE_Y / ny;
if (!idx)
{
wy = -1;
return;
}
idx--;
tile_idx += idx / (nx * ny);
if (oy + wy_pix > ymax)
wy_pix -= oy + wy_pix - ymax;
int xs = (tile_idx % TILEP_PER_ROW) * TILE_X;
int ys = (tile_idx / TILEP_PER_ROW) * TILE_Y;
xs += (idx % nx) * TILE_X / nx;
ys += ((idx / nx) % ny) * TILE_Y / ny;
x = xs / (float)m_width;
y = ys / (float)m_height;
wx = wx_pix / (float)m_width;
wy = wy_pix / (float)m_height;
}
void TilesTexture::get_texcoord(int idx, float &x, float &y,
float &wx, float &wy)
{
const unsigned int tile_size = 32;
unsigned int tiles_per_row = m_width / tile_size;
wx = tile_size / (float)m_width;
wy = tile_size / (float)m_height;
unsigned int row = idx / tiles_per_row;
unsigned int col = idx % tiles_per_row;
x = tile_size * col / (float)m_width;
y = tile_size * row / (float)m_height;
ASSERT(row >= 0);
ASSERT(col >= 0);
ASSERT(x + wx <= m_width);
ASSERT(y + wy <= m_height);
}
/*
* File: tilesdl.h
* Summary: SDL-related functionality for the tiles port
* Written by: Enne Walker
*/
#ifdef USE_TILE
#ifndef TILESDL_H
#define TILESDL_H
#include "debug.h"
#include "externs.h"
#include "FixVec.h"
#include "tilereg.h"
// This struct defines all of the state that any particular rendering needs.
// If other rendering states are needed, they should be added here so that
// they do not introduce unneeded side effects for other parts of the code
// that have not thought about turning that new state off.
struct GLState
{
GLState();
// vertex arrays
bool array_vertex;
bool array_texcoord;
bool array_colour;
// render state
bool blend;
bool texture;
};
enum key_mod
{
MOD_SHIFT = 0x1,
MOD_CTRL = 0x2,
MOD_ALT = 0x4
};
struct MouseEvent
{
enum mouse_event_type
{
PRESS,
RELEASE,
MOVE
};
enum mouse_event_button
{
NONE = 0x00,
LEFT = 0x01,
MIDDLE = 0x02,
RIGHT = 0x04,
SCROLL_UP = 0x08,
SCROLL_DOWN = 0x10
};
// kind of event
mouse_event_type event;
// if PRESS or RELEASE, the button pressed
mouse_event_button button;
// bitwise-or of buttons currently pressed
unsigned short held;
// bitwise-or of key mods currently pressed
unsigned char mod;
// location of events in pixels and in window coordinate space
unsigned int px;
unsigned int py;
};
class GLStateManager
{
public:
static void init();
static void set(const GLState& state);
};
class SDL_Surface;
class FTFont;
class TilesFramework
{
public:
TilesFramework();
virtual ~TilesFramework();
bool initialise();
void shutdown();
void load_dungeon(unsigned int *tileb, int gx, int gy);
void load_dungeon(int gx, int gy);
int getch();
int getch_ck();
void resize();
void clrscr();
void message_out(int which_line, int colour, const char *s, int firstcol, bool newline);
void cgotoxy(int x, int y, int region = GOTO_CRT);
void clear_message_window();
void update_minimap(int gx, int gy, map_feature f);
void clear_minimap();
void update_inventory();
void update_menu_inventory(unsigned int slot, const item_def &item, bool selected, char key);
void redraw();
void place_cursor(cursor_type type, const coord_def &gc);
void clear_text_tags(text_tag_type type);
void add_text_tag(text_tag_type type, const std::string &tag,
const coord_def &gc);
bool initialise_items();
const coord_def &get_cursor() const;
protected:
bool load_font(const char *font_file, int font_size);
int handle_mouse(MouseEvent &event);
// screen pixel dimensions
coord_def m_windowsz;
// screen pixels per view cell
coord_def m_viewsc;
SDL_Surface* m_context;
bool m_fullscreen;
enum LayerID
{
LAYER_NORMAL,
LAYER_CRT,
LAYER_TITLE,
LAYER_MAX
};
class Layer
{
public:
// Layers don't own these regions
std::vector<Region*> m_regions;
};
Layer m_layers[LAYER_MAX];
LayerID m_active_layer;
// Normal layer
DungeonRegion *m_region_tile;
StatRegion *m_region_stat;
MessageRegion *m_region_msg;
MapRegion *m_region_map;
InventoryRegion *m_region_self_inv;
// Full-screen CRT layer
CRTRegion *m_region_crt;
InventoryRegion *m_region_menu_inv;
FTFont *m_font;
void do_layout();
ImageManager m_image;
// Mouse state.
unsigned short m_buttons_held;
unsigned char m_key_mod;
coord_def m_mouse;
unsigned int m_last_tick_moved;
std::string m_tooltip;
};
// Main interface for tiles functions
extern TilesFramework tiles;
#ifdef __MINGW32__
#ifndef alloca
// Srsly, MinGW, wtf?
void *alloca(size_t);
#endif
#endif
#endif
#endif
#include "cio.h"
#include "itemname.h"
#include "items.h"
#include "itemprop.h"
#include "mon-util.h"
#include "player.h"
#include "stuff.h"
#include "tiles.h"
#include "tilesdl.h"
#include "travel.h"
#include "version.h"
#include "tiledef-dngn.h"
#include "tilefont.h"
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_image.h>
// Note: these defaults should match the OpenGL defaults
GLState::GLState() :
array_vertex(false),
array_texcoord(false),
array_colour(false),
blend(false),
texture(false)
{
}
void GLStateManager::init()
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0.0, 0.0, 0.0, 1.0f);
}
void GLStateManager::set(const GLState& state)
{
if (state.array_vertex)
glEnableClientState(GL_VERTEX_ARRAY);
else
glDisableClientState(GL_VERTEX_ARRAY);
if (state.array_texcoord)
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
else
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (state.array_colour)
{
glEnableClientState(GL_COLOR_ARRAY);
}
else
{
glDisableClientState(GL_COLOR_ARRAY);
// [enne] This should *not* be necessary, but the Linux OpenGL
// drive that I'm using sets this to the last colour of the
// colour array. So, we need to unset it here.
glColor3f(1.0f, 1.0f, 1.0f);
}
if (state.texture)
glEnable(GL_TEXTURE_2D);
else
glDisable(GL_TEXTURE_2D);
if (state.blend)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
}
TilesFramework tiles;
TilesFramework::TilesFramework() :
m_windowsz(1024, 768),
m_viewsc(0, 0),
m_context(NULL),
m_fullscreen(false),
m_active_layer(LAYER_CRT),
m_font(NULL),
m_buttons_held(0),
m_key_mod(0),
m_mouse(-1, -1),
m_last_tick_moved(0)
{
}
TilesFramework::~TilesFramework()
{
}
void TilesFramework::shutdown()
{
delete m_region_tile;
delete m_region_stat;
delete m_region_msg;
delete m_region_map;
delete m_region_self_inv;
delete m_region_crt;
delete m_region_menu_inv;
m_region_tile = NULL;
m_region_stat = NULL;
m_region_msg = NULL;
m_region_map = NULL;
m_region_self_inv = NULL;
m_region_crt = NULL;
m_region_menu_inv = NULL;
for (unsigned int i = 0; i < LAYER_MAX; i++)
{
m_layers[i].m_regions.clear();
}
SDL_Quit();
}
bool TilesFramework::initialise()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
printf ("Failed to initialise SDL: %s\n", SDL_GetError());
return false;
}
SDL_EnableUNICODE(true);
SDL_WM_SetCaption(CRAWL " " VERSION, CRAWL);
SDL_Surface *icon = IMG_Load("dat/tiles/stone_soup_icon-32x32.png");
if (!icon)
{
printf ("Failed to load icon: %s\n", SDL_GetError());
return false;
}
SDL_WM_SetIcon(icon, NULL);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
unsigned int flags = SDL_OPENGL;
if (m_fullscreen)
flags |= SDL_FULLSCREEN;
// TODO enne - add options for screen size and fullscreen
m_context = SDL_SetVideoMode(m_windowsz.x, m_windowsz.y, 0, flags);
if (!m_context)
{
printf ("Failed to set video mode: %s\n", SDL_GetError());
return false;
}
if (!m_image.load_textures())
return false;
// TODO enne - make this configurable (and fall back on default if fails)
// TODO enne - use Crawl's dat file loading utilities
const char *font_file = "dat/tiles/VeraMono.ttf";
const int font_size = 14;
if (!load_font(font_file, font_size))
return false;
ASSERT(m_font);
// TODO enne - grab these from options
unsigned int map_pixsz = 4;
// TODO enne - different font for tooltip and for dungeon tags
m_region_tile = new DungeonRegion(&m_image, m_font, TILE_X, TILE_Y);
m_region_map = new MapRegion(map_pixsz);
m_region_self_inv = new InventoryRegion(&m_image, TILE_X, TILE_Y);
m_region_msg = new MessageRegion(m_font);
m_region_stat = new StatRegion(m_font);
m_region_crt = new CRTRegion(m_font);
m_region_menu_inv = new InventoryRegion(&m_image, TILE_X, TILE_Y);
m_layers[LAYER_NORMAL].m_regions.push_back(m_region_tile);
m_layers[LAYER_NORMAL].m_regions.push_back(m_region_map);
m_layers[LAYER_NORMAL].m_regions.push_back(m_region_self_inv);
m_layers[LAYER_NORMAL].m_regions.push_back(m_region_msg);
m_layers[LAYER_NORMAL].m_regions.push_back(m_region_stat);
m_layers[LAYER_CRT].m_regions.push_back(m_region_crt);
m_layers[LAYER_CRT].m_regions.push_back(m_region_menu_inv);
cgotoxy(1, 1, GOTO_CRT);
GLStateManager::init();
resize();
return true;
}
bool TilesFramework::load_font(const char *font_file, int font_size)
{
m_font = new FTFont();
if (!m_font->load_font(font_file, font_size))
{
delete m_font;
m_font = NULL;
printf("Failed to open font '%s'\n", font_file);
return false;
}
return true;
}
void TilesFramework::load_dungeon(unsigned int *tileb, int gx, int gy)
{
unsigned int ox = m_region_tile->mx/2;
unsigned int oy = m_region_tile->my/2;
m_region_tile->load_dungeon(tileb, gx - ox, gy - oy);
coord_def win_start(gx - ox, gy - oy);
coord_def win_end(gx + ox + 1, gy + oy + 1);
m_region_map->set_window(win_start, win_end);
}
void TilesFramework::load_dungeon(int cx, int cy)
{
int wx = m_region_tile->mx;
int wy = m_region_tile->my;
unsigned int *tb = (unsigned int*)alloca(sizeof(unsigned int) *
wy * wx * 2);
int count = 0;
for (int y = 0; y < wy; y++)
{
for (int x = 0; x < wx; x++)
{
int fg;
int bg;
const coord_def gc(cx + x - wx/2,
cy + y - wy/2);
const coord_def ep = view2show(grid2view(gc));
// mini "viewwindow" routine
if (!map_bounds(gc))
{
fg = 0;
bg = TILE_DNGN_UNSEEN;
}
else if (!crawl_view.in_grid_los(gc) || !env.show(ep))
{
fg = env.tile_bk_fg[gc.x][gc.y];
bg = env.tile_bk_bg[gc.x][gc.y];
if (bg == 0)
bg |= TILE_DNGN_UNSEEN;
bg |= tile_unseen_flag(gc);
}
else
{
fg = env.tile_fg[ep.x-1][ep.y-1];
bg = env.tile_bg[ep.x-1][ep.y-1];
}
if (gc.x == cx && gc.y == cy)
bg |= TILE_FLAG_CURSOR1;
tb[count++] = fg;
tb[count++] = bg;
}
}
load_dungeon(tb, cx, cy);
tiles.redraw();
}
void TilesFramework::resize()
{
do_layout();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// TODO enne - need better resizing
// View size in pixels is (m_viewsc * crawl_view.viewsz)
m_viewsc.x = 32;
m_viewsc.y = 32;
// For ease, vertex positions are pixel positions.
glOrtho(0, m_windowsz.x, m_windowsz.y, 0, 0, 100);
}
static unsigned char _get_modifiers(SDL_keysym &keysym)
{
// keysym.mod can't be used to keep track of the modifier state.
// If shift is hit by itself, this will not include KMOD_SHIFT.
// Instead, look for the key itself as a separate event.
switch (keysym.sym)
{
case SDLK_LSHIFT:
case SDLK_RSHIFT:
return MOD_SHIFT;
case SDLK_LCTRL:
case SDLK_RCTRL:
return MOD_CTRL;
case SDLK_LALT:
case SDLK_RALT:
return MOD_ALT;
default:
return 0;
}
}
static int _translate_keysym(SDL_keysym &keysym)
{
// This function returns the key that was hit. Returning zero implies that
// the keypress (e.g. hitting shift on its own) should be eaten and not
// handled.
const int shift_offset = CK_SHIFT_UP - CK_UP;
const int ctrl_offset = CK_CTRL_UP - CK_UP;
int offset = 0;
if (keysym.mod & KMOD_CTRL)
offset = ctrl_offset;
else if (keysym.mod & KMOD_SHIFT)
offset = shift_offset;
switch (keysym.sym)
{
case SDLK_RETURN:
return CK_ENTER;
case SDLK_BACKSPACE:
return CK_BKSP;
case SDLK_ESCAPE:
return CK_ESCAPE;
case SDLK_DELETE:
return CK_DELETE;
case SDLK_UP:
return CK_UP + offset;
case SDLK_DOWN:
return CK_DOWN + offset;
case SDLK_LEFT:
return CK_LEFT + offset;
case SDLK_RIGHT:
return CK_RIGHT + offset;
case SDLK_INSERT:
return CK_INSERT + offset;
case SDLK_HOME:
return CK_HOME + offset;
case SDLK_END:
return CK_END + offset;
case SDLK_CLEAR:
return CK_CLEAR + offset;
case SDLK_PAGEUP:
return CK_PGUP + offset;
case SDLK_PAGEDOWN:
return CK_PGDN + offset;
default:
break;
}
bool is_ascii = ((keysym.unicode & 0xFF80) == 0);
return is_ascii ? keysym.unicode & 0x7F : 0;
}
int TilesFramework::getch()
{
// TODO enne - is there really a difference between these two functions??
return getch_ck();
}
int TilesFramework::handle_mouse(MouseEvent &event)
{
m_region_tile->place_cursor(CURSOR_MOUSE, Region::NO_CURSOR);
// Note: the mouse event goes to all regions in the active layer because
// we want to be able to start some GUI event (e.g. far viewing) and
// stop if it moves to another region.
int return_key = 0;
for (unsigned int i = 0; i < m_layers[m_active_layer].m_regions.size(); i++)
{
// TODO enne - what if two regions give a key?
int key = 0;
key = m_layers[m_active_layer].m_regions[i]->handle_mouse(event);
if (key)
return_key = key;
}
// Let regions take priority in any mouse mode.
if (return_key)
return return_key;
// Handle "more" mode globally here, rather than duplicate across regions.
if (mouse_control::current_mode() == MOUSE_MODE_MORE
&& event.button == MouseEvent::LEFT
&& event.event == MouseEvent::PRESS)
{
return '\r';
}
// TODO enne - in what cases should the buttons be returned?
#if 0
// If nothing else, return the mouse button that was pressed.
switch (event.button)
{
case MouseEvent::LEFT:
return CK_MOUSE_B1;
case MouseEvent::RIGHT:
return CK_MOUSE_B2;
case MouseEvent::MIDDLE:
return CK_MOUSE_B3;
case MouseEvent::SCROLL_UP:
return CK_MOUSE_B4;
case MouseEvent::SCROLL_DOWN:
return CK_MOUSE_B5;
default:
case MouseEvent::NONE:
return 0;
}
#endif
return 0;
}
static void _translate_event(const SDL_MouseMotionEvent &sdl_event,
MouseEvent &tile_event)
{
tile_event.held = MouseEvent::NONE;
tile_event.event = MouseEvent::MOVE;
tile_event.button = MouseEvent::NONE;
tile_event.px = sdl_event.x;
tile_event.py = sdl_event.y;
// TODO enne - do we want the relative motion?
}
static void _translate_event(const SDL_MouseButtonEvent &sdl_event,
MouseEvent &tile_event)
{
tile_event.held = MouseEvent::NONE;
tile_event.event = (sdl_event.type == SDL_MOUSEBUTTONDOWN) ?
MouseEvent::PRESS : MouseEvent::RELEASE;
switch (sdl_event.button)
{
case SDL_BUTTON_LEFT:
tile_event.button = MouseEvent::LEFT;
break;
case SDL_BUTTON_RIGHT:
tile_event.button = MouseEvent::RIGHT;
break;
case SDL_BUTTON_MIDDLE:
tile_event.button = MouseEvent::MIDDLE;
break;
case SDL_BUTTON_WHEELUP:
tile_event.button = MouseEvent::SCROLL_UP;
break;
case SDL_BUTTON_WHEELDOWN:
tile_event.button = MouseEvent::SCROLL_DOWN;
break;
default:
ASSERT(!"Unhandled button");
tile_event.button = MouseEvent::NONE;
break;
}
tile_event.px = sdl_event.x;
tile_event.py = sdl_event.y;
}
int TilesFramework::getch_ck()
{
SDL_Event event;
int key = 0;
while (!key)
{
unsigned int ticks = SDL_GetTicks();
if (SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
m_key_mod |= _get_modifiers(event.key.keysym);
key = _translate_keysym(event.key.keysym);
// If you hit a key, disable tooltips until the mouse
// is moved again.
m_last_tick_moved = ~0;
break;
case SDL_KEYUP:
m_key_mod &= ~_get_modifiers(event.key.keysym);
m_last_tick_moved = ~0;
break;
case SDL_MOUSEMOTION:
{
// Record mouse pos for tooltip timer
if (m_mouse.x != event.motion.x
|| m_mouse.y != event.motion.y)
{
m_last_tick_moved = ticks;
}
m_mouse.x = event.motion.x;
m_mouse.y = event.motion.y;
MouseEvent mouse_event;
_translate_event(event.motion, mouse_event);
mouse_event.held = m_buttons_held;
mouse_event.mod = m_key_mod;
key = handle_mouse(mouse_event);
}
break;
case SDL_MOUSEBUTTONUP:
{
MouseEvent mouse_event;
_translate_event(event.button, mouse_event);
m_buttons_held &= ~(mouse_event.button);
mouse_event.held = m_buttons_held;
mouse_event.mod = m_key_mod;
key = handle_mouse(mouse_event);
m_last_tick_moved = ticks;
}
break;
case SDL_MOUSEBUTTONDOWN:
{
MouseEvent mouse_event;
_translate_event(event.button, mouse_event);
m_buttons_held |= mouse_event.button;
mouse_event.held = m_buttons_held;
mouse_event.mod = m_key_mod;
key = handle_mouse(mouse_event);
m_last_tick_moved = ticks;
}
break;
case SDL_QUIT:
// TODO enne
exit(0);
case SDL_USEREVENT:
default:
break;
}
}
// TODO enne - outsource this value
unsigned int tooltip_ticks = 1000;
bool show_tooltip = ((ticks - m_last_tick_moved > tooltip_ticks)
&& ticks > m_last_tick_moved);
if (show_tooltip)
{
if (m_tooltip.empty())
{
for (unsigned int i = 0;
i < m_layers[m_active_layer].m_regions.size(); i++)
{
Region *reg = m_layers[m_active_layer].m_regions[i];
if (!reg->inside(m_mouse.x, m_mouse.y))
continue;
if (reg->update_tip_text(m_tooltip))
break;
}
}
}
else
{
m_tooltip.clear();
}
redraw();
}
return key;
}
void TilesFramework::do_layout()
{
const int map_stat_buffer = 5;
// TODO enne - use options
const int crt_width = 80;
const int crt_height = 30;
const int map_margin = 2;
// Size regions that we know about
m_region_tile->resize(crawl_view.viewsz.x, crawl_view.viewsz.y);
m_region_crt->resize(crt_width, crt_height);
m_region_stat->resize(crawl_view.hudsz.x, crawl_view.hudsz.y);
m_region_msg->resize(crawl_view.msgsz.x, crawl_view.msgsz.y);
m_region_map->resize(GXM, GYM);
// Place regions for normal layer
const int margin = 4;
m_region_tile->place(0, 0, margin);
m_region_msg->place(0, m_region_tile->ey, margin);
int stat_col = m_region_tile->ex + map_stat_buffer;
m_region_stat->place(stat_col, 0, 0);
m_region_map->place(stat_col, m_region_stat->ey, map_margin);
int inv_col = std::max(m_region_tile->ex, m_region_msg->ex);
m_region_self_inv->place(inv_col, m_region_map->ey, 0);
m_region_self_inv->resize_to_fit(m_windowsz.x -
m_region_self_inv->sx,
m_windowsz.y -
m_region_self_inv->sy);
// Place regions for crt layer
m_region_crt->place(0, 0, margin);
m_region_menu_inv->place(0, m_region_crt->ey, margin);
m_region_menu_inv->resize_to_fit(m_windowsz.x, m_windowsz.y -
m_region_menu_inv->sy);
}
void TilesFramework::clrscr()
{
TextRegion::cursor_region = NULL;
if (m_region_stat)
m_region_stat->clear();
if (m_region_msg)
m_region_msg->clear();
if (m_region_crt)
m_region_crt->clear();
if (m_region_menu_inv)
m_region_menu_inv->clear();
cgotoxy(1,1);
}
void TilesFramework::message_out(int which_line, int colour, const char *s, int firstcol, bool newline)
{
if (!firstcol)
firstcol = Options.delay_message_clear ? 2 : 1;
cgotoxy(firstcol, which_line + 1, GOTO_MSG);
textcolor(colour);
cprintf("%s", s);
if (newline && which_line == crawl_view.msgsz.y - 1)
m_region_msg->scroll();
}
void TilesFramework::clear_message_window()
{
m_region_msg->clear();
m_active_layer = LAYER_NORMAL;
}
void TilesFramework::cgotoxy(int x, int y, int region)
{
if (region == GOTO_LAST)
{
// nothing
}
else if (region == GOTO_CRT)
{
m_active_layer = LAYER_CRT;
TextRegion::text_mode = m_region_crt;
}
else if (region == GOTO_MSG)
{
m_active_layer = LAYER_NORMAL;
TextRegion::text_mode = m_region_msg;
}
else if (region == GOTO_STAT)
{
m_active_layer = LAYER_NORMAL;
TextRegion::text_mode = m_region_stat;
}
TextRegion::cgotoxy(x, y);
}
void TilesFramework::redraw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(m_viewsc.x, m_viewsc.y, 1.0f);
for (unsigned int i = 0; i < m_layers[m_active_layer].m_regions.size(); i++)
{
m_layers[m_active_layer].m_regions[i]->render();
}
// Draw tooltip
if (!m_tooltip.empty())
{
const coord_def min_pos(0, 0);
m_font->render_string(m_mouse.x, m_mouse.y - 2, m_tooltip.c_str(),
min_pos, m_windowsz, WHITE, false, 150,
BLUE, 5);
}
SDL_GL_SwapBuffers();
}
void TilesFramework::update_minimap(int gx, int gy, map_feature f)
{
if (!player_in_mappable_area())
return;
coord_def gc(gx, gy);
if (you.pos() == gc)
{
f = MF_PLAYER;
}
else if (f == MF_MONS_HOSTILE && mgrd[gx][gy] != NON_MONSTER)
{
const int grid = mgrd[gx][gy];
if (mons_friendly(&menv[grid]))
f = MF_MONS_FRIENDLY;
else if (mons_neutral(&menv[grid]))
f = MF_MONS_NEUTRAL;
else if (mons_class_flag(menv[grid].type, M_NO_EXP_GAIN))
f = MF_MONS_NO_EXP;
}
else if (f == MF_FLOOR || f == MF_MAP_FLOOR)
{
if (is_exclude_root(gc))
f = MF_EXCL_ROOT;
else if (is_excluded(gc))
f = MF_EXCL;
}
m_region_map->set(gx, gy, f);
}
void TilesFramework::clear_minimap()
{
m_region_map->clear();
}
static void _fill_item_info(InventoryTile &desc, const item_def &item)
{
desc.tile = tileidx_item(item);
int type = item.base_type;
if (type == OBJ_FOOD || type == OBJ_SCROLLS
|| type == OBJ_POTIONS || type == OBJ_MISSILES)
{
// -1 specifies don't display anything
desc.quantity = item.quantity == 1 ? -1 : item.quantity;
}
else if (type == OBJ_WANDS
&& ((item.flags & ISFLAG_KNOW_PLUSES)
|| item.plus2 == ZAPCOUNT_EMPTY))
{
desc.quantity = item.plus;
}
else
{
desc.quantity = -1;
}
desc.flag = 0;
if (item_cursed(item) && item_ident(item, ISFLAG_KNOW_CURSE))
desc.flag |= TILEI_FLAG_CURSE;
if (item_type_tried(item))
desc.flag |= TILEI_FLAG_TRIED;
if (item.x != -1)
desc.flag |= TILEI_FLAG_FLOOR;
}
void TilesFramework::update_inventory()
{
std::vector<InventoryTile> inv;
if (!Options.tile_show_items)
return;
unsigned int max_pack_row = (ENDOFPACK-1) / m_region_self_inv->mx + 1;
max_pack_row = std::min(m_region_self_inv->my - 1, max_pack_row);
unsigned int max_pack_items = max_pack_row * m_region_self_inv->mx;
// TODO enne - document that '.' and '_' no longer work
// TODO enne - if all inventory and ground can't fit, allow ground
// and inventory items on the same row.
// item.base_type <-> char conversion table
const static char *obj_syms = ")([/%#?=!#+\\0}x";
for (unsigned int c = 0; c < strlen(Options.tile_show_items); c++)
{
if (inv.size() >= max_pack_items)
break;
const char *find = strchr(obj_syms, Options.tile_show_items[c]);
if (!find)
continue;
object_class_type type = (object_class_type)(find - obj_syms);
// First, normal inventory
for (int i = 0; i < ENDOFPACK; i++)
{
if (!is_valid_item(you.inv[i]) || you.inv[i].quantity == 0)
continue;
if (you.inv[i].base_type != type)
continue;
InventoryTile desc;
_fill_item_info(desc, you.inv[i]);
desc.idx = i;
for (int eq = 0; eq < NUM_EQUIP; eq++)
{
if (you.equip[eq] == i)
{
desc.flag |= TILEI_FLAG_EQUIP;
break;
}
}
inv.push_back(desc);
}
}
// Finish out this row
while (inv.size() % m_region_self_inv->mx != 0)
{
InventoryTile desc;
inv.push_back(desc);
}
// How many ground items do we have?
unsigned int num_ground = 0;
for (int i = igrd[you.x_pos][you.y_pos]; i != NON_ITEM; i = mitm[i].link)
num_ground++;
// Add extra rows, if needed.
unsigned int ground_rows =
std::max(((int)num_ground-1) / (int)m_region_self_inv->mx + 1, 1);
while (inv.size() / m_region_self_inv->mx + ground_rows < m_region_self_inv->my)
{
for (unsigned int i = 0; i < m_region_self_inv->mx; i++)
{
InventoryTile desc;
inv.push_back(desc);
}
}
// Then, ground items...
for (unsigned int c = 0; c < strlen(Options.tile_show_items); c++)
{
if (inv.size() >= m_region_self_inv->mx * m_region_self_inv->my)
break;
const char *find = strchr(obj_syms, Options.tile_show_items[c]);
if (!find)
continue;
object_class_type type = (object_class_type)(find - obj_syms);
for (int i = igrd[you.x_pos][you.y_pos]; i != NON_ITEM; i = mitm[i].link)
{
if (inv.size() >= m_region_self_inv->mx * m_region_self_inv->my)
break;
if (mitm[i].base_type != type)
continue;
InventoryTile desc;
_fill_item_info(desc, mitm[i]);
desc.idx = i;
inv.push_back(desc);
}
}
// Finish out ground inventory
while (inv.size() < m_region_self_inv->mx * m_region_self_inv->my)
{
InventoryTile desc;
desc.flag = TILEI_FLAG_FLOOR;
inv.push_back(desc);
}
m_region_self_inv->update(inv.size(), &inv[0]);
}
void TilesFramework::update_menu_inventory(unsigned int slot,
const item_def &item,
bool selected, char key)
{
InventoryTile desc;
_fill_item_info(desc, item);
desc.key = key;
desc.idx = (desc.flag & TILEI_FLAG_FLOOR) ? item.index() :
letter_to_index(key);
if (selected)
desc.flag |= TILEI_FLAG_SELECT;
m_region_menu_inv->update_slot(slot, desc);
}
void TilesFramework::place_cursor(cursor_type type, const coord_def &gc)
{
m_region_tile->place_cursor(type, gc);
}
void TilesFramework::clear_text_tags(text_tag_type type)
{
m_region_tile->clear_text_tags(type);
}
void TilesFramework::add_text_tag(text_tag_type type, const std::string &tag,
const coord_def &gc)
{
m_region_tile->add_text_tag(type, tag, gc);
}
bool TilesFramework::initialise_items()
{
return (m_image.load_item_texture());
}
const coord_def &TilesFramework::get_cursor() const
{
return (m_region_tile->get_cursor());
}
// display dungeon: tileb = { fg(0,0),bg(0,0),fg(1,0),bg(1,0), ..
void TileDrawDungeon(unsigned int *tileb);
// display memorised dungeon
void TileDrawFarDungeon(int cx, int cy);
// display map centered on grid coords
void TileDrawMap(int gx, int gy);
void LoadDungeonView(unsigned int *tileb);
void StoreDungeonView(unsigned int *tileb);
// display inventry
void TileDrawInvData(int n, int flag, int *tiles, int *num,
int *idx, int *iflags);
void TileDrawOneItem(int region, int i, char key, int idx,
int tile, int num, bool floor,
bool select, bool equip, bool tried, bool cursed);
void TileRedrawInv(int region);
void TileClearInv(int region);
void TileMoveInvCursor(int ix);
int TileInvIdx(int i);
// refresh player tile
void TilePlayerRefresh();
#define TILEI_FLAG_SELECT 0x100
#define TILEI_FLAG_TRIED 0x200
#define TILEI_FLAG_EQUIP 0x400
#define TILEI_FLAG_FLOOR 0x800
#define TILEI_FLAG_CURSE 0x1000
#define TILEI_FLAG_CURSOR 0x2000
enum
{
TILEI_FLAG_SELECT = 0x0100,
TILEI_FLAG_TRIED = 0x0200,
TILEI_FLAG_EQUIP = 0x0400,
TILEI_FLAG_FLOOR = 0x0800,
TILEI_FLAG_CURSE = 0x1000,
TILEI_FLAG_CURSOR = 0x2000
};
#endif
/*
* File: tilereg.h
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
*/
#ifdef USE_TILE
#ifndef TILEREG_H
#define TILEREG_H
#include "tiletex.h"
#include "tiles.h"
#include <vector>
class ImageManager
{
public:
ImageManager();
virtual ~ImageManager();
bool load_textures();
bool load_item_texture();
void unload_textures();
FixedVector<TilesTexture, TEX_MAX> m_textures;
};
// Windows and internal regions (text, dungeon, map, etc)
class MouseEvent;
class Region
{
public:
Region();
virtual ~Region();
void resize(unsigned int mx, unsigned int my);
void place(unsigned int sx, unsigned int sy, unsigned int margin);
void resize_to_fit(int wx, int wy);
// Returns true if the mouse position is over the region
// If true, then cx and cy are set in the range [0..mx-1], [0..my-1]
virtual bool mouse_pos(int mouse_x, int mouse_y, int &cx, int &cy);
bool inside(unsigned int px, unsigned int py);
virtual bool update_tip_text(std::string &tip) { return false; }
virtual int handle_mouse(MouseEvent &event) = 0;
virtual void render() = 0;
virtual void clear() = 0;
// Geometry
// <-----------------wx----------------------->
// sx ox ex
// |margin| text/tile area |margin|
// Offset in pixels
unsigned int ox;
unsigned int oy;
// Unit size
unsigned int dx;
unsigned int dy;
// Region size in dx/dy
unsigned int mx;
unsigned int my;
// Width of the region in pixels
unsigned int wx;
unsigned int wy;
// Start position in pixels (top left)
unsigned int sx;
unsigned int sy;
// End position in pixels (bottom right)
unsigned int ex;
unsigned int ey;
static coord_def NO_CURSOR;
protected:
void recalculate();
virtual void on_resize() = 0;
};
class FTFont;
class TextRegion : public Region
{
public:
TextRegion(FTFont *font);
~TextRegion();
virtual void render();
virtual void clear();
// STATIC -
// TODO enne - move these to TilesFramework?
// where now printing? what color?
static unsigned int print_x;
static unsigned int print_y;
static int text_col;
// which region now printing?
static class TextRegion *text_mode;
// display cursor? where is the cursor now?
static int cursor_flag;
static class TextRegion *cursor_region;
static unsigned int cursor_x;
static unsigned int cursor_y;
// class methods
static void cgotoxy(int x, int y);
static int wherex();
static int wherey();
//static int get_number_of_lines(void);
static void _setcursortype(int curstype);
static void textbackground(int bg);
static void textcolor(int col);
// Object's method
void clear_to_end_of_line(void);
void putch(unsigned char chr);
void writeWChar(unsigned char *ch);
unsigned char *cbuf; //text backup
unsigned char *abuf; //textcolor backup
int cx_ofs; //cursor x offset
int cy_ofs; //cursor y offset
void addstr(char *buffer);
void addstr_aux(char *buffer, unsigned int len);
void adjust_region(int *x1, int *x2, int y);
void scroll();
//Sys dep
void draw_cursor(int x, int y, int width);
void draw_cursor(int x, int y);
void erase_cursor();
protected:
virtual void on_resize();
FTFont *m_font;
};
class StatRegion : public TextRegion
{
public:
StatRegion(FTFont *font);
virtual int handle_mouse(MouseEvent &event);
virtual bool update_tip_text(std::string &tip);
};
class MessageRegion : public TextRegion
{
public:
MessageRegion(FTFont *font);
virtual int handle_mouse(MouseEvent &event);
virtual bool update_tip_text(std::string &tip);
};
class CRTRegion : public TextRegion
{
public:
CRTRegion(FTFont *font);
virtual int handle_mouse(MouseEvent &event);
};
class TileRegion : public Region
{
public:
TileRegion(ImageManager *im, unsigned int tile_x, unsigned int tile_y);
~TileRegion();
protected:
void add_quad(TextureID tex, unsigned int idx, unsigned int x, unsigned int y, int ofs_x = 0, int ofs_y = 0);
ImageManager *m_image;
struct tile_vert
{
float pos_x;
float pos_y;
float tex_x;
float tex_y;
};
std::vector<tile_vert> m_verts;
};
struct TextTag
{
std::string tag;
coord_def gc;
};
enum cursor_type
{
CURSOR_MOUSE,
CURSOR_TUTORIAL,
CURSOR_MAX
};
enum text_tag_type
{
TAG_NAMED_MONSTER,
TAG_TUTORIAL,
TAG_MAX
};
class DungeonRegion : public TileRegion
{
public:
DungeonRegion(ImageManager *im, FTFont *tag_font,
unsigned int tile_x, unsigned int tile_y);
virtual ~DungeonRegion();
virtual void render();
virtual void clear();
virtual int handle_mouse(MouseEvent &event);
virtual bool update_tip_text(std::string &tip);
virtual void on_resize();
void load_dungeon(unsigned int* tileb, int cx_to_gx, int cy_to_gy);
void place_cursor(cursor_type type, const coord_def &gc);
bool on_screen(const coord_def &gc) const;
void clear_text_tags(text_tag_type type);
void add_text_tag(text_tag_type type, const std::string &tag,
const coord_def &gc);
const coord_def &get_cursor() const { return m_cursor[CURSOR_MOUSE]; }
protected:
void draw_background(unsigned int bg, unsigned int x, unsigned int y);
bool draw_objects(unsigned int fg, unsigned int x, unsigned int y);
void draw_player(unsigned int x, unsigned int y);
void draw_monster(unsigned int fg, unsigned int x, unsigned int y);
void draw_foreground(unsigned int bg, unsigned int fg, unsigned int x, unsigned int y);
void draw_doll(dolls_data &doll, unsigned int x, unsigned int y);
void draw_draco(int colour, int mon_idx, int equ_tile, unsigned int x, unsigned int y);
void add_quad_doll(unsigned int part, unsigned int idx, int ymax, unsigned int x, unsigned int y, int ox, int oy);
int get_buffer_index(const coord_def &gc);
void to_screen_coords(const coord_def &gc, coord_def& pc) const;
std::vector<unsigned int> m_tileb;
int m_cx_to_gx;
int m_cy_to_gy;
coord_def m_cursor[CURSOR_MAX];
std::vector<TextTag> m_tags[TAG_MAX];
FTFont *m_tag_font;
};
class InventoryTile
{
public:
InventoryTile();
// tile index
int tile;
// mitm/you.inv idx (depends on flag & TILEI_FLAG_FLOOR)
int idx;
// quantity of this item (0-999 valid, >999 shows as 999, <0 shows nothing)
short quantity;
// bitwise-or of TILEI_FLAG enumeration
unsigned short flag;
// for inventory items, the slot
char key;
bool empty() const;
};
class InventoryRegion : public TileRegion
{
public:
InventoryRegion(ImageManager *im, unsigned int tile_x, unsigned int tile_y);
virtual ~InventoryRegion();
virtual void clear();
virtual void render();
virtual void on_resize();
virtual int handle_mouse(MouseEvent &event);
void update(unsigned int num, InventoryTile *items);
void update_slot(unsigned int slot, InventoryTile &item);
virtual bool update_tip_text(std::string &tip);
protected:
void pack_tile(unsigned int x, unsigned int y, unsigned int idx);
void pack_verts();
void add_quad_char(char c, unsigned int x, unsigned int y, int ox, int oy);
void place_cursor(const coord_def &cursor);
unsigned int cursor_index() const;
unsigned int m_base_verts;
std::vector<InventoryTile> m_items;
unsigned char *m_flavour;
coord_def m_cursor;
bool m_need_to_pack;
};
enum map_colour
{
MAP_BLACK,
MAP_DKGREY,
MAP_MDGREY,
MAP_LTGREY,
MAP_WHITE,
MAP_BLUE,
MAP_LTBLUE,
MAP_DKBLUE,
MAP_GREEN,
MAP_LTGREEN,
MAP_DKGREEN,
MAP_CYAN,
MAP_LTCYAN,
MAP_DKCYAN,
MAP_RED,
MAP_LTRED,
MAP_DKRED,
MAP_MAGENTA,
MAP_LTMAGENTA,
MAP_DKMAGENTA,
MAP_YELLOW,
MAP_LTYELLOW,
MAP_DKYELLOW,
MAP_BROWN,
MAX_MAP_COL
};
class MapRegion : public Region
{
public:
MapRegion(unsigned int pixsz);
~MapRegion();
virtual void render();
virtual void clear();
virtual int handle_mouse(MouseEvent &event);
virtual bool update_tip_text(std::string &tip);
void init_colours();
void set(unsigned int gx, unsigned int gy, map_feature f);
void set_window(const coord_def &start, const coord_def &end);
protected:
virtual void on_resize();
void update_offsets();
map_colour m_colours[MF_MAX];
unsigned int m_min_gx, m_max_gx, m_min_gy, m_max_gy;
coord_def m_win_start;
coord_def m_win_end;
unsigned char *m_buf;
bool m_far_view;
};
#endif
#endif
/*
* File: tilereg.cc
* Summary: Region system implementaions
*
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2008-03-07 $
*/
#include "AppHdr.h"
#include "cio.h"
#include "debug.h"
#include "describe.h"
#include "food.h"
#include "itemname.h"
#include "it_use2.h"
#include "item_use.h"
#include "message.h"
#include "misc.h"
#include "newgame.h"
#include "mon-util.h"
#include "player.h"
#include "spells3.h"
#include "stuff.h"
#include "terrain.h"
#include "transfor.h"
#include "travel.h"
#include "tilereg.h"
#include "tiles.h"
#include "tilefont.h"
#include "tilesdl.h"
#include "tiledef-dngn.h"
#include <SDL_opengl.h>
coord_def Region::NO_CURSOR(-1, -1);
unsigned int TextRegion::print_x;
unsigned int TextRegion::print_y;
TextRegion *TextRegion::text_mode = NULL;
int TextRegion::text_col = 0;
TextRegion *TextRegion::cursor_region= NULL;
int TextRegion::cursor_flag = 0;
unsigned int TextRegion::cursor_x;
unsigned int TextRegion::cursor_y;
const int map_colours[MAX_MAP_COL][3] =
{
{ 0, 0, 0}, // BLACK
{128, 128, 128}, // DKGREY
{160, 160, 160}, // MDGREY
{192, 192, 192}, // LTGREY
{255, 255, 255}, // WHITE
{ 0, 64, 255}, // BLUE (actually cyan-blue)
{128, 128, 255}, // LTBLUE
{ 0, 32, 128}, // DKBLUE (maybe too dark)
{ 0, 255, 0}, // GREEN
{128, 255, 128}, // LTGREEN
{ 0, 128, 0}, // DKGREEN
{ 0, 255, 255}, // CYAN
{ 64, 255, 255}, // LTCYAN (maybe too pale)
{ 0, 128, 128}, // DKCYAN
{255, 0, 0}, // RED
{255, 128, 128}, // LTRED (actually pink)
{128, 0, 0}, // DKRED
{192, 0, 255}, // MAGENTA (actually blue-magenta)
{255, 128, 255}, // LTMAGENTA
{ 96, 0, 128}, // DKMAGENTA
{255, 255, 0}, // YELLOW
{255, 255, 64}, // LTYELLOW (maybe too pale)
{128, 128, 0}, // DKYELLOW
{165, 91, 0}, // BROWN
};
const int dir_dx[9] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
const int dir_dy[9] = {1, 1, 1, 0, 0, 0, -1, -1, -1};
const int cmd_normal[9] = {'b', 'j', 'n', 'h', '.', 'l', 'y', 'k', 'u'};
const int cmd_shift[9] = {'B', 'J', 'N', 'H', '5', 'L', 'Y', 'K', 'U'};
const int cmd_ctrl[9] = {CONTROL('B'), CONTROL('J'), CONTROL('N'),
CONTROL('H'), 'X', CONTROL('L'),
CONTROL('Y'), CONTROL('K'), CONTROL('U')};
const int cmd_dir[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
Region::Region() :
ox(0),
oy(0),
dx(0),
dy(0),
mx(0),
my(0),
wx(0),
wy(0),
sx(0),
sy(0),
ex(0),
ey(0)
{
}
void Region::resize(unsigned int _mx, unsigned int _my)
{
mx = _mx;
my = _my;
recalculate();
}
void Region::place(unsigned int _sx, unsigned int _sy, unsigned int margin)
{
sx = _sx;
sy = _sy;
ox = margin;
oy = margin;
recalculate();
}
void Region::resize_to_fit(int _wx, int _wy)
{
if (_wx < 0 || _wy < 0)
{
mx = wx = my = wy = 0;
ey = sy;
ex = sy;
return;
}
unsigned int inner_x = _wx - 2 * ox;
unsigned int inner_y = _wy - 2 * oy;
mx = dx ? inner_x / dx : 0;
my = dy ? inner_y / dy : 0;
recalculate();
}
void Region::recalculate()
{
wx = ox * 2 + mx * dx;
wy = oy * 2 + my * dy;
ex = sx + wx;
ey = sy + wy;
on_resize();
}
Region::~Region()
{
}
bool Region::inside(unsigned int x, unsigned int y)
{
// TODO enne - need to handle invalid/unintialised regions?
return (x >= sx && y >= sy && x <= ex && y <= ey);
}
bool Region::mouse_pos(int mouse_x, int mouse_y, int &cx, int &cy)
{
int x = mouse_x - ox - sx;
int y = mouse_y - oy - sy;
bool valid = (x >= 0 && y >= 0);
x /= dx;
y /= dy;
valid &= ((unsigned int)x < mx && (unsigned int)y < my);
cx = x;
cy = y;
return valid;
}
TileRegion::TileRegion(ImageManager* im, unsigned int tile_x, unsigned int tile_y)
{
ASSERT(im);
m_image = im;
dx = tile_x;
dy = tile_y;
}
TileRegion::~TileRegion()
{
}
DungeonRegion::DungeonRegion(ImageManager* im, FTFont *tag_font,
unsigned int tile_x, unsigned int tile_y) :
TileRegion(im, tile_x, tile_y),
m_cx_to_gx(0),
m_cy_to_gy(0),
m_tag_font(tag_font)
{
ASSERT(tag_font);
for (unsigned int i = 0; i < CURSOR_MAX; i++)
m_cursor[i] = NO_CURSOR;
}
DungeonRegion::~DungeonRegion()
{
}
void DungeonRegion::load_dungeon(unsigned int* tileb, int cx_to_gx, int cy_to_gy)
{
m_tileb.clear();
if (!tileb)
return;
unsigned int len = 2 * crawl_view.viewsz.x * crawl_view.viewsz.y;
m_tileb.resize(len);
// TODO enne - move this function into dungeonregion
tile_finish_dngn(tileb, you.pos().x, you.pos().y);
memcpy(&m_tileb[0], tileb, sizeof(unsigned int) * len);
m_cx_to_gx = cx_to_gx;
m_cy_to_gy = cy_to_gy;
place_cursor(CURSOR_TUTORIAL, m_cursor[CURSOR_TUTORIAL]);
}
void DungeonRegion::add_quad_doll(unsigned int part, unsigned int idx, int ymax, unsigned int x, unsigned int y, int ox_spec, int oy_spec)
{
float tex_sx, tex_sy, tex_wx, tex_wy;
int ox_extra, oy_extra, wx_pix, wy_pix;
m_image->m_textures[TEX_DOLL].get_texcoord_doll(part, idx, ymax, tex_sx, tex_sy, tex_wx, tex_wy, wx_pix, wy_pix, ox_extra, oy_extra);
if (wx_pix <= 0 || wy_pix <= 0)
return;
float pos_ox = (ox_spec + ox_extra) / (float)TILE_X;
float pos_oy = (oy_spec + oy_extra) / (float)TILE_Y;
float tex_ex = tex_sx + tex_wx;
float tex_ey = tex_sy + tex_wy;
float pos_sx = x + pos_ox;
float pos_sy = y + pos_oy;
float pos_ex = pos_sx + wx_pix / (float)TILE_X;
float pos_ey = pos_sy + wy_pix / (float)TILE_Y;
tile_vert v;
v.pos_x = pos_sx;
v.pos_y = pos_sy;
v.tex_x = tex_sx;
v.tex_y = tex_sy;
m_verts.push_back(v);
v.pos_y = pos_ey;
v.tex_y = tex_ey;
m_verts.push_back(v);
v.pos_x = pos_ex;
v.tex_x = tex_ex;
m_verts.push_back(v);
v.pos_y = pos_sy;
v.tex_y = tex_sy;
m_verts.push_back(v);
}
void TileRegion::add_quad(TextureID tex, unsigned int idx, unsigned int x, unsigned int y, int ofs_x, int ofs_y)
{
// Generate quad
//
// 0 - 3
// | |
// 1 - 2
//
// Data Layout:
// float2 (position)
// float2 (texcoord)
float tex_sx, tex_sy, tex_wx, tex_wy;
m_image->m_textures[tex].get_texcoord(idx, tex_sx, tex_sy, tex_wx, tex_wy);
float tex_ex = tex_sx + tex_wx;
float tex_ey = tex_sy + tex_wy;
float pos_sx = x + ofs_x / (float)TILE_X;
float pos_sy = y + ofs_y / (float)TILE_Y;
float pos_ex = pos_sx + 1;
float pos_ey = pos_sy + 1;
// TODO enne - handle wx/wy non-standard sizes
tile_vert v;
v.pos_x = pos_sx;
v.pos_y = pos_sy;
v.tex_x = tex_sx;
v.tex_y = tex_sy;
m_verts.push_back(v);
v.pos_y = pos_ey;
v.tex_y = tex_ey;
m_verts.push_back(v);
v.pos_x = pos_ex;
v.tex_x = tex_ex;
m_verts.push_back(v);
v.pos_y = pos_sy;
v.tex_y = tex_sy;
m_verts.push_back(v);
}
void DungeonRegion::draw_background(unsigned int bg, unsigned int x, unsigned int y)
{
unsigned int bg_idx = bg & TILE_FLAG_MASK;
if (bg_idx >= TILE_DNGN_WAX_WALL)
{
tile_flavour &flv = env.tile_flv[x + m_cx_to_gx][y + m_cy_to_gy];
add_quad(TEX_DUNGEON, flv.floor, x, y);
}
if (bg & TILE_FLAG_BLOOD)
{
tile_flavour &flv = env.tile_flv[x + m_cx_to_gx][y + m_cy_to_gy];
unsigned int offset = flv.special % tile_DNGN_count[IDX_BLOOD];
add_quad(TEX_DUNGEON, TILE_BLOOD + offset, x, y);
}
add_quad(TEX_DUNGEON, bg_idx, x, y);
if (bg & TILE_FLAG_HALO)
add_quad(TEX_DUNGEON, TILE_HALO, x, y);
if (bg & TILE_FLAG_SANCTUARY && !(bg & TILE_FLAG_UNSEEN))
add_quad(TEX_DUNGEON, TILE_SANCTUARY, x, y);
// Apply the travel exclusion under the foreground if the cell is
// visible. It will be applied later if the cell is unseen.
if (bg & TILE_FLAG_EXCL_CTR && !(bg & TILE_FLAG_UNSEEN))
add_quad(TEX_DUNGEON, TILE_TRAVEL_EXCLUSION_CENTRE_BG, x, y);
else if (bg & TILE_FLAG_TRAV_EXCL && !(bg & TILE_FLAG_UNSEEN))
add_quad(TEX_DUNGEON, TILE_TRAVEL_EXCLUSION_BG, x, y);
if (bg & TILE_FLAG_RAY)
add_quad(TEX_DUNGEON, TILE_RAY_MESH, x, y);
}
void DungeonRegion::draw_player(unsigned int x, unsigned int y)
{
dolls_data default_doll;
dolls_data player_doll;
dolls_data result;
// TODO enne - store character doll here and get gender
for (int i = 0; i < TILEP_PARTS_TOTAL; i++)
player_doll.parts[i] = TILEP_SHOW_EQUIP;
int gender = 0;
tilep_race_default(you.species, gender, you.experience_level,
default_doll.parts);
result = player_doll;
// TODO enne - make these configurable
result.parts[TILEP_PART_BASE] = default_doll.parts[TILEP_PART_BASE];
result.parts[TILEP_PART_DRCHEAD] = default_doll.parts[TILEP_PART_DRCHEAD];
result.parts[TILEP_PART_DRCWING] = default_doll.parts[TILEP_PART_DRCWING];
bool halo = inside_halo(you.x_pos, you.y_pos);
result.parts[TILEP_PART_HALO] = halo ? TILEP_HALO_TSO : 0;
if (result.parts[TILEP_PART_HAND1] == TILEP_SHOW_EQUIP)
{
int item = you.equip[EQ_WEAPON];
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
result.parts[TILEP_PART_HAND1] = TILEP_HAND1_BLADEHAND;
else if (item == -1)
result.parts[TILEP_PART_HAND1] = 0;
else
result.parts[TILEP_PART_HAND1] = tilep_equ_weapon(you.inv[item]);
}
if (result.parts[TILEP_PART_HAND2] == TILEP_SHOW_EQUIP)
{
int item = you.equip[EQ_SHIELD];
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
result.parts[TILEP_PART_HAND2] = TILEP_HAND2_BLADEHAND;
else if (item == -1)
result.parts[TILEP_PART_HAND2] = 0;
else
result.parts[TILEP_PART_HAND2] = tilep_equ_shield(you.inv[item]);
}
if (result.parts[TILEP_PART_BODY] == TILEP_SHOW_EQUIP)
{
int item = you.equip[EQ_BODY_ARMOUR];
if (item == -1)
result.parts[TILEP_PART_BODY] = 0;
else
result.parts[TILEP_PART_BODY] = tilep_equ_armour(you.inv[item]);
}
if (result.parts[TILEP_PART_CLOAK] == TILEP_SHOW_EQUIP)
{
int item = you.equip[EQ_CLOAK];
if (item == -1)
result.parts[TILEP_PART_CLOAK] = 0;
else
result.parts[TILEP_PART_CLOAK] = tilep_equ_cloak(you.inv[item]);
}
if (result.parts[TILEP_PART_HELM] == TILEP_SHOW_EQUIP)
{
int item = you.equip[EQ_HELMET];
if (item != -1)
{
result.parts[TILEP_PART_HELM] = tilep_equ_helm(you.inv[item]);
}
else if (player_mutation_level(MUT_HORNS) > 0)
{
switch (player_mutation_level(MUT_HORNS))
{
case 1:
result.parts[TILEP_PART_HELM] = TILEP_HELM_HORNS1;
break;
case 2:
result.parts[TILEP_PART_HELM] = TILEP_HELM_HORNS2;
break;
case 3:
result.parts[TILEP_PART_HELM] = TILEP_HELM_HORNS3;
break;
}
}
else
{
result.parts[TILEP_PART_HELM] = 0;
}
}
if (result.parts[TILEP_PART_BOOTS] == TILEP_SHOW_EQUIP)
{
int item = you.equip[EQ_BOOTS];
if (item != -1)
result.parts[TILEP_PART_BOOTS] = tilep_equ_boots(you.inv[item]);
else if (player_mutation_level(MUT_HOOVES))
result.parts[TILEP_PART_BOOTS] = TILEP_BOOTS_HOOVES;
else
result.parts[TILEP_PART_BOOTS] = 0;
}
if (result.parts[TILEP_PART_ARM] == TILEP_SHOW_EQUIP)
{
int item = you.equip[EQ_GLOVES];
if (item != -1)
result.parts[TILEP_PART_ARM] = tilep_equ_gloves(you.inv[item]);
else if (player_mutation_level(MUT_CLAWS) >= 3
|| you.species == SP_TROLL || you.species == SP_GHOUL)
{
// There is player_has_claws() but it is not equivalent.
// Claws appear if they're big enough to not wear gloves
// or on races that have claws.
result.parts[TILEP_PART_ARM] = TILEP_ARM_CLAWS;
}
else
result.parts[TILEP_PART_ARM] = 0;
}
draw_doll(result, x, y);
}
bool DungeonRegion::draw_objects(unsigned int fg, unsigned int x, unsigned int y)
{
unsigned int fg_idx = fg & TILE_FLAG_MASK;
// handled elsewhere
if (fg_idx == TILE_PLAYER)
return false;
int equ_tile;
int draco;
int mon_tile;
if (get_mcache_entry(fg_idx, mon_tile, equ_tile, draco))
{
if (!draco)
add_quad(TEX_DEFAULT, get_base_idx_from_mcache(fg_idx), x, y);
return true;
}
else if (fg_idx)
{
add_quad(TEX_DEFAULT, fg_idx, x, y);
}
return false;
}
void DungeonRegion::draw_doll(dolls_data &doll, unsigned int x, unsigned int y)
{
int p_order[TILEP_PARTS_TOTAL] =
{
TILEP_PART_SHADOW,
TILEP_PART_HALO,
TILEP_PART_DRCWING,
TILEP_PART_CLOAK,
TILEP_PART_BASE,
TILEP_PART_BOOTS,
TILEP_PART_LEG,
TILEP_PART_BODY,
TILEP_PART_ARM,
TILEP_PART_HAND1,
TILEP_PART_HAND2,
TILEP_PART_HAIR,
TILEP_PART_BEARD,
TILEP_PART_HELM,
TILEP_PART_DRCHEAD
};
int flags[TILEP_PARTS_TOTAL];
tilep_calc_flags(doll.parts, flags);
// For skirts, boots go under the leg armour. For pants, they go over.
if (doll.parts[TILEP_PART_LEG] < TILEP_LEG_SKIRT_OFS)
{
p_order[5] = TILEP_PART_BOOTS;
p_order[6] = TILEP_PART_LEG;
}
for (int i = 0; i < TILEP_PARTS_TOTAL; i++)
{
int p = p_order[i];
if (!doll.parts[p])
continue;
int ymax = TILE_Y;
if (flags[p] == TILEP_FLAG_CUT_CENTAUR
|| flags[p] == TILEP_FLAG_CUT_NAGA)
{
ymax = 18;
}
if (doll.parts[p] && p == TILEP_PART_BOOTS
&& (doll.parts[p] == TILEP_BOOTS_NAGA_BARDING
|| doll.parts[p] == TILEP_BOOTS_CENTAUR_BARDING))
{
// Special case for barding. They should be in "boots" but because
// they're double-wide, they're stored in a different part. We just
// intercept it here before drawing.
char tile = (doll.parts[p] == TILEP_BOOTS_NAGA_BARDING) ?
TILEP_SHADOW_NAGA_BARDING :
TILEP_SHADOW_CENTAUR_BARDING;
add_quad_doll(TILEP_PART_SHADOW, tile, TILE_Y, x, y, 0, 0);
}
else
{
add_quad_doll(p, doll.parts[p], ymax, x, y, 0, 0);
}
}
}
void DungeonRegion::draw_draco(int colour, int mon_idx, int equ_tile, unsigned int x, unsigned int y)
{
dolls_data doll;
int armour = 0;
int armour2 = 0;
int weapon = 0;
int weapon2 = 0;
int arm = 0;
for (int i = 0; i < TILEP_PARTS_TOTAL; i++)
doll.parts[i] = 0;
doll.parts[TILEP_PART_SHADOW] = 1;
doll.parts[TILEP_PART_BASE] = TILEP_BASE_DRACONIAN + colour * 2;
doll.parts[TILEP_PART_DRCWING] = 1 + colour;
doll.parts[TILEP_PART_DRCHEAD] = 1 + colour;
switch (mon_idx)
{
case MONS_DRACONIAN_CALLER:
weapon = TILEP_HAND1_STAFF_EVIL;
weapon2 = TILEP_HAND2_BOOK_YELLOW;
armour = TILEP_BODY_ROBE_BROWN;
break;
case MONS_DRACONIAN_MONK:
arm = TILEP_ARM_GLOVE_SHORT_BLUE;
armour = TILEP_BODY_KARATE2;
break;
case MONS_DRACONIAN_ZEALOT:
weapon = TILEP_HAND1_MACE;
weapon2 = TILEP_HAND2_BOOK_CYAN;
armour = TILEP_BODY_MONK_BLUE;
break;
case MONS_DRACONIAN_SHIFTER:
weapon = TILEP_HAND1_STAFF_LARGE;
armour = TILEP_BODY_ROBE_CYAN;
weapon2 = TILEP_HAND2_BOOK_GREEN;
break;
case MONS_DRACONIAN_ANNIHILATOR:
weapon = TILEP_HAND1_STAFF_RUBY;
weapon2 = TILEP_HAND2_FIRE_CYAN;
armour = TILEP_BODY_ROBE_GREEN_GOLD;
break;
case MONS_DRACONIAN_KNIGHT:
weapon = equ_tile;
weapon2 = TILEP_HAND2_SHIELD_KNIGHT_GRAY;
armour = TILEP_BODY_BPLATE_METAL1;
armour2 = TILEP_LEG_BELT_GRAY;
break;
case MONS_DRACONIAN_SCORCHER:
weapon = TILEP_HAND1_FIRE_RED;
weapon2 = TILEP_HAND2_BOOK_RED;
armour = TILEP_BODY_ROBE_RED;
break;
default:
weapon = equ_tile;
armour = TILEP_BODY_BELT2;
armour2 = TILEP_LEG_LOINCLOTH_RED;
break;
}
doll.parts[TILEP_PART_HAND1] = weapon;
doll.parts[TILEP_PART_HAND2] = weapon2;
doll.parts[TILEP_PART_BODY] = armour;
doll.parts[TILEP_PART_LEG] = armour2;
doll.parts[TILEP_PART_ARM] = arm;
draw_doll(doll, x, y);
}
void DungeonRegion::draw_monster(unsigned int fg, unsigned int x, unsigned int y)
{
// Currently, monsters only get displayed weapons (no armour)
unsigned int fg_idx = fg & TILE_FLAG_MASK;
if (fg_idx < TILE_MCACHE_START)
return;
int equ_tile;
int draco;
int mon_tile;
if (!get_mcache_entry(fg_idx, mon_tile, equ_tile, draco))
return;
if (draco == 0)
{
int ofs_x, ofs_y;
tile_get_monster_weapon_offset(mon_tile, ofs_x, ofs_y);
add_quad_doll(TILEP_PART_HAND1, equ_tile, TILE_Y, x, y, ofs_x, ofs_y);
// In some cases, overlay a second weapon tile...
if (mon_tile == TILE_MONS_DEEP_ELF_BLADEMASTER)
{
int eq2;
switch (equ_tile)
{
case TILEP_HAND1_DAGGER:
eq2 = TILEP_HAND2_DAGGER;
break;
case TILEP_HAND1_SABRE:
eq2 = TILEP_HAND2_SABRE;
break;
default:
case TILEP_HAND1_SHORT_SWORD_SLANT:
eq2 = TILEP_HAND2_SHORT_SWORD_SLANT;
break;
};
add_quad_doll(TILEP_PART_HAND2, eq2, TILE_Y, x, y, -ofs_x, ofs_y);
}
}
else
{
int colour;
switch (draco)
{
default:
case MONS_DRACONIAN: colour = 0; break;
case MONS_BLACK_DRACONIAN: colour = 1; break;
case MONS_YELLOW_DRACONIAN: colour = 2; break;
case MONS_GREEN_DRACONIAN: colour = 4; break;
case MONS_MOTTLED_DRACONIAN:colour = 5; break;
case MONS_PALE_DRACONIAN: colour = 6; break;
case MONS_PURPLE_DRACONIAN: colour = 7; break;
case MONS_RED_DRACONIAN: colour = 8; break;
case MONS_WHITE_DRACONIAN: colour = 9; break;
}
draw_draco(colour, mon_tile, equ_tile, x, y);
}
}
void DungeonRegion::draw_foreground(unsigned int bg, unsigned int fg, unsigned int x, unsigned int y)
{
unsigned int fg_idx = fg & TILE_FLAG_MASK;
unsigned int bg_idx = bg & TILE_FLAG_MASK;
if (fg_idx && !(fg & TILE_FLAG_FLYING))
{
if (bg_idx >= TILE_DNGN_LAVA && bg_idx <= TILE_DNGN_LAVA + 3)
{
add_quad(TEX_DEFAULT, TILE_MASK_LAVA, x, y);
}
else if (bg_idx >= TILE_DNGN_SHALLOW_WATER
&& bg_idx <= TILE_DNGN_SHALLOW_WATER + 3)
{
add_quad(TEX_DEFAULT, TILE_MASK_SHALLOW_WATER, x, y);
}
else if (bg_idx >= TILE_DNGN_DEEP_WATER
&& bg_idx <= TILE_DNGN_DEEP_WATER + 3)
{
add_quad(TEX_DEFAULT, TILE_MASK_DEEP_WATER, x, y);
}
}
if (fg & TILE_FLAG_NET)
add_quad(TEX_DEFAULT, TILE_TRAP_NET, x, y);
if (fg & TILE_FLAG_S_UNDER)
add_quad(TEX_DEFAULT, TILE_SOMETHING_UNDER, x, y);
// Pet mark
int status_shift = 0;
if (fg & TILE_FLAG_PET)
{
add_quad(TEX_DEFAULT, TILE_HEART, x, y);
status_shift += 10;
}
else if ((fg & TILE_FLAG_MAY_STAB) == TILE_FLAG_NEUTRAL)
{
add_quad(TEX_DEFAULT, TILE_NEUTRAL, x, y);
status_shift += 8;
}
else if ((fg & TILE_FLAG_MAY_STAB) == TILE_FLAG_STAB)
{
add_quad(TEX_DEFAULT, TILE_STAB_BRAND, x, y);
status_shift += 8;
}
else if ((fg & TILE_FLAG_MAY_STAB) == TILE_FLAG_MAY_STAB)
{
add_quad(TEX_DEFAULT, TILE_MAY_STAB_BRAND, x, y);
status_shift += 5;
}
if (fg & TILE_FLAG_POISON)
{
add_quad(TEX_DEFAULT, TILE_POISON, x, y, -status_shift, 0);
status_shift += 5;
}
if (fg & TILE_FLAG_ANIM_WEP)
{
add_quad(TEX_DEFAULT, TILE_ANIMATED_WEAPON, x, y);
}
if (bg & TILE_FLAG_UNSEEN)
add_quad(TEX_DEFAULT, TILE_MESH, x, y);
if (bg & TILE_FLAG_MM_UNSEEN)
add_quad(TEX_DEFAULT, TILE_MAGIC_MAP_MESH, x, y);
// Don't let the "new stair" icon cover up any existing icons, but
// draw it otherwise.
if (bg & TILE_FLAG_NEW_STAIR && status_shift == 0)
add_quad(TEX_DEFAULT, TILE_NEW_STAIR, x, y);
if (bg & TILE_FLAG_EXCL_CTR && (bg & TILE_FLAG_UNSEEN))
add_quad(TEX_DUNGEON, TILE_TRAVEL_EXCLUSION_CENTRE_FG, x, y);
else if (bg & TILE_FLAG_TRAV_EXCL && (bg & TILE_FLAG_UNSEEN))
add_quad(TEX_DUNGEON, TILE_TRAVEL_EXCLUSION_FG, x, y);
// Tutorial cursor takes precedence over other cursors.
if (bg & TILE_FLAG_TUT_CURSOR)
{
add_quad(TEX_DEFAULT, TILE_TUTORIAL_CURSOR, x, y);
}
else if (bg & TILE_FLAG_CURSOR)
{
int type = ((bg & TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR1) ?
TILE_CURSOR : TILE_CURSOR2;
if ((bg & TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR3)
type = TILE_CURSOR3;
add_quad(TEX_DEFAULT, type, x, y);
}
}
void DungeonRegion::render()
{
if (m_tileb.size() == 0)
return;
glLoadIdentity();
glTranslatef(sx + ox, sy + oy, 0);
glScalef(dx, dy, 1);
m_verts.clear();
m_verts.reserve(4 * crawl_view.viewsz.x * crawl_view.viewsz.y);
GLState state;
state.array_vertex = true;
state.array_texcoord = true;
state.blend = true;
state.texture = true;
GLStateManager::set(state);
int tile = 0;
for (int y = 0; y < crawl_view.viewsz.y; y++)
for (int x = 0; x < crawl_view.viewsz.x; x++)
{
unsigned int bg = m_tileb[tile + 1];
draw_background(bg, x, y);
tile += 2;
}
ASSERT(m_verts.size() > 0);
if (m_verts.size() > 0)
{
m_image->m_textures[TEX_DUNGEON].bind();
glVertexPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].pos_x);
glTexCoordPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].tex_x);
glDrawArrays(GL_QUADS, 0, m_verts.size());
}
tile = 0;
m_verts.clear();
int player_x = -1;
int player_y = -1;
bool need_doll = false;
for (int y = 0; y < crawl_view.viewsz.y; y++)
for (int x = 0; x < crawl_view.viewsz.x; x++)
{
unsigned int fg = m_tileb[tile];
need_doll |= draw_objects(fg, x, y);
if ((fg & TILE_FLAG_MASK) == TILE_PLAYER)
{
player_x = x;
player_y = y;
}
tile += 2;
}
if (m_verts.size() > 0)
{
m_image->m_textures[TEX_DEFAULT].bind();
glVertexPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].pos_x);
glTexCoordPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].tex_x);
glDrawArrays(GL_QUADS, 0, m_verts.size());
}
tile = 0;
m_verts.clear();
if (player_x != -1)
draw_player(player_x, player_y);
if (need_doll)
{
for (int y = 0; y < crawl_view.viewsz.y; y++)
for (int x = 0; x < crawl_view.viewsz.x; x++)
{
unsigned int fg = m_tileb[tile];
draw_monster(fg, x, y);
tile += 2;
}
}
if (m_verts.size() > 0)
{
m_image->m_textures[TEX_DOLL].bind();
glVertexPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].pos_x);
glTexCoordPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].tex_x);
glDrawArrays(GL_QUADS, 0, m_verts.size());
}
tile = 0;
m_verts.clear();
for (int y = 0; y < crawl_view.viewsz.y; y++)
for (int x = 0; x < crawl_view.viewsz.x; x++)
{
unsigned int fg = m_tileb[tile];
unsigned int bg = m_tileb[tile + 1];
draw_foreground(bg, fg, x, y);
tile += 2;
}
if (m_verts.size() > 0)
{
m_image->m_textures[TEX_DEFAULT].bind();
glVertexPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].pos_x);
glTexCoordPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].tex_x);
glDrawArrays(GL_QUADS, 0, m_verts.size());
}
// Draw text labels
// TODO enne - add an option for this
// TODO enne - be more intelligent about not covering stuff up
for (unsigned int t = 0; t < TAG_MAX; t++)
{
for (unsigned int i = 0; i < m_tags[t].size(); i++)
{
if (!on_screen(m_tags[t][i].gc))
continue;
coord_def pc;
to_screen_coords(m_tags[t][i].gc, pc);
// center this coord, which is at the top left of gc's cell
pc.x += dx / 2;
const coord_def min_pos(sx, sy);
const coord_def max_pos(ex, ey);
m_tag_font->render_string(pc.x, pc.y, m_tags[t][i].tag.c_str(),
min_pos, max_pos, WHITE, true);
}
}
}
void DungeonRegion::clear()
{
m_tileb.clear();
}
void DungeonRegion::on_resize()
{
// TODO enne
}
int DungeonRegion::handle_mouse(MouseEvent &event)
{
if (mouse_control::current_mode() == MOUSE_MODE_NORMAL
|| mouse_control::current_mode() == MOUSE_MODE_MACRO
|| mouse_control::current_mode() == MOUSE_MODE_MORE)
{
return 0;
}
int cx;
int cy;
if (!inside(event.px, event.py))
return 0;
bool on_map = mouse_pos(event.px, event.py, cx, cy);
const coord_def gc(cx + m_cx_to_gx, cy + m_cy_to_gy);
tiles.place_cursor(CURSOR_MOUSE, gc);
// TODO enne - can we handle this through tooltips
// Destroying the message area is such bad behaviour.
// mesclr();
// terse_describe_square(gc);
if (!on_map)
return 0;
if (mouse_control::current_mode() == MOUSE_MODE_TARGET
|| mouse_control::current_mode() == MOUSE_MODE_TARGET_DIR)
{
if (event.event == MouseEvent::MOVE)
{
return CK_MOUSE_MOVE;
}
else if (event.event == MouseEvent::PRESS
&& event.button == MouseEvent::LEFT && on_screen(gc))
{
return CK_MOUSE_CLICK;
}
return 0;
}
if (event.event != MouseEvent::PRESS)
return 0;
if (you.pos() == gc)
{
switch (event.button)
{
case MouseEvent::LEFT:
if (!(event.mod & MOD_SHIFT))
return 'g';
switch (grid_stair_direction(grd(gc)))
{
case CMD_GO_DOWNSTAIRS:
return ('>');
case CMD_GO_UPSTAIRS:
return ('<');
default:
return 0;
}
case MouseEvent::RIGHT:
if (!(event.mod & MOD_SHIFT))
return '%'; // Character overview.
if (you.religion != GOD_NO_GOD)
return '^'; // Religion screen.
// fall through...
default:
return 0;
}
}
// else not on player...
if (event.button == MouseEvent::RIGHT)
{
full_describe_square(gc);
return CK_MOUSE_CMD;
}
if (event.button != MouseEvent::LEFT)
return 0;
// If adjacent, return that key (modified by shift or ctrl, etc...)
coord_def dir = gc - you.pos();
for (unsigned int i = 0; i < 9; i++)
{
if (dir_dx[i] == dir.x && dir_dy[i] == dir.y)
{
if (event.mod & MOD_SHIFT)
return cmd_shift[i];
else if (event.mod & MOD_CTRL)
return cmd_ctrl[i];
else
return cmd_normal[i];
}
}
// Otherwise, travel to that grid.
if (!in_bounds(gc))
return 0;
// Activate travel.
start_travel(gc.x, gc.y);
return CK_MOUSE_CMD;
}
void DungeonRegion::to_screen_coords(const coord_def &gc, coord_def &pc) const
{
int cx = gc.x - m_cx_to_gx;
int cy = gc.y - m_cy_to_gy;
pc.x = sx + ox + cx * dx;
pc.y = sy + oy + cy * dy;
}
bool DungeonRegion::on_screen(const coord_def &gc) const
{
int x = gc.x - m_cx_to_gx;
int y = gc.y - m_cy_to_gy;
return (x >= 0 && (unsigned int)x < mx && y >= 0 && (unsigned int)y < my);
}
// Returns the index into m_tileb for the foreground tile.
// This value may not be valid. Check on_screen() first.
// Add one to the return value to get the background tile idx.
int DungeonRegion::get_buffer_index(const coord_def &gc)
{
int x = gc.x - m_cx_to_gx;
int y = gc.y - m_cy_to_gy;
return 2 * (x + y * mx);
}
void DungeonRegion::place_cursor(cursor_type type, const coord_def &gc)
{
unsigned int unmask = ~((type == CURSOR_MOUSE) ? TILE_FLAG_CURSOR :
TILE_FLAG_TUT_CURSOR);
unsigned int mask = (type == CURSOR_MOUSE) ? TILE_FLAG_CURSOR1 :
TILE_FLAG_TUT_CURSOR;
// Remove cursor from previous location
if (on_screen(m_cursor[type]))
{
unsigned int idx = get_buffer_index(m_cursor[type]) + 1;
m_tileb[idx] &= unmask;
}
// If we're only looking for a direction, put the mouse
// cursor next to the player to let them know that their
// spell/wand will only go one square.
if (mouse_control::current_mode() == MOUSE_MODE_TARGET_DIR
&& type == CURSOR_MOUSE)
{
coord_def delta = gc - you.pos();
int ax = abs(delta.x);
int ay = abs(delta.y);
coord_def result = you.pos();
if (1000 * ay < 414 * ax)
result += (delta.x > 0) ? coord_def(1, 0) : coord_def(-1, 0);
else if (1000 * ax < 414 * ay)
result += (delta.y > 0) ? coord_def(0, 1) : coord_def(0, -1);
else if (delta.x > 0)
result += (delta.y > 0) ? coord_def(1, 1) : coord_def(1, -1);
else if (delta.x < 0)
result += (delta.y > 0) ? coord_def(-1, 1) : coord_def(-1, -1);
m_cursor[type] = result;
}
else
{
m_cursor[type] = gc;
}
// Add cursor to new location
if ((m_cursor[type] != NO_CURSOR) && on_screen(m_cursor[type]))
{
unsigned int idx = get_buffer_index(m_cursor[type]) + 1;
m_tileb[idx] &= unmask;
// TODO enne - specify type of cursor in place_cursor? or determine type based on grd?
m_tileb[idx] |= mask;
}
}
bool DungeonRegion::update_tip_text(std::string& tip)
{
// TODO enne - it would be really nice to use the tutorial
// descriptions here for features, monsters, etc...
// Unfortunately, that would require quite a bit of rewriting
// and some parsing of formatting to get that to work.
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return false;
if (m_cursor[CURSOR_MOUSE] == you.pos())
{
tip = you.your_name;
tip += " (";
tip += get_species_abbrev(you.species);
tip += get_class_abbrev(you.char_class);
tip += ")";
if (igrd(m_cursor[CURSOR_MOUSE]) != NON_ITEM)
tip += "\n[L-Click] Pick up items (g)";
if (grid_stair_direction(grd(m_cursor[CURSOR_MOUSE])) != CMD_NO_CMD)
tip += "\n[Shift-L-Click] use stairs (</>)";
// Character overview.
tip += "\n[R-Click] Overview (%)";
// Religion.
if (you.religion != GOD_NO_GOD)
tip += "\n[Shift-R-Click] Religion (^)";
}
else if (abs(m_cursor[CURSOR_MOUSE].x - you.pos().x) <= 1
&& abs(m_cursor[CURSOR_MOUSE].y - you.pos().y) <= 1)
{
tip = "";
if (!grid_is_solid(m_cursor[CURSOR_MOUSE]))
{
int mon_num = mgrd(m_cursor[CURSOR_MOUSE]);
const monsters *mons = &menv[mon_num];
if (mon_num == NON_MONSTER || mons_friendly(mons))
{
tip = "[L-Click] Move\n";
}
else if (mon_num != NON_MONSTER)
{
tip = mons->name(DESC_CAP_A);
tip += "\n[L-Click] Attack\n";
}
}
tip += "[R-Click] Describe";
}
else
{
if (i_feel_safe() && !grid_is_solid(m_cursor[CURSOR_MOUSE]))
{
tip = "[L-Click] Travel\n";
}
tip += "[R-Click] Describe";
}
return true;
}
void DungeonRegion::clear_text_tags(text_tag_type type)
{
m_tags[type].clear();
}
void DungeonRegion::add_text_tag(text_tag_type type, const std::string &tag,
const coord_def &gc)
{
TextTag t;
t.tag = tag;
t.gc = gc;
m_tags[type].push_back(t);
}
InventoryTile::InventoryTile()
{
tile = 0;
idx = -1;
quantity = -1;
key = 0;
flag = 0;
}
bool InventoryTile::empty() const
{
return (idx == -1);
}
InventoryRegion::InventoryRegion(ImageManager* im, unsigned tile_x, unsigned int tile_y) :
TileRegion(im, tile_x, tile_y),
m_flavour(NULL), m_cursor(NO_CURSOR), m_need_to_pack(false)
{
}
InventoryRegion::~InventoryRegion()
{
delete[] m_flavour;
}
void InventoryRegion::clear()
{
m_items.clear();
m_verts.clear();
}
void InventoryRegion::on_resize()
{
delete[] m_flavour;
if (mx * my <= 0)
return;
m_flavour = new unsigned char[mx * my];
for (unsigned int i = 0; i < mx * my; i++)
{
m_flavour[i] = random2((unsigned char)~0);
}
}
void InventoryRegion::update(unsigned int num, InventoryTile *items)
{
m_items.clear();
for (unsigned int i = 0; i < num; i++)
{
m_items.push_back(items[i]);
}
m_need_to_pack = true;
}
void InventoryRegion::update_slot(unsigned int slot, InventoryTile &desc)
{
while (m_items.size() <= slot)
{
InventoryTile temp;
m_items.push_back(temp);
}
m_items[slot] = desc;
m_need_to_pack = true;
}
void InventoryRegion::render()
{
if (m_need_to_pack)
pack_verts();
if (m_verts.size() == 0)
return;
glLoadIdentity();
glTranslatef(sx + ox, sy + oy, 0);
glScalef(dx, dy, 1);
GLState state;
state.array_vertex = true;
state.array_texcoord = true;
state.blend = true;
state.texture = true;
GLStateManager::set(state);
m_image->m_textures[TEX_DUNGEON].bind();
glVertexPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].pos_x);
glTexCoordPointer(2, GL_FLOAT, sizeof(tile_vert), &m_verts[0].tex_x);
glDrawArrays(GL_QUADS, 0, m_base_verts);
m_image->m_textures[TEX_DEFAULT].bind();
glDrawArrays(GL_QUADS, m_base_verts, m_verts.size() - m_base_verts);
}
void InventoryRegion::add_quad_char(char c, unsigned int x, unsigned int y, int ofs_x, int ofs_y)
{
int idx = TILE_CHAR00 + (c - 32) / 8;
int subidx = c & 7;
float tex_sx, tex_sy, tex_wx, tex_wy;
m_image->m_textures[TEX_DEFAULT].get_texcoord(idx, tex_sx, tex_sy, tex_wx, tex_wy);
tex_wx /= 4.0f;
tex_wy /= 2.0f;
tex_sx += (subidx % 4) * tex_wx;
tex_sy += (subidx / 4) * tex_wy;
float tex_ex = tex_sx + tex_wx;
float tex_ey = tex_sy + tex_wy;
float pos_sx = x + ofs_x / (float)TILE_X;
float pos_sy = y + ofs_y / (float)TILE_Y;
float pos_ex = pos_sx + 0.25f;
float pos_ey = pos_sy + 0.5f;
tile_vert v;
v.pos_x = pos_sx;
v.pos_y = pos_sy;
v.tex_x = tex_sx;
v.tex_y = tex_sy;
m_verts.push_back(v);
v.pos_y = pos_ey;
v.tex_y = tex_ey;
m_verts.push_back(v);
v.pos_x = pos_ex;
v.tex_x = tex_ex;
m_verts.push_back(v);
v.pos_y = pos_sy;
v.tex_y = tex_sy;
m_verts.push_back(v);
}
void InventoryRegion::pack_verts()
{
m_need_to_pack = false;
m_verts.clear();
// ensure the cursor has been placed
place_cursor(m_cursor);
// Pack base separately, as it comes from a different texture...
unsigned int i = 0;
for (unsigned int y = 0; y < my; y++)
{
if (i >= m_items.size())
break;
for (unsigned int x = 0; x < mx; x++)
{
if (i >= m_items.size())
break;
InventoryTile &item = m_items[i++];
if (item.flag & TILEI_FLAG_FLOOR)
add_quad(TEX_DUNGEON, get_floor_tile_idx()
+ m_flavour[i] % get_num_floor_flavors(), x, y);
else
add_quad(TEX_DUNGEON, TILE_ITEM_SLOT, x, y);
}
}
// Make note of how many verts are used by the base
m_base_verts = m_verts.size();
i = 0;
for (unsigned int y = 0; y < my; y++)
{
if (i >= m_items.size())
break;
for (unsigned int x = 0; x < mx; x++)
{
if (i >= m_items.size())
break;
InventoryTile &item = m_items[i++];
if (item.flag & TILEI_FLAG_EQUIP)
{
if (item.flag & TILEI_FLAG_CURSE)
add_quad(TEX_DEFAULT, TILE_ITEM_SLOT_EQUIP_CURSED, x, y);
else
add_quad(TEX_DEFAULT, TILE_ITEM_SLOT_EQUIP, x, y);
}
else if (item.flag & TILEI_FLAG_CURSE)
add_quad(TEX_DEFAULT, TILE_ITEM_SLOT_CURSED, x, y);
// TODO enne - need better graphic here
if (item.flag & TILEI_FLAG_SELECT)
add_quad(TEX_DEFAULT, TILE_ITEM_SLOT_SELECTED, x, y);
if (item.flag & TILEI_FLAG_CURSOR)
add_quad(TEX_DEFAULT, TILE_CURSOR, x, y);
if (item.tile)
add_quad(TEX_DEFAULT, item.tile, x, y);
if (item.quantity != -1)
{
unsigned int num = item.quantity;
// If you have that many, who cares.
if (num > 999)
num = 999;
const int offset_amount = TILE_X/4;
int offset = 0;
int help = num;
int c100 = help/100;
help -= c100*100;
if (c100)
{
add_quad_char('0' + c100, x, y, offset, 0);
offset += offset_amount;
}
int c10 = help/10;
if (c10 || c100)
{
add_quad_char('0' + c10, x, y, offset, 0);
offset += offset_amount;
}
int c1 = help % 10;
add_quad_char('0' + c1, x, y, offset, 0);
}
if (item.flag & TILEI_FLAG_TRIED)
add_quad_char('?', x, y, 0, TILE_Y / 2);
}
}
}
unsigned int InventoryRegion::cursor_index() const
{
ASSERT(m_cursor != NO_CURSOR);
return m_cursor.x + m_cursor.y * mx;
}
void InventoryRegion::place_cursor(const coord_def &cursor)
{
if (m_cursor != NO_CURSOR)
{
m_items[cursor_index()].flag &= ~TILEI_FLAG_CURSOR;
m_need_to_pack = true;
}
m_cursor = cursor;
if (m_cursor == NO_CURSOR || cursor_index() >= m_items.size())
return;
// Add cursor to new location
m_items[cursor_index()].flag |= TILEI_FLAG_CURSOR;
m_need_to_pack = true;
}
int InventoryRegion::handle_mouse(MouseEvent &event)
{
int cx, cy;
if (!mouse_pos(event.px, event.py, cx, cy))
{
place_cursor(NO_CURSOR);
return 0;
}
const coord_def cursor(cx, cy);
place_cursor(cursor);
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return 0;
if (event.event != MouseEvent::PRESS)
return 0;
// TODO enne - if mouse_mode is command, then:
unsigned int item_idx = cursor_index();
if (item_idx >= m_items.size() || m_items[item_idx].empty())
return 0;
int idx = m_items[item_idx].idx;
bool on_floor = m_items[item_idx].flag & TILEI_FLAG_FLOOR;
ASSERT(idx >= 0);
// TODO enne - this is all really only valid for the on-screen inventory
// Do we subclass inventoryregion for the onscreen and offscreen versions?
char key = m_items[item_idx].key;
if (key)
return key;
if (event.button == MouseEvent::LEFT)
{
if (on_floor)
{
if (event.mod & MOD_SHIFT)
tile_item_use_floor(idx);
else
tile_item_pickup(idx);
}
else
{
if (event.mod & MOD_SHIFT)
tile_item_drop(idx);
else if (event.mod & MOD_CTRL)
tile_item_use_secondary(idx);
else
tile_item_use(idx);
}
// TODO enne - need to redraw inventory here?
return CK_MOUSE_CMD;
}
else if (event.button == MouseEvent::RIGHT)
{
if (on_floor)
{
if (event.mod & MOD_SHIFT)
tile_item_eat_floor(idx);
else
describe_item(mitm[idx]);
}
else
{
describe_item(you.inv[idx]);
}
return CK_MOUSE_CMD;
}
return 0;
}
// NOTE: Assumes the item is equipped in the first place!
static bool _is_true_equipped_item(item_def item)
{
// Weapons and staves are only truly equipped if wielded.
if (item.link == you.equip[EQ_WEAPON])
return (item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES);
// Cursed armour and rings are only truly equipped if *not* wielded.
return (item.link != you.equip[EQ_WEAPON]);
}
// Returns whether there's any action you can take with an item in inventory
// apart from dropping it.
static bool _can_use_item(const item_def &item, bool equipped)
{
// Vampires can drain corpses.
if (item.base_type == OBJ_CORPSES)
{
return (you.species == SP_VAMPIRE
&& item.sub_type != CORPSE_SKELETON
&& !food_is_rotten(item)
&& mons_has_blood(item.plus));
}
if (equipped && item_cursed(item))
{
// Misc. items/rods can always be evoked, cursed or not.
if (item.base_type == OBJ_MISCELLANY || item_is_rod(item))
return true;
// You can't unwield/fire a wielded cursed weapon/staff
// but cursed armour and rings can be unwielded without problems.
return (!_is_true_equipped_item(item));
}
// Mummies can't do anything with food or potions.
if (you.species == SP_MUMMY)
return (item.base_type != OBJ_POTIONS && item.base_type != OBJ_FOOD);
// In all other cases you can use the item in some way.
return true;
}
bool InventoryRegion::update_tip_text(std::string& tip)
{
unsigned int item_idx = cursor_index();
if (item_idx >= m_items.size() || m_items[item_idx].empty())
return false;
int idx = m_items[item_idx].idx;
// TODO enne - consider subclassing this class, rather than depending
// on "key" to determine if this is the crt inventory or the on screen one.
bool display_actions = (m_items[item_idx].key == 0
&& mouse_control::current_mode() == MOUSE_MODE_COMMAND);
// TODO enne - should the command keys here respect keymaps?
if (m_items[item_idx].flag & TILEI_FLAG_FLOOR)
{
const item_def &item = mitm[idx];
tip = "";
if (m_items[item_idx].key)
{
tip = m_items[item_idx].key;
tip += " - ";
}
tip += item.name(DESC_NOCAP_A);
if (!display_actions)
return true;
tip += "\n[L-Click] Pick up (g)";
if (item.base_type == OBJ_CORPSES
&& item.sub_type != CORPSE_SKELETON
&& !food_is_rotten(item))
{
tip += "\n[Shift-L-Click] ";
if (can_bottle_blood_from_corpse(item.plus))
tip += "Bottle blood";
else
tip += "Chop up";
tip += " (c)";
if (you.species == SP_VAMPIRE)
tip += "\n\n[Shift-R-Click] Drink blood (e)";
}
else if (item.base_type == OBJ_FOOD
&& you.is_undead != US_UNDEAD
&& you.species != SP_VAMPIRE)
{
tip += "\n[Shift-R-Click] Eat (e)";
}
}
else
{
const item_def &item = you.inv[idx];
tip = item.name(DESC_INVENTORY_EQUIP);
if (!display_actions)
return true;
int type = item.base_type;
const bool equipped = m_items[item_idx].flag & TILEI_FLAG_EQUIP;
bool wielded = (you.equip[EQ_WEAPON] == idx);
const int EQUIP_OFFSET = NUM_OBJECT_CLASSES;
if (_can_use_item(item, equipped))
{
tip += "\n[L-Click] ";
if (equipped)
{
if (wielded && type != OBJ_MISCELLANY && !item_is_rod(item))
{
if (type == OBJ_JEWELLERY || type == OBJ_ARMOUR
|| type == OBJ_WEAPONS || type == OBJ_STAVES)
{
type = OBJ_WEAPONS + EQUIP_OFFSET;
}
}
else
type += EQUIP_OFFSET;
}
switch (type)
{
// first equipable categories
case OBJ_WEAPONS:
case OBJ_STAVES:
case OBJ_MISCELLANY:
tip += "Wield (w)";
if (is_throwable(item, player_size(PSIZE_BODY)))
tip += "\n[Ctrl-L-Click] Fire (f)";
break;
case OBJ_WEAPONS + EQUIP_OFFSET:
tip += "Unwield";
if (is_throwable(item, player_size(PSIZE_BODY)))
tip += "\n[Ctrl-L-Click] Fire (f)";
break;
case OBJ_MISCELLANY + EQUIP_OFFSET:
if (item.sub_type >= MISC_DECK_OF_ESCAPE
&& item.sub_type <= MISC_DECK_OF_DEFENCE)
{
tip += "Draw a card (v)";
tip += "\n[Ctrl-L-Click] Unwield";
break;
}
// else fall-through
case OBJ_STAVES + EQUIP_OFFSET: // rods - other staves handled above
tip += "Evoke (v)";
tip += "\n[Ctrl-L-Click] Unwield";
break;
case OBJ_ARMOUR:
tip += "Wear (W)";
break;
case OBJ_ARMOUR + EQUIP_OFFSET:
tip += "Take off (T)";
break;
case OBJ_JEWELLERY:
tip += "Put on (P)";
break;
case OBJ_JEWELLERY + EQUIP_OFFSET:
tip += "Remove (R)";
break;
case OBJ_MISSILES:
tip += "Fire (f)";
if (wielded)
tip += "\n[Ctrl-L-Click] Unwield";
else if ( item.sub_type == MI_STONE
&& player_knows_spell(SPELL_SANDBLAST)
|| item.sub_type == MI_ARROW
&& player_knows_spell(
SPELL_STICKS_TO_SNAKES) )
{
// For Sandblast and Sticks to Snakes,
// respectively.
tip += "\n[Ctrl-L-Click] Wield (w)";
}
break;
case OBJ_WANDS:
tip += "Zap (Z)";
if (wielded)
tip += "\n[Ctrl-L-Click] Unwield";
break;
case OBJ_BOOKS:
if (item_type_known(item)
&& item.sub_type != BOOK_MANUAL
&& item.sub_type != BOOK_DESTRUCTION)
{
tip += "Memorise (M)";
if (wielded)
tip += "\n[Ctrl-L-Click] Unwield";
break;
}
// else fall-through
case OBJ_SCROLLS:
tip += "Read (r)";
if (wielded)
tip += "\n[Ctrl-L-Click] Unwield";
break;
case OBJ_POTIONS:
tip += "Quaff (q)";
// For Sublimation of Blood.
if (wielded)
tip += "\n[Ctrl-L-Click] Unwield";
else if ( item_type_known(item)
&& is_blood_potion(item)
&& player_knows_spell(
SPELL_SUBLIMATION_OF_BLOOD) )
{
tip += "\n[Ctrl-L-Click] Wield (w)";
}
break;
case OBJ_FOOD:
tip += "Eat (e)";
// For Sublimation of Blood.
if (wielded)
tip += "\n[Ctrl-L-Click] Unwield";
else if (item.sub_type == FOOD_CHUNK
&& player_knows_spell(
SPELL_SUBLIMATION_OF_BLOOD))
{
tip += "\n[Ctrl-L-Click] Wield (w)";
}
break;
case OBJ_CORPSES:
if (you.species == SP_VAMPIRE)
tip += "Drink blood (e)";
if (wielded)
{
if (you.species == SP_VAMPIRE)
tip += EOL;
tip += "[Ctrl-L-Click] Unwield";
}
break;
default:
tip += "Use";
}
}
// For Boneshards.
// Special handling since skeletons have no primary action.
if (item.base_type == OBJ_CORPSES
&& item.sub_type == CORPSE_SKELETON)
{
if (wielded)
tip += "\n[Ctrl-L-Click] Unwield";
else if (player_knows_spell(SPELL_BONE_SHARDS))
tip += "\n[Ctrl-L-Click] Wield (w)";
}
tip += "\n[R-Click] Info";
// Has to be non-equipped or non-cursed to drop.
if (!equipped || !_is_true_equipped_item(you.inv[idx])
|| !item_cursed(you.inv[idx]))
{
tip += "\n[Shift-L-Click] Drop (d)";
}
}
return true;
}
MapRegion::MapRegion(unsigned int pixsz) :
m_buf(NULL),
m_far_view(false)
{
dx = pixsz;
dy = pixsz;
clear();
init_colours();
}
void MapRegion::on_resize()
{
delete[] m_buf;
int size = mx * my;
m_buf = new unsigned char[size];
memset(m_buf, 0, sizeof(unsigned char) * size);
}
void MapRegion::init_colours()
{
// TODO enne - the options array for colours should be
// tied to the map feature enumeration to avoid this function.
m_colours[MF_UNSEEN] = (map_colour)Options.tile_unseen_col;
m_colours[MF_FLOOR] = (map_colour)Options.tile_floor_col;
m_colours[MF_WALL] = (map_colour)Options.tile_wall_col;
m_colours[MF_MAP_FLOOR] = (map_colour)Options.tile_floor_col; // TODO enne
m_colours[MF_MAP_WALL] = (map_colour)Options.tile_mapped_wall_col;
m_colours[MF_DOOR] = (map_colour)Options.tile_door_col;
m_colours[MF_ITEM] = (map_colour)Options.tile_item_col;
m_colours[MF_MONS_HOSTILE] = (map_colour)Options.tile_monster_col;
m_colours[MF_MONS_FRIENDLY] = (map_colour)Options.tile_friendly_col;
m_colours[MF_MONS_NEUTRAL] = (map_colour)Options.tile_neutral_col;
m_colours[MF_MONS_NO_EXP] = (map_colour)Options.tile_plant_col;
m_colours[MF_STAIR_UP] = (map_colour)Options.tile_upstairs_col;
m_colours[MF_STAIR_DOWN] = (map_colour)Options.tile_downstairs_col;
m_colours[MF_STAIR_BRANCH] = (map_colour)Options.tile_feature_col;
m_colours[MF_FEATURE] = (map_colour)Options.tile_feature_col;
m_colours[MF_WATER] = (map_colour)Options.tile_water_col;
m_colours[MF_LAVA] = (map_colour)Options.tile_lava_col;
m_colours[MF_TRAP] = (map_colour)Options.tile_trap_col;
m_colours[MF_EXCL_ROOT] = (map_colour)Options.tile_excl_centre_col;
m_colours[MF_EXCL] = (map_colour)Options.tile_excluded_col;
m_colours[MF_PLAYER] = (map_colour)Options.tile_player_col;
}
MapRegion::~MapRegion()
{
delete[] m_buf;
}
struct map_vertex
{
float x;
float y;
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
void MapRegion::render()
{
if (m_min_gx > m_max_gx || m_min_gy > m_max_gy)
return;
// [enne] - GL_POINTS should probably be used here, but there's (apparently)
// a bug in the OpenGL driver that I'm using and it doesn't respect
// glPointSize unless GL_SMOOTH_POINTS is on. GL_SMOOTH_POINTS is
// *terrible* for performance if it has to fall back on software rendering,
// so instead we'll just make quads.
glLoadIdentity();
glTranslatef(sx + ox, sy + oy, 0);
glScalef(dx, dx, 1);
std::vector<map_vertex> verts;
verts.reserve(4 * (m_max_gx - m_min_gx + 1) * (m_max_gy - m_min_gy + 1));
for (unsigned int x = m_min_gx; x <= m_max_gx; x++)
{
for (unsigned int y = m_min_gy; y <= m_max_gy; y++)
{
map_feature f = (map_feature)m_buf[x + y * mx];
map_colour c = m_colours[f];
unsigned int pos_x = x - m_min_gx;
unsigned int pos_y = y - m_min_gy;
map_vertex v;
v.r = map_colours[c][0];
v.g = map_colours[c][1];
v.b = map_colours[c][2];
v.a = 255;
v.x = pos_x;
v.y = pos_y;
verts.push_back(v);
v.x = pos_x;
v.y = pos_y + 1;
verts.push_back(v);
v.x = pos_x + 1;
v.y = pos_y + 1;
verts.push_back(v);
v.x = pos_x + 1;
v.y = pos_y;
verts.push_back(v);
}
}
GLState state;
state.array_vertex = true;
state.array_colour = true;
GLStateManager::set(state);
glVertexPointer(2, GL_FLOAT, sizeof(map_vertex), &verts[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(map_vertex), &verts[0].r);
glDrawArrays(GL_QUADS, 0, verts.size());
// TODO enne - make sure we're drawing within the map square here...
// Draw window box.
if (m_win_start.x == -1 && m_win_end.x == -1)
return;
verts.clear();
glLoadIdentity();
glTranslatef(sx + ox, sy + oy, 0);
map_vertex v;
int c = (int)Options.tile_window_col;
v.r = map_colours[c][0];
v.g = map_colours[c][1];
v.b = map_colours[c][2];
v.a = 255;
v.x = (int)dx * (m_win_start.x - (int)m_min_gx);
v.y = (int)dy * (m_win_start.y - (int)m_min_gy);
verts.push_back(v);
v.y = (int)dy * (m_win_end.y - (int)m_min_gy) + 1;
verts.push_back(v);
v.x = (int)dx * (m_win_end.x - (int)m_min_gx) + 1;
verts.push_back(v);
v.y = (int)dy * (m_win_start.y - (int)m_min_gy);
verts.push_back(v);
glVertexPointer(2, GL_FLOAT, sizeof(map_vertex), &verts[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(map_vertex), &verts[0].r);
glDrawArrays(GL_LINE_LOOP, 0, verts.size());
}
void MapRegion::update_offsets()
{
// adjust offsets to center map
ox = (wx - dx * (m_max_gx - m_min_gx)) / 2;
oy = (wy - dy * (m_max_gy - m_min_gy)) / 2;
}
void MapRegion::set(unsigned int gx, unsigned int gy, map_feature f)
{
ASSERT((unsigned int)f <= (unsigned char)~0);
m_buf[gx + gy * mx] = f;
if (f == MF_UNSEEN)
return;
// Get map extents
m_min_gx = std::min(m_min_gx, gx);
m_max_gx = std::max(m_max_gx, gx);
m_min_gy = std::min(m_min_gy, gy);
m_max_gy = std::max(m_max_gy, gy);
update_offsets();
}
void MapRegion::set_window(const coord_def &start, const coord_def &end)
{
m_win_start = start;
m_win_end = end;
}
void MapRegion::clear()
{
m_min_gx = GXM;
m_max_gx = 0;
m_min_gy = GYM;
m_max_gy = 0;
m_win_start.x = -1;
m_win_start.y = -1;
m_win_end.x = -1;
m_win_end.y = -1;
update_offsets();
if (m_buf)
memset(m_buf, 0, sizeof(*m_buf) * mx * my);
}
int MapRegion::handle_mouse(MouseEvent &event)
{
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return 0;
int cx;
int cy;
if (!mouse_pos(event.px, event.py, cx, cy))
{
if (m_far_view)
{
m_far_view = false;
tiles.load_dungeon(you.pos().x, you.pos().y);
return 0;
}
return 0;
}
const coord_def gc(m_min_gx + cx, m_min_gy + cy);
tiles.place_cursor(CURSOR_MOUSE, gc);
switch (event.event)
{
case MouseEvent::MOVE:
if (m_far_view)
tiles.load_dungeon(gc.x, gc.y);
return 0;
case MouseEvent::PRESS:
if (event.button == MouseEvent::LEFT)
{
if (!in_bounds(gc))
return 0;
start_travel(gc.x, gc.y);
}
else if (event.button == MouseEvent::RIGHT)
{
m_far_view = true;
tiles.load_dungeon(gc.x, gc.y);
}
return CK_MOUSE_CMD;
case MouseEvent::RELEASE:
if ((event.button == MouseEvent::RIGHT) && m_far_view)
{
tiles.load_dungeon(you.pos().x, you.pos().y);
}
return 0;
default:
return 0;
}
}
bool MapRegion::update_tip_text(std::string& tip)
{
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return false;
tip = "[L-Click] Travel / [R-Click] View";
return true;
}
void TextRegion::scroll()
{
for (unsigned int idx = 0; idx < mx*(my-1); idx++)
{
cbuf[idx] = cbuf[idx + mx];
abuf[idx] = abuf[idx + mx];
}
for (unsigned int idx = mx*(my-1); idx < mx*my; idx++)
{
cbuf[idx] = ' ';
abuf[idx] = 0;
}
if (print_y > 0)
print_y -= 1;
if (cursor_y > 0)
cursor_y -= 1;
}
TextRegion::TextRegion(FTFont *font) :
cbuf(NULL),
abuf(NULL),
cx_ofs(0),
cy_ofs(0),
m_font(font)
{
ASSERT(font);
dx = m_font->char_width();
dy = m_font->char_height();
// TODO enne - gah!
dx = 8;
}
void TextRegion::on_resize()
{
delete cbuf;
delete abuf;
unsigned int size = mx * my;
cbuf = new unsigned char[size];
abuf = new unsigned char[size];
for (unsigned int i = 0; i < size; i++)
{
cbuf[i] = ' ';
abuf[i] = 0;
}
}
TextRegion::~TextRegion()
{
delete[] cbuf;
delete[] abuf;
}
void TextRegion::adjust_region(int *x1, int *x2, int y)
{
*x2 = *x2 + 1;
}
void TextRegion::addstr(char *buffer)
{
char buf2[1024];
int len = strlen(buffer);
int j = 0;
for (int i = 0; i < len + 1; i++)
{
char c = buffer[i];
bool newline = false;
if (c == '\n' || c == '\r')
{
c = 0;
newline = true;
if (buffer[i+1] == '\n' || buffer[i+1] == '\r')
i++;
}
buf2[j] = c;
j++;
if (c == 0)
{
if (j-1 != 0)
addstr_aux(buf2, j - 1); // draw it
if (newline)
{
print_x = cx_ofs;
print_y++;
j = 0;
if (print_y - cy_ofs == my)
scroll();
}
}
}
if (cursor_flag)
cgotoxy(print_x+1, print_y+1);
}
void TextRegion::addstr_aux(char *buffer, unsigned int len)
{
int x = print_x - cx_ofs;
int y = print_y - cy_ofs;
int adrs = y * mx;
int head = x;
int tail = x + len - 1;
adjust_region(&head, &tail, y);
for (unsigned int i = 0; i < len && x + i < mx; i++)
{
cbuf[adrs+x+i] = buffer[i];
abuf[adrs+x+i] = text_col;
}
print_x += len;
}
void TextRegion::clear_to_end_of_line()
{
int cx = print_x - cx_ofs;
int cy = print_y - cy_ofs;
int col = text_col;
int adrs = cy * mx;
ASSERT(adrs + mx - 1 < mx * my);
for (unsigned int i = cx; i < mx; i++)
{
cbuf[adrs+i] = ' ';
abuf[adrs+i] = col;
}
}
void TextRegion::putch(unsigned char ch)
{
if (ch == 0)
ch=32;
addstr_aux((char *)&ch, 1);
}
void TextRegion::writeWChar(unsigned char *ch)
{
addstr_aux((char *)ch, 2);
}
void TextRegion::textcolor(int color)
{
text_col = color;
}
void TextRegion::textbackground(int col)
{
textcolor(col*16 + (text_col & 0xf));
}
void TextRegion::cgotoxy(int x, int y)
{
ASSERT(x >= 1);
ASSERT(y >= 1);
print_x = x-1;
print_y = y-1;
if (cursor_region != NULL && cursor_flag)
{
cursor_region ->erase_cursor();
cursor_region = NULL;
}
if (cursor_flag)
{
text_mode->draw_cursor(print_x, print_y);
cursor_x = print_x;
cursor_y = print_y;
cursor_region = text_mode;
}
}
int TextRegion::wherex()
{
return print_x + 1;
}
int TextRegion::wherey()
{
return print_y + 1;
}
void TextRegion::_setcursortype(int curstype)
{
cursor_flag = curstype;
if (cursor_region != NULL)
cursor_region->erase_cursor();
if (curstype)
{
text_mode->draw_cursor(print_x, print_y);
cursor_x = print_x;
cursor_y = print_y;
cursor_region = text_mode;
}
}
void TextRegion::draw_cursor(int x, int y)
{
// TODO enne
}
void TextRegion::erase_cursor()
{
// TODO enne
}
void TextRegion::render()
{
m_font->render_textblock(sx + ox, sy + oy, cbuf, abuf, mx, my);
}
void TextRegion::clear()
{
for (unsigned int i = 0; i < mx * my; i++)
{
cbuf[i] = ' ';
abuf[i] = 0;
}
}
StatRegion::StatRegion(FTFont *font) : TextRegion(font)
{
}
int StatRegion::handle_mouse(MouseEvent &event)
{
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return 0;
if (!inside(event.px, event.py))
return 0;
if (event.event != MouseEvent::PRESS || event.button != MouseEvent::LEFT)
return 0;
// Resting
return '5';
}
bool StatRegion::update_tip_text(std::string& tip)
{
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return false;
tip = "[L-Click] Rest / Search for a while";
return true;
}
MessageRegion::MessageRegion(FTFont *font) : TextRegion(font)
{
}
int MessageRegion::handle_mouse(MouseEvent &event)
{
// TODO enne - mouse scrolling here should mouse scroll up through
// the message history in the message pane, without going to the CRT.
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return 0;
if (!inside(event.px, event.py))
return 0;
if (event.event != MouseEvent::PRESS || event.button != MouseEvent::LEFT)
return 0;
return CONTROL('P');
}
bool MessageRegion::update_tip_text(std::string& tip)
{
if (mouse_control::current_mode() != MOUSE_MODE_COMMAND)
return false;
tip = "[L-Click] Browse message history";
return true;
}
CRTRegion::CRTRegion(FTFont *font) : TextRegion(font)
{
}
int CRTRegion::handle_mouse(MouseEvent &event)
{
// TODO enne - clicking on menu items? We could probably
// determine which items were clicked based on text size.
return 0;
}
ImageManager::ImageManager()
{
}
ImageManager::~ImageManager()
{
unload_textures();
}
bool ImageManager::load_textures()
{
GenericTexture::MipMapOptions mip = GenericTexture::MIPMAP_CREATE;
if (!m_textures[TEX_DUNGEON].load_texture("dngn.png", mip))
return false;
if (!m_textures[TEX_DOLL].load_texture("player.png", mip))
return false;
if (!m_textures[TEX_TITLE].load_texture("title.png", mip))
return false;
return true;
}
static void _copy_onto(unsigned char *pixels, unsigned int width,
unsigned int height, unsigned char *src,
int idx, bool blend)
{
const unsigned int tile_size = 32;
const unsigned int tiles_per_row = width / tile_size;
unsigned int row = idx / tiles_per_row;
unsigned int col = idx % tiles_per_row;
unsigned char *dest = &pixels[4 * 32 * (row * width + col)];
size_t dest_row_size = width * 4;
size_t src_row_size = 32 * 4;
if (blend)
{
for (unsigned int r = 0; r < 32; r++)
{
for (unsigned int c = 0; c < 32; c++)
{
unsigned char a = src[3];
unsigned char inv_a = 255 - src[3];
dest[0] = (src[0] * a + dest[0] * inv_a) / 255;
dest[1] = (src[1] * a + dest[1] * inv_a) / 255;
dest[2] = (src[2] * a + dest[2] * inv_a) / 255;
dest[3] = (src[3] * a + dest[3] * inv_a) / 255;
dest += 4;
src += 4;
}
dest += dest_row_size - src_row_size;
}
}
else
{
for (unsigned int r = 0; r < 32; r++)
{
memcpy(dest, src, src_row_size);
dest += dest_row_size;
src += src_row_size;
}
}
}
// Copy a 32x32 image at index idx from pixels into dest.
static void _copy_into(unsigned char *dest, unsigned char *pixels,
unsigned int width,
unsigned int height, int idx)
{
const unsigned int tile_size = 32;
const unsigned int tiles_per_row = width / tile_size;
unsigned int row = idx / tiles_per_row;
unsigned int col = idx % tiles_per_row;
unsigned char *src = &pixels[4 * 32 * (row * width + col)];
size_t src_row_size = width * 4;
size_t dest_row_size = 32 * 4;
for (unsigned int r = 0; r < 32; r++)
{
memcpy(dest, src, dest_row_size);
dest += dest_row_size;
src += src_row_size;
}
}
// Stores "over" on top of "under" in the location of "over".
static void _copy_under(unsigned char *pixels, unsigned int width,
unsigned int height, int idx_under, int idx_over)
{
size_t image_size = 32 * 32 * 4;
// Make a copy of the original images on the stack.
unsigned char *under = new unsigned char[image_size];
_copy_into(under, pixels, width, height, idx_under);
unsigned char *over = new unsigned char[image_size];
_copy_into(over, pixels, width, height, idx_over);
// Replace the over image with the under image
_copy_onto(pixels, width, height, under, idx_over, false);
// Blend the over image over top.
_copy_onto(pixels, width, height, over, idx_over, true);
delete[] under;
delete[] over;
}
static bool _process_item_image(unsigned char *pixels,
unsigned int width, unsigned int height)
{
for (int i = 0; i < NUM_POTIONS; i++)
{
int special = you.item_description[IDESC_POTIONS][i];
int tile0 = TILE_POTION_OFFSET + special % 14;
int tile1 = TILE_POT_HEALING + i;
_copy_under(pixels, width, height, tile0, tile1);
}
for (int i = 0; i < NUM_WANDS; i++)
{
int special = you.item_description[IDESC_WANDS][i];
int tile0 = TILE_WAND_OFFSET + special % 12;
int tile1 = TILE_WAND_FLAME + i;
_copy_under(pixels, width, height, tile0, tile1);
}
for (int i = 0; i < STAFF_SMITING; i++)
{
int special = you.item_description[IDESC_STAVES][i];
int tile0 = TILE_STAFF_OFFSET + (special / 4) % 10;
int tile1 = TILE_STAFF_WIZARDRY + i;
_copy_under(pixels, width, height, tile0, tile1);
}
for (int i = STAFF_SMITING; i < NUM_STAVES; i++)
{
int special = you.item_description[IDESC_STAVES][i];
int tile0 = TILE_ROD_OFFSET + (special / 4) % 10;
int tile1 = TILE_ROD_SMITING + i - STAFF_SMITING;
_copy_under(pixels, width, height, tile0, tile1);
}
return true;
}
bool ImageManager::load_item_texture()
{
// We need to load images in two passes: one for the title and one
// for the items. To handle identifiable items, the texture itself
// is modified. So, it cannot be loaded until after the item
// description table has been initialised.
GenericTexture::MipMapOptions mip = GenericTexture::MIPMAP_CREATE;
return m_textures[TEX_DEFAULT].load_texture("tile.png", mip,
&_process_item_image);
}
void ImageManager::unload_textures()
{
for (unsigned int i = 0; i < TEX_MAX; i++)
{
m_textures[i].unload_texture();
}
}
struct mcache_entry
{
int mon_tile;
int equ_tile;
int draco;
};
std::vector<mcache_entry> mcache;
int get_base_idx_from_mcache(int tile_idx)
{
int mcache_idx = tile_idx - TILE_MCACHE_START;
if (mcache_idx >= 0 && mcache_idx < (int)mcache.size())
{
return mcache[mcache_idx].mon_tile;
}
return tile_idx;
}
bool get_mcache_entry(int tile_idx, int &mon_idx, int &equ_tile, int &draco)
{
int mcache_idx = tile_idx - TILE_MCACHE_START;
if (mcache_idx >= 0 && (unsigned int)mcache_idx < mcache.size())
{
mon_idx = mcache[mcache_idx].mon_tile;
equ_tile = mcache[mcache_idx].equ_tile;
draco = mcache[mcache_idx].draco;
return true;
}
return false;
}
static int _mcache_register(int mon_tile, int equ_tile, int draco = 0)
{
mcache_entry entry;
entry.mon_tile = mon_tile;
entry.equ_tile = equ_tile;
entry.draco = draco;
env.tile_flavor[x][y].floor = floor_flavor;
env.tile_flavor[x][y].wall = wall_flavor;
env.tile_flv[x][y].floor = get_floor_tile_idx() + floor_flavor;
env.tile_flv[x][y].wall = get_wall_tile_idx() + wall_flavor;
if (env.tile_flavor[x][y].special != SPECIAL_N
&& env.tile_flavor[x][y].special != SPECIAL_S
&& env.tile_flavor[x][y].special != SPECIAL_E
&& env.tile_flavor[x][y].special != SPECIAL_W)
if (env.tile_flv[x][y].special != SPECIAL_N
&& env.tile_flv[x][y].special != SPECIAL_S
&& env.tile_flv[x][y].special != SPECIAL_E
&& env.tile_flv[x][y].special != SPECIAL_W)
wall_flv = env.tile_flavor[gx][gy].wall;
floor_flv = env.tile_flavor[gx][gy].floor;
special_flv = env.tile_flavor[gx][gy].special;
wall_flv = env.tile_flv[gx][gy].wall;
floor_flv = env.tile_flv[gx][gy].floor;
special_flv = env.tile_flv[gx][gy].special;
void tile_draw_dungeon(unsigned int *tileb)
{
tile_finish_dngn(tileb, you.x_pos, you.y_pos);
TileDrawDungeon(tileb);
}
#define swapint(a, b) {int tmp = a; a = b; b = tmp;}
// Item is unided(1) or tried(2) or id'ed (0)
static int _item_unid_type(const item_def &item)
{
if ((item.flags & ISFLAG_KNOW_TYPE) != 0)
return 0;
const int s = item.sub_type;
const id_arr& id = get_typeid_array();
int id0 = 0;
switch (item.base_type)
{
case OBJ_STAVES:
id0 = id[ IDTYPE_STAVES ][s];
if (id0 != ID_KNOWN_TYPE)
return 1;
else
return 0;
case OBJ_SCROLLS:
id0 = id[ IDTYPE_SCROLLS ][s];
break;
case OBJ_WANDS:
id0 = id[ IDTYPE_WANDS ][s];
break;
case OBJ_POTIONS:
id0 = id[ IDTYPE_POTIONS ][s];
break;
case OBJ_JEWELLERY:
if (is_artefact(item))
{
if (item.props.exists("jewellery_tried")
&& item.props["jewellery_tried"].get_bool())
{
return 2;
}
return 1;
}
id0 = id[ IDTYPE_JEWELLERY ][s];
break;
default:
return 0;
}
if (id0 == ID_TRIED_TYPE)
return 2;
else if (id0 != ID_KNOWN_TYPE)
return 1;
return 0;
}
// Helper routine: sort floor item index and pack into idx.
static int _pack_floor_item(int *idx, int *flag, int *isort, int max)
{
int n = 0;
static int isort_weapon2[NUM_WEAPONS];
static int isort_armour2[NUM_ARMOURS];
static const int isort_weapon[NUM_WEAPONS] =
{
WPN_WHIP, WPN_CLUB, WPN_HAMMER, WPN_MACE,
WPN_FLAIL, WPN_DEMON_WHIP,
WPN_ANKUS, WPN_MORNINGSTAR, WPN_EVENINGSTAR,
WPN_SPIKED_FLAIL, WPN_GREAT_MACE, WPN_DIRE_FLAIL,
WPN_GIANT_CLUB, WPN_GIANT_SPIKED_CLUB,
WPN_KNIFE, WPN_DAGGER, WPN_SHORT_SWORD, WPN_SABRE, WPN_QUICK_BLADE,
WPN_FALCHION, WPN_LONG_SWORD, WPN_SCIMITAR, WPN_KATANA,
WPN_DEMON_BLADE, WPN_DOUBLE_SWORD, WPN_GREAT_SWORD, WPN_TRIPLE_SWORD,
WPN_HAND_AXE, WPN_WAR_AXE, WPN_BROAD_AXE,
WPN_BATTLEAXE, WPN_EXECUTIONERS_AXE,
WPN_SPEAR, WPN_TRIDENT, WPN_HALBERD, WPN_SCYTHE,
WPN_GLAIVE, WPN_DEMON_TRIDENT,
WPN_QUARTERSTAFF,
WPN_SLING, WPN_BOW, WPN_CROSSBOW, WPN_HAND_CROSSBOW
};
static const int isort_armour[NUM_ARMOURS] =
{
ARM_ROBE,
ARM_ANIMAL_SKIN,
ARM_LEATHER_ARMOUR,
ARM_TROLL_LEATHER_ARMOUR,
ARM_RING_MAIL, ARM_SCALE_MAIL, ARM_CHAIN_MAIL,
ARM_SPLINT_MAIL, ARM_BANDED_MAIL, ARM_PLATE_MAIL,
ARM_CRYSTAL_PLATE_MAIL,
ARM_SWAMP_DRAGON_ARMOUR,
ARM_MOTTLED_DRAGON_ARMOUR,
ARM_STEAM_DRAGON_ARMOUR,
ARM_DRAGON_ARMOUR,
ARM_ICE_DRAGON_ARMOUR,
ARM_STORM_DRAGON_ARMOUR,
ARM_GOLD_DRAGON_ARMOUR,
ARM_TROLL_HIDE,
ARM_SWAMP_DRAGON_HIDE,
ARM_MOTTLED_DRAGON_HIDE,
ARM_STEAM_DRAGON_HIDE,
ARM_DRAGON_HIDE,
ARM_ICE_DRAGON_HIDE,
ARM_STORM_DRAGON_HIDE,
ARM_GOLD_DRAGON_HIDE,
ARM_CLOAK,
ARM_BUCKLER, ARM_SHIELD, ARM_LARGE_SHIELD,
ARM_HELMET, ARM_GLOVES, ARM_BOOTS
};
for (int i = 0; i < NUM_WEAPONS; i++)
isort_weapon2[isort_weapon[i]] = i;
for (int i = 0; i < NUM_ARMOURS; i++)
isort_armour2[isort_armour[i]] = i;
int o = igrd[you.x_pos][you.y_pos];
if (o == NON_ITEM) return 0;
while (o != NON_ITEM)
{
int id0 = _item_unid_type(mitm[o]);
int next = mitm[o].link;
int typ = mitm[o].base_type;
if (n >= max) break;
idx[n] = o;
isort[n] = typ * 256 * 3;
if (typ == OBJ_WEAPONS)
{
isort[n] += 3 * isort_weapon2[ mitm[o].sub_type];
}
if (typ == OBJ_ARMOUR)
{
isort[n] += 3 * isort_armour2[ mitm[o].sub_type ];
}
flag[n] = 0;
if (item_ident( mitm[o], ISFLAG_KNOW_CURSE ) &&
item_cursed(mitm[o]))
{
flag[n] |= TILEI_FLAG_CURSE;
}
if (id0 != 0)
{
isort[n] += id0;
if (id0 == 2)
flag[n] = TILEI_FLAG_TRIED;
}
flag[n] |= TILEI_FLAG_FLOOR;
// Simple Bubble sort
int k = n;
while (k > 0 && isort[k-1] > isort[k])
{
swapint(idx[k-1], idx[k]);
swapint(isort[k-1], isort[k]);
swapint(flag[k-1], flag[k]);
k--;
}
n++;
o = next;
}
return n;
}
// Helper routine: Calculate tile index and quantity data to be displayed
static void _finish_inven_data(int n, int *tiles, int *num, int *idx,
int *iflag)
{
int i;
for (i = 0; i < n; i++)
{
int q = -1;
int j = idx[i];
item_def *itm;
if (j == -1)
{
num[i] = -1;
tiles[i] = 0;
continue;
}
if (iflag[i] & TILEI_FLAG_FLOOR)
itm = &mitm[j];
else
itm = &you.inv[j];
int type = itm->base_type;
if (type == OBJ_FOOD || type == OBJ_SCROLLS
|| type == OBJ_POTIONS || type == OBJ_MISSILES)
{
q = itm->quantity;
}
if (q == 1)
q = -1;
if (type == OBJ_WANDS
&& ((itm->flags & ISFLAG_KNOW_PLUSES)
|| itm->plus2 == ZAPCOUNT_EMPTY))
{
q = itm->plus;
}
tiles[i] = tileidx_item(*itm);
num[i] = q;
}
}
// Display Inventory/floor items
#include "guic.h"
extern TileRegionClass *region_item;
extern TileRegionClass *region_item2;
extern WinClass *win_main;
void tile_draw_inv(int flag)
{
// "inventory" including items on floor
#define MAXINV 200
int tiles[MAXINV];
int num[MAXINV];
int idx[MAXINV];
int iflag[MAXINV];
int isort[MAXINV];
if (flag == -1)
{
flag = (win_main->active_layer == 0) ? REGION_INV1
: REGION_INV2;
}
TileRegionClass *r = (flag == REGION_INV1) ? region_item
: region_item2;
int numInvTiles = r->mx * r->my;
if (numInvTiles > MAXINV)
numInvTiles = MAXINV;
// Show one row of ground tiles, no matter what. This may cause some
// items not to show up, but theoretically you've ordered tile_show_items
// to prioritize the important stuff.
int max_inventory_items = std::min(numInvTiles - r->mx, ENDOFPACK);
// which items to show in inventory
const char *item_chars = Options.tile_show_items;
// show no items, please
if (item_chars[0] == 0)
return;
int eq_flag[ENDOFPACK];
int empty = 0; // counts empty slots
// first set eq_flag = 1 for all slots that actually hold valid items
// XXX: Why? --jpeg
for (int i = 0; i < max_inventory_items; i++)
{
eq_flag[i] =
(you.inv[i].quantity != 0 && is_valid_item( you.inv[i])) ? 1 : 0;
if (!eq_flag[i])
empty++;
}
// next, increase eq_flag to 2 if it's actually equipped
// FIX ME: Doesn't check for sensible equipment, i.e.
// wielded armour counts, too
for (int eq = 0; eq < NUM_EQUIP; eq++)
{
int slot = you.equip[eq];
if (slot >= 0 && slot < ENDOFPACK)
eq_flag[slot] = 2;
}
int n = 0;
// item.base_type <-> char conversion table
const static char *obj_syms = ")([/%#?=!#+\\0}x";
for (int i = 0; i < (int)strlen(item_chars); i++)
{
int top = n;
char ic = item_chars[i];
if (n >= numInvTiles)
break;
// Items on the floor
if (ic == '.')
{
n += _pack_floor_item(&idx[n], &iflag[n], &isort[n],
numInvTiles - n);
continue;
}
// empty slots
if (ic == '_')
{
for (int j = 0; j < empty && n < numInvTiles; j++)
{
idx[n] = -1;
iflag[n] = 0;
n++;
}
continue;
}
// convert item char to item type
int type = -1;
for (int j = 0; j < (int)strlen(obj_syms); j++)
{
if (obj_syms[j] == ic)
{
type = j;
break;
}
}
if (type == -1)
continue;
for (int j = 0; j < max_inventory_items && n < numInvTiles; j++)
{
if (you.inv[j].base_type == type && eq_flag[j] != 0)
{
int sval = NUM_EQUIP + you.inv[j].sub_type;
int base = 0;
int id0 = _item_unid_type(you.inv[j]);
idx[n] = j;
iflag[n] = 0;
if (type == OBJ_JEWELLERY && sval >= AMU_RAGE)
{
base = 1000;
sval = base + sval;
}
if (id0 == 2)
{
iflag[n] |= TILEI_FLAG_TRIED;
// To the tail
sval = base + 980;
}
else if (id0 == 1)
{
// To the tail
sval = base + 990;
}
// Equipment first
if (eq_flag[j] == 2)
{
//sval = base;
iflag[n] |= TILEI_FLAG_EQUIP;
}
if (item_cursed(you.inv[j])
&& item_ident( you.inv[j], ISFLAG_KNOW_CURSE ))
{
iflag[n] |= TILEI_FLAG_CURSE;
}
if (flag == REGION_INV2)
sval = j;
isort[n] = sval;
int k = n;
while (k > top && isort[k-1] > isort[k])
{
swapint(idx[k-1], idx[k]);
swapint(isort[k-1], isort[k]);
swapint(iflag[k-1], iflag[k]);
k--;
}
n++;
} // type == base
} // j
} // i
_finish_inven_data(n, tiles, num, idx, iflag);
for (int i = n; i < numInvTiles; i++)
{
tiles[i] = 0;
num[i] = 0;
idx[i] = -1;
iflag[i] = 0;
}
TileDrawInvData(n, flag, tiles, num, idx, iflag);
}
/*
* File: tilefont.h
* Created by: ennewalker on Sat Jan 5 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: ennewalker $ on $Date: 2008-03-07 $
*/
#ifndef TILEFONT_H
#define TILEFONT_H
#include "AppHdr.h"
#include "externs.h"
#include "tiletex.h"
// This class handles loading FreeType2 fonts and rendering them via OpenGL.
// TODO enne - Fonts could be made better by:
//
// * handling kerning
//
// * the possibility of streaming this class in and out so that Crawl doesn't
// have to link against FreeType2 or be forced do as much processing at
// load time.
class FTFont
{
public:
FTFont();
virtual ~FTFont();
bool load_font(const char *font_name, unsigned int font_size);
// render just text
void render_textblock(unsigned int x, unsigned int y,
unsigned char *chars, unsigned char *colours,
unsigned int width, unsigned int height,
bool drop_shadow = false);
// render text + background box
void render_string(unsigned int x, unsigned int y, const char *text,
const coord_def &min_pos, const coord_def &max_pos,
unsigned char font_colour, bool drop_shadow = false,
unsigned char box_alpha = 0,
unsigned char box_colour = 0, unsigned int outline = 0);
unsigned int char_width() const { return m_max_advance.x; }
unsigned int char_height() const { return m_max_advance.y; }
protected:
struct GlyphInfo
{
// offset before drawing glyph; can be negative
int offset;
// per-glyph horizontal advance
int advance;
bool renderable;
};
GlyphInfo *m_glyphs;
// cached value of the maximum advance from m_advance
coord_def m_max_advance;
// minimum offset (likely negative)
int m_min_offset;
GenericTexture m_tex;
};
#endif
/*
* File: tilefont.cc
* Created by: ennewalker on Sat Apr 26 01:33:53 2008 UTC
*
* Modified for Crawl Reference by $Author: ennewalker $ on $Date: 2008-03-07 $
*/
#include "tilefont.h"
#include "defines.h"
#include <SDL.h>
#include <SDL_opengl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
const unsigned char term_colours[MAX_TERM_COLOUR][3] =
{
{ 0, 0, 0}, // BLACK
{ 0, 82, 255}, // BLUE
{100, 185, 70}, // GREEN
{ 0, 180, 180}, // CYAN
{255, 48, 0}, // RED
{238, 92, 238}, // MAGENTA
{165, 91, 0}, // BROWN
{162, 162, 162}, // LIGHTGREY
{ 82, 82, 82}, // DARKGREY
{ 82, 102, 255}, // LIGHTBLUE
{ 82, 255, 82}, // LIGHTGREEN
{ 82, 255, 255}, // LIGHTCYAN
{255, 82, 82}, // LIGHTRED
{255, 82, 255}, // LIGHTMAGENTA
{255, 255, 82}, // YELLOW
{255, 255, 255} // WHITE
};
FTFont::FTFont() :
m_glyphs(NULL),
m_max_advance(0, 0),
m_min_offset(0)
{
}
FTFont::~FTFont()
{
delete[] m_glyphs;
}
bool FTFont::load_font(const char *font_name, unsigned int font_size)
{
FT_Library library;
FT_Face face;
FT_Error error;
error = FT_Init_FreeType(&library);
if (error)
{
fprintf(stderr, "Failed to initialize freetype library.\n");
return false;
}
error = FT_New_Face(library, font_name, 0, &face);
if (error == FT_Err_Unknown_File_Format)
{
fprintf(stderr, "Unknown font format for file '%s'\n", font_name);
return false;
}
else if (error)
{
fprintf(stderr, "Invalid font from file '%s'\n", font_name);
}
error = FT_Set_Pixel_Sizes(face, font_size, font_size);
ASSERT(!error);
// Get maximum advance
m_max_advance = coord_def(0,0);
int ascender = face->ascender >> 6;
int min_y = 100000; // TODO enne - fix me
int max_y = 0;
m_min_offset = 0;
m_glyphs = new GlyphInfo[256];
for (unsigned int c = 0; c < 256; c++)
{
m_glyphs[c].offset = 0;
m_glyphs[c].advance = 0;
m_glyphs[c].renderable = false;
FT_Int glyph_index = FT_Get_Char_Index(face, c);
if (!glyph_index)
{
continue;
}
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER);
ASSERT(!error);
FT_Bitmap *bmp = &face->glyph->bitmap;
int advance = face->glyph->advance.x >> 6;
m_max_advance.x = std::max(m_max_advance.x, advance);
min_y = std::min(min_y, ascender - face->glyph->bitmap_top);
max_y = std::max(max_y, ascender + bmp->rows - face->glyph->bitmap_top);
m_glyphs[c].offset = face->glyph->bitmap_left;
m_glyphs[c].advance = advance;
m_min_offset = std::min(m_min_offset, m_glyphs[c].offset);
}
// TEMP enne - this seems to be broken on OSX - it returns 8, when it should be 2?
m_max_advance.x = 10;
// The ascender and text height given by FreeType2 is ridiculously large
// (e.g. 37 pixels high for 14 pixel font). Use min and max bounding
// heights on the characters we care about to get better values for the
// text height and the ascender.
m_max_advance.y = max_y - min_y;
ascender -= min_y;
// Grow character size to power of 2
coord_def charsz(1,1);
while (charsz.x < m_max_advance.x)
charsz.x *= 2;
while (charsz.y < m_max_advance.y)
charsz.y *= 2;
// Fill out texture to be (16*charsz.x) X (16*charsz.y) X (32-bit)
// Having to blow out 8-bit alpha values into full 32-bit textures is
// kind of frustrating, but not all OpenGL implementations support the
// "esoteric" ALPHA8 format and it's not like this texture is very large.
unsigned int width = 16 * charsz.x;
unsigned int height = 16 * charsz.y;
unsigned char *pixels = new unsigned char[4 * width * height];
memset(pixels, 0, sizeof(unsigned char) * 4 * width * height);
for (unsigned int c = 0; c < 256; c++)
{
FT_Int glyph_index = FT_Get_Char_Index(face, c);
if (!glyph_index)
{
// If no mapping for this character, leave blank.
continue;
}
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER);
ASSERT(!error);
FT_Bitmap *bmp = &face->glyph->bitmap;
ASSERT(bmp);
// Some glyphs (e.g. " ") don't get a buffer.
if (!bmp->buffer)
continue;
m_glyphs[c].renderable = true;
int vert_offset = ascender - face->glyph->bitmap_top;
ASSERT(bmp->pixel_mode == FT_PIXEL_MODE_GRAY);
ASSERT(bmp->num_grays == 256);
ASSERT(bmp->width + face->glyph->bitmap_left <= m_max_advance.x);
ASSERT(bmp->rows <= m_max_advance.y);
ASSERT(vert_offset >= 0);
ASSERT(vert_offset + bmp->rows <= m_max_advance.y);
// Horizontal offset stored in m_glyphs and handled when drawing
unsigned int offset_x = (c % 16) * charsz.x;
unsigned int offset_y = (c / 16) * charsz.y + vert_offset;
for (int x = 0; x < bmp->width; x++)
for (int y = 0; y < bmp->rows; y++)
{
unsigned int idx = offset_x + x + (offset_y + y) * width;
idx *= 4;
unsigned char alpha = bmp->buffer[x + bmp->width * y];
pixels[idx] = 255;
pixels[idx + 1] = 255;
pixels[idx + 2] = 255;
pixels[idx + 3] = alpha;
}
}
bool success = m_tex.load_texture(pixels, width, height,
GenericTexture::MIPMAP_NONE);
delete[] pixels;
return success;
}
struct FontVertLayout
{
float pos_x;
float pos_y;
float tex_x;
float tex_y;
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
void FTFont::render_textblock(unsigned int x_pos, unsigned int y_pos,
unsigned char *chars, unsigned char *colours,
unsigned int width, unsigned int height,
bool drop_shadow)
{
if (!chars || !colours || !width || !height || !m_glyphs)
return;
coord_def adv(std::max(-m_min_offset, 0), 0);
unsigned int i = 0;
std::vector<FontVertLayout> verts;
// TODO enne - make this better
// This is bad for the CRT. Maybe we should just reserve some fixed limit?
// Maybe we should just cache this in FTFont?
verts.reserve(4 * width * height);
float texcoord_dy = (float)m_max_advance.y / (float)m_tex.height();
for (unsigned int y = 0; y < height; y++)
{
for (unsigned int x = 0; x < width; x++)
{
unsigned char c = chars[i];
unsigned int this_adv = m_glyphs[c].advance + 1;
adv.x += m_glyphs[c].offset;
if (m_glyphs[c].renderable)
{
unsigned char col = colours[i];
float tex_x = (float)(c % 16) / 16.0f;
float tex_y = (float)(c / 16) / 16.0f;
float tex_x2 = tex_x + (float)this_adv / (float)m_tex.width();
float tex_y2 = tex_y + texcoord_dy;
FontVertLayout v;
v.pos_x = adv.x;
v.pos_y = adv.y;
v.tex_x = tex_x;
v.tex_y = tex_y;
v.r = term_colours[col][0];
v.g = term_colours[col][1];
v.b = term_colours[col][2];
v.a = 255;
verts.push_back(v);
v.pos_x = adv.x;
v.pos_y = adv.y + m_max_advance.y;
v.tex_x = tex_x;
v.tex_y = tex_y2;
v.r = term_colours[col][0];
v.g = term_colours[col][1];
v.b = term_colours[col][2];
v.a = 255;
verts.push_back(v);
v.pos_x = adv.x + this_adv;
v.pos_y = adv.y + m_max_advance.y;
v.tex_x = tex_x2;
v.tex_y = tex_y2;
v.r = term_colours[col][0];
v.g = term_colours[col][1];
v.b = term_colours[col][2];
v.a = 255;
verts.push_back(v);
v.pos_x = adv.x + this_adv;
v.pos_y = adv.y;
v.tex_x = tex_x2;
v.tex_y = tex_y;
v.r = term_colours[col][0];
v.g = term_colours[col][1];
v.b = term_colours[col][2];
v.a = 255;
verts.push_back(v);
}
i++;
adv.x += this_adv - m_glyphs[c].offset - 1;
}
adv.x = 0;
adv.y += m_max_advance.y;
}
if (!verts.size())
return;
GLState state;
state.array_vertex = true;
state.array_texcoord = true;
state.blend = true;
state.texture = true;
GLStateManager::set(state);
m_tex.bind();
glVertexPointer(2, GL_FLOAT, sizeof(FontVertLayout), &verts[0].pos_x);
glTexCoordPointer(2, GL_FLOAT, sizeof(FontVertLayout), &verts[0].tex_x);
if (drop_shadow)
{
glColor3f(0.0f, 0.0f, 0.0f);
glLoadIdentity();
glTranslatef(x_pos + 1, y_pos + 1, 0.0f);
glDrawArrays(GL_QUADS, 0, verts.size());
glColor3f(1.0f, 1.0f, 1.0f);
}
glLoadIdentity();
glTranslatef(x_pos, y_pos, 0.0f);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(FontVertLayout), &verts[0].r);
glDrawArrays(GL_QUADS, 0, verts.size());
glDisableClientState(GL_COLOR_ARRAY);
}
struct box_vert
{
float x;
float y;
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
static void _draw_box(int x_pos, int y_pos, float width, float height,
float box_width, unsigned char box_colour,
unsigned char box_alpha)
{
box_vert verts[4];
for (unsigned int i = 0; i < 4; i++)
{
verts[i].r = term_colours[box_colour][0];
verts[i].g = term_colours[box_colour][1];
verts[i].b = term_colours[box_colour][2];
verts[i].a = box_alpha;
}
verts[0].x = x_pos - box_width;
verts[0].y = y_pos - box_width;
verts[1].x = verts[0].x;
verts[1].y = y_pos + height + box_width;
verts[2].x = x_pos + width + box_width;
verts[2].y = verts[1].y;
verts[3].x = verts[2].x;
verts[3].y = verts[0].y;
glLoadIdentity();
GLState state;
state.array_vertex = true;
state.array_colour = true;
state.blend = true;
GLStateManager::set(state);
glVertexPointer(2, GL_FLOAT, sizeof(box_vert), &verts[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(box_vert), &verts[0].r);
glDrawArrays(GL_QUADS, 0, sizeof(verts) / sizeof(box_vert));
}
void FTFont::render_string(unsigned int px, unsigned int py,
const char *text,
const coord_def &min_pos, const coord_def &max_pos,
unsigned char font_colour, bool drop_shadow,
unsigned char box_alpha,
unsigned char box_colour,
unsigned int outline)
{
ASSERT(text);
// Determine extent of this text
unsigned int max_rows = 1;
unsigned int cols = 0;
unsigned int max_cols = 0;
for (const char *itr = text; *itr; itr++)
{
cols++;
max_cols = std::max(cols, max_cols);
// NOTE: only newlines should be used for tool tips. Don't use EOL.
ASSERT(*itr != '\r');
if (*itr == '\n')
{
cols = 0;
max_rows++;
}
}
// Create the text block
unsigned char *chars = (unsigned char *)alloca(max_rows * max_cols);
unsigned char *colours = (unsigned char *)alloca(max_rows * max_cols);
memset(chars, ' ', max_rows * max_cols);
memset(colours, font_colour, max_rows * max_cols);
// Fill the text block
cols = 0;
unsigned int rows = 0;
for (const char *itr = text; *itr; itr++)
{
chars[cols + rows * max_cols] = *itr;
cols++;
if (*itr == '\n')
{
cols = 0;
rows++;
}
}
// Find a suitable location on screen
const int buffer = 5; // additional buffer size from edges
int wx = max_cols * char_width();
int wy = max_rows * char_height();
// text starting location
int tx = px - wx / 2;
int ty = py - wy - outline;
// box with extra buffer to test against min_pos/max_pos window size
int sx = tx - buffer;
int sy = ty - buffer;
int ex = sx + wx + buffer;
int ey = sy + wy + buffer;
if (ex > max_pos.x)
tx += max_pos.x - ex;
else if (sx < min_pos.x)
tx -= sx;
if (ey > max_pos.y)
ty += max_pos.y - ey;
else if (sy < min_pos.y)
ty -= sy;
if (box_alpha != 0)
_draw_box(tx, ty, wx, wy, outline, box_colour, box_alpha);
render_textblock(tx, ty, chars, colours, max_cols, max_rows, drop_shadow);
}
// normal tile count + iso tile count
#define TILE_TOTAL2 (TILE_TOTAL)
// normal tile count
#define TILE_NORMAL TILE_TOTAL
extern void TileDrawDungeonAux();
// Raw tile images
extern img_type TileImg;
extern img_type PlayerImg;
extern img_type WallImg;
extern img_type ScrBufImg;
extern WinClass *win_main;
// Regions
extern TileRegionClass *region_tile;
extern TextRegionClass *region_crt;
extern TextRegionClass *region_stat;
extern TextRegionClass *region_tip;
extern TextRegionClass *region_msg;
extern TileRegionClass *region_item;
extern TileRegionClass *region_item2;
#define ScrBufImg (region_tile->backbuf)
//Internal
static img_type DollCacheImg;
static void _tile_draw_grid(int xx, int yy);
static void _clear_tcache();
static void _init_tcache();
static void _register_tile_mask(int tile, int *cp,
char *ms, bool smalltile = false);
static void _tcache_compose_normal(int ix, int *fg, int *bg);
static void _mcache_init();
//Internal variables
static bool force_redraw_tile = false;
static bool force_redraw_inv = false;
void tile_set_force_redraw_tiles(bool redraw)
{
force_redraw_tile = redraw;
}
void tile_set_force_redraw_inv(bool redraw)
{
force_redraw_inv = redraw;
}
static unsigned int t1buf[TILE_DAT_XMAX+2][TILE_DAT_YMAX+2],
t2buf[TILE_DAT_XMAX+2][TILE_DAT_YMAX+2];
static unsigned int tb_bk[TILE_DAT_YMAX*TILE_DAT_XMAX*2];
#define MAX_ITEMLIST 200
int itemlist[MAX_ITEMLIST];
int itemlist_num[MAX_ITEMLIST];
int itemlist_idx[MAX_ITEMLIST];
char itemlist_key[MAX_ITEMLIST];
int itemlist_iflag[MAX_ITEMLIST];
int itemlist_flag = -1;
int itemlist_n = 0;
/******** Cache buffer for transparency operation *****/
static int last_cursor = -1;
//Internal cache Image buffer
static img_type tcache_image = 0;
//Start of a pointer string
static int tcache_head;
typedef struct tile_cache
{
unsigned int id[2];
int idx;
tile_cache *next;
tile_cache *prev;
} tile_cache;
// number of tile grids
static int tile_xmax;
static int tile_ymax;
static int max_tcache;
// [max_tcache]
static tile_cache *tcache;
// [x*y]
static int *screen_tcache_idx;
const int tcache_wx_normal = TILE_X;
const int tcache_wy_normal = TILE_Y;
const int tcache_ox_normal = 0;
const int tcache_oy_normal = 0;
const int tcache_nlayer_normal = 1;
const int region_sx_normal = 0;
const int region_sy_normal = 0;
const int region_wx_normal = TILE_X;
const int region_wy_normal = TILE_Y;
// ISO mode sink mask
static char *sink_mask;
/********* Image manipulation subroutines ****************/
img_type ImgLoadFileSimple(const char *name)
{
char fname[512];
#ifdef USE_X11
sprintf(fname,"tiles/%s.png", name);
std::string path = datafile_path(fname, true, true);
return ImgLoadFile(path.c_str());
#endif
#ifdef WIN32TILES
sprintf(fname,"tiles/%s.bmp", name);
std::string path = datafile_path(fname, true, true);
return ImgLoadFile(path.c_str());
#endif
}
// TileImg macro
void _ImgCopyFromTileImg(int idx, img_type dest, int dx, int dy, int copy,
char *mask = NULL, bool hilite = false)
{
int sx = (idx % TILE_PER_ROW)*TILE_X;
int sy = (idx / TILE_PER_ROW)*TILE_Y;
if (hilite)
{
if (mask != NULL)
ImgCopyMaskedH(TileImg, sx, sy, TILE_X, TILE_Y,
dest, dx, dy, mask);
else
ImgCopyH(TileImg, sx, sy, TILE_X, TILE_Y, dest, dx, dy, copy);
}
else
{
if (mask != NULL)
ImgCopyMasked(TileImg, sx, sy, TILE_X, TILE_Y,
dest, dx, dy, mask);
else
ImgCopy(TileImg, sx, sy, TILE_X, TILE_Y, dest, dx, dy, copy);
}
}
static void _ImgCopyToTileImg(int idx, img_type src, int sx, int sy, int copy,
char *mask = NULL, bool hilite = false)
{
int dx = (idx % TILE_PER_ROW)*TILE_X;
int dy = (idx / TILE_PER_ROW)*TILE_Y;
if (hilite)
{
if (mask != NULL)
ImgCopyMaskedH(src, sx, sy, TILE_X, TILE_Y,
TileImg, dx, dy, mask);
else
ImgCopyH(src, sx, sy, TILE_X, TILE_Y, TileImg, dx, dy, copy);
}
else
{
if (mask != NULL)
ImgCopyMasked(src, sx, sy, TILE_X, TILE_Y,
TileImg, dx, dy, mask);
else
ImgCopy(src, sx, sy, TILE_X, TILE_Y, TileImg, dx, dy, copy);
}
}
void TileInit()
{
textcolor(WHITE);
TileImg = ImgLoadFileSimple("tile");
PlayerImg = ImgLoadFileSimple("player");
WallImg = ImgLoadFileSimple("wall2d");
if (!TileImg)
{
cprintf("Main tile not initialized\n");
getch();
end(-1);
}
ImgSetTransparentPix(TileImg);
if (ImgWidth(TileImg)!= TILE_X * TILE_PER_ROW
|| ImgHeight(TileImg) <
TILE_Y * ((TILE_TOTAL + TILE_PER_ROW -1)/TILE_PER_ROW) )
{
cprintf("Main tile size invalid\n");
getch();
end(-1);
}
if (!PlayerImg)
{
cprintf("Player tile not initialized\n");
getch();
end(-1);
}
if (ImgWidth(PlayerImg)!= TILE_X * TILEP_PER_ROW)
{
cprintf("Player tile size invalid\n");
getch();
end(-1);
}
if (!WallImg)
{
cprintf("wall2d tile not initialized\n");
getch();
end(-1);
}
tile_xmax = tile_dngn_x;
tile_ymax = tile_dngn_y;
max_tcache = 4*tile_xmax*tile_ymax;
screen_tcache_idx = (int *)malloc(sizeof(int)* tile_xmax * tile_ymax);
tcache = (tile_cache *)malloc(sizeof(tile_cache)*max_tcache);
for (int x = 0; x < tile_xmax * tile_ymax; x++)
screen_tcache_idx[x] = -1;
sink_mask = (char *)malloc(TILE_X*TILE_Y);
_init_tcache();
DollCacheImg = ImgCreateSimple(TILE_X, TILE_Y);
for (int x = 0; x < TILE_DAT_XMAX + 2; x++)
{
for (int y = 0; y < TILE_DAT_YMAX + 2; y++)
{
t1buf[x][y] = 0;
t2buf[x][y] = TILE_DNGN_UNSEEN|TILE_FLAG_UNSEEN;
}
}
force_redraw_tile = false;
_mcache_init();
for (int x = 0; x < MAX_ITEMLIST; x++)
itemlist[x] = itemlist_num[x] = itemlist_key[x] = itemlist_idx[x] = 0;
}
void TileResizeScreen(int x0, int y0)
{
tile_xmax = x0;
tile_ymax = y0;
max_tcache = 4*tile_xmax*tile_ymax;
free(screen_tcache_idx);
screen_tcache_idx = (int *)malloc(sizeof(int)* tile_xmax * tile_ymax);
free(tcache);
tcache = (tile_cache *)malloc(sizeof(tile_cache)*max_tcache);
for (int x = 0; x < tile_xmax * tile_ymax; x++)
screen_tcache_idx[x] = -1;
_init_tcache();
crawl_view.viewsz.x = tile_xmax;
crawl_view.viewsz.y = tile_ymax;
crawl_view.vbuf.size(crawl_view.viewsz);
}
void _clear_tcache()
{
tcache_head = 0;
for (int i = 0; i < max_tcache; i++)
{
tcache[i].id[1] = tcache[i].id[0] = 0;
tcache[i].idx = i;
if (i == 0)
tcache[i].prev = NULL;
else
tcache[i].prev = &tcache[i-1];
if (i == max_tcache - 1)
tcache[i].next = NULL;
else
tcache[i].next = &tcache[i+1];
}
}
void _init_tcache()
{
_clear_tcache();
ImgDestroy(tcache_image);
tcache_image = ImgCreateSimple(tcache_wx_normal,
max_tcache*tcache_wy_normal);
}
// Move a cache to the top of pointer string
// to shorten the search time
static void _lift_tcache(int ix)
{
int head_old = tcache_head;
tile_cache *p = tcache[ix].prev;
tile_cache *n = tcache[ix].next;
ASSERT(ix < max_tcache);
ASSERT(head_old < max_tcache);
if (ix == head_old)
return;
if (p!=NULL)
p->next = n;
if (n!=NULL)
n->prev = p;
tcache_head = ix;
tcache[head_old].prev = &tcache[ix];
tcache[ix].next = &tcache[head_old];
}
// Find cached image of fg+bg
// If not found, compose and cache it
static int _tcache_find_id_normal(int *fg, int *bg, int *is_new)
{
tile_cache *tc0 = &tcache[tcache_head];
*is_new = 0;
while (true)
{
tile_cache *next = tc0->next;
if ((int)tc0->id[0] == fg[0] && (int)tc0->id[1] == bg[0])
break;
if (next == NULL)
{
//end of used cache
*is_new = 1;
_tcache_compose_normal(tc0->idx, fg, bg);
tc0->id[0] = fg[0];
tc0->id[1] = bg[0];
break;
}
tc0 = next;
}
_lift_tcache(tc0->idx);
return (tc0->idx);
}
// Overlay a tile onto an existing image with transparency operation.
static void _tcache_overlay(img_type img, int idx, int tile,
int *copy, char *mask, unsigned int shift_left = 0)
{
int x0, y0;
int sx = region_sx_normal + shift_left;
int sy = region_sy_normal;
int wx = region_wx_normal - shift_left;
int wy = region_wy_normal;
int ox = 0;
int oy = 0;
img_type src = TileImg;
int uy = wy;
tile &= TILE_FLAG_MASK;
x0 = (tile % TILE_PER_ROW) * TILE_X;
y0 = (tile / TILE_PER_ROW) * TILE_Y;
if (mask != NULL)
{
if (*copy == 2)
{
ImgCopyMaskedH(src, x0 + sx, y0 + sy, wx, wy,
img, ox, oy + idx*uy, mask);
}
else
{
ImgCopyMasked(src, x0 + sx, y0 + sy, wx, wy,
img, ox, oy + idx*uy, mask);
}
}
// Hack: hilite rim color
else if (*copy == 2)
{
ImgCopyH(src, x0 + sx, y0 + sy, wx, wy,
img, ox, oy + idx*uy, *copy);
}
else
{
ImgCopy(src, x0 + sx, y0 + sy, wx, wy,
img, ox, oy + idx*uy, *copy);
}
*copy = 0;
}
void _tcache_overlay_player(img_type img, int dx, int dy, int part, int idx,
int ymax, int *copy)
{
int xs, ys;
int tidx = tilep_parts_start[part];
int nx = tilep_parts_nx[part];
int ny = tilep_parts_ny[part];
int ox = tilep_parts_ox[part];
int oy = tilep_parts_oy[part];
int wx = TILE_X/nx;
int wy = TILE_Y/ny;
if (!idx)
return;
idx--;
tidx += idx/(nx*ny);
if (oy+wy > ymax)
wy -= oy + wy - ymax;
if (wy <= 0)
return;
xs = (tidx % TILEP_PER_ROW)*TILE_X;
ys = (tidx / TILEP_PER_ROW)*TILE_Y;
xs += (idx % nx)*(TILE_X/nx);
ys += ((idx/nx) % ny)*(TILE_Y/ny);
ImgCopy(PlayerImg, xs, ys, wx, wy,
img, dx+ox, dy+oy, *copy);
*copy = 0;
}
/* overlay a tile onto an exsisting image with transpalency operation */
void _register_tile_mask(int tile, int *copy,
char *mask, bool smalltile)
{
int x0, y0, x, y;
int sx = region_sx_normal;
int sy = region_sy_normal;
int wx = region_wx_normal;
int wy = region_wy_normal;
int ox = 0;
int oy = 0;
int ux = wx;
int uy = wy;
img_type src = TileImg;
tile &= TILE_FLAG_MASK;
x0 = (tile % TILE_PER_ROW) * TILE_X;
y0 = (tile / TILE_PER_ROW) * TILE_Y;
if (*copy != 0)
memset(mask, 0, ux*uy);
if (*copy == 2)
{
if (smalltile)
ux = wx;
for (x = 0; x < wx; x++)
for (y = 0; y < wy; y++)
{
if (!ImgIsTransparentAt(src, x0+sx+x, y0+sy+y))
mask[(y+oy) * ux + (x+ox)] = 1;
}
}
else
{
for (x = 0; x < wx; x += 2)
{
for (y = 0; y < wy; y += 2)
{
if (!ImgIsTransparentAt(src, x0+sx+x, y0+sy+y))
mask[(y+oy) * ux + (x+ox)] = 1;
}
}
}
*copy = 0;
}
void _tile_draw_grid(int xx, int yy)
{
int fg[4],bg[4],ix, ix_old, is_new;
if (xx < 0 || yy < 0 || xx >= tile_xmax || yy>= tile_ymax)
return;
fg[0] = t1buf[xx+1][yy+1];
bg[0] = t2buf[xx+1][yy+1];
ix_old = screen_tcache_idx[xx+yy*tile_xmax];
ix = _tcache_find_id_normal(fg, bg, &is_new);
screen_tcache_idx[xx+yy*tile_xmax] = ix;
if (is_new || ix!=ix_old || force_redraw_tile)
{
int x_dest = tcache_ox_normal+xx* TILE_UX_NORMAL;
int y_dest = tcache_oy_normal+yy* TILE_UY_NORMAL;
int wx = tcache_wx_normal;
int wy = tcache_wy_normal;
ImgCopy(tcache_image, 0, ix*wy, wx, wy, ScrBufImg, x_dest, y_dest, 1);
}
}
static void _update_single_grid(int x, int y)
{
_tile_draw_grid(x, y);
int sx = x*TILE_UX_NORMAL;
int sy = y*TILE_UY_NORMAL;
int wx = TILE_UX_NORMAL;
int wy = TILE_UY_NORMAL;
region_tile->redraw(sx, sy, sx+wx-1, sy+wy-1);
}
// Discard cache containing specific tile
static void _redraw_spx_tcache(int tile)
{
for (int idx = 0; idx < max_tcache; idx++)
{
int fg = tcache[idx].id[0];
int bg = tcache[idx].id[1];
if ((fg & TILE_FLAG_MASK) == tile
|| (bg & TILE_FLAG_MASK) == tile)
{
_tcache_compose_normal(idx, &fg, &bg);
}
}
}
static void _get_bbg(int bg, int *new_bg, int *bbg)
{
int bg0 = bg & TILE_FLAG_MASK;
*bbg = TILE_DNGN_FLOOR;
*new_bg = bg0;
if (bg0 == TILE_DNGN_UNSEEN || bg0 == 0
|| (bg0 >= TILE_DNGN_ROCK_WALL_OFS && bg0 < TILE_DNGN_WAX_WALL))
{
*bbg = 0;
}
else if (bg0 >= TILE_DNGN_FLOOR && bg0 <= TILE_DNGN_SHALLOW_WATER)
{
*bbg = bg;
*new_bg = 0;
}
}
static int _sink_mask_tile(int bg, int fg)
{
int bg0 = bg & TILE_FLAG_MASK;
if (fg == 0 || (fg & TILE_FLAG_FLYING) != 0)
return 0;
if ( bg0 >= TILE_DNGN_LAVA &&
bg0 <= TILE_DNGN_SHALLOW_WATER + 3)
{
return TILE_SINK_MASK;
}
return 0;
}
//normal
void _tcache_compose_normal(int ix, int *fg, int *bg)
{
int bbg;
int new_bg;
int c = 1;
int fg0 = fg[0];
int bg0 = bg[0];
int sink;
_get_bbg(bg0, &new_bg, &bbg);
if (bbg)
_tcache_overlay(tcache_image, ix, bbg, &c, NULL);
if (bg0 & TILE_FLAG_BLOOD)
_tcache_overlay(tcache_image, ix, TILE_BLOOD0 + ix % 5, &c, NULL);
if (new_bg)
_tcache_overlay(tcache_image, ix, new_bg, &c, NULL);
else if (bg0 & TILE_FLAG_HALO)
_tcache_overlay(tcache_image, ix, TILE_HALO, &c, NULL);
if ((bg0 & TILE_FLAG_SANCTUARY) && !(bg0 & TILE_FLAG_UNSEEN))
_tcache_overlay(tcache_image, ix, TILE_SANCTUARY, &c, NULL);
// Apply the travel exclusion under the foreground if the cell is
// visible. It will be applied later if the cell is unseen.
if ((bg0 & TILE_FLAG_TRAV_EXCL) && !(bg0 & TILE_FLAG_UNSEEN))
_tcache_overlay(tcache_image, ix, TILE_TRAVEL_EXCLUSION, &c, NULL);
else if ((bg0 & TILE_FLAG_EXCL_CTR) && !(bg0 & TILE_FLAG_UNSEEN))
_tcache_overlay(tcache_image, ix, TILE_TRAVEL_EXCL_CENTRE, &c, NULL);
if (bg0 & TILE_FLAG_RAY)
_tcache_overlay(tcache_image, ix, TILE_RAY_MESH, &c, NULL);
if (fg0)
{
sink = _sink_mask_tile(bg0, fg0);
if (sink)
{
int flag = 2;
_register_tile_mask(sink, &flag, sink_mask);
_tcache_overlay(tcache_image, ix, fg0, &c, sink_mask);
}
else
_tcache_overlay(tcache_image, ix, fg0, &c, NULL);
}
if (fg0 & TILE_FLAG_NET)
_tcache_overlay(tcache_image, ix, TILE_TRAP_NET, &c, NULL);
if (fg0 & TILE_FLAG_S_UNDER)
_tcache_overlay(tcache_image, ix, TILE_SOMETHING_UNDER, &c, NULL);
// Pet mark
int status_shift = 0;
if (fg0 & TILE_FLAG_PET)
{
_tcache_overlay(tcache_image, ix, TILE_HEART, &c, NULL);
status_shift += 10;
}
else if ((fg0 & TILE_FLAG_MAY_STAB) == TILE_FLAG_NEUTRAL)
{
_tcache_overlay(tcache_image, ix, TILE_NEUTRAL, &c, NULL);
status_shift += 8;
}
else if ((fg0 & TILE_FLAG_MAY_STAB) == TILE_FLAG_STAB)
{
_tcache_overlay(tcache_image, ix, TILE_STAB_BRAND, &c, NULL);
status_shift += 8;
}
else if ((fg0 & TILE_FLAG_MAY_STAB) == TILE_FLAG_MAY_STAB)
{
_tcache_overlay(tcache_image, ix, TILE_MAY_STAB_BRAND, &c,
NULL);
status_shift += 5;
}
if (fg0 & TILE_FLAG_POISON)
{
_tcache_overlay(tcache_image, ix, TILE_POISON, &c, NULL,
status_shift);
status_shift += 5;
}
if (fg0 & TILE_FLAG_ANIM_WEP)
{
_tcache_overlay(tcache_image, ix, TILE_ANIMATED_WEAPON, &c, NULL);
}
if (bg0 & TILE_FLAG_UNSEEN)
{
_tcache_overlay(tcache_image, ix, TILE_MESH, &c, NULL);
}
if (bg0 & TILE_FLAG_MM_UNSEEN)
{
_tcache_overlay(tcache_image, ix, TILE_MAGIC_MAP_MESH, &c,
NULL);
}
// Don't let the "new stair" icon cover up any existing icons, but
// draw it otherwise.
if (bg0 & TILE_FLAG_NEW_STAIR && status_shift == 0)
_tcache_overlay(tcache_image, ix, TILE_NEW_STAIR, &c, NULL);
if ((bg0 & TILE_FLAG_TRAV_EXCL) && (bg0 & TILE_FLAG_UNSEEN))
{
_tcache_overlay(tcache_image, ix, TILE_TRAVEL_EXCLUSION, &c,
NULL);
}
else if ((bg0 & TILE_FLAG_EXCL_CTR) && (bg0 & TILE_FLAG_UNSEEN))
{
_tcache_overlay(tcache_image, ix, TILE_TRAVEL_EXCL_CENTRE, &c,
NULL);
}
// Tile cursor
if (bg0 & TILE_FLAG_CURSOR)
{
int type = ((bg0 & TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR1) ?
TILE_CURSOR : TILE_CURSOR2;
if ((bg0 & TILE_FLAG_CURSOR) == TILE_FLAG_CURSOR3)
type = TILE_CURSOR3;
_tcache_overlay(tcache_image, ix, type, &c, NULL);
if (type != TILE_CURSOR3)
c = 2;
}
}
// Tile cursor
int TileDrawCursor(int x, int y, int cflag)
{
int oldc = t2buf[x+1][y+1] & TILE_FLAG_CURSOR;
t2buf[x+1][y+1] &= ~TILE_FLAG_CURSOR;
t2buf[x+1][y+1] |= cflag;
_update_single_grid(x, y);
return oldc;
}
}
void StoreDungeonView(unsigned int *tileb)
{
int x, y;
int count = 0;
if (tileb == NULL)
tileb = tb_bk;
for (y = 0; y < tile_dngn_y; y++)
{
for (x = 0; x < tile_dngn_x; x++)
{
tileb[count++] = t1buf[x+1][y+1];
tileb[count++] = t2buf[x+1][y+1];
}
}
}
void LoadDungeonView(unsigned int *tileb)
{
int x, y;
int count = 0;
if (tileb == NULL)
tileb = tb_bk;
for (y = 0; y < crawl_view.viewsz.y; y++)
{
for (x = 0; x < crawl_view.viewsz.x; x++)
{
if (tileb[count] == tileb[count+1])
tileb[count] = 0;
t1buf[x+1][y+1] = tileb[count++];
t2buf[x+1][y+1] = tileb[count++];
}
}
}
//Draw the tile screen once and for all
void TileDrawDungeon(unsigned int *tileb)
{
if (!TileImg)
return;
ASSERT(tile_dngn_x == crawl_view.viewsz.x);
ASSERT(tile_dngn_y == crawl_view.viewsz.y);
ASSERT(tile_xmax = crawl_view.viewsz.x);
ASSERT(tile_ymax = crawl_view.viewsz.y);
LoadDungeonView(tileb);
extern int tile_cursor_x;
tile_cursor_x = -1;
for (int x = 0; x < crawl_view.viewsz.x; x++)
for (int y = 0; y < crawl_view.viewsz.y; y++)
_tile_draw_grid(x, y);
force_redraw_tile = false;
TileDrawDungeonAux();
region_tile->redraw();
#endif
void TileDrawFarDungeon(int cx, int cy)
{
unsigned int tb[TILE_DAT_YMAX*TILE_DAT_XMAX*2];
int count = 0;
for (int y = 0; y < tile_dngn_y; y++)
{
for (int x = 0; x < tile_dngn_x; x++)
{
int fg;
int bg;
const coord_def gc(cx + x - tile_dngn_x/2,
cy + y - tile_dngn_y/2);
const coord_def ep = view2show(grid2view(gc));
// mini "viewwindow" routine
if (!map_bounds(gc))
{
fg = 0;
bg = TILE_DNGN_UNSEEN;
}
else if (!crawl_view.in_grid_los(gc) || !env.show(ep))
{
fg = env.tile_bk_fg[gc.x][gc.y];
bg = env.tile_bk_bg[gc.x][gc.y];
if (bg == 0)
bg |= TILE_DNGN_UNSEEN;
bg |= tile_unseen_flag(gc);
}
else
{
fg = env.tile_fg[ep.x-1][ep.y-1];
bg = env.tile_bg[ep.x-1][ep.y-1];
}
if (gc.x == cx && gc.y == cy)
bg |= TILE_FLAG_CURSOR1;
tb[count++] = fg;
tb[count++] = bg;
}
}
tile_finish_dngn(tb, cx, cy);
TileDrawDungeon(tb);
region_tile->redraw();
}
void TileDrawMap(int gx, int gy)
{
TileDrawFarDungeon(gx, gy);
}
// Load optional wall tile
static void _TileLoadWallAux(int idx_src, int idx_dst, img_type wall)
{
int tile_per_row = ImgWidth(wall) / TILE_X;
int sx = idx_src % tile_per_row;
int sy = idx_src / tile_per_row;
sx *= TILE_X;
sy *= TILE_Y;
_ImgCopyToTileImg(idx_dst, wall, sx, sy, 1);
}
floor_tile_idx = TILE_DNGN_FLOOR;
floor_flavors = tile_W2D_count[floor_idx];
int offset = floor_tile_idx;
for (int i = 0; i < floor_flavors; i++)
{
int idx_src = tile_W2D_start[floor_idx] + i;
int idx_dst = offset++;
_TileLoadWallAux(idx_src, idx_dst, WallImg);
}
// TODO enne - link floor tile index to the right location rather than
// starting at floor normal
floor_tile_idx = tile_DNGN_start[floor_idx];
floor_flavors = tile_DNGN_count[floor_idx];
wall_tile_idx = offset;
wall_flavors = tile_W2D_count[wall_idx];
for (int i = 0; i < wall_flavors; i++)
{
int idx_src = tile_W2D_start[wall_idx] + i;
int idx_dst = offset++;
_TileLoadWallAux(idx_src, idx_dst, WallImg);
}
wall_tile_idx = tile_DNGN_start[wall_idx];
wall_flavors = tile_DNGN_count[wall_idx];
special_tile_idx = offset;
special_flavors = tile_W2D_count[special_idx];
for (int i = 0; i < special_flavors; i++)
{
int idx_src = tile_W2D_start[special_idx] + i;
int idx_dst = offset++;
_TileLoadWallAux(idx_src, idx_dst, WallImg);
}
special_tile_idx = tile_DNGN_start[special_idx];
special_flavors = tile_DNGN_count[special_idx];
static int current_parts[TILEP_PARTS_TOTAL];
static bool _draw_doll(img_type img, dolls_data *doll, bool force_redraw = false,
bool your_doll = true)
{
const int p_order[TILEP_PARTS_TOTAL] =
{
TILEP_PART_SHADOW,
TILEP_PART_HALO,
TILEP_PART_DRCWING,
TILEP_PART_CLOAK,
TILEP_PART_BASE,
TILEP_PART_BOOTS,
TILEP_PART_LEG,
TILEP_PART_BODY,
TILEP_PART_ARM,
TILEP_PART_HAND1,
TILEP_PART_HAND2,
TILEP_PART_HAIR,
TILEP_PART_BEARD,
TILEP_PART_HELM,
TILEP_PART_DRCHEAD
};
int p_order2[TILEP_PARTS_TOTAL];
int i;
int flags[TILEP_PARTS_TOTAL];
int parts2[TILEP_PARTS_TOTAL];
int *parts = doll->parts;
int c = 1;
bool changed = false;
int default_parts[TILEP_PARTS_TOTAL];
memset(default_parts, 0, sizeof(default_parts));
if (your_doll)
{
tilep_race_default(you.species, parts[TILEP_PART_BASE] % 2,
you.experience_level, default_parts);
if (default_parts[TILEP_PART_BASE] != parts[TILEP_PART_BASE])
force_redraw = true;
parts[TILEP_PART_BASE] = default_parts[TILEP_PART_BASE];
// TODO enne - make these configurable.
parts[TILEP_PART_DRCHEAD] = default_parts[TILEP_PART_DRCHEAD];
parts[TILEP_PART_DRCWING] = default_parts[TILEP_PART_DRCWING];
bool halo = inside_halo(you.x_pos, you.y_pos);
parts[TILEP_PART_HALO] = halo ? TILEP_HALO_TSO : 0;
}
// convert TILEP_SHOW_EQUIP into real parts number
for (i = 0; i < TILEP_PARTS_TOTAL; i++)
{
parts2[i] = parts[i];
if (parts2[i] == TILEP_SHOW_EQUIP)
{
int item = -1;
switch (i)
{
case TILEP_PART_HAND1:
item = you.equip[EQ_WEAPON];
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
parts2[i] = TILEP_HAND1_BLADEHAND;
else if (item == -1)
parts2[i] = 0;
else
parts2[i] = tilep_equ_weapon(you.inv[item]);
break;
case TILEP_PART_HAND2:
item = you.equip[EQ_SHIELD];
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BLADE_HANDS)
parts2[i] = TILEP_HAND2_BLADEHAND;
else if (item == -1)
parts2[i] = 0;
else
parts2[i] = tilep_equ_shield(you.inv[item]);
break;
case TILEP_PART_BODY:
item = you.equip[EQ_BODY_ARMOUR];
if (item == -1)
parts2[i] = 0;
else
parts2[i] = tilep_equ_armour(you.inv[item]);
break;
case TILEP_PART_CLOAK:
item = you.equip[EQ_CLOAK];
if (item == -1)
parts2[i] = 0;
else
parts2[i] = tilep_equ_cloak(you.inv[item]);
break;
case TILEP_PART_HELM:
item = you.equip[EQ_HELMET];
if (item == -1)
parts2[i] = 0;
else
parts2[i] = tilep_equ_helm(you.inv[item]);
if (parts2[i] == 0 && player_mutation_level(MUT_HORNS) > 0)
{
switch (player_mutation_level(MUT_HORNS))
{
case 1:
parts2[i] = TILEP_HELM_HORNS1;
break;
case 2:
parts2[i] = TILEP_HELM_HORNS2;
break;
case 3:
parts2[i] = TILEP_HELM_HORNS3;
break;
}
}
break;
case TILEP_PART_BOOTS:
item = you.equip[EQ_BOOTS];
if (item == -1)
parts2[i] = 0;
else
parts2[i] = tilep_equ_boots(you.inv[item]);
if (parts2[i] == 0 && player_mutation_level(MUT_HOOVES))
parts2[i] = TILEP_BOOTS_HOOVES;
break;
case TILEP_PART_ARM:
item = you.equip[EQ_GLOVES];
if (item == -1)
parts2[i] = 0;
else
parts2[i] = tilep_equ_gloves(you.inv[item]);
// There is player_has_claws() but it is not equivalent.
// Claws appear if they're big enough to not wear gloves
// or on races that have claws.
if (parts2[i] == 0 && (player_mutation_level(MUT_CLAWS) >= 3
|| you.species == SP_TROLL || you.species == SP_GHOUL))
{
parts2[i] = TILEP_ARM_CLAWS;
}
break;
case TILEP_PART_HAIR:
case TILEP_PART_BEARD:
parts2[i] = default_parts[i];
break;
case TILEP_PART_LEG:
default:
parts2[i] = 0;
}
}
if (parts2[i] != current_parts[i])
changed = true;
current_parts[i] = parts2[i];
}
if (!changed && !force_redraw)
return (false);
tilep_calc_flags(parts2, flags);
ImgClear(img);
// Hack: change overlay order of boots/skirts.
for (i = 0; i < TILEP_PARTS_TOTAL; i++)
p_order2[i] = p_order[i];
// Swap boot and leg-armour.
if (parts2[TILEP_PART_LEG] < TILEP_LEG_SKIRT_OFS)
{
p_order2[6] = TILEP_PART_LEG;
p_order2[5] = TILEP_PART_BOOTS;
}
for (i = 0; i < TILEP_PARTS_TOTAL; i++)
{
int p = p_order2[i];
int ymax = TILE_Y;
if (flags[p] == TILEP_FLAG_CUT_CENTAUR
|| flags[p] == TILEP_FLAG_CUT_NAGA)
{
ymax=18;
}
if (parts2[p] && p == TILEP_PART_BOOTS
&& (parts2[p] == TILEP_BOOTS_NAGA_BARDING
|| parts2[p] == TILEP_BOOTS_CENTAUR_BARDING))
{
// Special case for barding. They should be in "boots" but because
// they're double-wide, they're stored in a different part. We just
// intercept it here before drawing.
char tile = (parts2[p] == TILEP_BOOTS_NAGA_BARDING) ?
TILEP_SHADOW_NAGA_BARDING :
TILEP_SHADOW_CENTAUR_BARDING;
_tcache_overlay_player(img, 0, 0, TILEP_PART_SHADOW,
tile, TILE_Y, &c);
}
else if (parts2[p] && flags[p])
_tcache_overlay_player(img, 0, 0, p, parts2[p], ymax, &c);
}
return (true);
}
}
void TilePlayerRefresh()
{
if (!_draw_doll(DollCacheImg, ¤t_doll))
return; // Not changed
_ImgCopyToTileImg(TILE_PLAYER, DollCacheImg, 0, 0, 1);
_redraw_spx_tcache(TILE_PLAYER);
force_redraw_tile = true;
const coord_def ep = grid2view(you.pos());
_update_single_grid(ep.x-1, ep.y-1);
#endif
void TilePlayerInit()
{
int i;
int cur_doll = 0;
int mode = TILEP_M_DEFAULT;
dolls_data doll;
int gender = 0;
for (i = 0; i < TILEP_PARTS_TOTAL; i++)
doll.parts[i] = 0;
tilep_race_default(you.species, gender, you.experience_level, doll.parts);
tilep_job_default(you.char_class, gender, doll.parts);
_load_doll_data("dolls.txt", &doll, 1, &mode, &cur_doll);
current_doll = doll;
_draw_doll(DollCacheImg, &doll);
_ImgCopyToTileImg(TILE_PLAYER, DollCacheImg, 0, 0, 1);
}
}
void TileInitItems()
{
for (int i = 0; i < NUM_POTIONS; i++)
{
int special = you.item_description[IDESC_POTIONS][i];
int tile0 = TILE_POTION_OFFSET + special % 14;
int tile1 = TILE_POT_HEALING + i;
_ImgCopyFromTileImg(tile0, DollCacheImg, 0, 0, 1);
_ImgCopyFromTileImg(tile1, DollCacheImg, 0, 0, 0);
_ImgCopyToTileImg(tile1, DollCacheImg, 0, 0, 1);
}
for (int i = 0; i < NUM_WANDS; i++)
{
int special = you.item_description[IDESC_WANDS][i];
int tile0 = TILE_WAND_OFFSET + special % 12;
int tile1 = TILE_WAND_FLAME + i;
_ImgCopyFromTileImg(tile0, DollCacheImg, 0, 0, 1);
_ImgCopyFromTileImg(tile1, DollCacheImg, 0, 0, 0);
_ImgCopyToTileImg(tile1, DollCacheImg, 0, 0, 1);
}
for (int i = 0; i < STAFF_SMITING; i++)
{
int special = you.item_description[IDESC_STAVES][i];
int tile0 = TILE_STAFF_OFFSET + (special / 4) % 10;
int tile1 = TILE_STAFF_WIZARDRY + i;
_ImgCopyFromTileImg(tile0, DollCacheImg, 0, 0, 1);
_ImgCopyFromTileImg(tile1, DollCacheImg, 0, 0, 0);
_ImgCopyToTileImg(tile1, DollCacheImg, 0, 0, 1);
}
for (int i = STAFF_SMITING; i < NUM_STAVES; i++)
{
int special = you.item_description[IDESC_STAVES][i];
int tile0 = TILE_ROD_OFFSET + (special / 4) % 10;
int tile1 = TILE_ROD_SMITING + i - STAFF_SMITING;
_ImgCopyFromTileImg(tile0, DollCacheImg, 0, 0, 1);
_ImgCopyFromTileImg(tile1, DollCacheImg, 0, 0, 0);
_ImgCopyToTileImg(tile1, DollCacheImg, 0, 0, 1);
}
#endif
// Monster weapon tile
#define N_MCACHE (TILE_MCACHE_END - TILE_MCACHE_START +1)
typedef struct mcache mcache;
struct mcache
{
bool lock_flag;
mcache *next;
int mon_tile;
int equ_tile;
int draco;
int idx;
};
mcache mc_data[N_MCACHE];
int handidx = hand == 1 ? TILEP_PART_HAND1 : TILEP_PART_HAND2;
int nx = tilep_parts_nx[handidx];
int ny = tilep_parts_ny[handidx];
int ox = tilep_parts_ox[handidx];
int oy = tilep_parts_oy[handidx];
int wx = std::min(TILE_X/nx + ofs_x, TILE_X/nx);
int wy = std::min(TILE_Y/ny + ofs_y, TILE_Y/ny);
int idx = equ_tile -1;
int tidx = tilep_parts_start[handidx] + idx/(nx*ny);
//Source pos
int xs = (tidx % TILEP_PER_ROW)*TILE_X + (idx % nx) * (TILE_X/nx) - ofs_x;
int ys = (tidx / TILEP_PER_ROW)*TILE_Y
+ ((idx/nx) % ny) * (TILE_Y/ny) - ofs_y;
ofs_x = 0;
ofs_y = 0;
ImgCopy(PlayerImg, xs, ys, wx, wy, DollCacheImg, ox, oy, 0);
}
static void _mcache_compose(int tile_idx, int mon_tile, int equ_tile)
{
int ofs_x = 0;
int ofs_y = 0;
// Copy monster tile
_ImgCopyFromTileImg(mon_tile, DollCacheImg, 0, 0, 1);
// Overlay weapon tile
_ImgCopyDoll(equ_tile, 1, ofs_x, ofs_y);
// In some cases, overlay a second weapon tile...
if (mon_tile == TILE_MONS_DEEP_ELF_BLADEMASTER)
{
int eq2;
switch (equ_tile)
{
case TILEP_HAND1_DAGGER:
eq2 = TILEP_HAND2_DAGGER;
break;
case TILEP_HAND1_SABRE:
eq2 = TILEP_HAND2_SABRE;
break;
default:
case TILEP_HAND1_SHORT_SWORD_SLANT:
eq2 = TILEP_HAND2_SHORT_SWORD_SLANT;
break;
};
_ImgCopyDoll(eq2, 2, -ofs_x, ofs_y);
}
// Copy to the buffer
_ImgCopyToTileImg(tile_idx, DollCacheImg, 0, 0, 1);
_redraw_spx_tcache(tile_idx);
dolls_data doll;
int x;
int color = draconian_color(race, -1);
int armour = 0;
int armour2 = 0;
int weapon = 0;
int weapon2 = 0;
int arm = 0;
for (x = 0; x < TILEP_PARTS_TOTAL; x++)
{
doll.parts[x] = 0;
current_parts[x] = 0;
}
doll.parts[TILEP_PART_SHADOW] = 1;
doll.parts[TILEP_PART_BASE] = TILEP_BASE_DRACONIAN + color *2;
doll.parts[TILEP_PART_DRCWING] = 1 + color;
doll.parts[TILEP_PART_DRCHEAD] = 1 + color;
switch(cls)
{
case MONS_DRACONIAN_CALLER:
weapon = TILEP_HAND1_STAFF_EVIL;
weapon2 = TILEP_HAND2_BOOK_YELLOW;
armour = TILEP_BODY_ROBE_BROWN;
break;
case MONS_DRACONIAN_MONK:
arm = TILEP_ARM_GLOVE_SHORT_BLUE;
armour = TILEP_BODY_KARATE2;
break;
case MONS_DRACONIAN_ZEALOT:
weapon = TILEP_HAND1_MACE;
weapon2 = TILEP_HAND2_BOOK_CYAN;
armour = TILEP_BODY_MONK_BLUE;
break;
case MONS_DRACONIAN_SHIFTER:
weapon = TILEP_HAND1_STAFF_LARGE;
armour = TILEP_BODY_ROBE_CYAN;
weapon2 = TILEP_HAND2_BOOK_GREEN;
break;
case MONS_DRACONIAN_ANNIHILATOR:
weapon = TILEP_HAND1_STAFF_RUBY;
weapon2 = TILEP_HAND2_FIRE_CYAN;
armour = TILEP_BODY_ROBE_GREEN_GOLD;
break;
case MONS_DRACONIAN_KNIGHT:
weapon = w;
weapon2 = TILEP_HAND2_SHIELD_KNIGHT_GRAY;
armour = TILEP_BODY_BPLATE_METAL1;
armour2 = TILEP_LEG_BELT_GRAY;
break;
case MONS_DRACONIAN_SCORCHER:
weapon = TILEP_HAND1_FIRE_RED;
weapon2 = TILEP_HAND2_BOOK_RED;
armour = TILEP_BODY_ROBE_RED;
break;
default:
weapon = w;
armour = TILEP_BODY_BELT2;
armour2 = TILEP_LEG_LOINCLOTH_RED;
break;
}
doll.parts[TILEP_PART_HAND1] = weapon;
doll.parts[TILEP_PART_HAND2] = weapon2;
doll.parts[TILEP_PART_BODY] = armour;
doll.parts[TILEP_PART_LEG] = armour2;
doll.parts[TILEP_PART_ARM] = arm;
ImgClear(DollCacheImg);
_draw_doll(DollCacheImg, &doll, true, false);
// Copy to the buffer
_ImgCopyToTileImg(tile_idx, DollCacheImg, 0, 0, 1);
_redraw_spx_tcache(tile_idx);
}
static void _mcache_init()
{
int i;
for (i = 0; i < N_MCACHE; i++)
{
mc_data[i].lock_flag = false;
mc_data[i].next = NULL;
if (i != N_MCACHE - 1)
mc_data[i].next = &mc_data[i+1];
mc_data[i].idx = TILE_MCACHE_START + i;
mc_data[i].mon_tile = 0;
mc_data[i].equ_tile = 0;
mc_data[i].draco = 0;
}
mc_head = &mc_data[0];
}
int get_base_idx_from_mcache(int tile_idx)
{
for (mcache *mc = mc_head; mc != NULL; mc = mc->next)
{
if (mc->idx == tile_idx)
return mc->mon_tile;
}
return tile_idx;
}
}
void TileMcacheUnlock()
{
int i;
for (i = 0; i < N_MCACHE; i++)
mc_data[i].lock_flag = false;
}
int TileMcacheFind(int mon_tile, int equ_tile, int draco)
{
mcache *mc = mc_head;
mcache *prev = NULL;
mcache *empty = NULL;
#ifdef DEBUG_DIAGNOSTICS
int count = 0;
char cache_info[40];
#endif
int best2 = -1;
int best3 = -1;
while (true)
{
if (mon_tile == mc->mon_tile && equ_tile == mc->equ_tile
&& draco == mc->draco)
{
// match found
// move cache to the head to reduce future search time
if (prev != NULL)
prev->next = mc->next;
if (mc != mc_head)
mc->next = mc_head;
mc_head = mc;
// lock it
mc->lock_flag=true;
// return cache index
return mc->idx;
}
else if (draco != 0 && mon_tile == mc->mon_tile && draco == mc->draco)
// second best for draconian: only weapon differ
best2 = mc->idx;
else if (draco != 0 && mon_tile == mc->mon_tile)
// third best for draconian: only class matches
best3 = mc->idx;
if (!mc->lock_flag)
empty = mc;
if (mc->next == NULL)
break;
prev = mc;
mc = mc->next;
#ifdef DEBUG_DIAGNOSTICS
count++;
#endif
} // while
// cache image not found and no room do draw it
if (empty == NULL)
{
#ifdef DEBUG_DIAGNOSTICS
snprintf( cache_info, 39, "mcache (M %d, E %d) cache full",
mon_tile, equ_tile);
mpr(cache_info, MSGCH_DIAGNOSTICS );
#endif
if (best2 != -1)
return best2;
if (best3 != -1)
return best3;
if (draco != 0)
return TILE_ERROR;
else
return mon_tile;
}
mc = empty;
#ifdef DEBUG_DIAGNOSTICS
snprintf( cache_info, 39, "mcache (M %d, E %d) newly composed",
mon_tile, equ_tile);
mpr(cache_info, MSGCH_DIAGNOSTICS );
#endif
// compose new image
if (draco != 0)
// race, class, weapon
_mcache_compose_draco(mc->idx, draco, mon_tile, equ_tile);
else
_mcache_compose(mc->idx, mon_tile, equ_tile);
mc->mon_tile = mon_tile;
mc->equ_tile = equ_tile;
mc->draco = draco;
// move cache to the head to reduce future search time
if (prev)
prev->next = mc->next;
if (mc != mc_head)
mc->next = mc_head;
mc_head = mc;
mc->lock_flag = true;
return mc->idx;
}
static void _TilePutch(int c, img_type Dest, int dx, int dy)
{
int tidx = TILE_CHAR00 + (c-32)/8;
int tidx2 = c & 7;
int sx = (tidx % TILE_PER_ROW)*TILE_X + (tidx2 % 4)*(TILE_X/4);
int sy = (tidx / TILE_PER_ROW)*TILE_Y + (tidx2 / 4)*(TILE_Y/2);;
ImgCopy(TileImg, sx, sy, TILE_X/4, TILE_Y/2,
Dest, dx, dy, 0);
}
void TileRedrawInv(int region)
{
TileRegionClass *r = (region == REGION_INV1) ? region_item:region_item2;
r->flag = true;
r->make_active();
r->redraw();
}
void TileClearInv(int region)
{
TileRegionClass *r = (region == REGION_INV1) ? region_item
: region_item2;
for (int i = 0; i < r->mx * r->my; i++)
{
TileDrawOneItem(region, i, 0, -1, -1, -1,
false, false, false, false, false);
}
last_cursor = -1;
itemlist_n = 0;
}
void TileDrawOneItem(int region, int i, char key, int idx,
int tile, int num, bool floor,
bool select, bool equip, bool tried, bool cursed)
{
ASSERT(idx >= -1 && idx < MAX_ITEMS);
TileRegionClass *r = (region == REGION_INV1) ? region_item
: region_item2;
int item_x = r->mx;
int dx = (i % item_x) * TILE_X;
int dy = (i / item_x) * TILE_Y;
if (tile == -1)
{
_ImgCopyFromTileImg(TILE_DNGN_UNSEEN, r->backbuf, dx, dy, 1);
return;
}
if (floor)
_ImgCopyFromTileImg(TILE_DNGN_FLOOR, r->backbuf, dx, dy, 1);
else
_ImgCopyFromTileImg(TILE_ITEM_SLOT, r->backbuf, dx, dy, 1);
if (equip)
{
if (cursed)
_ImgCopyFromTileImg(TILE_ITEM_SLOT_EQUIP_CURSED, r->backbuf,
dx, dy, 0);
else
_ImgCopyFromTileImg(TILE_ITEM_SLOT_EQUIP, r->backbuf, dx, dy, 0);
}
else if (cursed)
_ImgCopyFromTileImg(TILE_ITEM_SLOT_CURSED, r->backbuf, dx, dy, 0);
if (select)
_ImgCopyFromTileImg(TILE_RAY_MESH, r->backbuf, dx, dy, 0);
if (itemlist_iflag[i] & TILEI_FLAG_CURSOR)
_ImgCopyFromTileImg(TILE_CURSOR, r->backbuf, dx, dy, 0);
// Item tile
_ImgCopyFromTileImg(tile, r->backbuf, dx, dy, 0);
// quantity/charge
if (num != -1)
{
// If you have that many, who cares.
if (num > 999)
num = 999;
const int offset_amount = TILE_X/4;
int offset = 0;
int help = num;
int c100 = help/100;
help -= c100*100;
if (c100)
{
_TilePutch('0' + c100, r->backbuf, dx+offset, dy);
offset += offset_amount;
}
int c10 = help/10;
if (c10 || c100)
{
_TilePutch('0' + c10, r->backbuf, dx+offset, dy);
offset += offset_amount;
}
int c1 = help % 10;
_TilePutch('0' + c1, r->backbuf, dx+offset, dy);
}
// '?' mark
if (tried)
_TilePutch('?', r->backbuf, dx, dy + TILE_Y/2);
// record tile information as we draw it so that we can re-draw it at will
itemlist[i] = tile;
itemlist_num[i] = num;
itemlist_key[i] = key;
itemlist_idx[i] = idx;
itemlist_iflag[i] = 0;
if (floor)
itemlist_iflag[i] |= TILEI_FLAG_FLOOR;
if (tried)
itemlist_iflag[i] |= TILEI_FLAG_TRIED;
if (equip)
itemlist_iflag[i] |= TILEI_FLAG_EQUIP;
if (cursed)
itemlist_iflag[i] |= TILEI_FLAG_CURSE;
if (select)
itemlist_iflag[i] |= TILEI_FLAG_SELECT;
if (i >= itemlist_n)
itemlist_n = i+1;
#endif
void TileDrawInvData(int n, int flag, int *tiles, int *num, int *idx,
int *iflags)
{
int i;
TileRegionClass *r = (flag == REGION_INV1 ? region_item
: region_item2);
r->flag = true;
last_cursor = -1;
int old_itemlist_n = itemlist_n;
itemlist_n = n;
int item_x = r->mx;
int item_y = r->my;
for (i = 0; i < item_x * item_y; i++)
{
if (i == MAX_ITEMLIST)
break;
int tile0 = (i >= n) ? -1 : tiles[i];
int idx0 = (i >= n) ? -1 : idx[i];
char key = (iflags[i] & TILEI_FLAG_FLOOR) ? 0
: index_to_letter(idx[i]);
if (flag == itemlist_flag
&& tile0 == itemlist[i]
&& num[i] == itemlist_num[i]
&& key == itemlist_key[i]
&& idx0 == itemlist_idx[i]
&& iflags[i] == itemlist_iflag[i]
&& !force_redraw_inv
&& i < old_itemlist_n)
{
continue;
}
TileDrawOneItem(flag, i, key, idx0, tile0, num[i],
((iflags[i]&TILEI_FLAG_FLOOR) != 0),
((iflags[i]&TILEI_FLAG_SELECT) != 0),
((iflags[i]&TILEI_FLAG_EQUIP) != 0),
((iflags[i]&TILEI_FLAG_TRIED) != 0),
((iflags[i]&TILEI_FLAG_CURSE) != 0));
}
r->make_active();
r->redraw();
itemlist_flag = flag;
force_redraw_inv = false;
}
void TileDrawInvCursor(int ix, bool flag)
{
TileRegionClass *r =
(itemlist_flag == REGION_INV1) ? region_item
: region_item2;
int tile0 = itemlist[ix];
int num0 = itemlist_num[ix];
if (flag)
itemlist_iflag[ix] |= TILEI_FLAG_CURSOR;
else
itemlist_iflag[ix] &= ~TILEI_FLAG_CURSOR;
TileDrawOneItem(itemlist_flag, ix, itemlist_key[ix], itemlist_idx[ix], tile0, num0,
((itemlist_iflag[ix]&TILEI_FLAG_FLOOR) != 0),
((itemlist_iflag[ix]&TILEI_FLAG_SELECT) != 0),
((itemlist_iflag[ix]&TILEI_FLAG_EQUIP) != 0),
((itemlist_iflag[ix]&TILEI_FLAG_TRIED) != 0),
((itemlist_iflag[ix]&TILEI_FLAG_CURSE) != 0));
r->redraw();
}
void TileMoveInvCursor(int ix)
{
if (last_cursor != -1)
TileDrawInvCursor(last_cursor, false);
if (ix != -1)
TileDrawInvCursor(ix, true);
last_cursor = ix;
}
int TileInvIdx(int i)
{
if (i >= itemlist_n)
return -1;
else
return itemlist_idx[i];
}
marshallByte(th, env.tile_flavor[count_x][count_y].wall);
marshallByte(th, env.tile_flavor[count_x][count_y].floor);
marshallByte(th, env.tile_flavor[count_x][count_y].special);
marshallByte(th, env.tile_flv[count_x][count_y].wall);
marshallByte(th, env.tile_flv[count_x][count_y].floor);
marshallByte(th, env.tile_flv[count_x][count_y].special);
env.tile_flavor[x][y].wall = unmarshallByte(th);
env.tile_flavor[x][y].floor = unmarshallByte(th);
env.tile_flavor[x][y].special = unmarshallByte(th);
env.tile_flv[x][y].wall = unmarshallByte(th);
env.tile_flv[x][y].floor = unmarshallByte(th);
env.tile_flv[x][y].special = unmarshallByte(th);
%sdir dc-dngn
blank BLANK
dngn_unseen DNGN_UNSEEN
floor/pebble_gray0 DNGN_FLOOR
floor/pebble_gray1
floor/pebble_gray2
floor/pebble_gray3
floor/pebble_gray3
floor/pebble_gray3
floor/pebble_gray3
floor/pebble_gray3 DNGN_FLOOR_SPECIAL
wall/brick_brown0 DNGN_ROCK_WALL_OFS
wall/brick_brown1
wall/brick_brown2
wall/brick_brown3
wall/brick_brown3
wall/brick_brown3
wall/brick_brown3
wall/brick_brown3
wall/brick_brown3
wall/brick_brown3
wall/brick_brown3
wall/brick_brown3
floor/lava0 DNGN_LAVA
floor/lava1
floor/lava2
floor/lava3
dngn_deep_water DNGN_DEEP_WATER
dngn_deep_water
dngn_deep_water
dngn_deep_water
dngn_shallow_water DNGN_SHALLOW_WATER
dngn_shallow_water
dngn_shallow_water
dngn_shallow_water
wall/stone2_gray0 DNGN_STONE_WALL
wall/stone2_gray1
wall/stone2_gray2
wall/stone2_gray3
dngn_metal_wall DNGN_METAL_WALL
dngn_green_crystal_wall DNGN_GREEN_CRYSTAL_WALL
dngn_wax_wall DNGN_WAX_WALL
#dngn_rock_wall_00 DNGN_ROCK_WALL_OFS
#dngn_rock_wall_01 IGNORE_COMMENT
#dngn_rock_wall_02 IGNORE_COMMENT
#dngn_rock_wall_03 IGNORE_COMMENT
#dngn_rock_wall_04 IGNORE_COMMENT
#dngn_rock_wall_05 IGNORE_COMMENT
#dngn_rock_wall_06 IGNORE_COMMENT
#dngn_rock_wall_07 IGNORE_COMMENT
#dngn_rock_wall_08 IGNORE_COMMENT
#dngn_rock_wall_09 IGNORE_COMMENT
#dngn_rock_wall_10 IGNORE_COMMENT
#dngn_rock_wall_11 IGNORE_COMMENT
#dngn_rock_wall_12 IGNORE_COMMENT
#dngn_rock_wall_13 IGNORE_COMMENT
#dngn_rock_wall_14 IGNORE_COMMENT
#dngn_rock_wall_15 IGNORE_COMMENT
#dngn_stone_wall DNGN_STONE_WALL
dngn_closed_door DNGN_CLOSED_DOOR
dngn_open_door DNGN_OPEN_DOOR
###dc/wal8 DNGN_SECRET_DOOR
dngn_orcish_idol DNGN_ORCISH_IDOL
dngn_silver_statue DNGN_SILVER_STATUE
dngn_granite_statue DNGN_GRANITE_STATUE
dngn_orange_crystal_statue DNGN_ORANGE_CRYSTAL_STATUE
dngn_ice_statue DNGN_ICE_STATUE
###dc/wal1 DNGN_PERMAROCK_WALL
###dc/wal1 DNGN_LAST_SOLID_TILE
dngn_enter_hell DNGN_ENTER_HELL
dngn_branch_stairs DNGN_BRANCH_STAIRS
dngn_trap_shaft DNGN_TRAP_SHAFT
###847 DNGN_UNDISCOVERED_TRAP
stone_stairs_down DNGN_STONE_STAIRS_DOWN
#nh-dngn/staircase_down DNGN_STONE_STAIRS_DOWN_II
#nh-dngn/staircase_down DNGN_STONE_STAIRS_DOWN_III
rock_stairs_down DNGN_ROCK_STAIRS_DOWN
stone_stairs_up DNGN_STONE_STAIRS_UP
#nh-dngn/staircase_up DNGN_STONE_STAIRS_UP_II
#nh-dngn/staircase_up DNGN_STONE_STAIRS_UP_III
rock_stairs_up DNGN_ROCK_STAIRS_UP
dngn_enter_shop DNGN_ENTER_SHOP
dngn_enter_labyrinth DNGN_ENTER_LABYRINTH
dngn_enter_dis DNGN_ENTER_DIS
dngn_enter_gehenna DNGN_ENTER_GEHENNA
dngn_enter_cocytus DNGN_ENTER_COCYTUS
dngn_enter_tartarus DNGN_ENTER_TARTARUS
dngn_enter_abyss DNGN_ENTER_ABYSS
dngn_exit DNGN_EXIT_ABYSS
dngn_stone_arch DNGN_STONE_ARCH
dngn_enter_pandemonium DNGN_ENTER_PANDEMONIUM
dngn_exit DNGN_EXIT_PANDEMONIUM
dngn_transit_pandemonium DNGN_TRANSIT_PANDEMONIUM
####846 DNGN_BUILDER_SPECIAL_WALL
####846 DNGN_BUILDER_SPECIAL_FLOOR
dngn_enter DNGN_ENTER
#851 DNGN_ENTER_ORCISH_MINES
#851 DNGN_ENTER_HIVE
#851 DNGN_ENTER_LAIR
#851 DNGN_ENTER_SLIME_PITS
#851 DNGN_ENTER_VAULTS
#851 DNGN_ENTER_CRYPT
#851 DNGN_ENTER_HALL_OF_BLADES
#851 DNGN_ENTER_ZOT
#851 DNGN_ENTER_TEMPLE
#851 DNGN_ENTER_SNAKE_PIT
#851 DNGN_ENTER_ELVEN_HALLS
#851 DNGN_ENTER_TOMB
#851 DNGN_ENTER_SWAMP
dngn_return DNGN_RETURN
#850 DNGN_RETURN_FROM_ORCISH_MINES
#850 DNGN_RETURN_FROM_HIVE
#850 DNGN_RETURN_FROM_LAIR
#850 DNGN_RETURN_FROM_SLIME_PITS
#850 DNGN_RETURN_FROM_VAULTS
#850 DNGN_RETURN_FROM_CRYPT
#850 DNGN_RETURN_FROM_HALL_OF_BLADES
#850 DNGN_RETURN_FROM_ZOT
#850 DNGN_RETURN_FROM_TEMPLE
#850 DNGN_RETURN_FROM_SNAKE_PIT
#850 DNGN_RETURN_FROM_ELVEN_HALLS
#850 DNGN_RETURN_FROM_TOMB
#850 DNGN_RETURN_FROM_SWAMP
dngn_altar_zin DNGN_ALTAR_ZIN
dngn_altar_shining_one DNGN_ALTAR_SHINING_ONE
dngn_altar_kikubaaqudgha DNGN_ALTAR_KIKUBAAQUDGHA
dngn_altar_yredelemnul DNGN_ALTAR_YREDELEMNUL
dngn_altar_xom DNGN_ALTAR_XOM
dngn_altar_vehumet DNGN_ALTAR_VEHUMET
dngn_altar_okawaru DNGN_ALTAR_OKAWARU
dngn_altar_makhleb DNGN_ALTAR_MAKHLEB
dngn_altar_sif_muna DNGN_ALTAR_SIF_MUNA
dngn_altar_trog DNGN_ALTAR_TROG
dngn_altar_nemelex_xobeh DNGN_ALTAR_NEMELEX_XOBEH
dngn_altar_elyvilon DNGN_ALTAR_ELYVILON
dngn_altar_lugonu DNGN_ALTAR_LUGONU
dngn_altar_beogh DNGN_ALTAR_BEOGH
dngn_blue_fountain DNGN_BLUE_FOUNTAIN
dngn_sparkling_fountain DNGN_SPARKLING_FOUNTAIN
#858 DNGN_PERMADRY_FOUNTAIN
dngn_blood_fountain DNGN_BLOOD_FOUNTAIN
dngn_dry_fountain DNGN_DRY_FOUNTAIN
%rim 0
%rim 1
%rim 0
%rim 1
dngn_trap_dart DNGN_TRAP_DART
dngn_trap_arrow DNGN_TRAP_ARROW
dngn_trap_spear DNGN_TRAP_SPEAR
dngn_trap_axe DNGN_TRAP_AXE
dngn_trap_teleport DNGN_TRAP_TELEPORT
dngn_trap_alarm DNGN_TRAP_ALARM
dngn_trap_blade DNGN_TRAP_BLADE
dngn_trap_bolt DNGN_TRAP_BOLT
dngn_trap_net DNGN_TRAP_NET
dngn_trap_zot DNGN_TRAP_ZOT
dngn_trap_needle DNGN_TRAP_NEEDLE
%rim 0
%rim 1
gate_open_left DNGN_GATE_OPEN_LEFT
gate_open_middle DNGN_GATE_OPEN_MIDDLE
gate_open_right DNGN_GATE_OPEN_RIGHT
gate_closed_left DNGN_GATE_CLOSED_LEFT
gate_closed_middle DNGN_GATE_CLOSED_MIDDLE
gate_closed_right DNGN_GATE_CLOSED_RIGHT
dngn_transparent_wall DNGN_TRANSPARENT_WALL
floor/floor_nerves0 DNGN_FLOOR_CORRUPT
floor/floor_nerves1
floor/floor_nerves2
floor/floor_nerves3
wall/undead0 DNGN_WALL_CORRUPT
wall/undead1
wall/undead2
wall/undead3
# Do not separate basic floors and rock walls. They get overwritten by
# branch-specific floors and walls and will overwrite anything in between.
counts[tilecountidx++] = tilecount;
fprintf(sfp, "\n\n");
fprintf(sfp, "enum TILE_%sCOUNT_IDX {\n", enumprefix);
for (i = 0; i < tilecountidx; i++)
{
fprintf(sfp, " IDX_%s,\n", countnames[i]);
}
fprintf(sfp, " IDX_%sTOTAL\n};\n\n", enumprefix);
fprintf(sfp, "extern int tile_%scount[IDX_%sTOTAL];\n", enumprefix, enumprefix);
fprintf(sfp, "extern int tile_%sstart[IDX_%sTOTAL];\n\n", enumprefix, enumprefix);
%enumprefix W2D_
%tiledef tiledef-w2d.h
%tilecount tilecount-w2d.h
%width 16
%back none
%name wall2d
%sdir dc-dngn
wall/brick_brown0 WALL_NORMAL
wall/brick_brown1
wall/brick_brown2
wall/brick_brown3
floor/pebble_gray0 FLOOR_NORMAL
floor/pebble_gray1
floor/pebble_gray2
floor/pebble_gray3
floor/pebble_gray4
wall/relief0 WALL_HALL
wall/relief1
wall/relief2
wall/relief3
floor/mesh0 FLOOR_HALL
floor/mesh1
floor/mesh2
floor/mesh3
wall/hive0 WALL_HIVE
wall/hive1
wall/hive2
wall/hive3
floor/hive0 FLOOR_HIVE
floor/hive1
floor/hive2
floor/hive3
wall/ice0 WALL_ICE
wall/ice1
wall/ice2
wall/ice3
floor/ice0 FLOOR_ICE
floor/ice1
floor/ice2
floor/ice3
wall/lair0 WALL_LAIR
wall/lair1
wall/lair2
wall/lair3
floor/lair0 FLOOR_LAIR
floor/lair1
floor/lair2
floor/lair3
## orcs don't have their own floor or walls yet...
wall/lair0 WALL_ORC
wall/lair1
wall/lair2
wall/lair3
floor/hive0 FLOOR_ORC
floor/hive1
floor/hive2
floor/hive3
wall/slime0 WALL_SLIME
wall/slime1
wall/slime2
wall/slime3
floor/bog_green0 FLOOR_SLIME
floor/bog_green1
floor/bog_green2
floor/bog_green3
wall/snake0 WALL_SNAKE
wall/snake1
wall/snake2
wall/snake3
floor/snake0 FLOOR_SNAKE
floor/snake1
floor/snake2
floor/snake3
## swamp also doesn't have any unique walls...
wall/lair0 WALL_SWAMP
wall/lair1
wall/lair2
wall/lair3
floor/swamp0 FLOOR_SWAMP
floor/swamp1
floor/swamp2
floor/swamp3
wall/tomb0 WALL_TOMB
wall/tomb1
wall/tomb2
wall/tomb3
floor/tomb0 FLOOR_TOMB
floor/tomb1
floor/tomb2
floor/tomb3
wall/undead0 WALL_UNDEAD
wall/undead1
wall/undead2
wall/undead3
floor/tomb0 FLOOR_UNDEAD
floor/tomb1
floor/tomb2
floor/tomb3
wall/vault0 WALL_VAULT
wall/vault1
wall/vault2
wall/vault3
floor/rect_gray0 FLOOR_VAULT
floor/rect_gray1
floor/rect_gray2
floor/rect_gray3
wall/zot_blue0 WALL_ZOT_BLUE
wall/zot_blue1
wall/zot_blue2
wall/zot_blue3
floor/tomb0 FLOOR_ZOT_BLUE
floor/tomb1
floor/tomb2
floor/tomb3
wall/zot_cyan0 WALL_ZOT_CYAN
wall/zot_cyan1
wall/zot_cyan2
wall/zot_cyan3
floor/tomb0 FLOOR_ZOT_CYAN
floor/tomb1
floor/tomb2
floor/tomb3
wall/zot_gray0 WALL_ZOT_GRAY
wall/zot_gray1
wall/zot_gray2
wall/zot_gray3
floor/tomb0 FLOOR_ZOT_GRAY
floor/tomb1
floor/tomb2
floor/tomb3
wall/zot_green0 WALL_ZOT_GREEN
wall/zot_green1
wall/zot_green2
wall/zot_green3
floor/tomb0 FLOOR_ZOT_GREEN
floor/tomb1
floor/tomb2
floor/tomb3
wall/zot_magenta0 WALL_ZOT_MAGENTA
wall/zot_magenta1
wall/zot_magenta2
wall/zot_magenta3
floor/tomb0 FLOOR_ZOT_MAGENTA
floor/tomb1
floor/tomb2
floor/tomb3
wall/zot_red0 WALL_ZOT_RED
wall/zot_red1
wall/zot_red2
wall/zot_red3
floor/tomb0 FLOOR_ZOT_RED
floor/tomb1
floor/tomb2
floor/tomb3
wall/zot_yellow0 WALL_ZOT_YELLOW
wall/zot_yellow1
wall/zot_yellow2
wall/zot_yellow3
floor/tomb0 FLOOR_ZOT_YELLOW
floor/tomb1
floor/tomb2
floor/tomb3
wall/wall_flesh0 WALL_FLESH
wall/wall_flesh1
wall/wall_flesh2
wall/wall_flesh3
wall/wall_flesh4
wall/wall_flesh5
wall/wall_flesh6
floor/floor_nerves0 FLOOR_NERVES
floor/floor_nerves1
floor/floor_nerves2
floor/floor_nerves3
floor/floor_nerves4
floor/floor_nerves5
floor/floor_nerves6
wall/wall_vines0 WALL_VINES
wall/wall_vines1
wall/wall_vines2
wall/wall_vines3
wall/wall_vines4
wall/wall_vines5
wall/wall_vines6
floor/floor_vines0 FLOOR_VINES
floor/floor_vines1
floor/floor_vines2
floor/floor_vines3
floor/floor_vines4
floor/floor_vines5
floor/floor_vines6
wall/pebble_red0 WALL_PEBBLE_RED
wall/pebble_red1
wall/pebble_red2
wall/pebble_red3
floor/rough_red0 FLOOR_ROUGH_RED
floor/rough_red1
floor/rough_red2
floor/rough_red3
floor/floor_sand_stone0 FLOOR_SAND_STONE
floor/floor_sand_stone1
floor/floor_sand_stone2
floor/floor_sand_stone3
floor/floor_sand_stone4
floor/floor_sand_stone5
floor/floor_sand_stone6
floor/floor_sand_stone7
wall/wall_yellow_rock0 WALL_YELLOW_ROCK
wall/wall_yellow_rock1
wall/wall_yellow_rock2
wall/wall_yellow_rock3
wall/brick_gray0 WALL_BAZAAR_GRAY
wall/brick_gray1
wall/brick_gray2
wall/brick_gray3
wall/stone_gray0 WALL_BAZAAR_STONE
wall/stone_gray1
wall/stone_gray2
wall/stone_gray3
floor/grass0 FLOOR_BAZAAR_GRASS
floor/grass1
floor/grass2
floor/grass_n FLOOR_BAZAAR_GRASS1_SPECIAL
floor/grass_ne
floor/grass_e
floor/grass_se
floor/grass_s
floor/grass_sw
floor/grass_w
floor/grass_nw
floor/grass_full
%start
%compose floor/grass0
%compose floor/pedestal_n
%finish FLOOR_BAZAAR_GRASS2_SPECIAL
%start
%compose floor/grass1
%compose floor/pedestal_ne
%finish
%start
%compose floor/grass2
%compose floor/pedestal_e
%finish
%start
%compose floor/grass1
%compose floor/pedestal_se
%finish
%start
%compose floor/grass0
%compose floor/pedestal_s
%finish
%start
%compose floor/grass1
%compose floor/pedestal_sw
%finish
%start
%compose floor/grass2
%compose floor/pedestal_w
%finish
%start
%compose floor/grass0
%compose floor/pedestal_nw
%finish
floor/pedestal_full
%start
%compose floor/rect_gray0
%compose floor/pedestal_n
%finish FLOOR_BAZAAR_VAULT_SPECIAL
%start
%compose floor/rect_gray1
%compose floor/pedestal_ne
%finish
%start
%compose floor/rect_gray2
%compose floor/pedestal_e
%finish
%start
%compose floor/rect_gray3
%compose floor/pedestal_se
%finish
%start
%compose floor/rect_gray2
%compose floor/pedestal_s
%finish
%start
%compose floor/rect_gray1
%compose floor/pedestal_sw
%finish
%start
%compose floor/rect_gray0
%compose floor/pedestal_w
%finish
%start
%compose floor/rect_gray3
%compose floor/pedestal_nw
%finish
floor/pedestal_full
floor/dirt0 FLOOR_BAZAAR_DIRT
floor/dirt1
floor/dirt2
floor/dirt_n FLOOR_BAZAAR_DIRT_SPECIAL
floor/dirt_ne
floor/dirt_e
floor/dirt_se
floor/dirt_s
floor/dirt_sw
floor/dirt_w
floor/dirt_nw
floor/dirt_full
%enumprefix DNGN_
%tiledef tiledef-dngn.h
%tilecount tilecount-dngn.h
%width 16
%back none
%name dngn
%sdir dc-dngn
dngn_unseen DNGN_UNSEEN
wall/brick_brown0 WALL_NORMAL
wall/brick_brown1
wall/brick_brown2
wall/brick_brown3
floor/pebble_gray0 FLOOR_NORMAL
floor/pebble_gray1
floor/pebble_gray2
floor/pebble_gray3
floor/pebble_gray4
wall/relief0 WALL_HALL
wall/relief1
wall/relief2
wall/relief3
floor/mesh0 FLOOR_HALL
floor/mesh1
floor/mesh2
floor/mesh3
wall/hive0 WALL_HIVE
wall/hive1
wall/hive2
wall/hive3
floor/hive0 FLOOR_HIVE
floor/hive1
floor/hive2
floor/hive3
wall/ice0 WALL_ICE
wall/ice1
wall/ice2
wall/ice3
floor/ice0 FLOOR_ICE
floor/ice1
floor/ice2
floor/ice3
wall/lair0 WALL_LAIR
wall/lair1
wall/lair2
wall/lair3
floor/lair0 FLOOR_LAIR
floor/lair1
floor/lair2
floor/lair3
## orcs don't have their own floor or walls yet...
wall/lair0 WALL_ORC
wall/lair1
wall/lair2
wall/lair3
floor/hive0 FLOOR_ORC
floor/hive1
floor/hive2
floor/hive3
wall/slime0 WALL_SLIME
wall/slime1
wall/slime2
wall/slime3
floor/bog_green0 FLOOR_SLIME
floor/bog_green1
floor/bog_green2
floor/bog_green3
wall/snake0 WALL_SNAKE
wall/snake1
wall/snake2
wall/snake3
floor/snake0 FLOOR_SNAKE
floor/snake1
floor/snake2
floor/snake3
## swamp also doesn't have any unique walls...
wall/lair0 WALL_SWAMP
wall/lair1
wall/lair2
wall/lair3
floor/swamp0 FLOOR_SWAMP
floor/swamp1
floor/swamp2
floor/swamp3
wall/tomb0 WALL_TOMB
wall/tomb1
wall/tomb2
wall/tomb3
floor/tomb0 FLOOR_TOMB
floor/tomb1
floor/tomb2
floor/tomb3
wall/vault0 WALL_VAULT
wall/vault1
wall/vault2
wall/vault3
floor/rect_gray0 FLOOR_VAULT
floor/rect_gray1
floor/rect_gray2
floor/rect_gray3
wall/zot_blue0 WALL_ZOT_BLUE
wall/zot_blue1
wall/zot_blue2
wall/zot_blue3
wall/zot_cyan0 WALL_ZOT_CYAN
wall/zot_cyan1
wall/zot_cyan2
wall/zot_cyan3
wall/zot_gray0 WALL_ZOT_GRAY
wall/zot_gray1
wall/zot_gray2
wall/zot_gray3
wall/zot_green0 WALL_ZOT_GREEN
wall/zot_green1
wall/zot_green2
wall/zot_green3
wall/zot_magenta0 WALL_ZOT_MAGENTA
wall/zot_magenta1
wall/zot_magenta2
wall/zot_magenta3
wall/zot_red0 WALL_ZOT_RED
wall/zot_red1
wall/zot_red2
wall/zot_red3
wall/zot_yellow0 WALL_ZOT_YELLOW
wall/zot_yellow1
wall/zot_yellow2
wall/zot_yellow3
wall/wall_flesh0 WALL_FLESH
wall/wall_flesh1
wall/wall_flesh2
wall/wall_flesh3
wall/wall_flesh4
wall/wall_flesh5
wall/wall_flesh6
wall/wall_vines0 WALL_VINES
wall/wall_vines1
wall/wall_vines2
wall/wall_vines3
wall/wall_vines4
wall/wall_vines5
wall/wall_vines6
floor/floor_vines0 FLOOR_VINES
floor/floor_vines1
floor/floor_vines2
floor/floor_vines3
floor/floor_vines4
floor/floor_vines5
floor/floor_vines6
wall/pebble_red0 WALL_PEBBLE_RED
wall/pebble_red1
wall/pebble_red2
wall/pebble_red3
floor/rough_red0 FLOOR_ROUGH_RED
floor/rough_red1
floor/rough_red2
floor/rough_red3
floor/floor_sand_stone0 FLOOR_SAND_STONE
floor/floor_sand_stone1
floor/floor_sand_stone2
floor/floor_sand_stone3
floor/floor_sand_stone4
floor/floor_sand_stone5
floor/floor_sand_stone6
floor/floor_sand_stone7
wall/wall_yellow_rock0 WALL_YELLOW_ROCK
wall/wall_yellow_rock1
wall/wall_yellow_rock2
wall/wall_yellow_rock3
wall/brick_gray0 WALL_BAZAAR_GRAY
wall/brick_gray1
wall/brick_gray2
wall/brick_gray3
wall/stone_gray0 WALL_BAZAAR_STONE
wall/stone_gray1
wall/stone_gray2
wall/stone_gray3
floor/grass0 FLOOR_BAZAAR_GRASS
floor/grass1
floor/grass2
floor/grass_n FLOOR_BAZAAR_GRASS1_SPECIAL
floor/grass_ne
floor/grass_e
floor/grass_se
floor/grass_s
floor/grass_sw
floor/grass_w
floor/grass_nw
floor/grass_full
## NOTE: wall_undead and floor_nerves are used for the corruption effect.
## They need to go last.
wall/undead0 WALL_UNDEAD
wall/undead1
wall/undead2
wall/undead3
floor/floor_nerves0 FLOOR_NERVES
floor/floor_nerves1
floor/floor_nerves2
floor/floor_nerves3
floor/floor_nerves4
floor/floor_nerves5
floor/floor_nerves6
%start
%compose floor/grass0
%compose floor/pedestal_n
%finish FLOOR_BAZAAR_GRASS2_SPECIAL
%start
%compose floor/grass1
%compose floor/pedestal_ne
%finish
%start
%compose floor/grass2
%compose floor/pedestal_e
%finish
%start
%compose floor/grass1
%compose floor/pedestal_se
%finish
%start
%compose floor/grass0
%compose floor/pedestal_s
%finish
%start
%compose floor/grass1
%compose floor/pedestal_sw
%finish
%start
%compose floor/grass2
%compose floor/pedestal_w
%finish
%start
%compose floor/grass0
%compose floor/pedestal_nw
%finish
floor/pedestal_full
%start
%compose floor/rect_gray0
%compose floor/pedestal_n
%finish FLOOR_BAZAAR_VAULT_SPECIAL
%start
%compose floor/rect_gray1
%compose floor/pedestal_ne
%finish
%start
%compose floor/rect_gray2
%compose floor/pedestal_e
%finish
%start
%compose floor/rect_gray3
%compose floor/pedestal_se
%finish
%start
%compose floor/rect_gray2
%compose floor/pedestal_s
%finish
%start
%compose floor/rect_gray1
%compose floor/pedestal_sw
%finish
%start
%compose floor/rect_gray0
%compose floor/pedestal_w
%finish
%start
%compose floor/rect_gray3
%compose floor/pedestal_nw
%finish
floor/pedestal_full
floor/dirt0 FLOOR_BAZAAR_DIRT
floor/dirt1
floor/dirt2
floor/dirt_n FLOOR_BAZAAR_DIRT_SPECIAL
floor/dirt_ne
floor/dirt_e
floor/dirt_se
floor/dirt_s
floor/dirt_sw
floor/dirt_w
floor/dirt_nw
floor/dirt_full
floor/lava0 DNGN_LAVA
floor/lava1
floor/lava2
floor/lava3
dngn_deep_water DNGN_DEEP_WATER
dngn_deep_water
dngn_deep_water
dngn_deep_water
dngn_shallow_water DNGN_SHALLOW_WATER
dngn_shallow_water
dngn_shallow_water
dngn_shallow_water
wall/stone2_gray0 DNGN_STONE_WALL
wall/stone2_gray1
wall/stone2_gray2
wall/stone2_gray3
dngn_metal_wall DNGN_METAL_WALL
dngn_green_crystal_wall DNGN_GREEN_CRYSTAL_WALL
dngn_wax_wall DNGN_WAX_WALL
dngn_transparent_wall DNGN_TRANSPARENT_WALL
dngn_closed_door DNGN_CLOSED_DOOR
gate_closed_left DNGN_GATE_CLOSED_LEFT
gate_closed_middle DNGN_GATE_CLOSED_MIDDLE
gate_closed_right DNGN_GATE_CLOSED_RIGHT
dngn_open_door DNGN_OPEN_DOOR
gate_open_left DNGN_GATE_OPEN_LEFT
gate_open_middle DNGN_GATE_OPEN_MIDDLE
gate_open_right DNGN_GATE_OPEN_RIGHT
dngn_orcish_idol DNGN_ORCISH_IDOL
dngn_silver_statue DNGN_SILVER_STATUE
dngn_granite_statue DNGN_GRANITE_STATUE
%rim 1
dngn_enter_hell DNGN_ENTER_HELL
%rim 0
dngn_branch_stairs DNGN_BRANCH_STAIRS
dngn_trap_dart DNGN_TRAP_DART
dngn_trap_arrow DNGN_TRAP_ARROW
dngn_trap_spear DNGN_TRAP_SPEAR
dngn_trap_axe DNGN_TRAP_AXE
dngn_trap_teleport DNGN_TRAP_TELEPORT
dngn_trap_alarm DNGN_TRAP_ALARM
dngn_trap_blade DNGN_TRAP_BLADE
dngn_trap_bolt DNGN_TRAP_BOLT
dngn_trap_net DNGN_TRAP_NET
dngn_trap_zot DNGN_TRAP_ZOT
dngn_trap_needle DNGN_TRAP_NEEDLE
dngn_trap_shaft DNGN_TRAP_SHAFT
stone_stairs_down DNGN_STONE_STAIRS_DOWN
rock_stairs_down DNGN_ROCK_STAIRS_DOWN
stone_stairs_up DNGN_STONE_STAIRS_UP
rock_stairs_up DNGN_ROCK_STAIRS_UP
dngn_enter_shop DNGN_ENTER_SHOP
dngn_enter_labyrinth DNGN_ENTER_LABYRINTH
dngn_enter_dis DNGN_ENTER_DIS
dngn_enter_gehenna DNGN_ENTER_GEHENNA
dngn_enter_cocytus DNGN_ENTER_COCYTUS
dngn_enter_tartarus DNGN_ENTER_TARTARUS
dngn_enter_abyss DNGN_ENTER_ABYSS
dngn_exit DNGN_EXIT_ABYSS
dngn_stone_arch DNGN_STONE_ARCH
dngn_enter_pandemonium DNGN_ENTER_PANDEMONIUM
dngn_exit DNGN_EXIT_PANDEMONIUM
%rim 1
dngn_transit_pandemonium DNGN_TRANSIT_PANDEMONIUM
%rim 0
dngn_enter DNGN_ENTER
%rim 1
dngn_return DNGN_RETURN
%rim 0
dngn_altar_zin DNGN_ALTAR_ZIN
dngn_altar_shining_one DNGN_ALTAR_SHINING_ONE
dngn_altar_kikubaaqudgha DNGN_ALTAR_KIKUBAAQUDGHA
dngn_altar_yredelemnul DNGN_ALTAR_YREDELEMNUL
dngn_altar_xom DNGN_ALTAR_XOM
dngn_altar_vehumet DNGN_ALTAR_VEHUMET
dngn_altar_okawaru DNGN_ALTAR_OKAWARU
dngn_altar_makhleb DNGN_ALTAR_MAKHLEB
dngn_altar_sif_muna DNGN_ALTAR_SIF_MUNA
dngn_altar_trog DNGN_ALTAR_TROG
dngn_altar_nemelex_xobeh DNGN_ALTAR_NEMELEX_XOBEH
dngn_altar_elyvilon DNGN_ALTAR_ELYVILON
dngn_altar_lugonu DNGN_ALTAR_LUGONU
dngn_altar_beogh DNGN_ALTAR_BEOGH
dngn_blue_fountain DNGN_BLUE_FOUNTAIN
dngn_sparkling_fountain DNGN_SPARKLING_FOUNTAIN
dngn_blood_fountain DNGN_BLOOD_FOUNTAIN
dngn_dry_fountain DNGN_DRY_FOUNTAIN
## Miscellaneous entries that get drawn on the background
dc-misc/blood_red BLOOD
dc-misc/blood_red1
dc-misc/blood_red2
dc-misc/blood_red3
dc-misc/blood_red4
dc-misc/halo HALO
dc-misc/ray RAY_MESH
dc-misc/travel_exclusion TRAVEL_EXCLUSION_BG
dc-misc/travel_exclusion_centre TRAVEL_EXCLUSION_CENTRE_BG
dc-misc/slot ITEM_SLOT
effect/sanctuary SANCTUARY
%sdir dc-dngn
dngn_orange_crystal_statue DNGN_ORANGE_CRYSTAL_STATUE
dngn_ice_statue DNGN_ICE_STATUE
%sdir dc-mon
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
dc-misc/unseen_monster
#ifdef USE_TILE
// We could check for this above, but we need to do this post-move
// to force the merfolk tile to be out of water.
if ((!grid_is_water(new_grid) && grid_is_water(old_grid)
|| grid_is_water(new_grid) && !grid_is_water(old_grid))
&& you.species == SP_MERFOLK)
{
TilePlayerRefresh();
}
#endif
FREETYPE_INCLUDE := -I/sw/include/freetype2
# 10.5 Fink bug
FINK_OPENGL_WORKAROUND := -Wl,-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib
SDL_LDFLAGS += -framework Cocoa -L/usr/X11/lib $(FINK_OPENGL_WORKAROUND)
EXTRA_INCLUDES += -I/sw/include
LIB = -static -lwinmm -mwindows -lcomctl32 -L$(LUASRC) -l$(LUALIB) -L$(SQLSRC) -l$(SQLLIB) -lpcre
INCLUDES := -Iutil -I. -I$(LUASRC) -I$(SQLSRC)
LIB = -lwinmm -mwindows -lcomctl32 -L$(LUASRC) -l$(LUALIB) -L$(SQLSRC) -l$(SQLLIB) -lpng $(SDL_LDFLAGS) -lopengl32 -lglu32 -lSDL_image -lfreetype
INCLUDES := -Iutil -I. -I$(LUASRC) -I$(SQLSRC) $(EXTRA_INCLUDES)
mouse_mode mouse_control::ms_current_mode = MOUSE_MODE_NORMAL;
#ifdef USE_X11
#include <X11/Xlib.h>
#include <X11/X.h>
#elif defined(WINDOWS)
#include <windows.h>
// windows.h defines 'near' as an empty string for compatibility.
// This breaks the use of that as a variable name. Urgh.
#ifdef near
#undef near
#endif
#include <commdlg.h>
#endif
void libgui_init();
void libgui_shutdown();
void edit_prefs();
/* ***********************************************************************
Minimap related
* called from: misc view spells2
* *********************************************************************** */
void GmapInit(bool upd_tile);
void GmapDisplay(int linex, int liney);
void GmapUpdate(int x, int y, int what, bool upd_tile = true);
class mouse_control
{
public:
mouse_control(int mode)
{
oldmode = mouse_get_mode();
mouse_set_mode(mode);
}
~mouse_control()
{
mouse_set_mode(oldmode);
}
private:
int oldmode;
};
enum InvAction
{
INV_DROP,
INV_USE, // primary inventory use
INV_USE2, // secondary inventory use
INV_PICKUP,
INV_VIEW,
INV_USE_FLOOR,
INV_EAT_FLOOR,
INV_SELECT,
INV_NUMACTIONS
};
void gui_get_mouse_inv(int &idx, InvAction &act);
void tile_place_cursor(int x, int y, bool display);
void lock_region(int r);
void unlock_region(int r);
enum ScreenRegion
{
REGION_NONE,
REGION_CRT,
REGION_STAT, // stat area
REGION_MSG, // message area
REGION_MAP, // overview map area
REGION_DNGN,
REGION_TDNGN,
REGION_INV1, // items in inventory
REGION_INV2, // items in inventory?
REGION_XMAP,
REGION_TIP,
NUM_REGIONS
};
// types of events
#define EV_KEYIN 1
#define EV_MOVE 2
#define EV_BUTTON 3
#define EV_UNBUTTON 4
#define _NORMALCURSOR 1
#define _NOCURSOR 0
void clrscr();
void message_out(int which_line, int colour, const char *s, int firstcol = 0, bool newline = true);
void cgotoxy(int x, int y, int region = GOTO_CRT);
void clear_message_window();
void delay(int ms);
void update_screen();
int kbhit();
#define DCX (tile_dngn_x/2)
#define DCY (tile_dngn_y/2)
// libx11.cc or libwt.cc
extern void update_tip_text(const char *tip);
extern void libgui_init_sys();
extern void libgui_shutdown_sys();
extern void GetNextEvent(int *etype,
int *key, bool *shift, bool *ctrl,
int *x1, int *y1, int *x2, int *y2);
#ifdef WIN32TILES
// libwt.cc
extern bool windows_change_font(char *font_name, int *font_size, bool dos);
extern void windows_get_winpos(int *x, int *y);
extern void TileInitWin();
#endif
// Main window
WinClass *win_main;
// Regions
TextRegionClass *region_crt = NULL;
MapRegionClass *region_map = NULL;
TileRegionClass *region_tile = NULL;
TextRegionClass *region_stat = NULL;
TextRegionClass *region_msg = NULL;
TextRegionClass *region_dngn = NULL;
TextRegionClass *region_xmap = NULL;
TextRegionClass *region_tip = NULL;
TileRegionClass *region_item = NULL;
TileRegionClass *region_item2 = NULL;
// Raw tile images
img_type TileImg;
img_type PlayerImg;
img_type WallImg;
// for item use gui
#define MAX_ITEMLIST 60
extern int itemlist[MAX_ITEMLIST];
extern int itemlist_num[MAX_ITEMLIST];
extern int itemlist_idx[MAX_ITEMLIST];
extern char itemlist_key[MAX_ITEMLIST];
extern int itemlist_iflag[MAX_ITEMLIST];
extern int itemlist_flag;
extern int itemlist_n;
static bool gui_smart_cursor = false;
// Window prefs
static int crt_x = 80;
static int crt_y = 30;
static int map_px = 4;
static int msg_x = 77, msg_y = 10;
static int dngn_x = 19, dngn_y = 17;
static int winox = 0, winoy = 0;
#define MAX_PREF_CHAR 256
#ifdef USE_X11
#define UseDosChar false
static char font_name[MAX_PREF_CHAR+1] = "8x13";
#endif
#ifdef WIN32TILES
static char font_name[MAX_PREF_CHAR+1] = "courier";
#define UseDosChar (Options.use_dos_char)
static char dos_font_name[MAX_PREF_CHAR+1] = "Terminal";
static int dos_font_size = 16;
#endif
static int font_size = 12;
#define PREF_MODE_TILE 0
#define PREF_MODE_NUM 1
static const char *pref_mode_name[PREF_MODE_NUM] = { "Tile"};
typedef struct prefs
{
const char *name;
const char *tagname;
char type;
void *ptr;
int min, max;
int dummy_idx;
}prefs;
#ifdef WIN32TILES
#define MAX_PREFS 11
#else
#define MAX_PREFS 9
#endif
#define MAX_EDIT_PREFS 5
static int dummy_int[PREF_MODE_NUM][8];
static char dummy_str[PREF_MODE_NUM][2][MAX_PREF_CHAR+1];
struct prefs pref_data[MAX_PREFS] =
{
{"DUNGEON X", "DngnX", 'I', &dngn_x, 17, 35, 0},
{"DUNGEON Y", "DngnY", 'I', &dngn_y, 17, 35, 1},
{"MAP PX ", "MapPx", 'I', &map_px, 1, 10, 2},
{"MSG X ", "MsgX", 'I', &msg_x, 40, 80, 3},
{"MSG Y ", "MsgY", 'I', &msg_y, 8, 20, 4},
{"WIN TOP ", "WindowTop", 'I', &winox, -100, 2000, 5},
{"WIN LEFT ", "WindowLeft",'I', &winoy, -100, 2000, 6},
{"FONT ", "FontName", 'S', font_name, 0, 0, 0},
{"FONT SIZE", "FontSize", 'I', &font_size, 8, 24, 7}
#ifdef WIN32TILES
,{"DOS FONT", "DosFontName", 'S', dos_font_name, 0, 0, 1},
{"DOS FONT SIZE", "DosFontSize", 'I', &dos_font_size, 8, 24, 8}
#endif
};
static int pref_mode = 0;
static void _libgui_load_prefs();
static void _libgui_save_prefs();
//Internal variables
static int mouse_mode = MOUSE_MODE_NORMAL;
// Hack: prevent clrscr for some region.
static bool region_lock[NUM_REGIONS];
static bool toggle_telescope;
/***********************************************************/
//micromap color array
#define MAP_XMAX GXM
#define MAP_YMAX GYM
static unsigned char gmap_data[GXM][GYM];
static int gmap_min_x, gmap_max_x;
static int gmap_min_y, gmap_max_y;
static int gmap_ox, gmap_oy;
// Redefine color constants with shorter names to save space.
#define PX_0 0
#define PX_F 1
#define PX_W 2
#define PX_D 3
#define PX_WB 4
#define PX_I 5
#define PX_M 6
#define PX_US 7
#define PX_DS 8
#define PX_SS 9
#define PX_WT 10
#define PX_LV 11
#define PX_T 12
#define PX_MS 13
static char _gmap_to_colour(char gm)
{
switch (gm)
{
case PX_0: // unseen
default:
return Options.tile_unseen_col;
case PX_F: // floor
return Options.tile_floor_col;
case PX_W: // walls
return Options.tile_wall_col;
case PX_WB: // walls detected by Magic Mapping
return Options.tile_mapped_wall_col;
case PX_D: // doors
return Options.tile_door_col;
case PX_I: // items
return Options.tile_item_col;
case PX_M: // (hostile) monsters
return Options.tile_monster_col;
case PX_US: // upstairs
return Options.tile_upstairs_col;
case PX_DS: // downstairs
return Options.tile_downstairs_col;
case PX_MS: // misc. features (altars, portals, fountains, ...)
case PX_SS: // special stairs (?)
return Options.tile_feature_col;
case PX_WT: // water
return Options.tile_water_col;
case PX_LV: // lava
return Options.tile_lava_col;
case PX_T: // traps
return Options.tile_trap_col;
}
}
static const char gmap_col[256] = {
/* 0x00 */ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0x08 */ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0x10 */ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0x18 */ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* ' ' '!' '"' '#' '$' '%' '&' ''' */
/* 0x20 */ PX_0, PX_I, PX_I, PX_F, PX_I, PX_I, PX_M, PX_D,
/* '(' ')' '*' '+' ',' '-' '.' '/' */
/* 0x28 */ PX_I, PX_I, PX_WB,PX_I, PX_F, PX_0, PX_F, PX_I,
/* 0 1 2 3 4 5 6 7 */
/* 0x30 */ PX_0, PX_M, PX_M, PX_M, PX_M, PX_M, PX_0, PX_0,
/* 8 9 : ; < = > ? */
/* 0x38 */ PX_MS,PX_0, PX_0, PX_M, PX_US,PX_I, PX_DS,PX_I,
/* @ A B C D E F G */
/* 0x40 */ PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M,
/* H I J K L M N O */
/* 0x48 */ PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M,
/* P Q R S T U V W */
/* 0x50 */ PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M,
/* X Y Z [ \ ] ^ _ */
/* 0x58 */ PX_M, PX_M, PX_M, PX_I, PX_I, PX_I, PX_T, PX_MS,
/* ` a b c d e f g */
/* 0x60 */ PX_0, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M,
/* h i j k l m n o */
/* 0x68 */ PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M,
/* p q r s t u v w */
/* 0x70 */ PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M, PX_M,
/* x y z { | } ~ WALL */
/* 0x78 */ PX_M, PX_M, PX_M, PX_WT,PX_0, PX_I, PX_I, PX_W,
/* old cralwj symbols */
/* �� �s �E �� �� �� �� �� */
/* 0x80 */ PX_D, PX_SS,PX_F, PX_MS,PX_MS,PX_MS,PX_D, PX_WT,
/* �t �� �� �� �� �� �� */
/* 0x88 */ PX_SS,PX_W, PX_W, PX_W, PX_W, PX_LV, PX_I, PX_0,
/**/
/* 0x90 144*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0x98 152*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xa0 160*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xa8 168*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xb0 176*/ PX_WB,PX_W, PX_W, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xb8 184*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xc0 192*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xc8 200*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xd0 208*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xd8 216*/ PX_0, PX_0, PX_0, PX_0, PX_MS, PX_0, PX_0, PX_0,
/* 0xe0 224*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0,
/* 0xe8 232*/ PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_0, PX_MS,
/* 0xf0 240*/ PX_0, PX_0, PX_0, PX_0, PX_MS,PX_0, PX_0, PX_WT,
/* 0xf8 248*/ PX_0, PX_F, PX_F, PX_0, PX_0, PX_0, PX_D, PX_0
};
int mouse_grid_x;
int mouse_grid_y;
bool mouse_in_dngn = false;
static void _gui_set_mouse_view_pos(bool in_dngn, int cx, int cy)
{
const coord_def& gc = view2grid(coord_def(cx,cy));
mouse_grid_x = gc.x;
mouse_grid_y = gc.y;
ASSERT(!in_dngn || gc.x >= 0 && gc.y >= 0 && gc.x < GXM && gc.y < GYM);
mouse_in_dngn = in_dngn;
}
bool gui_get_mouse_grid_pos(coord_def &gc)
{
if (mouse_in_dngn)
{
gc.x = mouse_grid_x;
gc.y = mouse_grid_y;
ASSERT(gc.x >= 0 && gc.y >= 0 && gc.x < GXM && gc.y < GYM);
}
return mouse_in_dngn;
}
int inv_idx = 0;
InvAction inv_action = INV_NUMACTIONS;
static void _gui_set_mouse_inv(int idx, InvAction act)
{
inv_idx = idx;
inv_action = act;
}
void gui_get_mouse_inv(int &idx, InvAction &act)
{
idx = inv_idx;
act = inv_action;
}
void GmapUpdate(int x, int y, int what, bool upd_tile)
{
// If you can't map the area, the minimap won't show.
if (!player_in_mappable_area())
return;
int c;
if (x == you.x_pos && y == you.y_pos)
c = Options.tile_player_col; // Player position always highlighted.
else
{
const coord_def gc(x,y);
unsigned int feature = grd(gc);
unsigned int grid_symbol;
unsigned short grid_color;
get_item_symbol(feature, &grid_symbol, &grid_color);
switch (what)
{
// In some cases (like smoke), update the gmap with the ground color
// instead. This keeps it prettier in the case of lava + smoke.
case '#':
c = _gmap_to_colour(gmap_col[grid_symbol & 0xff]);
break;
default:
c = _gmap_to_colour(gmap_col[what & 0xff]);
break;
}
if (c == Options.tile_monster_col && mgrd[x][y] != NON_MONSTER)
{
const int grid = mgrd[x][y];
if (mons_friendly(&menv[grid]))
c = Options.tile_friendly_col; // colour friendly monsters
else if (mons_neutral(&menv[grid]))
c = Options.tile_neutral_col; // colour neutral monsters
else if (mons_class_flag(menv[grid].type, M_NO_EXP_GAIN))
c = Options.tile_plant_col; // colour zero xp monsters
}
if (c == Options.tile_floor_col || c == Options.tile_item_col)
{
if (is_exclude_root( coord_def(x,y) ))
c = Options.tile_excl_centre_col;
else if (c == Options.tile_floor_col && is_excluded(coord_def(x,y)))
c = Options.tile_excluded_col;
}
}
int oldc = gmap_data[x][y];
gmap_data[x][y] = c;
// NOTE: In the case of a magic mapping, we really want the
// map to update with the correct feature (stone instead of rock wall,
// fountains instead of TILE_ERROR). tileidx_unseen won't give that
// to us. However, we can't give the player all the information,
// since that might be cheating in some cases. This could be rewritten.
int t = tile_idx_unseen_terrain(x, y, what);
if (c != 0 && c!= oldc && upd_tile)
{
if (c == PX_I || c == PX_M)
{
env.tile_bk_bg[x][y] = t;
if (env.tile_bk_bg[x][y] == 0)
env.tile_bk_bg[x][y] = tileidx_feature(DNGN_UNSEEN, x, y);
}
else
{
env.tile_bk_bg[x][y] = t;
}
}
else if (c == 0)
{
// Forget map.
env.tile_bk_fg[x][y] = 0;
env.tile_bk_bg[x][y] = t;
return;
}
if (x < gmap_min_x)
gmap_min_x = x;
else if (x > gmap_max_x)
gmap_max_x = x;
if (y < gmap_min_y)
gmap_min_y = y;
else if (y > gmap_max_y)
gmap_max_y = y;
}
void GmapInit(bool upd_tile)
{
// If you can't map the area, the minimap won't show.
if (!player_in_mappable_area())
return;
int x, y;
gmap_min_x = gmap_max_x = you.x_pos - 1;
gmap_min_y = gmap_max_y = you.y_pos - 1;
for (y = 0; y < GYM; y++)
for (x = 0; x < GXM; x++)
GmapUpdate(x, y, env.map[x][y].glyph(), upd_tile);
}
void GmapDisplay(int linex, int liney)
{
static unsigned char buf2[GXM*GYM];
int ox, oy;
for (int x = 0; x < GXM*GYM; x++)
buf2[x] = 0;
if (!player_in_mappable_area())
{
// Don't bother in the Abyss or Labyrinth.
region_map->flag = true;
region_map->draw_data(buf2, false, 0, 0);
return;
}
ox = ( gmap_min_x + (GXM - 1 - gmap_max_x) ) / 2;
oy = ( gmap_min_y + (GYM - 1 - gmap_max_y) ) / 2;
int count = ox + oy * GXM;
gmap_ox = ox - gmap_min_x;
gmap_oy = oy - gmap_min_y;
for (int y = gmap_min_y; y <= gmap_max_y; y++)
{
for (int x = gmap_min_x; x <= gmap_max_x; x++, count++)
if (count >= 0 && count < GXM*GYM)
buf2[count] = gmap_data[x][y];
count += GXM - (gmap_max_x - gmap_min_x + 1);
}
// Highlight centre of the map (ox, oy).
ox += linex - gmap_min_x;
oy += liney - gmap_min_y;
// [enne] Maybe we need another colour for the highlight?
// [jpeg] I think reusing the player colour is okay, because that's
// usually where the centre will be.
buf2[ox + oy * GXM] = Options.tile_player_col;
region_map->flag = true;
region_map->draw_data(buf2, true, ox, oy);
}
// Initialize routines.
static void _do_layout()
{
// buffer between map region and stat region
const int map_stat_buffer = 5;
#define LAYER_NML 0
#define LAYER_CRT 1
#define LAYER_XMAP 2
win_main->wx = win_main->wy = 10;
int tm = region_crt->dx;
if (UseDosChar)
win_main->placeRegion(region_xmap, LAYER_XMAP, 0, 0, tm, tm, tm, tm);
RegionClass *lowest;
// tile 2d mode
win_main->placeRegion(region_tile, LAYER_NML, 0, 0);
win_main->placeRegion(region_msg, LAYER_NML, region_tile, PLACE_BOTTOM,
tm, tm, tm, tm);
int sx = std::max(region_msg->ex + region_msg->dx, region_tile->ex)
+ map_stat_buffer;
int sy = 0;
win_main->placeRegion(region_stat, LAYER_NML, sx, sy);
win_main->placeRegion(region_map, LAYER_NML, region_stat, PLACE_BOTTOM);
if (region_tip)
{
win_main->placeRegion(region_tip, LAYER_NML, region_map, PLACE_BOTTOM);
lowest = region_tip;
}
else
lowest = region_map;
int item_x = (win_main->wx-2*tm) / TILE_X;
int item_y = (52 + item_x -1) / item_x;
region_item2 -> resize(item_x, item_y, TILE_X, TILE_Y);
// Update crt size appropriately, based on the window size.
int crt_pwx = win_main->wx;
int crt_wx = crt_pwx / region_crt->dx;
int crt_pwy = win_main->wy - 2*tm - item_y * region_item2->dy;
int crt_wy = crt_pwy / region_crt->dy;
region_crt->resize(crt_wx, crt_wy);
win_main->placeRegion(region_crt, LAYER_CRT, 0, 0, tm, tm, tm, tm);
win_main->placeRegion(region_item2, LAYER_CRT, region_crt, PLACE_BOTTOM,
tm, tm, tm, tm);
if (Options.tile_show_items[0] != 0)
{
item_x = (win_main->wx - lowest->sx) / TILE_X;
item_y = (win_main->wy - lowest->ey) / TILE_Y;
RegionClass *r0 = lowest;
int place = PLACE_BOTTOM;
int item_x2 = (win_main->wx - region_msg->ex) / TILE_X;
int item_y2 = (win_main->wy - region_msg->sy) / TILE_Y;
if (item_x * item_y < item_x2 * item_y2
&& lowest->ey < region_msg->sy)
{
item_x = item_x2;
item_y = item_y2;
r0 = region_msg;
place = PLACE_RIGHT;
}
while (item_x * item_y < 40)
item_y++;
region_item -> resize(item_x, item_y, TILE_X, TILE_Y);
win_main->placeRegion (region_item, LAYER_NML, r0, place);
}
}
void libgui_init()
{
int i;
int map_margin = 2;
libgui_init_sys();
for (i = 0; i < NUM_REGIONS; i++)
region_lock[i] = false;
pref_mode = PREF_MODE_TILE;
_libgui_load_prefs();
// Adjust sizes.
if (dngn_x & 1 == 0) dngn_x++;
if (dngn_y & 1 == 0) dngn_y++;
if (font_size & 1 == 1) font_size--;
tile_dngn_x = dngn_x;
tile_dngn_y = dngn_y;
/****************************************************/
win_main = new WinClass();
win_main->ox = winox;
win_main->oy = winoy;
region_crt = new TextRegionClass(crt_x, crt_y, 0, 0);
region_crt->id = REGION_CRT;
TextRegionClass::text_mode = region_crt;
region_map =
new MapRegionClass(MAP_XMAX+map_margin,
MAP_YMAX+map_margin,
map_margin, map_margin,
2);
region_map->id = REGION_MAP;
region_map->dx = map_px;
region_map->dy = map_px;
TileInit();
#ifdef WIN32TILES
TileInitWin();
#endif
if (Options.tile_show_items[0] != 0)
{
// temporal size
region_item = new TileRegionClass(1, 1, TILE_X, TILE_Y);
region_item->id = REGION_INV1;
}
// temporal size
region_item2 = new TileRegionClass(1, 1, TILE_X, TILE_Y);
region_item2->id = REGION_INV2;
region_tile =
new TileRegionClass(tile_dngn_x, tile_dngn_y,
TILE_UX_NORMAL, TILE_UY_NORMAL);
region_tile->id = REGION_DNGN;
#if DEBUG_DIAGNOSTICS
// One more line for debug GPS.
region_stat = new TextRegionClass(crawl_view.hudsz.x,
crawl_view.hudsz.y + 1, 0, 0);
#else
region_stat = new TextRegionClass(crawl_view.hudsz.x,
crawl_view.hudsz.y, 0, 0);
#endif
region_stat->id = REGION_STAT;
region_msg = new TextRegionClass(msg_x, msg_y, 0, 0);
region_msg->id = REGION_MSG;
if (UseDosChar)
{
region_xmap = new TextRegionClass(crt_x, crt_y, 0, 0);
region_xmap->id = REGION_XMAP;
}
#ifdef WIN32TILES
region_crt->init_font(font_name, font_size);
region_stat->copy_font(region_crt);
region_msg->copy_font(region_crt);
if (UseDosChar)
{
region_xmap->dos_char = true;
region_xmap->init_font(dos_font_name, dos_font_size);
}
#elif defined(USE_X11)
const unsigned int region_tip_height = 3;
region_tip = new TextRegionClass(region_stat->mx, region_tip_height, 0, 0);
region_tip->id = REGION_TIP;
region_crt->init_font(font_name);
region_stat->init_font(font_name);
region_msg->init_font(font_name);
region_tip->init_font(font_name);
if (region_dngn)
region_dngn->init_font(font_name);
#endif
}
void libgui_shutdown()
{
if (TileImg)
ImgDestroy(TileImg);
if (PlayerImg)
ImgDestroy(PlayerImg);
if (WallImg)
ImgDestroy(WallImg);
// Do this before delete win_main.
_libgui_save_prefs();
std::vector<RegionClass *>::iterator r;
for (r = win_main->regions.begin();r != win_main->regions.end();r++)
{
RegionClass* pRegion = *r;
delete (pRegion);
}
delete win_main;
libgui_shutdown_sys();
}
// Save, Load, and Edit window prefs.
static void _libgui_load_prefs()
{
int i, mode;
FILE *fp;
char buf[256];
char tagbuf[256];
// set default
for (mode = 0; mode < PREF_MODE_NUM; mode++)
{
for (i = 0; i < MAX_PREFS; i++)
{
struct prefs *p = &pref_data[i];
int idx = p->dummy_idx;
if (p->type == 'I')
dummy_int[mode][idx] = *(int *)p->ptr;
else if (p->type == 'S')
strncpy(dummy_str[mode][idx], (char *)p->ptr, MAX_PREF_CHAR);
}
}
const char *baseTxt = "wininit.txt";
std::string winTxtString = datafile_path(baseTxt, false, true);
const char *winTxt = (winTxtString.c_str()[0] == 0 ? baseTxt
: winTxtString.c_str());
if ( (fp = fopen(winTxt, "r")) != NULL )
{
while (!feof(fp))
{
fgets(buf, 250, fp);
i = 0;
while (buf[i] >= 32 && i < 120)
{
i++;
}
buf[i] = 0;
for (i = 0; i < MAX_PREFS; i++)
{
struct prefs *p = &pref_data[i];
for (mode = 0; mode < PREF_MODE_NUM; mode++)
{
sprintf(tagbuf, "%s:%s", pref_mode_name[mode], p->tagname);
if (strncmp(buf, tagbuf, strlen(tagbuf)) == 0)
{
char *dat = &buf[strlen(tagbuf)+1];
if (p->type == 'I')
{
int val = atoi(dat);
if (val > p->max)
val = p->max;
if (val < p->min)
val = p->min;
dummy_int[mode][p->dummy_idx] = val;
if (mode == pref_mode)
*(int *)p->ptr = val;
}
else if (p->type == 'S')
{
strncpy(dummy_str[mode][p->dummy_idx], dat,
MAX_PREF_CHAR);
if (mode == pref_mode)
strncpy((char *)p->ptr, dat, MAX_PREF_CHAR);
}
break;
}
}
}
} // while (!end of file)
}
}
static void _libgui_save_prefs()
{
int i, mode;
FILE *fp;
if (!win_main)
return;
winox = win_main->ox;
winoy = win_main->oy;
#ifdef WIN32TILES
windows_get_winpos(&winox, &winoy);
#endif
for (i = 0; i < MAX_PREFS; i++)
{
struct prefs *p = &pref_data[i];
int idx = p->dummy_idx;
if (p->type == 'I')
dummy_int[pref_mode][idx] = *(int *)p->ptr;
else if (p->type == 'S')
strncpy(dummy_str[pref_mode][idx], (char *)p->ptr, MAX_PREF_CHAR);
}
// Use the same directory as for macros.
// (Yes, this is an arbitrary decision.)
std::string dir = !Options.macro_dir.empty() ? Options.macro_dir :
!SysEnv.crawl_dir.empty() ? SysEnv.crawl_dir : "";
if (!dir.empty())
{
#ifndef DGL_MACRO_ABSOLUTE_PATH
if (dir[dir.length() - 1] != FILE_SEPARATOR)
dir += FILE_SEPARATOR;
#endif
}
const char *baseTxt = "wininit.txt";
std::string winTxtString = dir + baseTxt;
if ( (fp = fopen(winTxtString.c_str(), "w")) == NULL )
winTxtString = datafile_path(baseTxt, false, true);
const char *winTxt = winTxtString.c_str()[0] == 0 ? baseTxt
: winTxtString.c_str();
if ( (fp = fopen(winTxt, "w")) != NULL )
{
for (mode = 0; mode < PREF_MODE_NUM; mode++)
{
for (i = 0; i < MAX_PREFS; i++)
{
struct prefs *p = &pref_data[i];
int idx = p->dummy_idx;
if (p->type == 'I')
{
fprintf(fp, "%s:%s=%d\n", pref_mode_name[mode],
p->tagname, dummy_int[mode][idx]);
}
else if (p->type == 'S')
{
fprintf(fp, "%s:%s=%s\n", pref_mode_name[mode],
p->tagname, dummy_str[mode][idx]);
}
}
fprintf(fp, "\n");
}
fclose(fp);
}
}
}
}
void edit_prefs()
{
int i;
int cur_pos = 0;
cursor_control cs(false);
bool need_draw_stat = true;
bool need_draw_msg = true;
if (region_tip)
region_tip->clear();
region_stat->clear();
region_msg->clear();
viewwindow(true, false);
while (true)
{
bool upd_msg = false;
bool upd_dngn = false;
bool upd_crt = false;
bool upd_map = false;
bool need_resize = false;
int inc = 0;
if (need_draw_msg)
{
textcolor(LIGHTGREY);
region_msg->clear();
textcolor(WHITE);
cgotoxy (4, 4, GOTO_MSG);
cprintf("j, k, up, down : Select pref");
cgotoxy (4, 5, GOTO_MSG);
cprintf("h, l, left, right : Decrease/Increase");
cgotoxy (4, 6, GOTO_MSG);
cprintf("H, L : Dec/Inc by 10");
need_draw_msg = false;
}
if (need_draw_stat)
{
region_stat->clear();
for (i = 0; i < MAX_EDIT_PREFS; i++)
{
struct prefs *p = &pref_data[i];
cgotoxy(2, i+2, GOTO_STAT);
if (i == cur_pos)
{
textcolor(0xf0);
cprintf(">");
}
else
{
textcolor(LIGHTGREY);
cprintf(" ");
}
if (pref_data[i].type == 'I')
cprintf(" %s: %3d ", p->name, *(int *)p->ptr);
else
cprintf(" %s: %s", p->name, (char *)p->ptr);
}
textcolor(LIGHTGREY);
#ifdef WIN32TILES
cgotoxy(4, MAX_EDIT_PREFS+3, GOTO_STAT);
cprintf("FONT: %s %d",font_name, font_size);
if (UseDosChar)
{
cgotoxy(4, MAX_EDIT_PREFS+4, GOTO_STAT);
cprintf("DOSFONT: %s %d", dos_font_name, dos_font_size);
}
#else
cgotoxy(4, MAX_EDIT_PREFS+3, GOTO_STAT);
cprintf("FONT: %s",font_name);
#endif
int *dat = (int *)pref_data[cur_pos].ptr;
#define WHITEIF(x) (dat == &x)?0xf0:LIGHTGREY
_draw_hgauge(3, 1, 3, GOTO_MSG, msg_x-2, WHITEIF(msg_x));
clear_to_end_of_line();
_draw_vgauge(1, 1, 1, GOTO_MSG, msg_y, WHITEIF(msg_y));
need_draw_stat = false;
}
int key = getch();
struct prefs *p = &pref_data[cur_pos];
int *dat = (int *)p->ptr;
if (key == 0x1b || key == '\r')
break;
if (key == 'j' || key == CK_DOWN)
{
cur_pos++;
need_draw_stat = true;
}
if (key == 'k' || key == CK_UP)
{
cur_pos--;
need_draw_stat = true;
}
if (key == CK_LEFT)
key = 'h';
if (key == CK_RIGHT)
key = 'l';
cur_pos = (cur_pos + MAX_EDIT_PREFS) % MAX_EDIT_PREFS;
switch(key)
{
case 'l': inc = 1; break;
case 'L': inc = 10; break;
case 'h': inc = -1; break;
case 'H': inc = -10; break;
}
int crt_x_old = crt_x;
int crt_y_old = crt_y;
int map_px_old = map_px;
int msg_x_old = msg_x;
int msg_y_old = msg_y;
int dngn_x_old = dngn_x;
int dngn_y_old = dngn_y;
if (p->type == 'I' && inc != 0)
{
if (dat == &dngn_x || dat == &dngn_y)
{
if (inc == 1)
inc++;
else if (inc == -1)
inc--;
}
int olddat = *dat;
(*dat)+= inc;
if (*dat > p->max)
*dat = p->max;
if (*dat < p->min)
*dat = p->min;
if (olddat == *dat)
continue;
need_resize = true;
}
if (need_resize)
{
need_draw_stat = need_draw_msg = true;
// crt screen layouts
// Resize msg?
if (msg_x != msg_x_old || msg_y != msg_y_old)
{
upd_msg = true;
region_msg->resize(msg_x, msg_y);
}
// Resize crt?
if (crt_x != crt_x_old || crt_y != crt_y_old)
{
upd_crt = true;
region_crt->resize(crt_x, crt_y);
}
// Resize map?
if (map_px != map_px_old)
{
upd_map = true;
region_map->resize( 0, 0, map_px, map_px);
}
// Resize dngn tile screen?
if (dngn_x != dngn_x_old || dngn_y != dngn_y_old)
{
clrscr();
upd_dngn = true;
tile_dngn_x = dngn_x;
tile_dngn_y = dngn_y;
region_tile->resize(dngn_x, dngn_y, 0, 0);
}
_do_layout();
win_main->resize();
win_main->clear();
// Now screens are all black.
if (upd_map)
region_map->resize_backbuf();
if (upd_dngn)
{
region_tile -> resize_backbuf();
tile_set_force_redraw_tiles(true);
TileResizeScreen(dngn_x, dngn_y);
}
if (region_item)
region_item->resize_backbuf();
if (region_item2)
region_item2->resize_backbuf();
tile_set_force_redraw_inv(true);
tile_draw_inv(REGION_INV1);
region_map->force_redraw = true;
viewwindow(true, true);
region_tile->redraw();
region_item->redraw();
} // need resize
} // while-loop
clrscr();
redraw_screen();
mpr("Done.");
}
// Tiptext help info
typedef struct tip_info
{
int sx;
int ex;
int sy;
int ey;
const char *tiptext;
const char *tipfilename;
} tip_info;
static int old_tip_idx = -1;
static void _tip_grid(int gx, int gy, bool do_null = true, int minimap = 0)
{
mesclr();
const coord_def gc(gx,gy);
terse_describe_square(gc);
}
int tile_cursor_x = -1;
int tile_cursor_y = -1;
int tile_cursor_flag = 0;
void tile_place_cursor(int x, int y, bool display)
{
if (tile_cursor_x != -1)
{
// erase old cursor
TileDrawCursor(tile_cursor_x, tile_cursor_y, tile_cursor_flag);
}
if (!display)
{
tile_cursor_x = -1;
return;
}
int new_flag = TILE_FLAG_CURSOR1;
const coord_def vp(x+1, y+1);
const coord_def gc = view2grid(vp);
const coord_def ep = grid2show(gc);
if (gc.x < 0 || gc.y < 0 || gc.x >= GXM || gc.y >= GYM)
{
// off the dungeon...
tile_cursor_x = -1;
return;
}
else if (!crawl_view.in_grid_los(gc) || !env.show(ep))
{
new_flag = TILE_FLAG_CURSOR2;
}
tile_cursor_x = x;
tile_cursor_y = y;
tile_cursor_flag = TileDrawCursor(x, y, new_flag);
}
int convert_cursor_pos(int mx, int my, int *cx, int *cy)
{
std::vector <RegionClass *>::iterator r;
WinClass *w = win_main;
int id = REGION_NONE;
int x, y;
int mx0 = 0;
for (r = w->regions.begin();r != w->regions.end();r++)
{
if (! (*r)->is_active())
continue;
if ( (*r)->mouse_pos(mx, my, cx, cy) )
{
id = (*r)->id;
mx0 = (*r)->mx;
break;
}
}
x = *cx;
y = *cy;
/********************************************/
if (id == REGION_TDNGN)
{
x--;
if (!in_viewport_bounds(x+1,y+1))
return REGION_NONE;
}
if (id == REGION_MAP)
{
x -= gmap_ox - region_map->marker_length + 1;
y -= gmap_oy - region_map->marker_length + 1;
}
if (id == REGION_INV1 || id == REGION_INV2)
{
x = x + y * mx0;
y = 0;
}
if (id == REGION_DNGN)
{
// Out of LOS range
if (!in_viewport_bounds(x+1,y+1))
return REGION_NONE;
}
*cx = x;
*cy = y;
return id;
}
// NOTE: Assumes the item is equipped in the first place!
static bool _is_true_equipped_item(item_def item)
{
// Weapons and staves are only truly equipped if wielded.
if (item.link == you.equip[EQ_WEAPON])
return (item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES);
// Cursed armour and rings are only truly equipped if *not* wielded.
return (item.link != you.equip[EQ_WEAPON]);
}
// Returns whether there's any action you can take with an item in inventory
// apart from dropping it.
static bool _can_use_item(item_def item, bool equipped)
{
// Vampires can drain corpses.
if (item.base_type == OBJ_CORPSES)
{
return (you.species == SP_VAMPIRE
&& item.sub_type != CORPSE_SKELETON
&& !food_is_rotten(item)
&& mons_has_blood(item.plus));
}
if (equipped && item_cursed(item))
{
// Misc. items/rods can always be evoked, cursed or not.
if (item.base_type == OBJ_MISCELLANY || item_is_rod(item))
return (true);
// You can't unwield/fire a wielded cursed weapon/staff
// but cursed armour and rings can be unwielded without problems.
return (!_is_true_equipped_item(item));
// Mummies can't do anything with food or potions.
if (you.species == SP_MUMMY)
return (item.base_type != OBJ_POTIONS && item.base_type != OBJ_FOOD);
// In all other cases you can use the item in some way.
return (true);
static int _handle_mouse_motion(int mouse_x, int mouse_y, bool init)
{
int cx = -1;
int cy = -1;
int mode = 0;
static int oldcx = -1;
static int oldcy = -1;
static int oldmode = -1;
static int olditem = -1;
if (init)
{
oldcx = -1;
oldcy = -1;
oldmode = -1;
old_tip_idx = -1;
olditem = -1;
return 0;
}
switch(mouse_mode)
{
case MOUSE_MODE_NORMAL:
case MOUSE_MODE_MORE:
case MOUSE_MODE_MACRO:
return 0;
break;
}
if (mouse_x < 0)
{
mode = 0;
oldcx = oldcy = -10;
}
else
mode = convert_cursor_pos(mouse_x, mouse_y, &cx, &cy);
if (oldcx == cx && oldcy == cy && oldmode == mode)
return 0;
// erase old cursor
if (oldmode == REGION_DNGN && mode != oldmode)
{
oldcx = -10;
//_setcursortype(0);
}
if (olditem != -1)
{
oldcx = -10;
TileMoveInvCursor(-1);
olditem = -1;
}
if ( oldmode == REGION_DNGN && mode != oldmode)
{
oldcx = -10;
tile_place_cursor(0, 0, false);
}
if (toggle_telescope && mode != REGION_MAP)
{
TileDrawDungeon(NULL);
toggle_telescope = false;
}
bool valid_tip_region = (mode == REGION_MAP || mode == REGION_DNGN
|| mode == REGION_INV1 || mode == REGION_INV2
|| mode == REGION_MSG || mode == REGION_STAT);
if (valid_tip_region && mode != oldmode)
update_tip_text("");
if (toggle_telescope && mode == REGION_MAP)
{
oldmode = mode;
oldcx = cx;
oldcy = cy;
_tip_grid(cx-1, cy-1, 1);
TileDrawFarDungeon(cx-1, cy-1);
return 0;
}
if (mode == REGION_INV1 || mode == REGION_INV2)
{
oldcx = cx;
oldcy = cy;
oldmode = mode;
int ix = TileInvIdx(cx);
std::string desc;
if (ix != -1)
{
bool display_actions = (mode == REGION_INV1);
if (itemlist_iflag[cx] & TILEI_FLAG_FLOOR)
{
const item_def item = mitm[ix];
if (itemlist_key[cx])
{
desc = itemlist_key[cx];
desc += " - ";
}
desc += item.name(DESC_NOCAP_A);
if (display_actions)
desc += EOL "[L-Click] Pick up (g)";
if (item.base_type == OBJ_CORPSES
&& item.sub_type != CORPSE_SKELETON
&& !food_is_rotten(item))
{
desc += EOL "[Shift-L-Click] ";
if (can_bottle_blood_from_corpse( item.plus))
desc += "Bottle blood";
else
desc += "Chop up";
desc += " (c)";
if (you.species == SP_VAMPIRE)
desc += EOL "[Shift-R-Click] Drink blood (e)";
}
else if (item.base_type == OBJ_FOOD
&& you.is_undead != US_UNDEAD
&& you.species != SP_VAMPIRE)
{
desc += EOL "[Shift-R-Click] Eat (e)";
}
}
else // in inventory
{
const item_def item = you.inv[ix];
desc = item.name(DESC_INVENTORY_EQUIP);
if (display_actions)
{
int type = item.base_type;
const bool equipped = itemlist_iflag[cx] & TILEI_FLAG_EQUIP;
bool wielded = (you.equip[EQ_WEAPON] == ix);
desc += EOL;
if (_can_use_item(you.inv[ix], equipped))
{
desc += "[L-Click] ";
if (equipped)
{
if (wielded
&& type != OBJ_MISCELLANY
&& !item_is_rod(item))
{
if (type == OBJ_JEWELLERY || type == OBJ_ARMOUR
|| type == OBJ_WEAPONS || type == OBJ_STAVES)
{
type = OBJ_WEAPONS + 18;
}
}
else
type += 18;
}
switch (type)
{
// first equipable categories
case OBJ_WEAPONS:
case OBJ_STAVES:
case OBJ_MISCELLANY:
desc += "Wield (w)";
if (is_throwable(item, player_size(PSIZE_BODY)))
desc += EOL "[Ctrl-L-Click] Fire (f)";
break;
case OBJ_WEAPONS + 18:
desc += "Unwield";
if (is_throwable(item, player_size(PSIZE_BODY)))
desc += EOL "[Ctrl-L-Click] Fire (f)";
break;
case OBJ_MISCELLANY + 18:
if (item.sub_type >= MISC_DECK_OF_ESCAPE
&& item.sub_type <= MISC_DECK_OF_DEFENCE)
{
desc += "Draw a card (v)";
desc += EOL "[Ctrl-L-Click] Unwield";
break;
}
// else fall-through
case OBJ_STAVES + 18: // rods - other staves handled above
desc += "Evoke (v)";
desc += EOL "[Ctrl-L-Click] Unwield";
break;
case OBJ_ARMOUR:
desc += "Wear (W)";
break;
case OBJ_ARMOUR + 18:
desc += "Take off (T)";
break;
case OBJ_JEWELLERY:
desc += "Put on (P)";
break;
case OBJ_JEWELLERY + 18:
desc += "Remove (R)";
break;
case OBJ_MISSILES:
desc += "Fire (f)";
if (wielded)
desc += EOL "[Ctrl-L-Click] Unwield";
else if ( item.sub_type == MI_STONE
&& player_knows_spell(SPELL_SANDBLAST)
|| item.sub_type == MI_ARROW
&& player_knows_spell(
SPELL_STICKS_TO_SNAKES) )
{
// For Sandblast and Sticks to Snakes,
// respectively.
desc += EOL "[Ctrl-L-Click] Wield (w)";
}
break;
case OBJ_WANDS:
desc += "Zap (Z)";
if (wielded)
desc += EOL "[Ctrl-L-Click] Unwield";
break;
case OBJ_BOOKS:
if (item_type_known(item)
&& item.sub_type != BOOK_MANUAL
&& item.sub_type != BOOK_DESTRUCTION)
{
desc += "Memorise (M)";
if (wielded)
desc += EOL "[Ctrl-L-Click] Unwield";
break;
}
// else fall-through
case OBJ_SCROLLS:
desc += "Read (r)";
if (wielded)
desc += EOL "[Ctrl-L-Click] Unwield";
break;
case OBJ_POTIONS:
desc += "Quaff (q)";
// For Sublimation of Blood.
if (wielded)
desc += EOL "[Ctrl-L-Click] Unwield";
else if ( item_type_known(item)
&& is_blood_potion(item)
&& player_knows_spell(
SPELL_SUBLIMATION_OF_BLOOD) )
{
desc += EOL "[Ctrl-L-Click] Wield (w)";
}
break;
case OBJ_FOOD:
desc += "Eat (e)";
// For Sublimation of Blood.
if (wielded)
desc += EOL "[Ctrl-L-Click] Unwield";
else if (item.sub_type == FOOD_CHUNK
&& player_knows_spell(
SPELL_SUBLIMATION_OF_BLOOD))
{
desc += EOL "[Ctrl-L-Click] Wield (w)";
}
break;
case OBJ_CORPSES:
if (you.species == SP_VAMPIRE)
desc += "Drink blood (e)";
if (wielded)
{
if (you.species == SP_VAMPIRE)
desc += EOL;
desc += "[Ctrl-L-Click] Unwield";
}
break;
default:
desc += "Use";
}
}
// For Boneshards.
// Special handling since skeletons have no primary action.
if (item.base_type == OBJ_CORPSES
&& item.sub_type == CORPSE_SKELETON)
{
if (wielded)
desc += EOL "[Ctrl-L-Click] Unwield";
else if (player_knows_spell(SPELL_BONE_SHARDS))
desc += EOL "[Ctrl-L-Click] Wield (w)";
}
desc += EOL "[R-Click] Info";
// Has to be non-equipped or non-cursed to drop.
if (!equipped || !_is_true_equipped_item(you.inv[ix])
|| !item_cursed(you.inv[ix]))
{
desc += EOL "[Shift-L-Click] Drop (d)";
}
}
}
update_tip_text(desc.c_str());
itemlist_flag = mode;
TileMoveInvCursor(cx);
olditem = cx;
}
else
update_tip_text("");
return 0;
}
if (mouse_mode == MOUSE_MODE_TARGET
|| mouse_mode == MOUSE_MODE_TARGET_DIR)
{
if (mode == REGION_DNGN || mode == REGION_TDNGN)
{
oldcx = cx;
oldcy = cy;
oldmode = mode;
_gui_set_mouse_view_pos(true, cx+1, cy+1);
return CK_MOUSE_MOVE;
}
}
_gui_set_mouse_view_pos(false, -1, -1);
if (mode == REGION_TDNGN || mode == REGION_DNGN)
{
if (mode == oldmode && oldcx == DCX && oldcy == DCY)
update_tip_text("");
oldcx = cx;
oldcy = cy;
oldmode = mode;
if (mode == REGION_DNGN)
tile_place_cursor(cx, cy, true);
else if (mode == REGION_TDNGN)
cgotoxy(cx+2, cy+1, GOTO_DNGN);
const int gx = view2gridX(cx) + 1;
const int gy = view2gridY(cy) + 1;
_tip_grid(gx, gy);
// mouse-over info on player
if (cx == DCX && cy == DCY)
{
std::string desc = you.your_name;
desc += " (";
desc += get_species_abbrev(you.species);
desc += get_class_abbrev(you.char_class);
desc += ")";
if (igrd[you.x_pos][you.y_pos] != NON_ITEM)
desc += EOL "[L-Click] Pick up items (g)";
if (grid_stair_direction( grd[gx][gy] ) != CMD_NO_CMD)
desc += EOL "[Shift-L-Click] use stairs (</>)";
// Character overview.
desc += EOL "[R-Click] Overview (%)";
// Religion.
if (you.religion != GOD_NO_GOD)
desc += EOL "[Shift-R-Click] Religion (^)";
update_tip_text(desc.c_str());
}
return 0;
}
if (mode == REGION_MAP && mouse_mode == MOUSE_MODE_COMMAND)
{
if (oldmode != REGION_MAP)
update_tip_text("[L-Click] Travel / [R-Click] View");
else
_tip_grid(cx - 1, cy - 1, false, 1);
oldmode = mode;
oldcx = cx;
oldcy = cy;
return 0;
}
if (mode == REGION_MSG && mouse_mode == MOUSE_MODE_COMMAND)
{
if (oldmode != REGION_MSG)
update_tip_text("[L-Click] Browse message history");
oldmode = mode;
oldcx = cx;
oldcy = cy;
return 0;
}
if (mode == REGION_STAT && mouse_mode == MOUSE_MODE_COMMAND)
{
if (oldmode != REGION_STAT)
update_tip_text("[L-Click] Rest / Search for a while");
oldmode = mode;
oldcx = cx;
oldcy = cy;
return 0;
}
return 0;
}
static int _handle_mouse_button(int mx, int my, int button,
bool shift, bool ctrl)
{
int dir;
const int dx[9] = {-1, 0, 1,
-1, 0, 1,
-1, 0, 1};
const int dy[9] = { 1, 1, 1,
0, 0, 0,
-1,-1,-1};
const int cmd_n[9] = {'b', 'j', 'n', 'h', '.', 'l', 'y', 'k', 'u'};
const int cmd_s[9] = {'B', 'J', 'N', 'H', '5', 'L', 'Y', 'K', 'U'};
const int cmd_c[9] = {
CONTROL('B'), CONTROL('J'), CONTROL('N'), CONTROL('H'),
'X', CONTROL('L'), CONTROL('Y'), CONTROL('K'), CONTROL('U'),
};
const int cmd_dir[9] = {'1','2','3','4','5','6','7','8','9'};
int trig = CK_MOUSE_B1;
switch (button)
{
case 2: trig = CK_MOUSE_B2; break;
case 3: trig = CK_MOUSE_B3; break;
case 4: trig = CK_MOUSE_B4; break;
case 5: trig = CK_MOUSE_B5; break;
default: break;
}
if (shift)
trig |= 512;
if (ctrl)
trig |= 1024;
switch (mouse_mode)
{
case MOUSE_MODE_NORMAL:
return trig;
case MOUSE_MODE_MORE:
return '\r';
}
int cx,cy;
int mode;
static int oldcx = -1;
static int oldcy = -1;
static bool enable_wheel = true;
static int old_button = 0;
static int old_hp = 0;
mode = convert_cursor_pos(mx, my, &cx, &cy);
// Prevent accidental wheel slip and subsequent char death.
if (mouse_mode == MOUSE_MODE_COMMAND && (button == 4 || button == 5)
&& button == old_button && oldcx == cx && oldcy == cy)
{
if (!enable_wheel)
return 0;
if (you.hp < old_hp)
{
mpr("Wheel move aborted (rotate opposite to resume)");
enable_wheel = false;
return 0;
}
}
old_hp = you.hp;
enable_wheel = true;
old_button = button;
oldcx = cx;
oldcy = cy;
if (toggle_telescope)
{
// Quit telescope mode.
TileDrawDungeon(NULL);
toggle_telescope = false;
}
if (mode == REGION_INV2)
{
int ix = TileInvIdx(cx);
int key = itemlist_key[cx];
if (ix != -1 && key)
return key;
else
return 0;
}
// Clicked on item.
if (mode == REGION_INV1)
{
int ix = TileInvIdx(cx);
if (ix != -1)
{
if (button == 2)
{
// Describe item.
if (itemlist_iflag[cx] & TILEI_FLAG_FLOOR)
{
if (shift)
{
_gui_set_mouse_inv(ix, INV_EAT_FLOOR);
return CK_MOUSE_B1ITEM;
}
else
_gui_set_mouse_inv(-ix, INV_VIEW);
}
else
_gui_set_mouse_inv(ix, INV_VIEW);
TileMoveInvCursor(-1);
return CK_MOUSE_B2ITEM;
}
else if (button == 1)
{
// Floor item
if (itemlist_iflag[cx] & TILEI_FLAG_FLOOR)
{
// Try to pick up one item.
if (!shift)
_gui_set_mouse_inv(ix, INV_PICKUP);
else
_gui_set_mouse_inv(ix, INV_USE_FLOOR);
return CK_MOUSE_B1ITEM;
}
// Use item.
if (shift)
_gui_set_mouse_inv(ix, INV_DROP);
else if (ctrl)
_gui_set_mouse_inv(ix, INV_USE2);
else
_gui_set_mouse_inv(ix, INV_USE);
return CK_MOUSE_B1ITEM;
}
}
return trig;
}
if (mode == REGION_MSG && mouse_mode == MOUSE_MODE_COMMAND)
{
return CONTROL('P');
}
if (mode == REGION_STAT && mouse_mode == MOUSE_MODE_COMMAND)
{
return '5';
}
if ((mouse_mode == MOUSE_MODE_COMMAND || mouse_mode == MOUSE_MODE_MACRO)
&& (mode == REGION_DNGN || mode == REGION_TDNGN))
{
if (button == 1 && cx == DCX && cy == DCY)
{
// Pick up items.
if (!shift)
return 'g';
// Else attempt to use stairs on square.
const int gx = view2gridX(cx) + 1;
const int gy = view2gridY(cy) + 1;
switch (grid_stair_direction( grd[gx][gy] ))
{
case CMD_GO_DOWNSTAIRS:
return ('>');
case CMD_GO_UPSTAIRS:
return ('<');
default:
break;
}
}
if (button == 2)
{
// Describe yourself.
if (cx == DCX && cy == DCY)
{
if (!shift)
return '%'; // Character overview.
if (you.religion != GOD_NO_GOD)
return '^'; // Religion screen.
}
// trigger
if (mouse_mode == MOUSE_MODE_MACRO)
return trig;
// R-Click: try to describe grid; otherwise return trigger key.
if (!in_los_bounds(cx+1,cy+1))
return CK_MOUSE_B2;
const int gx = view2gridX(cx) + 1;
const int gy = view2gridY(cy) + 1;
full_describe_square(coord_def(gx,gy));
return CK_MOUSE_DONE;
}
// button = 1 or 4, 5
// First check if 3x3 grid around @ is clicked.
// If so, return equivalent numpad key.
int adir = -1;
for (dir = 0; dir < 9; dir++)
{
if (DCX + dx[dir] == cx && DCY + dy[dir] == cy)
{
adir = dir;
break;
}
}
if (adir != -1)
{
if (shift)
return cmd_s[adir];
else if (ctrl)
return cmd_c[adir];
else
return cmd_n[dir];
}
if (button != 1)
return trig;
// Otherwise travel to that grid.
const coord_def gc = view2grid(coord_def(cx+1, cy+1));
if (!map_bounds(gc))
return 0;
// Activate travel.
start_travel(gc.x, gc.y);
return CK_MOUSE_DONE;
}
if (mouse_mode == MOUSE_MODE_COMMAND && mode == REGION_MAP)
{
// Begin telescope mode.
if (button == 2)
{
toggle_telescope = true;
StoreDungeonView(NULL);
TileDrawFarDungeon(cx-1,cy-1);
return 0;
}
if (button != 1)
return trig;
// L-click: try to travel to the grid.
const coord_def gc(cx-1, cy-1);
if (!map_bounds(gc))
return 0;
// Activate travel.
start_travel(gc.x, gc.y);
return CK_MOUSE_DONE;
}
// target selection
if ((mouse_mode == MOUSE_MODE_TARGET || mouse_mode == MOUSE_MODE_TARGET_DIR)
&& button == 1 && (mode == REGION_DNGN || mode == REGION_TDNGN))
{
_gui_set_mouse_view_pos(true, cx+1, cy+1);
return CK_MOUSE_CLICK;
}
_gui_set_mouse_view_pos(false, 0, 0);
if (mouse_mode == MOUSE_MODE_TARGET_DIR && button == 1
&& (mode == REGION_DNGN || mode == REGION_TDNGN))
{
if (cx < DCX-1 || cy < DCY-1 || cx > DCX+1 || cy > DCY+1)
return 0;
for (dir = 0; dir < 9; dir++)
if (DCX + dx[dir] == cx && DCY + dy[dir] == cy)
return cmd_dir[dir];
return 0;
}
return trig;
}
static int _handle_mouse_unbutton(int mx, int my, int button)
{
if (toggle_telescope)
TileDrawDungeon(NULL);
toggle_telescope = false;
return 0;
}
int getch_ck()
{
int etype = 0;
int x1,y1,x2,y2;
int key;
bool sh, ct;
int k;
while (true)
{
k = 0;
GetNextEvent(&etype, &key, &sh, &ct, &x1, &y1, &x2, &y2);
switch(etype)
{
case EV_BUTTON:
k = _handle_mouse_button(x1, y1, key, sh, ct);
break;
case EV_MOVE:
k = _handle_mouse_motion(x1, y1, false);
break;
case EV_UNBUTTON:
k = _handle_mouse_unbutton(x1, y1, key);
break;
case EV_KEYIN:
k = key;
break;
default:
break;
}
if (k != 0)
break;
}
return k;
}
int getch()
{
static int ck_tr[] =
{
'k', 'j', 'h', 'l', '.', 'y', 'b', '.', 'u', 'n',
'K', 'J', 'H', 'L', '5', 'Y', 'B', '5', 'U', 'N',
11, 10, 8, 12, '0', 25, 2, 'C', 21, 14
};
int keyin = getch_ck();
if (keyin >= CK_UP && keyin <= CK_CTRL_PGDN)
return ck_tr[ keyin - CK_UP ];
if (keyin == CK_DELETE)
return '.';
return keyin;
}
}
void mouse_set_mode(int mode)
{
mouse_mode = mode;
// Init cursor etc.
_handle_mouse_motion(0, 0, true);
}
int mouse_get_mode()
{
return mouse_mode;
if (region_tip)
region_tip->resize(geom.hudsz.x, 3);
region_msg->resize(geom.msgsz.x, geom.msgsz.y);
region_stat->resize(geom.hudsz.x, geom.hudsz.y);
_do_layout();
_init_regions();
}
void lock_region(int r)
{
if (r >= 0 && r < NUM_REGIONS)
region_lock[r] = true;
}
void unlock_region(int r)
{
if (r >= 0 && r < NUM_REGIONS)
region_lock[r] = false;
}
/*
* Wrapper
*/
void clrscr()
{
win_main->clear();
TextRegionClass::cursor_region = NULL;
// Clear Text regions.
if (!region_lock[REGION_CRT])
region_crt->clear();
if (region_msg && !region_lock[REGION_MSG])
region_msg->clear();
if (region_stat && !region_lock[REGION_STAT])
region_stat->clear();
if (region_dngn && !region_lock[REGION_TDNGN])
region_dngn->clear();
if (region_tip && !region_lock[REGION_TIP])
region_tip->clear();
// Hack: Do not erase the backbuffer; instead just hide it.
if (region_map)
{
if (region_lock[REGION_MAP])
region_map->redraw();
else
region_map->flag = false;
}
if (region_item)
{
if (region_lock[REGION_INV1])
region_item->redraw();
else
region_item->flag = false;
}
if (region_item2)
{
if (region_lock[REGION_INV2])
region_item2->redraw();
else
{
TileClearInv(REGION_INV2);
region_item2->flag = false;
}
}
cgotoxy(1, 1);
geom.viewsz.x = 17;
geom.viewsz.y = 17;
TextRegionClass::textbackground(bg);
}
void cgotoxy(int x, int y, int region)
{
if (region == GOTO_LAST)
{
// nothing
}
else if (region == GOTO_CRT)
TextRegionClass::text_mode = region_crt;
else if (region == GOTO_MSG)
TextRegionClass::text_mode = region_msg;
else if (region == GOTO_STAT)
TextRegionClass::text_mode = region_stat;
TextRegionClass::text_mode->flag = true;
TextRegionClass::cgotoxy(x, y);
}
void _setcursortype(int curstype)
{
TextRegionClass::_setcursortype(curstype);
}
void enable_smart_cursor(bool cursor)
{
gui_smart_cursor = cursor;
TextRegion::textbackground(bg);
int xx, yy;
unsigned char *ptr = buf;
//cgotoxy(1, 1, GOTO_CRT);
for (yy = sy-1; yy <= ey-1; yy++)
{
unsigned char *c = &(r->cbuf[yy*(r->mx)+sx-1]);
unsigned char *a = &(r->abuf[yy*(r->mx)+sx-1]);
for (xx = sx-1; xx <= ex-1; xx++)
{
*c = *ptr;
void clear_message_window()
{
tiles.clear_message_window();
}
ptr++;
if (mono)
*a = WHITE;
else
{
*a = *ptr;
ptr++;
}
c++;
a++;
}
}
r->make_active();
r->redraw(sx-1, sy-1, ex-1, ey-1);
void update_screen()
{
tiles.redraw();
FILE *fp = fopen(name, "r");
int max = get_number_of_lines();
// Look for the presence of any keyboard events in the queue.
SDL_Event store;
int count = SDL_PeepEvents(&store, 1, SDL_PEEKEVENT,
SDL_EVENTMASK(SDL_KEYDOWN));
// SDL Error?
ASSERT(count != -1);
#define DELIMITER_END "-------------------------------------------------------------------------------"
#define DELIMITER_MORE "...(more)... "
unsigned char buf[80*MAXTEXTLINES], buf2[84];
int nlines = 0;
int cline = 0;
int i;
#ifdef UNIX
int itoa(int value, char *strptr, int radix)
{
unsigned int bitmask = 32768;
int ctr = 0;
int startflag = 0;
for (i = 0; i < 80*MAXTEXTLINES; i++)
buf[i] = ' ';
while (nlines < MAXTEXTLINES)
else if (radix == 2) /* int to "binary string" */
i = 0;
while (i < 79 && buf2[i] != 13 && buf2[i] != 10)
i++;
if (!startflag) /* Special case if value == 0 */
sprintf((strptr + ctr++), "0");
fclose(fp);
clrscr();
while (true)
{
cgotoxy(1, 1);
if (cline == 0)
cprintf(DELIMITER_END);
else
cprintf(DELIMITER_MORE);
return (0); /* Me? Fail? Nah. */
}
cgotoxy(1, max);
if (cline + max-2 >= nlines)
cprintf(DELIMITER_END);
else
cprintf(DELIMITER_MORE);
// Convert string to lowercase.
char *strlwr(char *str)
{
unsigned int i;
cgotoxy(14, max);
cprintf("[j/k/+/-/SPACE/b: scroll q/ESC/RETURN: exit]");
mouse_set_mode(MOUSE_MODE_MORE);
int key = getch();
mouse_set_mode(MOUSE_MODE_NORMAL);
if (key == 'q' || key == ESCAPE || key =='\r')
break;
else if (key == '-' || key == 'b')
cline -= max-2;
else if (key == 'k')
cline --;
else if (key == '+' || key == ' ')
cline += max-2;
else if (key == 'j')
cline++;
else if (key == CK_MOUSE_B4)
cline--;
else if (key == CK_MOUSE_B5)
cline++;
for (i = 0; i < strlen(str); i++)
str[i] = tolower(str[i]);
#endif // #ifdef UNIX
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
void tile_use_item(int idx, InvAction act);
void tile_item_use_floor(int idx);
void tile_item_pickup(int idx);
void tile_item_drop(int idx);
void tile_item_eat_floor(int idx);
void tile_item_use(int idx);
void tile_item_use_secondary(int idx);
else if (act == INV_DROP)
}
void tile_item_pickup(int idx)
{
pickup_single_item(idx, mitm[idx].quantity);
}
void tile_item_drop(int idx)
{
drop_item(idx, you.inv[idx].quantity);
}
void tile_item_eat_floor(int idx)
{
if (mitm[idx].base_type == OBJ_CORPSES
&& you.species == SP_VAMPIRE
|| mitm[idx].base_type == OBJ_FOOD
&& you.is_undead != US_UNDEAD && you.species != SP_VAMPIRE)
if (mitm[idx].base_type == OBJ_CORPSES
&& mitm[idx].sub_type != CORPSE_SKELETON
&& !food_is_rotten(mitm[idx]))
{
butchery(idx);
}
return;
if (check_warning_inscriptions(item, OPER_FIRE))
fire_thing(idx); // fire weapons
if (mitm[idx].base_type == OBJ_CORPSES
&& you.species == SP_VAMPIRE
|| mitm[idx].base_type == OBJ_FOOD
&& you.is_undead != US_UNDEAD && you.species != SP_VAMPIRE)
if (you.equip[EQ_WEAPON] == idx
&& check_warning_inscriptions(item, OPER_WIELD))
const item_def item = you.inv[idx];
wield_weapon(true, PROMPT_GOT_SPECIAL); // unwield
}
else if (_valid_weapon_swap(item)
&& check_warning_inscriptions(item, OPER_WIELD))
{
// secondary wield for several spells and such
wield_weapon(true, idx); // wield
}
}
if (item.base_type == OBJ_WEAPONS
&& is_throwable(item, player_size(PSIZE_BODY)))
{
if (check_warning_inscriptions(item, OPER_FIRE))
fire_thing(idx); // fire weapons
}
else if (item.base_type == OBJ_MISCELLANY
|| item.base_type == OBJ_STAVES
&& item_is_rod(item)) // unwield rods/misc. items
{
if (you.equip[EQ_WEAPON] == idx
&& check_warning_inscriptions(item, OPER_WIELD))
{
wield_weapon(true, PROMPT_GOT_SPECIAL); // unwield
}
}
else if (you.equip[EQ_WEAPON] == idx
&& check_warning_inscriptions(item, OPER_WIELD))
{
wield_weapon(true, PROMPT_GOT_SPECIAL); // unwield
}
else if (_valid_weapon_swap(item)
&& check_warning_inscriptions(item, OPER_WIELD))
{
// secondary wield for several spells and such
wield_weapon(true, idx); // wield
}
void tile_item_use(int idx)
{
const item_def item = you.inv[idx];
int draw_quantity = ie->quantity > 1 ? ie->quantity : -1;
bool is_item_on_floor = true;
bool is_item_tried = false;
char c = 0;
int idx = -1;
if (ie->item)
{
is_item_on_floor = ie->item->x != -1;
is_item_tried = item_type_tried(*ie->item);
c = ie->hotkeys.size() > 0 ? ie->hotkeys[0] : 0;
idx = (is_item_on_floor ? ie->item->index() :
letter_to_index(c));
}
TileDrawOneItem(REGION_INV2, get_entry_index(ie), c,
idx, tileidx_item(*ie->item), draw_quantity,
is_item_on_floor, ie->selected(), ie->is_item_equipped(),
is_item_tried, ie->is_item_cursed());
char key = ie->hotkeys.size() > 0 ? ie->hotkeys[0] : 0;
tiles.update_menu_inventory(get_entry_index(ie), *ie->item, ie->selected(), key);
enum map_feature
{
MF_UNSEEN,
MF_FLOOR,
MF_WALL,
MF_MAP_FLOOR,
MF_MAP_WALL,
MF_DOOR,
MF_ITEM,
MF_MONS_HOSTILE,
MF_MONS_FRIENDLY,
MF_MONS_NEUTRAL,
MF_MONS_NO_EXP,
MF_STAIR_UP,
MF_STAIR_DOWN,
MF_STAIR_BRANCH,
MF_FEATURE,
MF_WATER,
MF_LAVA,
MF_TRAP,
MF_EXCL_ROOT,
MF_EXCL,
MF_PLAYER,
MF_MAX,
MF_SKIP
};
#ifdef USE_TILE
if (key_command == CMD_TARGET_MOUSE_MOVE)
{
continue;
}
else if (key_command == CMD_TARGET_MOUSE_SELECT)
{
const coord_def &gc = tiles.get_cursor();
if (gc == Region::NO_CURSOR)
continue;
coord_def delta = gc - you.pos();
if (delta.x < -1 || delta.x > 1
|| delta.y < -1 || delta.y > 1)
{
// This shouldn't happen.
continue;
}
moves.dx = delta.x;
moves.dy = delta.y;
moves.isMe = (delta.x == 0) && (delta.y == 0);
break;
}
#endif
#ifdef WIN32TILES
int old_main( int argc, char *argv[] )
#else
int main( int argc, char *argv[] )
#ifdef USE_TILE
#include <SDL_main.h>
case CMD_EDIT_PREFS:
edit_prefs();
break;
case CMD_USE_ITEM:
{
int idx;
InvAction act;
gui_get_mouse_inv(idx, act);
tile_use_item(idx, act);
}
break;
case CMD_VIEW_ITEM:
{
int idx;
InvAction act;
gui_get_mouse_inv(idx, act);
if (idx < 0) // item on floor
describe_item(mitm[-idx]);
else // item in inventory
describe_item(you.inv[idx], true);
redraw_screen();
}
break;
#ifdef USE_TILE
tile_draw_inv(REGION_INV1);
#ifdef USE_X11
update_screen();
#endif
mouse_set_mode(MOUSE_MODE_COMMAND);
mouse_control mc(MOUSE_MODE_COMMAND);