From be2c8a35a5e961212d17eb28c03c4549bae997cb Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Sat, 29 Jul 2023 02:21:36 +0100 Subject: [PATCH] title image, ui tweaks --- resources/cave_tunnel80x60.xp | Bin 19990 -> 0 bytes resources/title_image.xp | Bin 0 -> 16789 bytes src/gamelog/builder.rs | 2 +- src/gamesystem.rs | 3 +- src/{gui.rs => gui/mod.rs} | 213 ++++++++++------------------------ src/gui/tooltip.rs | 153 ++++++++++++++++++++++++ src/inventory_system.rs | 7 +- src/main.rs | 2 +- src/map_builders/town.rs | 2 +- src/raws/rawmaster.rs | 21 ++-- src/rex_assets.rs | 6 +- 11 files changed, 238 insertions(+), 171 deletions(-) delete mode 100644 resources/cave_tunnel80x60.xp create mode 100644 resources/title_image.xp rename src/{gui.rs => gui/mod.rs} (80%) create mode 100644 src/gui/tooltip.rs diff --git a/resources/cave_tunnel80x60.xp b/resources/cave_tunnel80x60.xp deleted file mode 100644 index 4ff4a5c8776b732a03695488d0284d35b673d90c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19990 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 diff --git a/resources/title_image.xp b/resources/title_image.xp new file mode 100644 index 0000000000000000000000000000000000000000..c95bf1628dc475fac73435de41f0f0921a3bd972 GIT binary patch literal 16789 zcmb2|=3oE;rvGo}mY2j{-S|IVLvK^n`@Q1cn^Je4n6~C#&Q8y1)svs*o!o2A!{%dn z^rWS!o3=5rKTy1!Hl#S=Mm_kZpE{%EgV zRQ9!J~wCP&CTEE{q3*+^H~1=@9p)!w=ex6-MGK}gSfCPXOD=qFl)~g0eS8o z5qWXu9uX-amL3rq5r!U<0tfp9mHmx>8z(w7F*i;;bl9n3;-bY$4HG9#7HarDxsr|X zU)_V8`G+=p`E)Sf``*^d#;okx($4hW^0S0}|8XVdLk-`3Ds{AsWGebUPJW!Uxbgem z=09u<@3((^^{Kj<>2Krr&p%H8eAOyGkH6>2`unU0e#`!AW@A$3mAH`KaIe3SnVmtI z^%p;j)=$<~S7k5kmp8b?dg+U`&uiUShCSb>@1K6Xb^o0G<^~A@A6{{vpR)f_+1%Xg zUGE=keI)v5`$q};rSJW>)v~M3+v_{~$4N8YhgUgxIoa-ouiX8IZ=YA~w#=5de^v-y zY5wR1^<3NXPoNu+3WAGSdKl@8qZtSOP@db zt-IpQ{Jr05*w4>=zqNL@ulnz6;&PAYZmezh-TeES_-xr%zh|6n`zX2PZu~s?T%FS9 zu%-3;xqq!b^8M5IPkU?b-I?`*|H`i~%vtg0nA0zd+wX65u&)&OP$#YWFHUZAX5U+@ z&wQVxF3bw_|9Shz$#u^US6(eU|9fBlmAm^?XS+UnzqPjgY;@qJp8>c3-+ZU9>v3Ob z{*R6g6FTNqiwMaq+oor5!G6PYxmK3eFaM@)TR!cV``aZcm(yp@`}Vix)*jpQr@q!$ zJb(1w{J{Nm&hzh=&zoU&<$L7KxVN|SzN}T3MrQ=hl(%Onx?A zDGQIcEBEi8zdz1XF8N8~@03@J>({;Ax#XXrk(9-T{|>e7+F~3Z*ngd5X8-xM%ckOc z?)S6b&Rj^|U6cEtoBhj+m5cS6e}9+0v48sC$Nz6GTCneH>;8^OZ+Cr=-KM@EpZ9nA z+jVdEn%Vz7U)QBOY2#OeoPF)#lO~;B*UHlRvi!^Y^2GmjdviGNKeYP&;6Q+_c$M1i znV({EzRj#US{^Vzch=$X*l*`2{;2-ht>o-{VE_H%4Y7*RJxBZt-7hg7_`T}vz8mjW zoqhI2_iJu^j{gc@;oS0L-_G3Fax(Ss9PO0X6OF<;yLgz>tC!^(PSUk2$lRTLn2C*- z=fe5N!U>nf=V|^w|5c}@-R;%(qi(Iu|2xbdM1HK!4L@8~T4|s2(e3`lp!>F~_Wf=) zo1fHuJa;4iX6|=?92Gvq725A-tlRthuG#z~>)$I@e9+j-{Uu>fUG49RIt})#DzV5@D-22CN%Zmz%ExkWcK$!E~x9%Ct8=l5XC-ipWR)g zd2>^k&9TqP?=N4Q{P_9D|C59sAH2C_%axRbC2!X7C>#%()G#q9Sg6tbTw;ritf<`D z^84R%HBWXPsIFVM(DA@;O}+dFF`l#6-JBO-cXErgS@iYtc?XvY_U%(Sew7YcwVk2Ty+Ph$ z_OuJ`7ysQ<3JCwNY+~W`b<4tS%N*Zd>`L`+m{|7q2IG_PvU291PcJ?Bg%$u+IaAQ2Ww^J0guI}Pc=+D)}zPlCS|y%q$MkOpGoDUr7zWIr!Bd2 zM@GSayGdo%(vzW+)0UKE{;Jn>SnHZKYhUyFPu4+8Dwj%RCLLZPsp&myV$r6}jW(+r z8y)8HXWsjN`rJvzPu8D4fBv#P_34w8mm4=+n6TkOoMq-O<=Oj}r1o-f_5}1xNK1;X z-spc}0i$DcRpf*R2O1K3WtE+rmA>50iPO+X2$&F{#dfkV_L%gW=2q69?JsSYPjg{mcUh5l#I^0{O8YJz-mWX*%}i`eXI=QY zLS`4=`@XOI-p=g*_K{ZatDiIG+xO2?(XvtTddvM))k?=AO4rw?!lP%O*KA=iA&F%{ z^_kDteg1D&`_cB}8%AEe6YPuF6Aw4tp8-!rV@bNJ82-u?eKs3b(i zAn5j$%mdO}kGQrT&$Mg*B_#7gevR$J;_L6@{kwX5`$Frt6n|HB*yH_RfkCfLlCo3s z)qNMH&3V21kG6Mbr{@8W{d->9J-9mkfFm=r>HcGq#?RN?+P^48N#bOP7!R9U)syr3 zjBkb6+p@n@y^ESVImAl-#16MoU4u*6`SmP&l$oEeyJ~qdJ3j6FYX&!~Z$Ga;xFc$% z{#A8t+~T2rb+nV|MS!S#m6a5-e7!bR&R8}#C< zdiLvoZajPP|NkX}+ty;bubJF_y?JuKA$<0)Y5#8K7t3z$;rWwZ*Zy#S`_>J2?{lBC zmhUL}_f!1Ko#NsbYgQjvp)!!jjY9;}~5gr7iJZTDkP@r9J=4r!dlAwd*2z`ckB)r(Dz5)Z>y^xpSS=iMzKph)KNs z-OkUTeD}lO<^$Sy%U+*7;PL&>Grfc*_wRhoPFSKozk*5PW%>7e%spQoG=FDS-m7%h zL%!yRqQRxx`SPr8Re!gJH^wwSmS<$NaPz5oC1KH#Ch_Y2d6_U&G|KYMmCl+o_YMPF(ys zxBT8`c7^>fzT9t^X!q}ncEXY~Jthi^8P3&cp6e+-+gFxW!p`=C^%c+b7au0PxL2$w zv`D$3yr!{uZPDgS4HL!m=j@NrJxPN%_PxGd zzIvaH&RLK8st=3_OWNgX9w<)z_vg8Kgu+jv}# zvFNH?r9{WqdDhYrnO9CE9`Jbia;1aGo3G`K8NcKIvpp%VDdIZuf9X<&jlPPTcej7PXRiFzx98igS67w! z?KzGp?JX7YSoiAc^u~$ztbVZx{H^}WVQ}f9c|7|k9yx2iBYd*fbv~+DH;nyl*j)VW zf4y+tnzmlvlIhFd;|(`@-|u5h3f=ejS@u?iE4`QN|8hyZ)L-t$w2|pjh`;aT^S^&6 zE2RIwrM>>;o|L^813Vf$c*q5G??V$DJuW<;d1rH7pKGTGyZg)U(4EKvSf#V zgr>5ssk3R%=T#P;Z`V(lzdxUKd+O4D<3}QbLNW_i8!J0CD>*gqc|84!;<=d%rih61 z_L!_&DCS|Zsa9KHcJXQ710MB%4!>`_(X1}d?pF0`rTV;}vz6~|E^n+@Ha(tck)^&3 z{}H)8f5krBdnq1Y!M9@XFXaH;O4b*#wW1YUpM1R@#~hbi_5bhphVb=qRSzW_%+YNgJU^WKHc4txcS`QrLw!eo0l`~bSnSL?fb_4(}e`ysK9SHIu)+e~2fr*nbLFAjDesJ@@K z^QYT`t0xy<+GBX)`TY4mVwC6Y_Yn3j{v`52ZgHq(;iKXQTlL?28eh`S+b!DRDsRm7 zVy+*{q}kEC89i*ie7)aTb8q^6hM#*LFK@KDe2z=x+^1zr3%xZDWEWe6-`SRTW|i+b zE7fzKmxeEPP4bZyve0l*U8h{IR=g-|hpPH9_1Et`db+)?SnRg2XZJ{}{uPq2ZS(zi*Zw z@G$@PY7T4Cas^yLi^EBW^`RGGFhC{N|l zWm=`WZ)>s5wAqsx_pCQMw{h+7Eo);oudUn?D!L(b9TzVj(;~r{GacUFE>JLYnl)$T zW~Gko{6&iwHQqT`__#4eO-zruNPL+OW72vh<%U0e%az))Ws5UBGBVC;|f*3yJqj@$K1I6qY7+K|PD(!V5L=7wdi4?%m<7ow@c@b8hVHv(E}twc~p``KOiIde^R=AYZOanT}0hd*Ctl{#$dFt%>^?kQ)uNaVy- z3A2(JQB#}##4NCy$=_pA;vx9KYm4P!uQrCC_YN^7Ecvr%PEG7`%N+{*FRse6ec7qQ z7AGARA0E9vTUY;9?MK&H!ZCaEqysXI1NN8xj63^P_w5^&SJK;=m1C>VhB}z!9JW&U zc5|ihVaXDHyDu67tBW3qOjz;rMtsAO@b@z8Ro`|V_ z_e z-1%SYRHH}o>Bfnx=9sQc);`8?Hm`T>wdAwDybkmJo)m7Z=#aeJaBH>af#0vDoSeLT z#rMTqGxBG1nQXS@eNi3VIB}W(Y(ACe)n82=wx$RR=x-@ItkvtUf3sHbg2!sM?i2t76fB{96o9 zR)zL4x=96_$#fi-Gvuk*D;j?2;-wqc;&!icvv|zS%>IQvE51g1+KlkN3D2(fHvM5z zNRN+T`4ZE{bk>oV-A&4JQOT01Zm&$YsBJZ>6Fe3!70q~;m@@O2!qcaV8_kzxO5W%B zvdg6Ry6FWQv*ar43CpWbDk;p%yEo^j)gi~sb8BuoES`9Cb7+)?@4LG1S__h8qZ=lM zm91rRvnsf&sPH~w3y;LgO@A94>YcFCxpeE*10IvrwlQpF4{og3wN3MY$L2IY z_N3Zn{_ItApP#vEdcSz7WaiONPY-xVU(3I-;9LK+4+k2X*|)skRQ6X)LAmhsu153a z7q%8vPG7g@{-(;uVr%s;Y)p^~m>a|RMUtoc!fI)GdGYlV-}l!QDSwEXYJUIU3*Wh+ z-+x`?Z?x0wb*PWFo)DM%TSOr|*~$2V;i`!TX7?}M_vC3B)73d!a?bwPeB5bu(L>hf z@fD8iF9t>LHF0x%)4O!}vL)GXX3U(&sIu(jImTD2#h*jt?|f|37t5Hac5lH}-j1^? zS26E>bK%A(udnW3oUSPD^E#WEwTAswp&H|Qm$M7gv$E&%?5SH_o27l>4N_}o|2YwJptX$o{s)ED+7c?*M5BWuerT3 zrQhzym4r{e`Fq$^g1;R5?NAr^`pC+)!h7!6&=^oKP}-rp#64=n%Sb_#O2otBKNM6K5^ph zqSgb_h1-2+@*MepZlU8mVORgtt)cTko)!$ZQ&NnML)lwL|MeA(Kvo=nvX91CcY)@8A6=BX_cQ5~d!-K0r z+xPt_IT5CLIZ9E-NGIs{w%o7BC6#Y(>iyz#rd^arj%QEhte!6>4|;1g3g@)gW_$hN z`?hFhw&>Hv+9CgQ!n(e-?zDR)@HMO1q<8*vre3!&rrss#OjoC`G`>3R%$$pSdjfxK zS~}Ok*mdK9+xCwt4hZ}2=hzeV>C5N!j2|r?ORKM}op~X~-ZA<1%HXJmn*85WW@cs1 z%F=Fp;r-KNfuJkXg&1#z4^b2Lsk-T|%UK)zenOq8t*vV8am7uWE^RhhmR2%%>P$Y9 zrc-S9s!vwmyAZ%1;_Wlp|KvF)t5?%zE;im>pAANQ7Oqb#2rqdZap+ZOtizIb zdJkmRM{M3z-TQ6L&pyk|%a}jD;Vksb+MN72DarKsjf*=aBwkKbpT}zC_Uljf`4!V_ zzMeVlu;~9`2D`NhohYovYX_l&9n(>Ki!Nzjl3qMxvjH}KK4c+SSWz{~;745RDSIj~i?*0Ai z_TcLN%(uChO}J*6SF25kpE+&P!hdtZ*Vf+pQg-&6&7T{_2R!`k{t6jfO7^$oKa!t& zn?vRJ=2~Ha-nUU)B_@m6DvEWtooZiabEn~7-7WR9^d~h}>m+aADzkcVe}DY{e}Aj` zjW@npxjt>bchND9JJ!}elr*BRS(;f{nOWV+p8E3WVrAt;p^LsRKHuHl*>ySjEjll@uag#SjWnwm@1wcmZwmXP(EkhY{>1Gk)qj(jxLUf8+9Vk)4${BP(C6&Dp7XTS96r|M9L%mx3;R@$~cTVxOgXO7p~P z$(_D_p=URq)l4#Zeowxscw4RU$IO+nm3qswW~`pJ=dnMR_Cn^ z&Ye|iBH4QX+h^&tm;$`FS zdj2P!RWBSB{BI`rGj2TZZ^zj4WsS+yd5msV?{=m)PK=wNCb-z=qwvet=kZr0qu1}R zdr~^LbZhEsvj??78Jly%o6leS`Fw8qzH@KVeapYgc+7WAkDFo}RLA~xsn4v5b^qJh z8z;W2f5Exn+tc$0W}n{BEB9^h@3!1)+}d+*mNZx8uP)EMz4OFU-*YkI=LFYD+ivnJ zZf9S=M?~V~@%D9$ZdG3%vddkq4Dh%ACon^1y~ZW=pI_f@ocQj? zQC)|5n|{~-U-0U}`uzWv0=kvIJQXa9)AjCJ=gZbUU%NQ&Z}t1T+wWht49VaB_1SH! z)$dxL&u5;rcIs2!d)67N^|Myzp55(Vf9|`HP{~`fq??Po?sZMP_ICd+>5gZ2{!2`F z{=&bX@%@SZ+-D*8r}pHQo{HVgX0d#)5#Bcx4W6@Ue|DH~t$L#j&YOX!= zCGUy{b_$WJr_X0zRO)ZX)>HE8iTDAJ`oFJK3@%+??$2mh_Df|#a{SzXQR(;URDG9T zj(@pvYxZ@W(n#)@U^^2}Mqa!jvUYm6;s9^6o=7;XD`U-_Dip-s!wf;PR477!MdyByqYrDhbj zIQ-nZ-u|wR>o2w%XzvY3?mqTuV(+cf>!l)@mXw>X74-<&UuSA?>0b9XX63up=kI=h zRda3kyFJVjFMm1zZj4wd|Cd4H<+1tyI98nB{nIRV>w%vy%L&KzIs`_-6TDxx0I>!Xsl(xbJ?D}9m-<466p_k zrcIKa^xmYkLbbo-vF~=qi__WVSc|^xuNTOOGm);?yzE`=k#jxPKlg64-GFh z&iuuZ&3!kGtx8nyEb80YU1F1Z{oGoI!x^8}ux+m_vy z0d7X`zW?g`$j7IrA+cuLl8{+9c!SqPKKd>H?}gigtCQ~kf9UVuP==t)q)4yTjzCVvx1pX(A70(IM|DrnK`@a8t6E5D_ z-p9}x(6@)Br{vGy?F|#{{{CQ2Sdzcb>Thq=!vD&?CEJth+Sh%2BD(4AgG2wCa`|;{ zd)Qy!85BQbwUk|r$^@NrH@p_y^uBy#zV&AHcl&yyZ;!Zyv9DpW7LF z=QVRpwoiucjI{~(@1^BNrcU0ia)H~`y~SUHp2X=As_FeK{w_0cYeYDzbuA-r^%37-rW!$FY*4?x8EsK9BVhe4LGRLA*mmwvd`R5&nj@O>%|9ml;*yiIdLA( z7oI~6*Y{m`7U0#@>2>M7hW06TBdhI&yat!@-~Um)aBoe1t6=!CqO&iA`|WvpO1|_e zJLsHnmuIRx{(3#b#bw{`{q+dv-S_#|YPQR#t-f7UUll&Tu85~&UG1NTg|X(pU#iP9 zU%jl~Fwt+mU1`)?(c>IDUfoHH&rn{W`aj2(p?-hkKPhqX6DG!;U!{&SZq;8_`S$eG z@L1ju?{{oMOYau_J}bri{8>s<{r>ut+sQ|ksczA_COWZis+X@PgHYuXl_je~LM8++ znYr!GnlCZE$-<8o36+$3#FV(qsZxAb=6rUgwshR`&;PT$+LO#`1n`<9gEwqlm7XPakUHW z7u9Zb-D%^tchlPJ&2L$ct#+(E>EV0o#mkH8N7P=%8CynXT1IBZy*9S6Pv6iNow`gl z{Z&tK_!DVKx%IoORjiXczWrF$CKmcq;@FBma{_L18(sjoc^;I75 z@U{|Xkh~syWn;*5xwR3OIG5NP*PBg9p8Glc#hr$;+2M>+cQsDjwl|V-KWo~YrMnC*?5j6?t3GwSN9X#^I@9FiS6<9>PIlvwUR+$*^|`pa zw8qL>)i7Fl@th|uGP1fSd_7Nvp3Pe$b$f;J3^Cmq+((p5uQDr}nqDz`*>$I|xAbwz zGymFB)(Od9uO9HoogCfJ^Jc3blhLL}XV@bRs*f?f?OhvjiLqx(V(xdgtE=Cf`H~~+ z_&~0rtp3UF-(P&*C8xi;eTc)-R#!Ln`|+7(wQ2^JrfhrZP#0Ls{NY)A*}Gf3A>MgR zlSKbN^lv<-zwf5f7x!%%(|13*;I@JN-0t)0t@Dj`D5P)rHFM6Jk_TJ$IX@b5W+|`m z-4cGqwC~X8h_tMrWw(}XdZ>E9BUpW_Pv~yL-Fr*7y)!mVjX5kbm)orL(2kW>i_?!? zIcZ$7?9sHduNx+s;Bj4chuoaE=PuN5V0YlM z(W}gy5|xQG2 z+a^9ubmnUO^4+_u{k6@WMStcf^(sr;Hex<9(=TRi?qx+U&O$@Zs&jhQN8+D6$y8Ey zYWT-@|DWwTS*e@Vt?%de=D4G`oztm;>5&*iL+W~ zSZ06oIm?-MV+XItz3PWS3KQQS(L6AFXY}4QTZ2oX;j!FH`fIP&J@_lzOTroZ%dnv{*Q#JlDGZR+;u& zYiTdt!rwEElcT-v)KB;?E-%fjVivteq$B=rC8t1bkeL6)UoW_H>6t)G6by|Uy-$k*sSS=-{4<}Q_6KkM{ki{1Zr zeJ)L3w|8UelNjUkbIMav(-_v5-z>bi)S)E9Q#_z{CYwpIxtK)e&#t@$Gk3pU7goFT zQ&)CFxOvXvrZ0D|h)2uyl`pJ%lcDgJKb@7!_{*D{Q$$3ktcd$~_0-12+F$p^ghvM2 zaYfdAcPyTi2 z>OAqc`$Rlg>OaOQR5qrrZur6+wVX-$s+aMlO;7J0@Cc77JS)0Nb$Wc6=!auWTkhE$ z+Y=d9&ZGAr?56zG3(g|{HmN1dxE zQq;ZZt#sZ^Z7nk+n{Chk&k5HIY}dG1(y_1o+fmu$^D;AYB4e{+OG8BsF5TPvyJ4c< z&0eVQi^u zZ2!KHo^^qD7fie0esjsOU9a5MEh=|H)FYUAk_ogK_y(6~%*Ckd5%+F2Fn%jNYupqrm|M&AR zKAN2y4^;Q;P4<$R{P<3Mm}B92Zu??4<;RNA|4*21zPizF+tm6sZ#TT3)$Fk6^wjHd z3k|c&zwgR>8|gpCK(eFF^7G#CH7}UrYH#kVRljg=V}6N+nVOQ>GWEkk^VeLI3Exwc z+qU+7OvsG*B^R|z7w_7$CaRWI*TXxww!2C^%w&mMPxcztPkpyeS;f8$v9MSlu$br7 z=Ch}Y&o-Q{w-Cxz-(083S*WSCRQ2fcm+yVOJw3c%PR;i8?C=fLv^6!1T|Dj1n=dhE zt)D$ldG=cP>87K7({`xNH#0n)DP5Yp?e?|wO=lODpY<-Ty2ve7!f8B zOF=@HzxDpmFE2clXSzDw*`eyp-Pd7XZ%pr;-0-6|)2MA*iKW4%b+Nn4U!FLyt5o{H zO}COD;m1LxGRrq8Y!CP?|1fdk!^FK=pW514+Fu*nR=K>)h-J+BY};!(wf9xJM(DKu zRaff#3lkkT#%V{Tx&>^L+`sLg-F)wLOU|A0VU6pYs#0j!fOQW|EuiBH2Z`kAB@h zJ9|5$vaC%B^MsFUnXkvM{aVNm*QcL5cXaM9qq5V_-a05h35~s#?&a_8b^T7b zQ;o@oxaxCk{CqqtakUSP&n{oHaN8zF<^E-DvzE=2ag^G_4co^)3kJhDjzqn-SOiQzp8vJS^2sf?Yvd{a?(+UJ&l`< zkG;COIxO4vD(~y-`4?mru6bVGaoI%jVqsSJCN-a2-_*6YlEOT-<%8L_9FGZHYxwYl z;9~_nc%QUR%ni;xaT!OurfOf=Z#ZrF_U9T#*;j8q zi~ICHYt^ajEncFJBf|DPwqY$doo=jJ-g?qFK6TECGo00iZw?!ErQA99N2-3}?s-k` zyZYB^NUye(d&ONmajB}a_ts-tuiehhHO^kQt}uQ_0po>^LQVsr@74>aeUSJbnJC&? zS)9&T`RUba>5_9St55XkNgM9UX)$N^vyP08ja)63d3stdsL{5EvEsM8Ol3~)+*_-D z?%MfTjA5gG_cVs9-?loO%YXT4>8r&%x+aGjN}etbnHtFb*4r^Jt?}0HU$;(GZPnUx za|_d+%iHd9tq|OEc}vV6ky}=7%5(IO+GMA=WTd#PFmGDE@4~YS`#$J}giZ_3T-U!d z&5di#DF@w+FHfJEdOAESc0;f9_53T60@6z^%&_~tOtQ1IA>wSSX^fhG*331ZjehJ+ z)^_W^YUlFwhT&8x^-nvO>P6c)kF%ERy=AiAw?CPgTwI$P&BHd{oPH_s=mBfDr`s&| zRZKEu{;jv|9$#%pdOG_B^)1;`!!lpKin_S8G{P+J4nxltw^==0R==Y^%3g7ap5Hl@ z_2%IfYvrO>+g{pwsbook{Dp~2PB(;uLNaRWEP2!Po1a7v%zpXyMFhv5z2$EF+XCI9 zLoLepUh48%JK^vvt8F{x&g+Zo*w!NSwbklKaiYyRQ_nMuPoAbSt*>3!_A#O`u&yxB z|7+@f35(CZ+g7EmaWpSH^rLeZH>0-Hr+=Hew6>=F{Z;C)^~iQ%nbO6(cdw4l{-+aj zgK^IVXwr`NH#-P%@beqnPIf5>~^T(|ruyNjM`EeJeq zq_FMs$|olc+0%F=R~u~O<>lpjJ6Acm{#e@57gt|=USZkOvm$(p^SU`rOXJwKY8vXP z1(wFe^y{gbb?-}jC`R=mtb`n38yyRK<%w%Jw7)~%Zw8+CjBuS<9L zZi>$C(v7>b^Tzet?;@6L>$F?HaNjaVcOQ$zJ)+0e{H6GptbcgLD@M`RtxoUW=G)U3 z-(~z#eVzH@q?2odOa5eJMgI=js=r0cdzudGFP$@N_XIiDop~9Y{>tXFUZzm&`y0F} zkIJ51-}yK;{(nZ)?~(=2_wc;fsl&Kx_vVK3lFPQ`-N$o;w4LW#M&AufKeKG|wq2sz zYBh8As>^NusT+OAW$u!z(m^&A9p_peF5mHutDtDrADbwts@UkXX_2wf_FY21oi?YR zpL6&2bl-V5jCQL3etl)|jcc4yAb+u7Ihn38Izt!G-LzpV1_#Y?H$ z)3WyLE_kSKzwA6Oc3$4cC1~SzGB*FnC%)y|c+*$k-g0DH zJ;T~5xo5kw|1HVBx^%L9QI@!&+2iV)*EhI^UJ>%TVihHI?7)oaFLdmpxFzt^?( zY1)|?X3nPV>-};h`AufOS^ehqs)%?_?JI{c%>hq)vA2 zsY^>^9cnUun=E+TJ6ZkZI=1fVdhu&^PW#C%#$Z{UdGDi5-y>JIHurCGr@6SfIbTP< zJTc4u+&ul7saub&6ds{-!{f0zsVcz20T<-N2@0m)Q>n21U zx~O1x`HRn#7p6IeykA?RF5R-)8M<}l+FY;M`%e9N*D|f}!0XR9?#r8QDw%SwP}aEW ziNxBOA>qN1%OxMqG)_AcQoUhSweE!(X}kgUo0B%avpo=Z@yAD9hpkJB_r0^S&HwkO za+i2vc69XWJ~18{3x*E5u(&jZKRMZJu4Sci(h1XTwpuFHSwR zH`3*;wp6UB;&3yc!|&8N|M-n|yH>Hee^bKtFD);8-|=*EMfh#ilq#e-A zXY%gv&Ti>3GNU9Pe7_>9`$Qm!qnZY^`SPEuOSO1%#w>7rtR-HymdOj(QuKYc1rGl2D`gGI@9%|H|yua|U+Sz3V(-+0=*1x%Q z^To3GP3ha;&8WNiw7M~+RDZXO#LGvv)0y6H)Lws&J!Mb&ebeyFxh!(YZ(CNc+b1RQ z^1#8v>{~wlKluK?z=;(XzuMa@(LTHGZoPm+=J9i~4xd_Xmoq5GZvOwk^w+C>+3T6z zc0D|9&ZzwN$FbWDb;rLqhR0hdU%7w({Ql+VCMU(x&HCTehO~;ReD9{y2sXHy_G9Zu9UibW0TXHw+5%48m0wH+}`!-p!G$L|M@*S zTR+rwRo8Re|MyXLZg)f9`88~p=Eq&!>hpY6sa_P%ldD&=cYnDVzqw9$!k>4)&N|G0 z$LpYUHFtM|&2#DPOdENk%b7a8x8<-d+IYJx=TaoQwcagem-6p1d?r$nTu=U+<=oa(OLWV~CCO)0j-@PhgQ^YA~Dy!F`QbRX_Xychb;PDI1^@yP`V zviuyAo?Yb)>-C+Y_WjPvX)@yC(#uWrf1d1#TWNVl_EJ>9>>Ku{PMtb&$@*+n)X&Pw z1J(5_!@s1;&1$$sSd*;&TH-%I8guV?OHe;u>Qp?vX! z7Ymn!ssz1_*s{afwCvy^SMDwMH!nzj$aMDhx%u}QRixtX?G3rkt`oP3$>YuCy?L#D z0h`i=B_7DH_}IPQWPRQa)%$(vR}`Z}XYbpvs9=@Jd&76@j&phRgs!mslDckYx@V`S z?QSKjtGg;Exo zr-y{~t-W%_GxDa!f=TOVz0|POh|=-hw|E&_#nN5Bep$^uf8O-7u(}`Hy%$@TraE<> z`;(WG#kR=#T-@c{+{?FaRe1(4+rs>Fk7uq!@{*MYvVX>2eX-=_=J&V76^xW@j22Bl z{*bS7+ulzv7H4>`aL&ABV*L8{*^bhixyFlbEMBzl!{s@BbBKO2z-Yrp`Z6?XOXK|D}VM&Z&KrRlW2j;-kP? zyYo}mC@-x%-yn3p;s5bj28)-hd~*9>>-(qw4WkccpV}?2;M@PR%y>~P=j3JnYcuc7 zXp1@&URfW!By-9{z7YPJ;!}4^lXg@W`o!e;OJCn(mb|pbzt#6q`Gw@qJUh%yHnZ6rn|m=LbKdnUrKNL= zPfk(WcWtHW(@92~8}9Y@@YL4*)LN~`#>U3N_N^;)gN|#QSe3|>ZXm0oA*$?_6*2S&*?6Z5xi4z)o z_Xh?}3=Euj@1CKq!TEd31h>5H$y^b>aiihJUq>!;-&`bS=l(@%P4eSw+RtBZJF|1K z`2zKgp~*#S1xi*e-I3L6{q5-7hsI~KXYc5``%QD5&DP@BADUaTr~J@Ty}ffs@iRNw z^8L-<4=?|&*Ev;VZt^xmvHy-_(G@}2q5f5&a#`>TJR zX#MQ7Q9E+K&3x>%XW5gsBQWo`vd#G^SSp;-M;qH)~~xI zD{quNTfFY0_)WJBO-#(qRq>v)_kG}M_4r(6aO}Iyvu{4>X^Jn_Iyp5tmwaXY-yhyP z>FujqcITf7R-QAH-Trs}TM6Z3Q>HALGH)icpWPYL(`K5AE7SAV3VVP2|3mXn%Cqj= zQ12X5tsi{R`m-bjzxiFd9DLbSIsNpF8(Ew;w5}UJ+E}eNKljmP=lN$i8vfmxcD$r_ zvV~+pUDxmb=dSG9ry5u2wQb+Zw-NVm}x*H{+{Q##g6aSKkPl##VPZ1<65(au@Clcxw>q7=(_Ts6~|Y7s4PCNYFB^meDPbK zr!F71?X%q+Xme~{@7eOt|8wR)k~&*jXQ_H!j=yi|woG-?*?*_(J3sUN1O5Kq-oCdt zcvrqw}8UFVol7K+*H9e;MY9D%XDFxKo=x|NmQSt%7u+ zn)!!9E6>=lvi)MuvT?D05%v7R6VBi{bN}s#7yB-L>Wl|_mTd9o684j4&h(r)6ZiMs zlP61_JW*MHw(LDi`7@6KN5{CvzLlSUPW8R@q`G@)b9kbucc^Juq8%i|fQ5qdS2+-s|m{?|pykbJML~f4rFc(o)iU=kw5?k36%K_A6Ui zX+{0MyzQREe1@phD7M=gHuD{CckIr#ZTVc^)1Fh@mzypBgD=W`pR%>JakTOA9@ZJ> z7jA!U9pk?}IoUGrl&sH9<zxdp#o)YEmo6*w?Z)Q|HIASxBXdZ`^?_>+_c%Z zHouJh|oa)vi%LMbRQ(m8ptm>ZD<@ILcjkHOh<93xz+s?Bm&2xO?+wvh4YmdTvf-aY@XaD5va)a;Bf|*3Qnm zAXi{AX{PnNOWC)#Drpo11SG7NvbZ8%J~#6DpE;2S&amDL^S>GP`Bqr_jx{y&wTp7E zn&fP~o%8wP-FfHCxAznper9TIWo=z07<1V)>qwCbXd%9lq8sir`US%vcQPz#xQ!()!%kz1=3!X)=Fa5A#L&4YR zb^j7#N@~t$89whk@8ivyzWdv{I~~StY27-K_Qi7B?>8{k+16dSD04e+;+>ll-lty4 z=?w6qyf9}zvoYHj;WiKln;}*UOy}4qdgG&0AnZFMGw7ecu%`1?3KlFe{^|u%vmw2&K zru;i6J=&_HZhTs^tw!QE+qSAxzfK<+=|~tYNfB6w)JhvgH>+N_e|d@_^s;Z z^Chy2%q7B%N@kq%dmz{TrFVVSd8 zjxBu}m$2mRZ8K)&x3_lkO1$jaJDo|nP@Kt&onMYYNp=^X#LHjOc?@n=H7_nC{_Q*5 zzRr5h`Z#UhfA4=CcG%}UE2CwzU*GF_+j8&n^jz6mR5?9NAYoZ^^3yZZjvjS6{?el$ zt0*X|Xnl?Be7Ugy8}G(v%{a}Mx-9+Gp6plL$+pq5?9uYqwicNy>nbas)h@Iz*w;MY zUEcrpxvR`e4|{o)&S(22@+=@DQ{&>kfMSd7)jvO_9?)JJu}?%|I}csjwyOH=tgG3jYgM1G-Mwb!V?pq+F*ehl6I*zlWBO!imVXs6w7 zzDwRO+;`!WaoU6TPt|XSEeKe(Zq=G=wU>7^N0pYQZapXU{FKW%mHY|Mrp}rL*_UAv zSgm7o?aB=XmH10nZmc;jv9L!jmd)k8x3|~V@(=IKO-)Tqzt%*@Hm{3#bkjH}!7ecU Q^8fh5d#vmaJY`@20Pms2%K!iX literal 0 HcmV?d00001 diff --git a/src/gamelog/builder.rs b/src/gamelog/builder.rs index 4f36cb0..a29f9ad 100644 --- a/src/gamelog/builder.rs +++ b/src/gamelog/builder.rs @@ -35,7 +35,7 @@ impl Logger { /// Appends a period to the current message logger. pub fn period(mut self) -> Self { - self.fragments.push(LogFragment { colour: self.current_colour, text: ".".to_string() }); + self.fragments.push(LogFragment { colour: self.current_colour, text: ". ".to_string() }); return self; } diff --git a/src/gamesystem.rs b/src/gamesystem.rs index ee79882..f191450 100644 --- a/src/gamesystem.rs +++ b/src/gamesystem.rs @@ -47,6 +47,7 @@ pub fn skill_bonus(skill: Skill, skills: &Skills) -> i32 { } } +/// Roll 4d6 and drop the lowest, for rolling d20-style stats pub fn roll_4d6(rng: &mut rltk::RandomNumberGenerator) -> i32 { let mut rolls: Vec = Vec::new(); for _i in 0..4 { @@ -55,10 +56,8 @@ pub fn roll_4d6(rng: &mut rltk::RandomNumberGenerator) -> i32 { rolls.sort_unstable(); let mut roll = 0; - rltk::console::log(format!("roll 0")); for i in 1..rolls.len() { roll += rolls[i]; - rltk::console::log(format!("+ {}", rolls[i])); } return roll; diff --git a/src/gui.rs b/src/gui/mod.rs similarity index 80% rename from src/gui.rs rename to src/gui/mod.rs index 744a0f3..77d32b2 100644 --- a/src/gui.rs +++ b/src/gui/mod.rs @@ -6,6 +6,7 @@ use super::{ use rltk::{Rltk, VirtualKeyCode, RGB}; use specs::prelude::*; use std::collections::BTreeMap; +mod tooltip; pub fn draw_lerping_bar( ctx: &mut Rltk, @@ -38,7 +39,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { ctx.draw_hollow_box(0, 0, 70, 8, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); // Log box ctx.draw_hollow_box(0, 9, 70, 42, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); // Camera box ctx.draw_hollow_box(0, 52, 70, 3, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); // Stats box - ctx.draw_hollow_box(71, 0, 28, 55, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); // Side box + ctx.draw_hollow_box(71, 0, 33, 55, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); // Side box // Render stats let pools = ecs.read_storage::(); @@ -144,14 +145,10 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { } // Draw consumables - ctx.print_color(72, y, RGB::named(rltk::BLACK), RGB::named(rltk::WHITE), "Consumables"); - let consumables = ecs.read_storage::(); - for (_entity, _pack, name) in - (&consumables, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) - { - y += 1; - ctx.print_color(72, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), format!("- {}", &name.name)); - } + ctx.print_color(72, y, RGB::named(rltk::BLACK), RGB::named(rltk::WHITE), "Backpack"); + y += 1; + let (player_inventory, _inventory_ids) = get_player_inventory(&ecs); + y = print_options(player_inventory, 72, y, ctx); // Draw entities seen on screen let viewsheds = ecs.read_storage::(); @@ -188,8 +185,8 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { seen_entities.sort_by(|a, b| b.0.cmp(&a.0)); if !seen_entities.is_empty() { - y += 2; - ctx.print_color(72, y, RGB::named(rltk::BLACK), RGB::named(rltk::WHITE), "You see"); + y += 1; + ctx.print_color(72, y, RGB::named(rltk::BLACK), RGB::named(rltk::WHITE), "In View"); for entity in seen_entities { y += 1; ctx.print_color(72, y, entity.1, RGB::named(rltk::BLACK), entity.0); @@ -214,7 +211,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { &format!("T{}", crate::gamelog::get_event_count("turns")), ); - draw_tooltips(ecs, ctx); + tooltip::draw_tooltips(ecs, ctx); } pub fn get_input_direction( @@ -249,89 +246,6 @@ pub fn get_input_direction( } } -fn draw_tooltips(ecs: &World, ctx: &mut Rltk) { - let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = camera::get_screen_bounds(ecs, ctx); - let map = ecs.fetch::(); - let names = ecs.read_storage::(); - let positions = ecs.read_storage::(); - let hidden = ecs.read_storage::(); - - let mouse_pos = ctx.mouse_pos(); - let mut mouse_pos_adjusted = mouse_pos; - mouse_pos_adjusted.0 += min_x - x_offset; - mouse_pos_adjusted.1 += min_y - y_offset; - if mouse_pos_adjusted.0 >= map.width - || mouse_pos_adjusted.1 >= map.height - || mouse_pos_adjusted.1 < 0 // Might need to be 1, and -1 from map height/width. - || mouse_pos_adjusted.0 < 0 - { - return; - } - if !(map.visible_tiles[map.xy_idx(mouse_pos_adjusted.0, mouse_pos_adjusted.1)] - || map.telepath_tiles[map.xy_idx(mouse_pos_adjusted.0, mouse_pos_adjusted.1)]) - { - return; - } - let mut tooltip: Vec = Vec::new(); - for (name, position, _hidden) in (&names, &positions, !&hidden).join() { - if position.x == mouse_pos_adjusted.0 && position.y == mouse_pos_adjusted.1 { - tooltip.push(name.name.to_string()); - } - } - - if !tooltip.is_empty() { - if mouse_pos.0 > 40 { - let arrow_pos = Point::new(mouse_pos.0 - 2, mouse_pos.1); - let left_x = mouse_pos.0 - 3; - let mut y = mouse_pos.1; - for s in tooltip.iter() { - for i in 0..2 { - ctx.print_color( - arrow_pos.x + i, - y, - RGB::named(rltk::WHITE), - RGB::named(rltk::GREY), - &" ".to_string(), - ); - } - ctx.print_color_right(left_x, y, RGB::named(rltk::WHITE), RGB::named(rltk::GREY), s); - y += 1; - } - ctx.print_color( - arrow_pos.x, - arrow_pos.y, - RGB::named(rltk::WHITE), - RGB::named(rltk::GREY), - &"->".to_string(), - ); - } else { - let arrow_pos = Point::new(mouse_pos.0 + 1, mouse_pos.1); - let left_x = mouse_pos.0 + 3; - let mut y = mouse_pos.1; - for s in tooltip.iter() { - for i in 0..2 { - ctx.print_color( - arrow_pos.x + 1 + i, - y, - RGB::named(rltk::WHITE), - RGB::named(rltk::GREY), - &" ".to_string(), - ); - } - ctx.print_color(left_x + 1, y, RGB::named(rltk::WHITE), RGB::named(rltk::DARKGREY), s); - y += 1; - } - ctx.print_color( - arrow_pos.x, - arrow_pos.y, - RGB::named(rltk::WHITE), - RGB::named(rltk::GREY), - &"<-".to_string(), - ); - } - } -} - #[derive(PartialEq, Copy, Clone)] pub enum ItemMenuResult { Cancel, @@ -339,15 +253,16 @@ pub enum ItemMenuResult { Selected, } -pub fn print_options(inventory: BTreeMap<(String, String), i32>, mut y: i32, ctx: &mut Rltk) { +pub fn print_options(inventory: BTreeMap<(String, String), i32>, mut x: i32, mut y: i32, ctx: &mut Rltk) -> i32 { let mut j = 0; + let initial_x: i32 = x; for (name, item_count) in &inventory { + x = initial_x; // Print the character required to access this item. i.e. (a) - ctx.set(17, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), rltk::to_cp437('(')); - ctx.set(18, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + j as rltk::FontCharType); - ctx.set(19, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), rltk::to_cp437(')')); + ctx.set(x, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), 97 + j as rltk::FontCharType); + + x += 2; - let mut x = 21; if item_count > &1 { // If more than one, print the number and pluralise // i.e. (a) 3 daggers @@ -374,6 +289,8 @@ pub fn print_options(inventory: BTreeMap<(String, String), i32>, mut y: i32, ctx y += 1; j += 1; } + + return y; } pub fn show_help(ctx: &mut Rltk) -> YesNoResult { @@ -423,14 +340,12 @@ pub fn show_help(ctx: &mut Rltk) -> YesNoResult { } } -pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { - let player_entity = gs.ecs.fetch::(); - let names = gs.ecs.read_storage::(); - let backpack = gs.ecs.read_storage::(); - let entities = gs.ecs.entities(); +pub fn get_player_inventory(ecs: &World) -> (BTreeMap<(String, String), i32>, BTreeMap) { + let player_entity = ecs.fetch::(); + let names = ecs.read_storage::(); + let backpack = ecs.read_storage::(); + let entities = ecs.entities(); - // FIXME: This is unwieldy. Having a separate data structure for (name, id) and (name, count) is not good. - // But it works, and this might get cut anyway as I get further along in the design, so leaving as is atm. let mut inventory_ids: BTreeMap = BTreeMap::new(); let mut player_inventory: BTreeMap<(String, String), i32> = BTreeMap::new(); for (entity, _pack, name) in (&entities, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) { @@ -441,13 +356,18 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option inventory_ids.entry(name.name.to_string()).or_insert(entity); } + return (player_inventory, inventory_ids); +} + +pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { + let (player_inventory, inventory_ids) = get_player_inventory(&gs.ecs); let count = player_inventory.len(); let y = (25 - (count / 2)) as i32; ctx.draw_box(15, y - 2, 45, (count + 3) as i32, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); ctx.print_color(18, y - 2, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "Inventory"); ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "ESC to cancel"); - print_options(player_inventory, y, ctx); + print_options(player_inventory, 17, y, ctx); match ctx.key { None => (ItemMenuResult::NoResponse, None), @@ -465,28 +385,14 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option } pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option) { - let player_entity = gs.ecs.fetch::(); - let names = gs.ecs.read_storage::(); - let backpack = gs.ecs.read_storage::(); - let entities = gs.ecs.entities(); - - let mut inventory_ids: BTreeMap = BTreeMap::new(); - let mut player_inventory: BTreeMap<(String, String), i32> = BTreeMap::new(); - for (entity, _pack, name) in (&entities, &backpack, &names).join().filter(|item| item.1.owner == *player_entity) { - player_inventory - .entry((name.name.to_string(), name.plural.to_string())) - .and_modify(|count| *count += 1) - .or_insert(1); - inventory_ids.entry(name.name.to_string()).or_insert(entity); - } - + let (player_inventory, inventory_ids) = get_player_inventory(&gs.ecs); let count = player_inventory.len(); let y = (25 - (count / 2)) as i32; ctx.draw_box(15, y - 2, 45, (count + 3) as i32, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); ctx.print_color(18, y - 2, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "Drop what?"); ctx.print_color(18, y + count as i32 + 1, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "ESC to cancel"); - print_options(player_inventory, y, ctx); + print_options(player_inventory, 17, y, ctx); match ctx.key { None => (ItemMenuResult::NoResponse, None), @@ -636,34 +542,41 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { ctx.render_xp_sprite(&assets.menu, 0, 0); - ctx.print_color(50, 26, RGB::named(rltk::GREEN), RGB::from_f32(0.11, 0.11, 0.11), "RUST-RL"); + let x = 46; + let mut y = 26; + let mut height = 8; + if !save_exists { + height -= 1; + } + + ctx.draw_box_double(x, y - 4, 13, height, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK)); + ctx.print_color(x + 3, y - 2, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "RUST-RL!"); if let RunState::MainMenu { menu_selection: selection } = *runstate { - let mut y = 29; - if selection == MainMenuSelection::NewGame { - ctx.print_color(47, y, RGB::named(rltk::YELLOW), RGB::from_f32(0.11, 0.11, 0.11), "["); - ctx.print_color(49, y, RGB::named(rltk::GREEN), RGB::from_f32(0.11, 0.11, 0.11), "new game"); - ctx.print_color(58, y, RGB::named(rltk::YELLOW), RGB::from_f32(0.11, 0.11, 0.11), "]"); - } else { - ctx.print_color(49, y, RGB::named(rltk::WHITE), RGB::from_f32(0.11, 0.11, 0.11), "new game"); - } - y += 2; if save_exists { if selection == MainMenuSelection::LoadGame { - ctx.print_color(46, y, RGB::named(rltk::YELLOW), RGB::from_f32(0.11, 0.11, 0.11), "["); - ctx.print_color(48, y, RGB::named(rltk::GREEN), RGB::from_f32(0.11, 0.11, 0.11), "load game"); - ctx.print_color(58, y, RGB::named(rltk::YELLOW), RGB::from_f32(0.11, 0.11, 0.11), "]"); + ctx.print_color(x + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "["); + ctx.print_color(x + 3, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "continue"); + ctx.print_color(x + 11, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "]"); } else { - ctx.print_color(48, y, RGB::named(rltk::WHITE), RGB::from_f32(0.11, 0.11, 0.11), "load game"); + ctx.print_color(x + 3, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "continue"); } - y += 2; + y += 1; } - if selection == MainMenuSelection::Quit { - ctx.print_color(47, y, RGB::named(rltk::YELLOW), RGB::from_f32(0.11, 0.11, 0.11), "["); - ctx.print_color(49, y, RGB::named(rltk::GREEN), RGB::from_f32(0.11, 0.11, 0.11), "goodbye!"); - ctx.print_color(58, y, RGB::named(rltk::YELLOW), RGB::from_f32(0.11, 0.11, 0.11), "]"); + if selection == MainMenuSelection::NewGame { + ctx.print_color(x + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "["); + ctx.print_color(x + 3, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "new game"); + ctx.print_color(x + 11, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "]"); } else { - ctx.print_color(53, y, RGB::named(rltk::WHITE), RGB::from_f32(0.11, 0.11, 0.11), "quit"); + ctx.print_color(x + 3, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "new game"); + } + y += 1; + if selection == MainMenuSelection::Quit { + ctx.print_color(x + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "["); + ctx.print_color(x + 3, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "goodbye!"); + ctx.print_color(x + 11, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "]"); + } else { + ctx.print_color(x + 5, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "quit"); } match ctx.key { @@ -677,9 +590,9 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => { let mut new_selection; match selection { - MainMenuSelection::NewGame => new_selection = MainMenuSelection::Quit, - MainMenuSelection::LoadGame => new_selection = MainMenuSelection::NewGame, - MainMenuSelection::Quit => new_selection = MainMenuSelection::LoadGame, + MainMenuSelection::NewGame => new_selection = MainMenuSelection::LoadGame, + MainMenuSelection::LoadGame => new_selection = MainMenuSelection::Quit, + MainMenuSelection::Quit => new_selection = MainMenuSelection::NewGame, } if new_selection == MainMenuSelection::LoadGame && !save_exists { new_selection = MainMenuSelection::NewGame; @@ -689,9 +602,9 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => { let mut new_selection; match selection { - MainMenuSelection::NewGame => new_selection = MainMenuSelection::LoadGame, - MainMenuSelection::LoadGame => new_selection = MainMenuSelection::Quit, - MainMenuSelection::Quit => new_selection = MainMenuSelection::NewGame, + MainMenuSelection::NewGame => new_selection = MainMenuSelection::Quit, + MainMenuSelection::LoadGame => new_selection = MainMenuSelection::NewGame, + MainMenuSelection::Quit => new_selection = MainMenuSelection::LoadGame, } if new_selection == MainMenuSelection::LoadGame && !save_exists { new_selection = MainMenuSelection::Quit; diff --git a/src/gui/tooltip.rs b/src/gui/tooltip.rs new file mode 100644 index 0000000..d6980c8 --- /dev/null +++ b/src/gui/tooltip.rs @@ -0,0 +1,153 @@ +use super::{camera::get_screen_bounds, Attributes, Hidden, Map, Name, Pools, Position, Rltk, World, RGB}; +use rltk::prelude::*; +use specs::prelude::*; + +struct Tooltip { + lines: Vec, +} + +impl Tooltip { + fn new() -> Tooltip { + return Tooltip { lines: Vec::new() }; + } + fn add(&mut self, line: S) { + self.lines.push(line.to_string()); + } + fn width(&self) -> i32 { + let mut max = 0; + for s in self.lines.iter() { + if s.len() > max { + max = s.len(); + } + } + return max as i32 + 2i32; + } + fn height(&self) -> i32 { + return self.lines.len() as i32 + 2i32; + } + fn render(&self, ctx: &mut Rltk, x: i32, y: i32) { + let weak = RGB::named(rltk::CYAN); + let strong = RGB::named(rltk::ORANGE); + + ctx.draw_box(x, y, self.width() - 1, self.height() - 1, RGB::named(WHITE), RGB::named(BLACK)); + for (i, s) in self.lines.iter().enumerate() { + let col = if i == 0 { + RGB::named(WHITE) + } else if s.starts_with('-') { + weak + } else { + strong + }; + ctx.print_color(x + 1, y + i as i32 + 1, col, RGB::named(BLACK), &s); + } + } +} + +#[rustfmt::skip] +pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) { + let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds(ecs, ctx); + let map = ecs.fetch::(); + let names = ecs.read_storage::(); + let positions = ecs.read_storage::(); + let hidden = ecs.read_storage::(); + let attributes = ecs.read_storage::(); + let pools = ecs.read_storage::(); + let entities = ecs.entities(); + let player_entity = ecs.fetch::(); + + let mouse_pos = ctx.mouse_pos(); + let mut mouse_pos_adjusted = mouse_pos; + mouse_pos_adjusted.0 += min_x - x_offset; + mouse_pos_adjusted.1 += min_y - y_offset; + if mouse_pos_adjusted.0 >= map.width + || mouse_pos_adjusted.1 >= map.height + || mouse_pos_adjusted.1 < 0 // Might need to be 1, and -1 from map height/width. + || mouse_pos_adjusted.0 < 0 + { + return; + } + if !(map.visible_tiles[map.xy_idx(mouse_pos_adjusted.0, mouse_pos_adjusted.1)] + || map.telepath_tiles[map.xy_idx(mouse_pos_adjusted.0, mouse_pos_adjusted.1)]) + { + return; + } + + let mut tooltips: Vec = Vec::new(); + for (entity, name, position, _hidden) in (&entities, &names, &positions, !&hidden).join() { + if position.x == mouse_pos_adjusted.0 && position.y == mouse_pos_adjusted.1 { + let mut tip = Tooltip::new(); + tip.add(name.name.to_string()); + // Attributes + let attr = attributes.get(entity); + if let Some(a) = attr { + let mut s = "".to_string(); + if a.strength.bonus < -2 { s += "weak "}; + if a.strength.bonus > 2 { s += "strong "}; + if a.dexterity.bonus < -2 { s += "clumsy "}; + if a.dexterity.bonus > 2 { s += "agile "}; + if a.constitution.bonus < -2 { s += "frail "}; + if a.constitution.bonus > 2 { s += "hardy "}; + if a.intelligence.bonus < -2 { s += "dim "}; + if a.intelligence.bonus > 2 { s += "smart "}; + if a.wisdom.bonus < -2 { s += "unwise "}; + if a.wisdom.bonus > 2 { s += "wisened "}; + if a.charisma.bonus < -2 { s += "ugly "}; + if a.charisma.bonus > 2 { s += "attractive "}; + if !s.is_empty() { + tip.add(s); + } + } + // Pools + let pool = pools.get(entity); + let player_pool = pools.get(*player_entity).unwrap(); + if let Some(p) = pool { + let level_diff: i32 = p.level - player_pool.level; + if level_diff <= -2 { + tip.add("-weak-"); + } else if level_diff >= 2 { + tip.add("*threatening*"); + } + } + tooltips.push(tip); + } + } + + if tooltips.is_empty() { return ; } + + let box_gray : RGB = RGB::from_hex("#999999").expect("Oops"); + let white = RGB::named(rltk::WHITE); + + let arrow; + let arrow_x; + let arrow_y = mouse_pos.1; + if mouse_pos.0 < 50 { + // Render to the left + arrow = to_cp437('→'); + arrow_x = mouse_pos.0 - 1; + } else { + // Render to the right + arrow = to_cp437('←'); + arrow_x = mouse_pos.0 + 1; + } + ctx.set(arrow_x, arrow_y, white, box_gray, arrow); + + let mut total_height = 0; + for t in tooltips.iter() { + total_height += t.height(); + } + + let mut y = mouse_pos.1 - (total_height / 2); + while y + (total_height / 2) > 50 { + y -= 1; + } + + for t in tooltips.iter() { + let x = if mouse_pos.0 < 40 { + mouse_pos.0 - (1 + t.width()) + } else { + mouse_pos.0 + (1 + t.width()) + }; + t.render(ctx, x, y); + y += t.height(); + } +} diff --git a/src/inventory_system.rs b/src/inventory_system.rs index 0fd6776..9f90e7d 100644 --- a/src/inventory_system.rs +++ b/src/inventory_system.rs @@ -303,12 +303,7 @@ impl<'a> System<'a> for ItemUseSystem { damage_logger = damage_logger .append("The") .npc_name(&entity_name.name) - .colour(rltk::WHITE) - .append("takes") - .damage(damage.amount) - .colour(rltk::WHITE) - .append("damage from the") - .item_name_n(format!("{}", &item_being_used.name)) + .append("is hit!") .period(); needs_damage_log = true; } diff --git a/src/main.rs b/src/main.rs index d790da8..04c47cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -482,7 +482,7 @@ impl GameState for State { } } -const DISPLAYWIDTH: i32 = 100; +const DISPLAYWIDTH: i32 = 105; const DISPLAYHEIGHT: i32 = 56; fn main() -> rltk::BError { diff --git a/src/map_builders/town.rs b/src/map_builders/town.rs index eafcc59..9bb1b6c 100644 --- a/src/map_builders/town.rs +++ b/src/map_builders/town.rs @@ -2,7 +2,7 @@ use super::{BuilderChain, BuilderMap, InitialMapBuilder, Position, TileType}; use std::collections::HashSet; pub fn town_builder(new_id: i32, _rng: &mut rltk::RandomNumberGenerator, width: i32, height: i32) -> BuilderChain { - let difficulty = 0; + let difficulty = 7; rltk::console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty)); let mut chain = BuilderChain::new(new_id, width, height, difficulty); chain.start_with(TownBuilder::new()); diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index e4657d6..48e0faf 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -416,7 +416,7 @@ pub fn table_by_name(raws: &RawMaster, key: &str, difficulty: i32) -> RandomTabl use super::SpawnTableEntry; let upper_bound = difficulty; - let lower_bound = 1; + let lower_bound = difficulty / 6; let available_options: Vec<&SpawnTableEntry> = spawn_table .table @@ -425,14 +425,21 @@ pub fn table_by_name(raws: &RawMaster, key: &str, difficulty: i32) -> RandomTabl .collect(); let mut rt = RandomTable::new(); - for e in available_options.iter() { - rt = rt.add(e.id.clone(), e.weight); - } + if !available_options.is_empty() { + for e in available_options.iter() { + rt = rt.add(e.id.clone(), e.weight); + } - return rt; - } else { - return RandomTable::new().add("debug", 1); + return rt; + } } + if SPAWN_LOGGING { + rltk::console::log(format!( + "SPAWNLOG: Something went wrong when trying to spawn {} @ map difficulty {}. Returned debug entry.", + key, difficulty + )); + } + return RandomTable::new().add("debug", 1); } pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) { diff --git a/src/rex_assets.rs b/src/rex_assets.rs index 8a7be72..b451e94 100644 --- a/src/rex_assets.rs +++ b/src/rex_assets.rs @@ -1,6 +1,6 @@ use rltk::rex::XpFile; -rltk::embedded_resource!(CAVE_TUNNEL, "../resources/cave_tunnel80x60.xp"); +rltk::embedded_resource!(TITLEIMAGE_105_56_BYTES, "../resources/title_image.xp"); rltk::embedded_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp"); rltk::embedded_resource!(WFC_POPULATED, "../resources/wfc-populated.xp"); @@ -11,10 +11,10 @@ pub struct RexAssets { impl RexAssets { #[allow(clippy::new_without_default)] pub fn new() -> RexAssets { - rltk::link_resource!(CAVE_TUNNEL, "../resources/cave_tunnel80x60.xp"); + rltk::link_resource!(TITLEIMAGE_105_56_BYTES, "../resources/title_image.xp"); rltk::link_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp"); rltk::link_resource!(WFC_POPULATED, "../resources/wfc-populated.xp"); - RexAssets { menu: XpFile::from_resource("../resources/cave_tunnel80x60.xp").unwrap() } + RexAssets { menu: XpFile::from_resource("../resources/title_image.xp").unwrap() } } }