From c09a6f83e97535bf32938ee448023f4e382d687a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 11 May 2014 02:14:54 +0200 Subject: [PATCH] Lotta new stuff, new fonts, inventory sys, food-health, awesomeness --- res/font/Born2bSportyV2.ttf | Bin 0 -> 55532 bytes res/font/C64Font.ttf | Bin 0 -> 20076 bytes res/font/DigitalMonsters.ttf | Bin 0 -> 8112 bytes res/font/Handheld.ttf | Bin 0 -> 10620 bytes res/font/Simpleton.ttf | Bin 0 -> 8196 bytes res/img/gui.png | Bin 4699 -> 6667 bytes res/img/gui.xcf | Bin 54346 -> 187969 bytes src/mightypork/gamecore/gui/ActionGroup.java | 36 ++++ .../gui/components/VisualComponent.java | 4 +- .../gui/components/layout/GridLayout.java | 2 +- .../layout/HorizontalFixedFlowLayout.java | 14 +- .../layout/VerticalFixedFlowLayout.java | 13 +- .../gui/components/painters/TextPainter.java | 5 +- src/mightypork/gamecore/render/Render.java | 3 +- .../resources/fonts/FontRenderer.java | 14 +- .../gamecore/resources/fonts/GLFont.java | 9 + .../resources/fonts/impl/CachedFont.java | 25 +++ .../resources/fonts/impl/DeferredFont.java | 24 +++ .../gamecore/util/math/color/Color.java | 20 -- .../gamecore/util/math/color/pal/RGB.java | 41 ++-- src/mightypork/rogue/App.java | 2 +- src/mightypork/rogue/Res.java | 21 +- src/mightypork/rogue/screens/FpsOverlay.java | 10 +- .../rogue/screens/game/HudLayer.java | 46 ++-- .../rogue/screens/game/InvLayer.java | 197 ++++++++++++++++++ .../rogue/screens/game/InvSlot.java | 118 +++++++++++ .../rogue/screens/game/ScreenGame.java | 135 ++++++++++-- .../rogue/screens/game/WorldLayer.java | 12 +- .../rogue/screens/menu/MenuButton.java | 5 +- .../rogue/screens/menu/MenuLayer.java | 6 +- .../screens/test_bouncyboxes/BouncyBox.java | 4 +- .../test_bouncyboxes/LayerBouncyBoxes.java | 6 +- src/mightypork/rogue/world/PlayerControl.java | 1 - src/mightypork/rogue/world/PlayerInfo.java | 14 +- src/mightypork/rogue/world/World.java | 55 ++++- .../world/entity/entities/RatEntity.java | 9 +- .../entity/modules/EntityModuleHealth.java | 6 + .../rogue/world/events/WorldPauseRequest.java | 26 +++ .../rogue/world/gen/LevelGenerator.java | 27 ++- .../rogue/world/gen/ScratchMap.java | 18 +- src/mightypork/rogue/world/gui/MapView.java | 24 +-- .../world/gui/interaction/MIPKeyboard.java | 5 +- .../rogue/world/item/items/ItemMeat.java | 2 +- src/mightypork/rogue/world/level/Level.java | 23 +- .../rogue/world/tile/tiles/TileWithItems.java | 16 ++ 45 files changed, 826 insertions(+), 172 deletions(-) create mode 100644 res/font/Born2bSportyV2.ttf create mode 100644 res/font/C64Font.ttf create mode 100644 res/font/DigitalMonsters.ttf create mode 100644 res/font/Handheld.ttf create mode 100644 res/font/Simpleton.ttf create mode 100644 src/mightypork/gamecore/gui/ActionGroup.java create mode 100644 src/mightypork/rogue/screens/game/InvLayer.java create mode 100644 src/mightypork/rogue/screens/game/InvSlot.java diff --git a/res/font/Born2bSportyV2.ttf b/res/font/Born2bSportyV2.ttf new file mode 100644 index 0000000000000000000000000000000000000000..02001782191bb61a6e111d0c10cae154ef9a298f GIT binary patch literal 55532 zcmdsg3!EKQegE&A``YYoNJ6qab0NtR0tCW7l59e<;pQDeNJ27JiHOp`i4&;!A*k9*E<3u+U>39rIV}T^M%t?KpOVmrWi^@{MHI+P7qXkl;)Z5hesD#?Ts-Hs1 zJ4~wnh5FSblu}uc5=EqcqozD=>KhxonQAoaM@2(JLBP@n1S+XpXb$Jp4*Y7!#8gue z)j&WEQmg5j$xAtx*>b+;o|P2WTo&GUFr?hwxAjtW>^;cEz-W@z*JJwX;b&bpJVy=m zvRtxZ1vnT##m8gD!TAQbDD(JhNxtDZ+!J1qikxahA#YL^TO4HIhp-gbr zkn)f0^C%aXe9b>x3mr%~FTWUR&QG4rxCfXLLxxL%c3ue_!eY zhP_V?zI(ntb@xL!A%6F~d(OdyjtFJ^6I%UqM71KJ9H}phsD^)h6zp#%vEYfGLkZ_* zQjsCj#WV}KPP&~QRX?r&xo~^ouEN_2Z!f%~@WH|tin`cQ+)~_Dd``TW!aO}Ou-gE5T$KG}9p09uG>#M)?o$|k13IV>QqpaKcIWWWgghvwh zKqyTQQ?mdGl&DMX+1w3V)=ZFCK7ryaDDu0>>c9bHeap&RHY=(Y4Z zx{-#!-_OxqbT_??eu>^gzeW$z2kArf>+}$Pm>#A_=r`%N=u!G8eT06S9;3(UNfff`hALMH;tM*I3J+5;CvJP4BbiZR@2oCe}^+q;1{c>qp zFVG$Ic0}X%&^zdz^ow*a{R+x|ncheD(|hT=sBsk?Qdg*r>PmXE+N?H7JsB@R^5)+L zaPuHNqs~&VRfp6)>QVKKdP%qGnfhYAS>K`Whvl{vmK0uJc%blfv9q|Ucti2l;)BJ{ z7Qa)PRT?ebU;0AnhvoCio6CpF50pP&e!ikBJ(bOsJ1UPUOZ0~HpsC{eu&F#0ff4Ke2?XPrP)Um7MwvLZ>JlpY7=Q*95I`?$m z*ZJwrf0}&SPHmgI zX6l})k52vUv{R=onKnA@?rG0Yd+F3OPF;8E{!{Nc^}$o0nqHhfWBLWtYt#2kfA93C zXLQckJmdBmPt5pk*MhFmuE)B*ciMu}_MG_ndy$>5rWLl{3m`)Xuo| zjK|J+@yrX(+;`^vXFhXQ`&lc_8awN;vtB%V#@U7mwbD{)CEfxT)*JX1rINH zdck)uoptGkOW$(oM=yP$=d_+pJ-7Ef*7Ma~-FsQ@q25P&ztMMo-@d+w`o7VBPXEUK zyZb-U|GkB?7VcU2{)I0rnziW0Meknp)x|RwuUb5|_<_YwFaE*6oPpO4ynEoOfmfC+ zTypc0hnIYF>G?}Y*R@}SdQ!Bo@;)j>dynMywH(nlH ze*fjq)Y@yc+D*0h*1oWE>dF->53PLr$|qKSW7X7Em#x~r>W)>9t@`TfQ&z89eQ5Rl ztN&>Ai)+qUvt-SUYwla~`86-E?OS`p+WXdiVO@FMW$UhAcmKN2tuL~_v&7a-;%9g$@hqpYm*`%szwPQLuKwD#soOSgyJg#B+n&2->NOj$x$T+{U-R7d z&g~a$-?ja&?N4rhdB=hs`*+;G1^fKdpO?n)>ahp3;vT+c`(y%rI+!9HT$3z|&KI_n=y)s%l>MU>RvSf|}eByNpSt zu8LKJx|7gjkm?@PsH11wRPl4i2`3ffW6Y5=po`Uea>aME!3dx}AcV{L87m`%@ zfqpp`aKEZlVbOfO2vqkk>R+@>bur5Mg|20~ ztG}wdySlqfWd_jVVe#l1@LVoT65NSFe@g>s%5h7NL z5$|^pP470$^4$cs)eYOl*=&iRui~gFfyNk5=N(1ba&7?B2MxlXq& zDtN@o6p=-Q@!4eHm|p;bBFIbN#GJLZD6lF?3y=674x<}96hrRk%KajwZp^XB#!@Xr z@?`!AFbc$o42*fww#3RU6o=4K zdCR}h){7P}zc^?Zgo?Y2mW4z#J@5)=kfGrez|0GXz}g_oK=80jVFP3X5;r4hh!W1F zpPPK3vP|F^g^W+L%*Bt+Mg-1&RKp0s91Fc#WWQ3?h5kYIVGT^h89=$n(J~G{g~8IY z5?TqQC4TZmxzOHjE=;86tOjB;ZiziHFt7c%dMsUQM}1SB34AeHrRZ!sya_v#dHb*CDVx!6Ek=s3(3IO2U7R zG0;UxFC|(-`@;VQ`v#=O!_XfgYKcKTyxm-Q1I30s&t+09gb*UWi22k&+kkM-R2dSD z?3pTUNQ}5z^8-LN_$AR}1tV*Ti|p(8V5m5h9`PYN5YtS!ofsiY{Fb`sA+z-fNg!aK22$CozC@A>MMM z0An2F>$Ap{CGD~Xjn6~O3Em5XZOe*qD$=6|o@KhY0_OuQz^ERuzm_}P5WVlOVLrsR z`?76x){7Ob(N4(Sdz+|X{)Oe@DKCpVEW#ZYQ{)OsobhNx3Mt9;u4Ry zaYIE5Wi zIs_6y>5y>-M8@S+`Csfj8TZTmeW0 zv?5f8JDaztUreIDdBiz*qNF^O#a!`{98Ve_Y@DTuT{7LU?HLnjshs5@v9G%L7#)%D zf&q9i97P8t!#AKEw_&8v$%V5?Z_iMxMB(h}U^DEsn;fVfvIM`YHZ6+fBAm)51gwqrm9HxmAtRyomrkFg}Mc}&Xl z7BI3&=%Ap-aVISTo@MMU{+!Ls@XMo~@g?c(G{EmBKbnq`^WGRgO8L2I0&)J1S#`n>;Z|YLC1(E5EB-mWHu|yK1bixVjNU# z%rf6>Q;_F{SW$#k6~M2ZuVpfe)k)o5=#mI$gRhCH+rZch@v&F4cto z92Rvfz(57s8%|7%i5p$d&PLC@568Zyf1ePWpwz+^S~1rNJu}Qn5o69c-1EAo32Va~ z!l2`iE(O-vjV*g3{vvYZ3ruU< zvso*c)y3Y*=IU3^IpCopnz9(K+69A52kUI#X5R*(wZ znNcnbzTx4p-(lM^V^M%8p{d|kZGD)Lf`yh0d*^P}u7KE>rZ9oH&&p5Q&j8cLGdAp4 zN?7tp5{zA3C)$+PteYvCSx3o8z$_a9jTzL* zCNwSfjmIPKK&GDq7n%KB8bS@Va9CcBN76T8Y{9E`EK+pth!t3#vK(rhOA|!b=WF&?!O*P(K2f1{!7nzGuuD00NV4x;g zqp=t^mU)nSC|AoxoW%_aMQ=DUFLo6jLNasEIEz^_a5N+6-wkZ-#N#52Mds~JbU`b3@fZC0JNxA`^`Nil=7UI!q zp%bg>{uXo*3Bou*Tc2}&#qgtHe+9dy!Ir>+gV&Q(u)V^dbmX95{~Qz`bLsOCm#$_$ z#1mV~mFX@}jjp`AYcBI8bLexCLIbRnE^ynW$pH*fvt_~*#6fwIjgqX-aceNVsG97_ zIFoy4bfwae(KW-=M3`b`zM9QMH75^S08p%Fs%b#O+$MSf*f0N+^#TR9pcVXM|JPWG zs>va;OD;2V#+D;Zg3GLz^TJFSvzT$}`N&;?zEB5)*fV%-6CKD95fXQrSf&P`3trsd zNJDsG!Dw>ugEaE_*yrpbTySl&QA3F@XI~GiC$v|LkCh)E$Ehls_!5snBcjLY-Yc7N zuW1XSMR}AT#}Vo;5>sFpz!U2l*19B$VUc3`3kymz#J8S7jGT=!)vRK`439Xx5Zl1K z0a^t19`MY;e9c1$xEA(fGFTBe+U=cmWb3;E3lC~!xmZ{jB~6#g#(&9#3^#sssP_3f zDCW|_h?DsQWAt1vl1H2sF)kZ-xQIIm>JT!qdoeW(giF%Zqn@P(}9Ahyo*2HL|rl@{=9#&eFZ1U#ObFpbIRl z%~|#iiHZND7mOHG%b2!KD&(0nLmlCpdvW7dFVvzx|KALh+$><74|9Y zMPNbfQ`on_uVj>_OtclhQh>f8DWO?r&P&`2%W#+HA|RFm);1ACqbue(4k>&N(>eZ; zA_nq-KeD*EO>nFOU~#4@}&VT6XHluTJKX&#rc4d(GUfRPM`z}&tt)|9r@ zBDX1d)U(dE!R<=Lvc`%&oy7^;kob`&8z2KVLbOOX|IvUq0*V;F)S-zlnMd|z=%aak zm?aBs0W5xvE5tmXXlyA(XUveA9)=`y7P(FcC-VxCzKS?`eAkRmNLi5fHzJLiGV1yZ z$7&$oDTpRvL(`4bF0!$37yLu6ydADMz{&ZBj8U%OW^A0wy{ua}C^ z9NZWg{x$Uvp{nsLtcyzC#(4d!7gh#2q~&j=jg?Hd3^sicnmC)boEmf=F(nZr$Uj0- zK!)kJbxqemgN*PCa7^CPF{O@PO1S4(9$5tV@VlCFF*Ff`GXOXh=@%I%NA$e+5iQuQ zgfe$%ZHVt}BbGsKoQW~J)IRF@6J1|uc1dOLKtOnw)rv!$d8mxxO$=97>pgK??4e`@ z9q|?inecq#1Pho=&uO(GvM9VrzlLi|0}Eur+HbDag3UF%*N7ABJu6!G5@l zXFo9Wz?%fx5?w|7Sk7T-*Frm7P6G_9gD9sy7kd~WLm3!u#|h||mdLgl5CUV)EQ^pZP zz!AyWoH*ZHrTm0F%=lUSFw58Uxp~+cnuCMFX@p;lUry8D+xF1pa^M|(4%N_3D4AVA z_+-W_ru&h=xywe82pwh00WBtWP+CcijHN&2ejRqpi;%K-T430SNqL@z=lHt@aEs9l zAg*G6T@SxG;)oxYM}qblw3NEtBZ<>Y;Snedsp(iNlO6$!BB zIg2W26Dg~#!{*jNeF#_wJjWQ*PZ^Y427A=7M>EE_#Km2HWr}AugB>VPU6x24@W^Fy zQpc&ssd@hy=4ecRil`2KgS>pf7AbM}cp$CeF(cfrzzoK`5*Nt)FU%Tl1W_HVx`HOw z2J&J3uzenJ^XNSly5`WGQ%v5E;r$-ory+aa(VlX4Y6RUw7F%%+8gVqH?K>N38K2YE ztAkJaz9#$y4IvLy?z^p%F6lh;~j4xA1B+bF~ z4_3xD%51`QE0JalMEuKaosr`m55R=&cntXGqKCND$iS?{20ZhKL~Ph@18OoLW3YV0 z_(gn%&VXwVVT8_$}sECGymCB$_^>S zfYzFIL_#LFWjkMqNHQ6hxg9!oT$WlFtDh@%&|{ZrOmo|>!;{_#bi(bI`#HleTt;Bu zDW8#x^TgV4Gn~F1=ioevb{wEBvOmT=yzz}eJIcX&((Ne0&8oKj8Ug=wzheWvKoWk$ z{8;8;yaaTmDFP3*3>a1`ab|rk3}CPv3=A`N*<4w)kk-k-921r+*uGYhfEbe0?{x|g>yn{LEVGmnT%1s~304^ueK zXz=P-{6;U$TcYevC8>zIF@EkyIB4|W?io&jFOeC~O8dRn&iV{PvehVP*ddH4yh!E! zoyI<^1zfH{haf$~uu$^;PBt$8zFihyK|>DVGDr_Lyb+c=bb%bFpg+peoOBBr_#FjfV_WU zS%Fv1(yHQJzib<3#U+I2@{wd>cbT8UJ>syqBiKiTe#Jyv9cpU^f#2kLwU*U8Wd? z9YNIA&v0Bj94?i6KGfLuF4D zzn^9BSq<`hOZdhU_L<;1{kn4uFeyLIaNQBPOwc)N)}bc-V_&la4vsJ6EyMyil5f$V z>yc0fQEs(@(WT7zHqakCy6e)&Tsxac{7BBadS;Iv!n6RxBAfU2m($0&7FIW3)D&Y3 z*pY=_pRoV;6Gpneo#pVC7<*I?&tAtl<-QBZ>%(*SYmPA=8<+znjzJypC;l;yKNE5{ z*oR{(8=qHQ9dCk(EisR`CfKqurMW`a?PHT9Qqb-T5vi>a5-a5Ll^Z3%Wk7azp0qw5 zsb}k?;t`Oh2m33nz)@ACAPmC0t=VT5VjtC|E<0F=H!zrofMh@Dy!`Aq3 zF7;f*0VSUO3G<)e4#4?rDXoX1dkt1Y<#PlSLl$LZVplKL5sMtkQ`9cH3+qP7IyL@gbzEYP)yvJgyx zEBs^^lzYjqEw7D70rqBDr)KU8>{yN?PZGnSxpIH`h4R; zgNFzE?ebrKGW+mAEoO}(UppgXtsnfL!K6nU}IL@?ItI%o_h z=2QKlV=gf;If+F^csI=KHQ~LRY*@`yW%VR&SKjlSF11BV5ks##fJGBWmAV&!XK9hv+Be>5OH>`$`g%cx< z@RRikzGyh&bcrT+ZF!UVDEsXYo?GCynJ^goOILBc)Jhrf?YAFdjJ5I26Zh>0mKdhJ zgXPjXh;iMuy+qfF19HTU*? z0p2JJuY0MW@k10Ri`Mlua4+V2pAHopNx~v}n)KX3Kzv5l@MHTh*|TMKUfVCF1+#%s zP&*FtVK&h@w-@pC_4}%&TWs#XlJ+UFbB%ioqg~sN%SYU@qLnUJYGle}kjT``2s;$rJ#o z<1yP7c*7gFc%cs6y}VV8g%S}u-UDIL;pI{6G|D0;4+C^zVAlW}Qp<#m=%pTR6L{L_ z7X69YdCM=D)@_!RC-=$Tbd&N9HjjL|!#|dJxw#a?Gi|ZShNMf3lk&nxP<;rQt*?sKi zqOMUj!ksU#`1{TIGksLHXlIb zZ>r=$$}Vr{g8-8UBgy6-EG$m|CXW}{KR~a39-gBQH%1NT;{Bv+NLqvo{$(FgQml#d z4j<&sdrulxio(4^6UG-Y20rY>%LI7K9{xuHE$Y{njOY}3so^j< zZE0?A(s%TldHrPEiUml&d82?fV5HWSe1SIzu^iZ}G|DQpWu^r|w%X7E-(%v&aE}*n z2ugne?xZj~)*Vjto4xXdYVosX%sxKvcvu=CUbAn)-#E8C`;HdjpFO}h{GTLtF9JKB zi*+p-{mZnH%v_8sh3;l^-G=wLnFwHdzPMcXn~Dj zBMUaVZ~Ki`_QE_~t@76v<20mZD5R4F4(q4H|H1R7Xb#3Ll!lyh@vZf`m81?@wlN+ z9)D$y0_)|FH}Vp+MtS46MID2H6z`0`Vf5E%!69~r;f_ego^sW^O$voR2B`5|g4s0; zTT1D?4ePP+X?3Ai><~6jS+8(}c3gm!r(kDts!1A`8Kt1bsjJKjhOgOnbq%^3#9uGw zd1J>x{a;-Omx1bmN15=)D|C%i8yaA{1N_xFLxV6_{}td@lLqIFLVsjNM_~+G|E~N= z2C&{UfoIVxzdx}OnhkM=y5)C6TErQTC+`~6%+EmWXsJk~@8mu9GH*~w!q+;kC-nYC zJ{3mah5{Ynmsm3YuUG_wrYIkHEzY^;tjz0K#wxP6Irl5dCxy}*mJWEd_{V$GbC}Ja%x*T}54uKJJ7IL0yzz_z)|>Kq!+5OmZIpTjv$^A^9EaM- zQ}kzT#=hCgrW<|*I|!>IhLCf_Ipvm169aS1dbZhNfRTsh>4a(}%Bji4q=il-7+0Jw z@5F+CjSV_#8c%y7kj8)_+{EF!2e)$o?Gw21%~S(}@K&vZ5HSYaGKYz)BmS!={2kT- zj;7(ic`iU+-;eBbF2$vRO+g)0;NhywH3cJ_#yT;7#nt?MRs@@776CRyfXYWKXLc*# z-#?2_MKVE%Oq1PZ{z*qa!=1wP^Ro_c@_b|N!rzIFut!I};)|JNUMj_2B5)9X z?b27`%3RO>eP_stXN0VjEZ?39$TsE*d_YvF7ipYe1Ht!6W8Bn)Q;mv%8_Bn0OVIW- z(YKl11|w`MNV*0j?2GYy#8Qfo3DDp|@Ss0nl=#l6>E}g>PP{SKF?@g?wn@kfb|IV# zBJ83v&p6uZo}Y~8@r)<~dx&EDuqKlcUTffnbpaX86K zuoI00egt*?;XZxB0tA{Uw-l1}CDpiFx)88A| zT5Q{46vD!VIjE3=2R$2D{267~saURm*wDh4_!(YcqY-%ShMosIFuK6}W@kWhjAwI> z#`$7W#v6 zN4f?bxSa}aVItY7(9bh9@;W>A2355VbrRzuvz@tz0)2|w(TE(*rr)@PK{jG@Ksn7> z!FEANfX8trYgTA3;YO~uOguTTL-c46k+~)p3$h$#kJ4 zk|`jFiOE61x9s71CPy=LAK7;~u}grRbQrATJ6o8ibm&t4^_9qh%t_tTRu3^`Bk!%x zW`D)&hniXZ9nmSzfuZY%+|7ge(I97|9FV)2%7@v&C*=HSoss z1rXei^Y7w%JTlvjzo%xlE)^gS{BbCrB5Biznu(>koKy1b3+RyU`lsA^c>OBC;H{mV|u6pR(=o$Vvc%f7eIm03#d; zZ5R!pKK?pFM$g&GY8E50zC>(vHau!C!!)}NxLcIZ_{s2%zk8{$Bb~o_&PX#~c8W6S zj>EDP{rm<(;wylTC0w@&eEh$(8iMCMP#75rPr?tsx$T66?jJayPfmoXOit>d)?Ygu zq&c=gdut`Ki0h%WbPawAvj4b-v8nwYwpchE2gYmCokEV1Mi!!*f2l)|#5BGS0ZjY- z-F#cB$I@V>Ip`er5Uul7z{~5%Ji7-2hHXJX=Eb@S|G8`)2^4@=3?k*SVh6P$ja*4O z{*$@k^w&=zEspunirt2`E^f=1yKKbgfSNQ;U&@uXWyHRc=fc68>>|ToO~bNDu&s1b zCWaXG`8Uo1Coc!=L9@S;cZTY|9cbu}%!3VQPiWEjOVG(<@qX?Fd3vX+X3N>`cSHkm z>%Q2*8jy|vJPv?I$UD&EtpU5|EDz|jj2$$wf)=#T6v$y@!#cp&;zHg}h5ct8&^7nA z5`oB{`dWmc#dP-Q9F9Um#ndDwAVmT#mUGT2)!#uKXcU5%b&q*3xJX!ZxBvnfve%>l zUL53evZRf!gdg^15=F@0aA5?d=g>S21P=Mn{bU7v3G67zrgBp5`xf(V4(0;D2D|0V z){@do3RuGh)Z*n6vA<;bI7XHsLb2-z?2mPo`_<-tKW@O_3s_$NBW=*dT>K6Ve~Ha% z#!p=&s&L^)%3>lb_$InglM7+qv&{ z^EDV$qa~R?pIC(-;b~T!Tec8OGyYx|)WcV7SLFC{ zHpTW~^q9QfQku{o(FJYR=efU?j5o%`*P1W$apW!IU60$+5ZkmaNq7(%Eo|7Z_ZKEa zfWN2~a=k$_Smt=ET8Ro8PQl5w?iQsxous0Q82eqxav2Uh|R8}`91x(oT+3TRBzG4s~ID}#>t z)cioMtOs*EhJA$yPLgQM2NL4*G0_@H zO>OIEgdPQq9<6Ixgp@jV~PxhjxkcV`EUk2WlDt(L|)3~UBfBTHD32a6bo=#ED&EF z7{@(A=Q!Zg_?;x#FM*oo&%>}$14@y-i*?}W+0lu|d6YCMkN6(p&`hh~yVSIPEp8HG zko6ne`cE38$Ct?6#A|MjxK8NJgJLE=IauD(f3nQ1zZB}xR7C7NGM(^fgyB2+h@HIp zYZ{tmFR*!D0+xaWO+WAE`{>3=ZO3}#GO1Kb-Q0ubZ-C58p!4F7?A8v(Pt(m8Xi`8j zg8=h{z-KeIb{+!<=J#ZtMkWngSuermY_XWkwSUd(h;Nl2w$t%DG^9Nt?Fu0qfGtBZhit zYjJF8VR`?6{eISO^Kb(0o0F4Xn+3g)MFd%_w!L~58kUG|?)?cS}sSh~yN5lmVuE@wng6wT_Vg(*jX2pXBwm>x5)R_r# z^w)F^5ee2KX3I)fWB18&1Dbgp+!aq?^b!zZaoRS*9*bKElmoA4W@FIt74eBVw^R_+ z1p_gDd55tUqZ7a5&!5QD!OQKuCHIL?3{L0Fm~Fu;ugRaRA5C;Ued zi-;`dYcuo=zI#z;yap-&WP@z0# zttWnp?4J9I8N^gec~uz_>S^&8NU$!8XiLTcFmKV_UZFKBYW zP9SC6i9Tn$v7K$vjbVRt-7*1D4izYm>v`oF2}};6-NHx<^41(S_V7e&;Ur>9=1Efx zryAOWd7ms7%c~dnYhfI?T|dkF;lUp}N25mhP#{!Gqlr8cSsY03E$zdtM(r1rN1w!hti#`elgp#10{s^&vEybra`RMI?55 zyLGayeg)qDhP9n`@#`nQvJ=`?!-|%T^RYW;qH(^n0V_{wlhC}2^IKShvFlB|J}upt zjq$_DWxT~$*Ap0PipMu9&<7tSb3A6>Gkm0YcenM0X~ihoEhnHoD6>3cCQ>r+M!9~f zmUw(eSxP=XzBQUi)^N=p2#))?ZTM{@yeOO&RpiLaOF?$vi@L?vVp$dbD2(}AYjqx$ z_Y;Wug}~JNxhFm$U}%+ipXX|fezQ<;CvIGAitlly5kAfSgAuY1wcpAtz~8}&5HHjR z;&s-Og-FVLjE_Yq#2?0&vWO}i<8!6~wD2+E7~fz^`#{!i9+ngX`Q!(2z`2N^{LBfO zRVogUD3Sxa%(NLBH{n}zlDofKzy&+Pa#fQ$wqIt@&rNh@{U`5!ayly4vxQk zM%@!NZZpSg*w-G>nY_{}-zO8h#uuvH>*42r<5yhiKrX zP@U93{&=Jd;YLmoU|%lZ+6d&7C9Z%ANK4l;k5ng?`9x4?#OM3V2xH!sD6t%4M3qHG zlaMaJ?Xt$9z*0}4kD3t`^6hk*%`22&Zu6STbc4+o;QQWV^F=)KMVl|tRJZ`~0(klq zbt$-0#YuoU13!~jG!uT)_dJPiVx#TxqJ&l*JUrTW(=~?<9v*x1 zPF!C_!?Xtwj?w{K4DT5^iZlzwWzFFx1YA~+VnX!n1U-kr)d{sg_2UPm|5kka%ax|4p6{*c~H|3r7uJ@gCo zYxJA+5WS7QNQzDF<7gY*&lQ~DFMh?`)M?}T;y z8FcbF`aJCXDf)Bz0{t`HOn*U7)0gPCX)k?;-bK&QSLiQciT^_XN^hmtLwj$4J?)1E zAAla;2qR>j9;Gq5h2BIj(yeqG4Du)Gr|2#81bvWxnr^3veuln9-= zopg*|QIpjvYKodl$MJoOY3fupT`4sKbBd>_)72U3Om&tzTg^m&b&fihen9`FW~td~ zj_OwDsk!QWHBVijE>su63ty}*Q47#2e@K6&dQ`9K!>sp0wMZ>i18Rv{sxCwCvmBwv z3i<~9y}BIl+pkos)M~XxtySyPdbL4ap*E^3)h2ZnJw_i>o7EPzRb8#NscY1BwL|Sx z*V2#ZWqN`BLG4o4sq58i)D7w<)N9r2)QxIL-K2J_J!)9ptoEvXYDB$Wy+Q3)2j~yf zs5+<)sW;L$=^xc$bwrJ+qv{s*CUvWNv$~D`hMuFprRV9d>F?A}s<)`0Qn#z0#@8l( zM%|%)R^6$7PTi$`Ufr$Us@|r4LA_o5qPj=DL%mbIiyl_Lq<&f5tA0hjTfIl!r+!tv zSG`Z&uYOIvUwuG5pgyP`R3B0g(FfG8s}HN+P!Fr$RFA0NQje;SsE?}OR*$KVsmImt zsE@1PRiB{usNYjhsNbjesZXjuP@htNs6MU!AHJsX8TCi%kJXdv|EtfcKT)4kf2uyO z{!Bfk{#<=QeNjEFzNEga{z834{iS+F{grxF{k8h4`Wy9}`djri^>^xd^>y_P_4n!p z^$+Ts>L1lVsee{4s((@6Qva&Ht^Q4YNBz6{uKEx4J@tL{lKM~e1NC3(hw4Y_Wpzxw zqK+fJP+IGPF6xpl>xypElXSc8(4Bg+K1EN_Q}r}`s-CWA=q`PlK3$)o&(vq>v-M0} ztsEU4>FHV7W71W9Hto0RBAYI)tUNHZ`|!ch%8*IRD{neHe9LfoNRrCRgL@B-4!@x? zWYUh+yGIW1K6>Eh{lm9*>`wCStM?on8``~lcyz3Nx6hW>>>dK>@*b0{0iL0;%36zX z*dknO5DrVyzSh@nANJYGT1&>TNy}>u#9>J~)+dB?>`n6R>pg(>y*}Hye)qux2Zju> zoqL0ejtxoOj(thKxZ$Ru!^M3#m9H2Z*}rGFJR(Wu3d_le<>U&($%ql%6_(}^ljXFxXY)s&GygtcyUKtS5`G(ZR-owMgqx*+O_l)c=ZyMTtbZof1Uy{yE;dA?gi}EHT zp#72*H-Y=&ew@miP5n_*e{)c!b2PXpZ#MNujetjo4jnu)cKG0-eZz&dqk9X(qkAh` zEb|8~^IHt_2PK)jW#7@!y+enO9@sy0bZqj$@T$Dc&~Vt$uq{B_c{sQzZ!6I4V_JLPnuWI9wEDg^i|zG*P1o9Vok`bPcxx@ZwHDr5 z3vaE3x7Na2YvHZ6@YXJ|aF$BiKd`oa<^DtahQy_Rx_L5HA;PYsXCKq$}V* z%>69~M%W>liygtk?OP5E?==sV1YU8~@Yqmk{ScaS#X>D!kD>ygmbULhuE=0ZR}LLI zG=!#e;HEu8`l_RP^HIHP1O_a4^wyEWwtWXn*Np5vFjUw+bhKh|7PjsiDXhkC>yeR8 zhO=j6`0((Nkt0*=1Ma$gC}D0mptlVK2p5w^9CI^{n)|M*+%8G|;!SwGw3nGF?HS%b zHdL{&inrlLfp3lpOAM^^24QKxVQKWJzICK>(C||@yzgN72s6`LlB6&Oo-E$NA@H*s zKaf#6$l~l|aE_cQb>wwgm_`@&rd+g3Wy9Uj%_AedJw1K>lWcBLug?wm+!CK#>T-*F zY_50VB3IVyYxMdWy}m}DtI^ZvarE`Mx_t|M&co|l?8`jlJ`cIiL+?{V~d91A^;g&xO3k7J?7vC!j4;Het$v-v z97{ZoB_78Tk7KFFvDD*O>TxXfIF@=GOFfRI9>-FTV<3UzaP;=L8ofQPMsJU+(c9yw z>Rl@Sv9G6pO>ynf!w1><^AF=u6{m`8ajHnA64Hfcu%?b5#~4l7k=rR4hw&^d f&zP9;x4R?hpS<$e-|>^5yLJ9bPQQ3@^|t>8=z|?L literal 0 HcmV?d00001 diff --git a/res/font/C64Font.ttf b/res/font/C64Font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..133de49c61588a95d973a0561abca6dd363bbc61 GIT binary patch literal 20076 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 literal 0 HcmV?d00001 diff --git a/res/font/DigitalMonsters.ttf b/res/font/DigitalMonsters.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d97c1cc66cd356a65fecced6566bea458f85efe8 GIT binary patch literal 8112 zcmb_hZH!b`8Gg^X_s;BBS(atG6&QAx;d?18I}A(NopM1~K3b?+ii*^-fdw{!g_H%+ z^v8*b+SvLLQ-7EkLmG?;sRl^2N#)1H*jf`pqlre7Y7K4pQLR53jsB<|pZ7iI&fGh9 zb_MF4x%ZyW=e*zNz4wwLqB&&9qr+ok`}aO|x#NAJ-WSliXy^7FW7J8DQJ+SA@nes# z8~Vx@w)GLI6R00Ja%%j{!QC$}AkzOv+n0}=pYEe2`dK3X8T9+d$IqUrR)I{tCsA)X ze)5aQD&KwSVWI#SJ>NeuF@BVGT>3To{)Tho2{Z(+>oX$sJWh<_R%)7kUUdKTS#kVj8Z>U|DXV~zo&1Y4a2{MQp)xc*eT+it zql+F@i4K7_gJ$N1Z|7-=+@C->l+!?3AqWVSaVP5NGpHMPxBa1vGZt)_=)3mv2{(M8xaK_A?@lGdPgD~)q&_3i4d z>R+mFRsUT5WAzW!-&TL@kTE=Ys7y_Pq(COKlsLeq=TktGp=?VlwY7KLH>Y!M*Szle zx%+!$JDGU8bA#zFMp{sO@UMI4!HSR zHlscmy#}?uH&pEE?^;ppDlAcR|9<0!zWkp9OY||uG^~FpJ)j)Xa4|QaO2dV6FrxB7 zC2W2OE$pT2rwgfS*Jh)Jkrt!h+h_=Y8tfB>A2C|BYsj7}83t*At z;rv@Ozj^Eu)DLY9Xb_(pQDq-|`|Mc?%Rn;;KVe%+9o7m!wv(d)?lP+#p;(u_5g+!F zhh14}o!z968X7=g=;YjA*SF6yhI9wm!6PX{^ALJoCp2&2Oap4Hnxr`|y4P%#ERWKN z5B=p8VoW7ACtZxks9stnF-k169+JRzq^XF~Ze9dIEJd+NuMlsEq^%oe1CvvbOtiB2 zgwNLJMY5qd&WzFBqub~YV(;t)=Q~S7nTqIfa$UXu>--q^IkJKH9#h-5q*rm zN}`$v_HaV|U=zqV^Vz$=1<96YV$5!d4~&&H$(5ysv6@0BAKs^7dF+$r3}$4YKx`_J zZ$Q2)c2p?G=g1&CONdYxJYwY#+LlXjt3s5rA!O0n4zNIw$Ef zM4jdq=X^bIw3a4JB4c*i;YiUz|VT zi9;SbWcPy2ir4erH5+jz1`Fv~9pUW`A&1y%alxPUrvyId{mqxt6vw>NvWX9j`^+-C zgCcZ-72forNmikRXwAP6Mx(>gHui&WOQVTR$K08Zh{g(N=i*K4O13SPW&zv@2@v#MS-YO3dEDJp9G@V&P6B_Zx6@2OJ2!)s6GjUX+8k0yc1Bq=mnsC}4-}2?T$!{JRBbeCT+NtC$ozW95%qj3BM>nyN zQBjj98Op_5_j-QeSR~=`s2-xqcFb= z@n@PI`7YM)hnRseLV_D_!aH2X6+9TGR!0bd@8`zFe7Z- zZ7fLHA8Z;RR`YRokk)qB(uYb6hl{46?!dV>O;-*|9Y z;XCL9uB@qpcDb^L?|V zK;7b-Q{Z$Z5gZQn7NccVo5zqn9Jb8MmZ*Xw^+QGp=wA}3yY>RSW?=0F< z!*w6({Cb(c)@7&_@4q|nzP%G#?V@?`_xXr-_e1yiW=0DT#}?5NT8bTXIkLf($c$Fw z?dKXiwXH=4!sHKOoel8njo8~Z;k(~v8lh1tgYq3TMmwSV-L!`up+}*Mee@W8f<8%~ zqQ_}JJpo($G<}9Xi!X(rqeJwh(%ExUlY@g>2Zd&ZZ-+>B9Q|`Z6~DQ+9CB;aBlll@ Sc;zh~`TB){t$gS2)c*w~6ky>1 literal 0 HcmV?d00001 diff --git a/res/font/Handheld.ttf b/res/font/Handheld.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c68c1aab5fb9dadf3f9fe8bb2bc8c123aff0433b GIT binary patch literal 10620 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 aJ%GLLj+Q_B?2SM1$)7(qw3Q`)bNFA-6Cs}f literal 0 HcmV?d00001 diff --git a/res/font/Simpleton.ttf b/res/font/Simpleton.ttf new file mode 100644 index 0000000000000000000000000000000000000000..74b81752e6c9322e52b28d7460fb9664919e87d6 GIT binary patch literal 8196 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 literal 0 HcmV?d00001 diff --git a/res/img/gui.png b/res/img/gui.png index 18a87c1e489945fcaee8fc7d28d4f4dee9c0196c..890576a47365acbccdde8854ba7fe24f1ccdc3fc 100644 GIT binary patch literal 6667 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 JwdVrw{2xsiCei=^ diff --git a/res/img/gui.xcf b/res/img/gui.xcf index 87087253fb77aa54842ca46bf765b2972d3cbac2..4185224afc787261a89a567b67da0e11ab6751af 100644 GIT binary patch literal 187969 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 delta 3042 zcmcguYitx%6#nLJpKO7RwNM_Rqp6hWrl4(9DlN1D)ZjuQb_EnHw3y1XD$*c@A;B1g zP#{-2goM&6!B!wG9drpTp)@+Fs1@1_5*WH14~Z;>pj5cMZmUFpl&SCP!2S8 z04+O!1LQ~3fv;}J>ss4mjR=uW<|5(%aWJGpSSLEIQ({g0Ti%dbBU4bWN$+s-X+&AH zEvcQhF5(<ku$0W8bFXO72S%d#_M5-poW{OuY?}kpi$MU#6Z}~_D)r9s)_p=MeugS zW@vtB?)V&Mo|co5mz)#oTPw5XI^>nAfwFFOLMfLKK&X*%838UM00flKV;eN8dX-3> zvZyP-_0vr?F5^B%5x5<(S(~0HcF0vL21?fl3AvoG2%$#C35z&k5m2Or9^0T%)vLsS z5_!o}E7Ar>1bc8Q$K7U+lNZ7Icx0X<_FHQtA!rB*&7--OqsQa+$b~ag1-fM)<3%C% z_|8{|yf{tBL2|mlK{?&l%1te4R(qZvCo4nh23u_{9(O}LI|*^Y(F}!N1l7lP1fQlb z#*Pg~FqiUk>^sPpgn2Hxfp&XF?XtCT{6!&>I;^uVWZ1m&rJ**zGG&D(l7!`)dPFe( z?oj@O=)hM=kw2T+*hI8O+w%9&#@x#9B+e37fWj7FJTrH~E`t6Oe;_UpzXQ)Z01p#o zDif@DyLy(v3^iQVB=26A`dSNOmk7yzt8S}Pll#m2M_5T_F za`5~!YC{*taznw;pFJ}p6z-n8qg)AhV%sxXJU~!;WVg}ZJl7=#%hnxzW%jZRv$cC{+UETYcvTP&5swm20n;u4GwA=CNqh#pzJ+KY z_7fcc#!z53kEc1iRaLj-`!^F~TxgR0Fyi~;mMXhipvNw`sq$*ofLN7pd46@;14pm^ z@70@0!Z(zYs)n;NsdFtBC!;-QU;L#GTsDnmGzW5!aYiN?Q=)^eeeIrkrTj}#bob9g zDQn--eZ*ngbjMcO3zYF^p==nzpM^5kz;f2Y`RT+hU_lD7Fq6n7#uKjqZ?k^B_Yt49 z!z%P{=p!eu&$8Cl{G7l{VvfZ-FRE_e3w$^P@{wQCeAg;O!2ma^skTXR1rDv|o7trE zPE_+Pxes#G=jn3jPM37~N5~R?rmQ%Y^W_>*keG#MP1M>W=v~j$w@K%ns4s%gZ3uUwY1E6h zEHv`F*+g4pOe23qY|?or8ejI!`9$P#J9_^#XS^s#JwcXdWTU_ESt?TafZne)<>h%y>n|z1%iBa@E`s=;kNB@Y{9ZR@- xO@DTYOih?UOT25YIVpyZL`Qqre-*h-aD5#=0;eN;9oBbT20C@$*^{EI-`^X%a_s;B diff --git a/src/mightypork/gamecore/gui/ActionGroup.java b/src/mightypork/gamecore/gui/ActionGroup.java new file mode 100644 index 0000000..fbc591a --- /dev/null +++ b/src/mightypork/gamecore/gui/ActionGroup.java @@ -0,0 +1,36 @@ +package mightypork.gamecore.gui; + + +import java.util.HashSet; +import java.util.Set; + + +public class ActionGroup implements Enableable { + + private boolean enabled = true; + + private final Set groupMembers = new HashSet<>(); + + + @Override + public void enable(boolean yes) + { + enabled = yes; + for (final Enableable e : groupMembers) + e.enable(yes); + } + + + @Override + public boolean isEnabled() + { + return enabled; + } + + + public void add(Enableable action) + { + groupMembers.add(action); + } + +} diff --git a/src/mightypork/gamecore/gui/components/VisualComponent.java b/src/mightypork/gamecore/gui/components/VisualComponent.java index 6f6552a..ae806e6 100644 --- a/src/mightypork/gamecore/gui/components/VisualComponent.java +++ b/src/mightypork/gamecore/gui/components/VisualComponent.java @@ -70,7 +70,9 @@ public abstract class VisualComponent extends AbstractRectCache implements Compo @Override public final void onLayoutChanged() { - if (source == null) throw new NullPointerException("Component is missing a bounding rect."); + if (getRect() == null) { + throw new NullPointerException("Component is missing a bounding rect."); + } poll(); } diff --git a/src/mightypork/gamecore/gui/components/layout/GridLayout.java b/src/mightypork/gamecore/gui/components/layout/GridLayout.java index db21534..945655b 100644 --- a/src/mightypork/gamecore/gui/components/layout/GridLayout.java +++ b/src/mightypork/gamecore/gui/components/layout/GridLayout.java @@ -65,11 +65,11 @@ public class GridLayout extends LayoutComponent { /** * Put with span * + * @param elem * @param row * @param column * @param rowspan * @param colspan - * @param elem */ public void put(Component elem, int row, int column, int rowspan, int colspan) { diff --git a/src/mightypork/gamecore/gui/components/layout/HorizontalFixedFlowLayout.java b/src/mightypork/gamecore/gui/components/layout/HorizontalFixedFlowLayout.java index 28c40a0..cde7ea2 100644 --- a/src/mightypork/gamecore/gui/components/layout/HorizontalFixedFlowLayout.java +++ b/src/mightypork/gamecore/gui/components/layout/HorizontalFixedFlowLayout.java @@ -18,7 +18,7 @@ import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; public class HorizontalFixedFlowLayout extends LayoutComponent { private int col = 0; - private final Num colWidth; + private Num elementWidth; private final AlignX align; @@ -31,7 +31,7 @@ public class HorizontalFixedFlowLayout extends LayoutComponent { public HorizontalFixedFlowLayout(AppAccess app, RectBound context, Num elementWidth, AlignX align) { super(app, context); - this.colWidth = elementWidth; + this.elementWidth = elementWidth; this.align = align; if (align != AlignX.LEFT && align != AlignX.RIGHT) { @@ -67,10 +67,10 @@ public class HorizontalFixedFlowLayout extends LayoutComponent { switch (align) { case LEFT: - r = leftEdge().growRight(colWidth).moveX(colWidth.mul(col++)); + r = leftEdge().growRight(elementWidth).moveX(elementWidth.mul(col++)); break; case RIGHT: - r = rightEdge().growLeft(colWidth).moveX(colWidth.mul(-(col++))); + r = rightEdge().growLeft(elementWidth).moveX(elementWidth.mul(-(col++))); break; default: throw new IllegalArgumentException("Bad align."); @@ -81,4 +81,10 @@ public class HorizontalFixedFlowLayout extends LayoutComponent { attach(elem); } + + public void setElementWidth(Num elementWidth) + { + this.elementWidth = elementWidth; + } + } diff --git a/src/mightypork/gamecore/gui/components/layout/VerticalFixedFlowLayout.java b/src/mightypork/gamecore/gui/components/layout/VerticalFixedFlowLayout.java index a7955e9..daf955f 100644 --- a/src/mightypork/gamecore/gui/components/layout/VerticalFixedFlowLayout.java +++ b/src/mightypork/gamecore/gui/components/layout/VerticalFixedFlowLayout.java @@ -18,7 +18,7 @@ import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; public class VerticalFixedFlowLayout extends LayoutComponent { private int row = 0; - private final Num rowHeight; + private Num elementHeight; private final AlignY align; @@ -31,7 +31,7 @@ public class VerticalFixedFlowLayout extends LayoutComponent { public VerticalFixedFlowLayout(AppAccess app, RectBound context, Num elementHeight, AlignY align) { super(app, context); - this.rowHeight = elementHeight; + this.elementHeight = elementHeight; this.align = align; if (align != AlignY.TOP && align != AlignY.BOTTOM) { @@ -67,10 +67,10 @@ public class VerticalFixedFlowLayout extends LayoutComponent { switch (align) { case TOP: - r = topEdge().growDown(rowHeight).moveY(rowHeight.mul(row++)); + r = topEdge().growDown(elementHeight).moveY(elementHeight.mul(row++)); break; case BOTTOM: - r = bottomEdge().growUp(rowHeight).moveY(rowHeight.mul(-(row++))); + r = bottomEdge().growUp(elementHeight).moveY(elementHeight.mul(-(row++))); break; default: throw new IllegalArgumentException("Bad align."); @@ -81,4 +81,9 @@ public class VerticalFixedFlowLayout extends LayoutComponent { attach(elem); } + + public void setElementHeight(Num elementHeight) + { + this.elementHeight = elementHeight; + } } diff --git a/src/mightypork/gamecore/gui/components/painters/TextPainter.java b/src/mightypork/gamecore/gui/components/painters/TextPainter.java index 7eb4cad..20df900 100644 --- a/src/mightypork/gamecore/gui/components/painters/TextPainter.java +++ b/src/mightypork/gamecore/gui/components/painters/TextPainter.java @@ -6,6 +6,7 @@ import mightypork.gamecore.gui.components.VisualComponent; import mightypork.gamecore.resources.fonts.FontRenderer; import mightypork.gamecore.resources.fonts.GLFont; import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.strings.StringProvider; @@ -27,7 +28,7 @@ public class TextPainter extends VisualComponent { private StringProvider text; private boolean shadow; - private Color shadowColor = Color.BLACK; + private Color shadowColor = RGB.BLACK; private Vect shadowOffset = Vect.make(2, 2); @@ -36,7 +37,7 @@ public class TextPainter extends VisualComponent { */ public TextPainter(GLFont font) { - this(font, AlignX.LEFT, Color.WHITE); + this(font, AlignX.LEFT, RGB.WHITE); } diff --git a/src/mightypork/gamecore/render/Render.java b/src/mightypork/gamecore/render/Render.java index e3afe42..66bd8fb 100644 --- a/src/mightypork/gamecore/render/Render.java +++ b/src/mightypork/gamecore/render/Render.java @@ -11,6 +11,7 @@ import mightypork.gamecore.resources.textures.GLTexture; import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.util.files.FileUtils; import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.rect.caching.RectDigest; import mightypork.gamecore.util.math.constraints.vect.Vect; @@ -432,7 +433,7 @@ public class Render { */ public static void quadTextured(Rect quad, TxQuad txquad) { - quadTextured(quad, txquad, Color.WHITE); + quadTextured(quad, txquad, RGB.WHITE); } diff --git a/src/mightypork/gamecore/resources/fonts/FontRenderer.java b/src/mightypork/gamecore/resources/fonts/FontRenderer.java index 446b08b..11e5a46 100644 --- a/src/mightypork/gamecore/resources/fonts/FontRenderer.java +++ b/src/mightypork/gamecore/resources/fonts/FontRenderer.java @@ -4,6 +4,7 @@ package mightypork.gamecore.resources.fonts; import mightypork.gamecore.gui.AlignX; import mightypork.gamecore.render.Render; import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.vect.Vect; @@ -25,7 +26,7 @@ public class FontRenderer { */ public FontRenderer(GLFont font) { - this(font, Color.WHITE); + this(font, RGB.WHITE); } @@ -68,7 +69,10 @@ public class FontRenderer { private double getScale(double height) { - return height / font.getLineHeight(); + final double fontHeight = font.getLineHeight(); + final double usefulHeight = fontHeight - fontHeight * font.getTopDiscardRatio() - fontHeight * font.getBottomDiscardRatio(); + + return height / usefulHeight; } @@ -106,8 +110,10 @@ public class FontRenderer { { Render.pushMatrix(); - Render.translateXY(pos); - Render.scaleXY(getScale(height)); + final double sc = getScale(height); + + Render.translate(pos.x(), pos.y() - font.getTopDiscardRatio() * sc); + Render.scaleXY(sc); font.draw(text, color); diff --git a/src/mightypork/gamecore/resources/fonts/GLFont.java b/src/mightypork/gamecore/resources/fonts/GLFont.java index fba6ebb..f17557d 100644 --- a/src/mightypork/gamecore/resources/fonts/GLFont.java +++ b/src/mightypork/gamecore/resources/fonts/GLFont.java @@ -47,4 +47,13 @@ public interface GLFont { * @return specified font size */ int getFontSize(); + + + void setDiscardRatio(double top, double bottom); + + + double getTopDiscardRatio(); + + + double getBottomDiscardRatio(); } diff --git a/src/mightypork/gamecore/resources/fonts/impl/CachedFont.java b/src/mightypork/gamecore/resources/fonts/impl/CachedFont.java index de023a8..c084560 100644 --- a/src/mightypork/gamecore/resources/fonts/impl/CachedFont.java +++ b/src/mightypork/gamecore/resources/fonts/impl/CachedFont.java @@ -77,6 +77,10 @@ public class CachedFont implements GLFont { private final FilterMode filter; + private double discardTop; + + private double discardBottom; + /** * Make a font @@ -448,4 +452,25 @@ public class CachedFont implements GLFont { return Vect.make(getWidth(text), getLineHeight()); } + + @Override + public void setDiscardRatio(double top, double bottom) + { + discardTop = top; + discardBottom = bottom; + } + + + @Override + public double getTopDiscardRatio() + { + return discardTop; + } + + + @Override + public double getBottomDiscardRatio() + { + return discardBottom; + } } diff --git a/src/mightypork/gamecore/resources/fonts/impl/DeferredFont.java b/src/mightypork/gamecore/resources/fonts/impl/DeferredFont.java index 1a1e2ce..ae9b23b 100644 --- a/src/mightypork/gamecore/resources/fonts/impl/DeferredFont.java +++ b/src/mightypork/gamecore/resources/fonts/impl/DeferredFont.java @@ -44,6 +44,8 @@ public class DeferredFont extends DeferredResource implements GLFont { private String chars; private FilterMode filter; private boolean antialias; + private double discardTop; + private double discardBottom; /** @@ -208,4 +210,26 @@ public class DeferredFont extends DeferredResource implements GLFont { // this will have to suffice font = null; } + + + @Override + public void setDiscardRatio(double top, double bottom) + { + discardTop = top; + discardBottom = bottom; + } + + + @Override + public double getTopDiscardRatio() + { + return discardTop; + } + + + @Override + public double getBottomDiscardRatio() + { + return discardBottom; + } } diff --git a/src/mightypork/gamecore/util/math/color/Color.java b/src/mightypork/gamecore/util/math/color/Color.java index 75132fa..edb19cc 100644 --- a/src/mightypork/gamecore/util/math/color/Color.java +++ b/src/mightypork/gamecore/util/math/color/Color.java @@ -17,26 +17,6 @@ import mightypork.gamecore.util.math.constraints.num.Num; */ public abstract class Color { - public static final Color NONE = rgba(0, 0, 0, 0); - public static final Color SHADOW = rgba(0, 0, 0, 0.5); - - public static final Color WHITE = fromHex(0xFFFFFF); - public static final Color BLACK = fromHex(0x000000); - public static final Color DARK_GRAY = fromHex(0x808080); - public static final Color GRAY = rgb(0.5, 0.5, 0.5); - public static final Color LIGHT_GRAY = rgb(0.75, 0.75, 0.75); - - public static final Color RED = rgb(1, 0, 0); - public static final Color GREEN = rgb(0, 1, 0); - public static final Color BLUE = rgb(0, 0, 1); - - public static final Color YELLOW = rgb(1, 1, 0); - public static final Color MAGENTA = rgb(1, 0, 1); - public static final Color CYAN = rgb(0, 1, 1); - - public static final Color ORANGE = rgb(1, 0.78, 0); - public static final Color PINK = rgb(1, 0.68, 0.68); - private static final Stack alphaStack = new Stack<>(); private static volatile boolean alphaStackEnabled = true; diff --git a/src/mightypork/gamecore/util/math/color/pal/RGB.java b/src/mightypork/gamecore/util/math/color/pal/RGB.java index 36a84c8..ac81669 100644 --- a/src/mightypork/gamecore/util/math/color/pal/RGB.java +++ b/src/mightypork/gamecore/util/math/color/pal/RGB.java @@ -9,24 +9,35 @@ import mightypork.gamecore.util.math.color.Color; * * @author MightyPork */ -public interface RGB { +public class RGB { - Color WHITE = Color.fromHex(0xFFFFFF); - Color BLACK = Color.fromHex(0x000000); - Color GRAY_DARK = Color.fromHex(0x808080); - Color GRAY = Color.fromHex(0xA0A0A0); - Color GRAY_LIGHT = Color.fromHex(0xC0C0C0); + public static final Color BLACK_10 = Color.rgba(0, 0, 0, 0.1); + public static final Color BLACK_20 = Color.rgba(0, 0, 0, 0.2); + public static final Color BLACK_30 = Color.rgba(0, 0, 0, 0.3); + public static final Color BLACK_40 = Color.rgba(0, 0, 0, 0.4); + public static final Color BLACK_50 = Color.rgba(0, 0, 0, 0.5); + public static final Color BLACK_60 = Color.rgba(0, 0, 0, 0.6); + public static final Color BLACK_70 = Color.rgba(0, 0, 0, 0.7); + public static final Color BLACK_80 = Color.rgba(0, 0, 0, 0.8); + public static final Color BLACK_90 = Color.rgba(0, 0, 0, 0.9); - Color RED = Color.fromHex(0xFF0000); - Color GREEN = Color.fromHex(0x00FF00); - Color BLUE = Color.fromHex(0x0000FF); - Color YELLOW = Color.fromHex(0xFFFF00); - Color CYAN = Color.fromHex(0x00FFFF); - Color MAGENTA = Color.fromHex(0xFF00FF); + public static final Color WHITE = Color.fromHex(0xFFFFFF); + public static final Color BLACK = Color.fromHex(0x000000); + public static final Color GRAY_DARK = Color.fromHex(0x808080); + public static final Color GRAY = Color.fromHex(0xA0A0A0); + public static final Color GRAY_LIGHT = Color.fromHex(0xC0C0C0); - Color PINK = Color.fromHex(0xFF3FFC); - Color ORANGE = Color.fromHex(0xFC4800); + public static final Color RED = Color.fromHex(0xFF0000); + public static final Color GREEN = Color.fromHex(0x00FF00); + public static final Color BLUE = Color.fromHex(0x0000FF); - Color NONE = Color.NONE; + public static final Color YELLOW = Color.fromHex(0xFFFF00); + public static final Color CYAN = Color.fromHex(0x00FFFF); + public static final Color MAGENTA = Color.fromHex(0xFF00FF); + + public static final Color PINK = Color.fromHex(0xFF3FFC); + public static final Color ORANGE = Color.fromHex(0xFC4800); + + public static final Color NONE = Color.rgba(0, 0, 0, 0); } diff --git a/src/mightypork/rogue/App.java b/src/mightypork/rogue/App.java index 7502336..9c6eaee 100644 --- a/src/mightypork/rogue/App.java +++ b/src/mightypork/rogue/App.java @@ -130,7 +130,7 @@ public final class App extends BaseApp { bindEventToKey(new CrossfadeRequest(null), Keys.L_CONTROL, Keys.Q); - bindEventToKey(new CrossfadeRequest("menu"), Keys.ESCAPE); + bindEventToKey(new CrossfadeRequest("menu"), Keys.L_CONTROL, Keys.M); } diff --git a/src/mightypork/rogue/Res.java b/src/mightypork/rogue/Res.java index 2684de5..8f57b4a 100644 --- a/src/mightypork/rogue/Res.java +++ b/src/mightypork/rogue/Res.java @@ -49,14 +49,17 @@ public final class Res { private static void loadFonts() { - fonts.loadFont("polygon_pixel", new DeferredFont("/res/font/PolygonPixel5x7Standard.ttf", Glyphs.basic, 16)); - fonts.loadFont("press_start", new DeferredFont("/res/font/PressStart2P.ttf", Glyphs.basic, 16)); + DeferredFont font; + + //fonts.loadFont("polygon_pixel", new DeferredFont("/res/font/PolygonPixel5x7Standard.ttf", Glyphs.basic, 16)); + fonts.loadFont("press_start", font = new DeferredFont("/res/font/PressStart2P.ttf", Glyphs.basic, 16)); + fonts.loadFont("polygon_pixel", font = new DeferredFont("/res/font/Simpleton.ttf", Glyphs.basic, 16)); + font.setDiscardRatio(5 / 16D, 2 / 16D); // aliases based on concrete usage - fonts.addAlias("default", "polygon_pixel"); - fonts.addAlias("main_menu_button", "press_start"); - fonts.addAlias("main_menu_title", "press_start"); - fonts.addAlias("hud", "press_start"); + fonts.addAlias("thick", "press_start"); + + fonts.addAlias("thin", "polygon_pixel"); } @@ -88,6 +91,12 @@ public final class Res { textures.add("nav.button.fg.attack", grid.makeQuad(2, 6)); textures.add("nav.button.fg.options", grid.makeQuad(3, 6)); textures.add("nav.button.fg.help", grid.makeQuad(4, 6)); + textures.add("nav.button.fg.map", grid.makeQuad(5, 6)); + textures.add("nav.button.fg.pause", grid.makeQuad(6, 6)); + textures.add("nav.button.fg.magnify", grid.makeQuad(7, 6)); + + textures.add("inv.slot.base", grid.makeQuad(0, 5)); + textures.add("inv.slot.selected", grid.makeQuad(1, 5)); // sprites diff --git a/src/mightypork/rogue/screens/FpsOverlay.java b/src/mightypork/rogue/screens/FpsOverlay.java index ef3dc94..40769b1 100644 --- a/src/mightypork/rogue/screens/FpsOverlay.java +++ b/src/mightypork/rogue/screens/FpsOverlay.java @@ -9,7 +9,7 @@ import mightypork.gamecore.gui.screens.Overlay; import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.Keys; import mightypork.gamecore.resources.fonts.GLFont; -import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.num.Num; import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; import mightypork.gamecore.util.math.constraints.vect.Vect; @@ -38,12 +38,12 @@ public class FpsOverlay extends Overlay { } }); - final GLFont font = Res.getFont("default"); + final GLFont font = Res.getFont("thin"); final Num h = root.height(); - final RectBound constraint = root.shrink(h.perc(3)).topRight().startRect().growDown(h.perc(8).max(32)); + final RectBound constraint = root.shrink(h.perc(3)).topRight().startRect().growDown(h.perc(5).max(16)); - tp = new TextPainter(font, AlignX.RIGHT, Color.WHITE, new StringProvider() { + tp = new TextPainter(font, AlignX.RIGHT, RGB.WHITE, new StringProvider() { @Override public String getString() @@ -53,7 +53,7 @@ public class FpsOverlay extends Overlay { }); tp.setRect(constraint); - tp.setShadow(Color.BLACK, Vect.make(tp.height().div(16).round())); + tp.setShadow(RGB.BLACK, Vect.make(tp.height().div(8).round())); root.add(tp); diff --git a/src/mightypork/rogue/screens/game/HudLayer.java b/src/mightypork/rogue/screens/game/HudLayer.java index d4c8233..eb1bc99 100644 --- a/src/mightypork/rogue/screens/game/HudLayer.java +++ b/src/mightypork/rogue/screens/game/HudLayer.java @@ -3,15 +3,13 @@ package mightypork.rogue.screens.game; import mightypork.gamecore.gui.AlignX; import mightypork.gamecore.gui.components.painters.TextPainter; -import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.ScreenLayer; -import mightypork.gamecore.input.KeyStroke; -import mightypork.gamecore.input.Keys; import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.num.Num; import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.strings.StringProvider; import mightypork.rogue.Res; +import mightypork.rogue.world.World; import mightypork.rogue.world.WorldProvider; import mightypork.rogue.world.gui.Minimap; @@ -36,27 +34,21 @@ public class HudLayer extends ScreenLayer { } }; - private Minimap mm; + protected Minimap mm; + private final ScreenGame gameScreen; - public HudLayer(Screen screen) + + public HudLayer(ScreenGame screen) { super(screen); + this.gameScreen = screen; buildNav(); buildDisplays(); buildMinimap(); - - bindKey(new KeyStroke(Keys.M), new Runnable() { - - @Override - public void run() - { - mm.setVisible(!mm.isVisible()); - } - }); } @@ -90,12 +82,13 @@ public class HudLayer extends ScreenLayer { root.add(hearts); - final TextPainter lvl = new TextPainter(Res.getFont("hud"), AlignX.RIGHT, RGB.WHITE, new StringProvider() { + final TextPainter lvl = new TextPainter(Res.getFont("thick"), AlignX.RIGHT, RGB.WHITE, new StringProvider() { @Override public String getString() { - return "Floor " + (1 + WorldProvider.get().getWorld().getPlayer().getLevelNumber()); + final World w = WorldProvider.get().getWorld(); + return (w.isPaused() ? "[P] " : "") + "Floor " + (1 + w.getPlayer().getLevelNumber()); } }); @@ -117,14 +110,27 @@ public class HudLayer extends ScreenLayer { nav.setRect(root.bottomEdge().growUp(root.height().perc(12))); root.add(nav); + NavButton btn; + // ltr - nav.addLeft(new NavButton(Res.txq("nav.button.fg.inventory"))); - nav.addLeft(new NavButton(Res.txq("nav.button.fg.eat"))); - nav.addLeft(new NavButton(Res.txq("nav.button.fg.attack"))); + nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.inventory"))); + btn.setAction(gameScreen.actionInv); + + nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.eat"))); + btn.setAction(gameScreen.actionEat); - // rtl + nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.pause"))); + btn.setAction(gameScreen.actionTogglePause); + + // TODO actions nav.addRight(new NavButton(Res.txq("nav.button.fg.options"))); nav.addRight(new NavButton(Res.txq("nav.button.fg.help"))); + + nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.map"))); + btn.setAction(gameScreen.actionToggleMinimap); + + nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.magnify"))); + btn.setAction(gameScreen.actionToggleZoom); } diff --git a/src/mightypork/rogue/screens/game/InvLayer.java b/src/mightypork/rogue/screens/game/InvLayer.java new file mode 100644 index 0000000..243f2df --- /dev/null +++ b/src/mightypork/rogue/screens/game/InvLayer.java @@ -0,0 +1,197 @@ +package mightypork.rogue.screens.game; + + +import mightypork.gamecore.gui.AlignX; +import mightypork.gamecore.gui.components.layout.ConstraintLayout; +import mightypork.gamecore.gui.components.layout.GridLayout; +import mightypork.gamecore.gui.components.layout.HorizontalFixedFlowLayout; +import mightypork.gamecore.gui.components.painters.QuadPainter; +import mightypork.gamecore.gui.components.painters.TextPainter; +import mightypork.gamecore.gui.screens.ScreenLayer; +import mightypork.gamecore.input.KeyStroke; +import mightypork.gamecore.input.Keys; +import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; +import mightypork.gamecore.util.math.constraints.num.Num; +import mightypork.gamecore.util.math.constraints.rect.Rect; +import mightypork.gamecore.util.strings.StringProvider; +import mightypork.rogue.Res; +import mightypork.rogue.screens.game.ScreenGame.GScrState; +import mightypork.rogue.world.World.PlayerFacade; +import mightypork.rogue.world.WorldProvider; +import mightypork.rogue.world.item.Item; +import mightypork.rogue.world.item.ItemType; + + +public class InvLayer extends ScreenLayer { + + private final StringProvider contextStrProv = new StringProvider() { + + @Override + public String getString() + { + String s = "Esc - close"; + + final int selected = getSelectedSlot(); + if (selected != -1) { + + final PlayerFacade pl = WorldProvider.get().getPlayer(); + + final Item itm = pl.getInventory().getItem(selected); + if (itm != null && !itm.isEmpty()) { + s = "D - drop, " + s; + + if (itm.getType() == ItemType.FOOD) { + s = "E - eat, " + s; + } + + if (itm.getType() == ItemType.WEAPON) { + s = "E - equip, " + s; + } + } + } + + return s; + } + }; + + private final InvSlot[] slots = new InvSlot[8]; + + + private int getSelectedSlot() + { + for (final InvSlot sl : slots) { + if (sl.selected) { + // stuff + return sl.index; + } + } + return -1; + } + + + public InvLayer(final ScreenGame screen) + { + super(screen); + + final Rect fg = root.shrink(root.height().perc(15)); + + final QuadPainter qp = new QuadPainter(Color.rgba(0, 0, 0, 0.5)); + qp.setRect(root); + root.add(qp); + + int pos = 0; + + final GridLayout gl = new GridLayout(root, fg, 21, 1); + root.add(gl); + + final TextPainter txp = new TextPainter(Res.getFont("thick"), AlignX.CENTER, RGB.YELLOW, "Inventory"); + gl.put(txp, pos, 0, 2, 1); + pos += 3; + + final HorizontalFixedFlowLayout row1 = new HorizontalFixedFlowLayout(root, null, AlignX.LEFT); + row1.setElementWidth(row1.height()); + final ConstraintLayout cl1 = new ConstraintLayout(root); + row1.setRect(cl1.axisV().grow(cl1.height().mul(2), Num.ZERO)); + cl1.add(row1); + + gl.put(cl1, pos, 0, 8, 1); + pos += 8; + + row1.add(slots[0] = new InvSlot(0, slots)); + row1.add(slots[1] = new InvSlot(1, slots)); + row1.add(slots[2] = new InvSlot(2, slots)); + row1.add(slots[3] = new InvSlot(3, slots)); + + + final HorizontalFixedFlowLayout row2 = new HorizontalFixedFlowLayout(root, null, AlignX.LEFT); + row2.setElementWidth(row2.height()); + final ConstraintLayout cl2 = new ConstraintLayout(root); + row2.setRect(cl2.axisV().grow(cl2.height().mul(2), Num.ZERO)); + cl2.add(row2); + gl.put(cl2, pos, 0, 8, 1); + pos += 8; + + row2.add(slots[4] = new InvSlot(4, slots)); + row2.add(slots[5] = new InvSlot(5, slots)); + row2.add(slots[6] = new InvSlot(6, slots)); + row2.add(slots[7] = new InvSlot(7, slots)); + + final TextPainter txp2 = new TextPainter(Res.getFont("thin"), AlignX.CENTER, RGB.WHITE, contextStrProv); + gl.put(txp2, pos + 1, 0, 1, 1); + + setVisible(false); + + bindKey(new KeyStroke(Keys.ESCAPE), new Runnable() { + + @Override + public void run() + { + if (!isVisible()) return; + + screen.setState(GScrState.WORLD); + } + }); + + bindKey(new KeyStroke(Keys.E), new Runnable() { + + @Override + public void run() + { + if (!isVisible()) return; + + final int selected = getSelectedSlot(); + if (selected != -1) { + final PlayerFacade pl = WorldProvider.get().getPlayer(); + final Item itm = pl.getInventory().getItem(selected); + if (itm != null && !itm.isEmpty()) { + + if (itm.getType() == ItemType.FOOD) { + if (pl.eatFood(itm)) { + if (itm.consume()) { + pl.getInventory().setItem(selected, null); + } + } + } + + if (itm.getType() == ItemType.WEAPON) { + pl.selectWeapon(selected); + } + } + } + } + }); + + bindKey(new KeyStroke(Keys.D), new Runnable() { + + @Override + public void run() + { + if (!isVisible()) return; + + final int selected = getSelectedSlot(); + if (selected != -1) { + final PlayerFacade pl = WorldProvider.get().getPlayer(); + final Item itm = pl.getInventory().getItem(selected); + if (itm != null && !itm.isEmpty()) { + + final Item piece = itm.split(1); + if (itm.isEmpty()) pl.getInventory().setItem(selected, null); + + if (!pl.getLevel().getTile(pl.getCoord()).dropItem(piece)) { + pl.getInventory().addItem(piece); // add back + } + } + } + } + }); + } + + + @Override + public int getZIndex() + { + return 200; + } + +} diff --git a/src/mightypork/rogue/screens/game/InvSlot.java b/src/mightypork/rogue/screens/game/InvSlot.java new file mode 100644 index 0000000..9247872 --- /dev/null +++ b/src/mightypork/rogue/screens/game/InvSlot.java @@ -0,0 +1,118 @@ +package mightypork.rogue.screens.game; + + +import mightypork.gamecore.gui.Action; +import mightypork.gamecore.gui.AlignX; +import mightypork.gamecore.gui.components.ClickableComponent; +import mightypork.gamecore.gui.components.painters.TextPainter; +import mightypork.gamecore.render.Render; +import mightypork.gamecore.resources.textures.TxQuad; +import mightypork.gamecore.util.math.color.pal.RGB; +import mightypork.gamecore.util.math.constraints.rect.caching.RectCache; +import mightypork.rogue.Res; +import mightypork.rogue.world.World.PlayerFacade; +import mightypork.rogue.world.WorldProvider; +import mightypork.rogue.world.item.Item; + + +/** + * Button in the ingame nav + * + * @author MightyPork + */ +public class InvSlot extends ClickableComponent { + + private final TxQuad txBase, txSelected; + + protected boolean selected = false; + protected int index; + + private final RectCache itemRect; + + private final InvSlot[] slots; + + private final TextPainter txt; + + private final RectCache txtRect; + + + public InvSlot(int index, InvSlot[] allSlots) + { + super(); + this.txBase = Res.txq("inv.slot.base"); + this.txSelected = Res.txq("inv.slot.selected"); + + this.index = index; + this.slots = allSlots; + + this.itemRect = getRect().shrink(height().perc(16)).cached(); + + //@formatter:off + this.txtRect = itemRect.bottomEdge() + .move(itemRect.height().perc(5).neg(), itemRect.height().perc(10).neg()) + .growUp(itemRect.height().perc(35)).cached(); + //@formatter:on + + txt = new TextPainter(Res.getFont("thin"), AlignX.RIGHT, RGB.WHITE); + txt.setRect(txtRect); + txt.setShadow(RGB.BLACK_60, txt.getRect().height().div(8).toVectXY()); + + setAction(new Action() { + + @Override + protected void execute() + { + for (final InvSlot sl : slots) { + sl.selected = false; + } + + selected = true; + } + + }); + } + + + @Override + public void updateLayout() + { + itemRect.poll(); + txtRect.poll(); + } + + + @Override + protected void renderComponent() + { + TxQuad bg; + + if (selected) { + bg = txSelected; + } else { + bg = txBase; + } + + Render.quadTextured(this, bg); + + final PlayerFacade pl = WorldProvider.get().getPlayer(); + + final Item itm = pl.getInventory().getItem(index); + if (itm != null && !itm.isEmpty()) { + itm.render(itemRect); + if (itm.getAmount() > 1) { + txt.setText("" + itm.getAmount()); + txt.setColor(RGB.WHITE); + txt.render(); + } + + if (pl.getSelectedWeapon() == index) { + txt.setText("*"); + txt.setColor(RGB.YELLOW); + txt.render(); + } + + + } + } + +} diff --git a/src/mightypork/rogue/screens/game/ScreenGame.java b/src/mightypork/rogue/screens/game/ScreenGame.java index bb43efa..da2fae2 100644 --- a/src/mightypork/rogue/screens/game/ScreenGame.java +++ b/src/mightypork/rogue/screens/game/ScreenGame.java @@ -4,26 +4,131 @@ package mightypork.rogue.screens.game; import java.util.Random; import mightypork.gamecore.app.AppAccess; +import mightypork.gamecore.gui.Action; +import mightypork.gamecore.gui.ActionGroup; import mightypork.gamecore.gui.screens.LayeredScreen; import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.Keys; import mightypork.rogue.world.WorldProvider; import mightypork.rogue.world.events.WorldPauseRequest; +import mightypork.rogue.world.events.WorldPauseRequest.PauseAction; public class ScreenGame extends LayeredScreen { + /** + * Game gui state. + * + * @author MightyPork + */ + public enum GScrState + { + WORLD, INV; + } + private final Random rand = new Random(); + private InvLayer invLayer; + private HudLayer hudLayer; + + private GScrState state = GScrState.WORLD; + + private final ActionGroup worldActions = new ActionGroup(); + + public Action actionEat = new Action() { + + @Override + public void execute() + { + WorldProvider.get().getPlayer().tryToEatSomeFood(); + } + }; + + public Action actionInv = new Action() { + + @Override + public void execute() + { + setState(GScrState.INV); + } + }; + + public Action actionToggleMinimap = new Action() { + + @Override + public void execute() + { + hudLayer.mm.setVisible(!hudLayer.mm.isVisible()); + } + }; + + public Action actionTogglePause = new Action() { + + @Override + public void execute() + { + getEventBus().send(new WorldPauseRequest(PauseAction.TOGGLE)); + } + }; + + public Action actionToggleZoom = new Action() { + + @Override + public void execute() + { + worldLayer.map.toggleMag(); + } + }; + + private WorldLayer worldLayer; + + + /** + * Set gui state (overlay) + * + * @param nstate new state + */ + public void setState(GScrState nstate) + { + if (this.state == nstate) return; + + if (nstate != GScrState.WORLD) { // leaving world. + getEventBus().send(new WorldPauseRequest(PauseAction.PAUSE)); + + worldActions.enable(false); // disable world actions + } + + if (nstate == GScrState.WORLD) { + getEventBus().send(new WorldPauseRequest(PauseAction.RESUME)); + + invLayer.setVisible(false); // hide all extra layers + + worldActions.enable(true); + } + + if (nstate == GScrState.INV) { + invLayer.setVisible(true); + } + + this.state = nstate; + } + + + public GScrState getState() + { + return state; + } public ScreenGame(AppAccess app) { super(app); - addLayer(new HudLayer(this)); - addLayer(new WorldLayer(this)); + addLayer(invLayer = new InvLayer(this)); + addLayer(hudLayer = new HudLayer(this)); + addLayer(worldLayer = new WorldLayer(this)); + // TODO temporary here ↓ bindKey(new KeyStroke(Keys.L_CONTROL, Keys.N), new Runnable() { @Override @@ -33,18 +138,22 @@ public class ScreenGame extends LayeredScreen { } }); - final Runnable pauseIt = new Runnable() { - - @Override - public void run() - { - getEventBus().send(new WorldPauseRequest()); - } - }; - //pause key - bindKey(new KeyStroke(Keys.P), pauseIt); - bindKey(new KeyStroke(Keys.PAUSE), pauseIt); + bindKey(new KeyStroke(Keys.P), actionTogglePause); + bindKey(new KeyStroke(Keys.PAUSE), actionTogglePause); + + bindKey(new KeyStroke(Keys.I), actionInv); + bindKey(new KeyStroke(Keys.E), actionEat); + bindKey(new KeyStroke(Keys.M), actionToggleMinimap); + bindKey(new KeyStroke(Keys.Z), actionToggleZoom); + + worldActions.add(actionEat); + worldActions.add(actionInv); + worldActions.add(actionToggleMinimap); + worldActions.add(actionTogglePause); + worldActions.add(actionToggleZoom); + + worldActions.enable(true); } diff --git a/src/mightypork/rogue/screens/game/WorldLayer.java b/src/mightypork/rogue/screens/game/WorldLayer.java index 5ad645c..a84bef0 100644 --- a/src/mightypork/rogue/screens/game/WorldLayer.java +++ b/src/mightypork/rogue/screens/game/WorldLayer.java @@ -11,7 +11,7 @@ import mightypork.rogue.world.gui.interaction.MIPMouse; public class WorldLayer extends ScreenLayer { - private final MapView worldView; + protected final MapView map; public WorldLayer(Screen screen) @@ -20,17 +20,17 @@ public class WorldLayer extends ScreenLayer { // render component - worldView = new MapView(); + map = new MapView(); // map input plugins - worldView.addPlugin(new MIPKeyboard(worldView)); - worldView.addPlugin(new MIPMouse(worldView)); + map.addPlugin(new MIPKeyboard(map)); + map.addPlugin(new MIPMouse(map)); // size of lower navbar final Num lownav = root.height().perc(12); - worldView.setRect(root.shrinkBottom(lownav)); + map.setRect(root.shrinkBottom(lownav)); - root.add(worldView); + root.add(map); } diff --git a/src/mightypork/rogue/screens/menu/MenuButton.java b/src/mightypork/rogue/screens/menu/MenuButton.java index e4b5c68..fd0842e 100644 --- a/src/mightypork/rogue/screens/menu/MenuButton.java +++ b/src/mightypork/rogue/screens/menu/MenuButton.java @@ -7,6 +7,7 @@ import mightypork.gamecore.gui.components.painters.TextPainter; import mightypork.gamecore.input.InputSystem; import mightypork.gamecore.resources.fonts.GLFont; import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.mutable.VectVar; import mightypork.rogue.Res; @@ -14,7 +15,7 @@ import mightypork.rogue.Res; class MenuButton extends ClickableComponent { - private static GLFont font = Res.getFont("main_menu_button"); + private static GLFont font = Res.getFont("thick"); private final TextPainter painter; private final VectVar offset = Vect.makeVar(); @@ -30,7 +31,7 @@ class MenuButton extends ClickableComponent { this.painter = new TextPainter(font, AlignX.CENTER, this.color, text); this.painter.setRect(this); - this.painter.setShadow(Color.BLACK.withAlpha(0.3), offset); + this.painter.setShadow(RGB.BLACK_30, offset); } diff --git a/src/mightypork/rogue/screens/menu/MenuLayer.java b/src/mightypork/rogue/screens/menu/MenuLayer.java index 3a54c54..c6131c6 100644 --- a/src/mightypork/rogue/screens/menu/MenuLayer.java +++ b/src/mightypork/rogue/screens/menu/MenuLayer.java @@ -29,7 +29,7 @@ class MenuLayer extends ScreenLayer { { final Rect menuBox = root.shrink(Num.ZERO, root.height().mul(0.15)).moveY(root.height().mul(-0.04)); - final GridLayout layout = new GridLayout(root, menuBox, 14, 1); + final GridLayout layout = new GridLayout(root, menuBox, 11, 1); layout.enableCaching(true); final QuadPainter bg = QuadPainter.gradV(Color.fromHex(0x007eb3), PAL16.SEABLUE); @@ -60,7 +60,7 @@ class MenuLayer extends ScreenLayer { layout.put(btn, r, 0, 2, 1); r += 3; - + /* // bouncy text button btn = new MenuButton("Bouncy", PAL16.CLOUDBLUE); btn.setAction(new Action() { @@ -73,7 +73,7 @@ class MenuLayer extends ScreenLayer { }); layout.put(btn, r, 0, 2, 1); r += 3; - + */ // quit button btn = new MenuButton("Bye!", PAL16.BLOODRED); diff --git a/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java b/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java index feef5f8..48c9817 100644 --- a/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java +++ b/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java @@ -7,7 +7,7 @@ import mightypork.gamecore.eventbus.events.Updateable; import mightypork.gamecore.gui.components.VisualComponent; import mightypork.gamecore.render.Render; import mightypork.gamecore.util.math.Easing; -import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.num.Num; import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated; import mightypork.gamecore.util.math.constraints.rect.Rect; @@ -41,7 +41,7 @@ public class BouncyBox extends VisualComponent implements Updateable { @Override public void renderComponent() { - Render.quad(box, Color.GREEN); + Render.quad(box, RGB.GREEN); } diff --git a/src/mightypork/rogue/screens/test_bouncyboxes/LayerBouncyBoxes.java b/src/mightypork/rogue/screens/test_bouncyboxes/LayerBouncyBoxes.java index 4366279..2d63bd6 100644 --- a/src/mightypork/rogue/screens/test_bouncyboxes/LayerBouncyBoxes.java +++ b/src/mightypork/rogue/screens/test_bouncyboxes/LayerBouncyBoxes.java @@ -11,7 +11,7 @@ import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.ScreenLayer; import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.Keys; -import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.num.Num; import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.rogue.Res; @@ -55,10 +55,10 @@ public class LayerBouncyBoxes extends ScreenLayer { boxes.add(bbr); } - final TextPainter tp = new TextPainter(Res.getFont("default"), AlignX.LEFT, Color.WHITE); + final TextPainter tp = new TextPainter(Res.getFont("thick"), AlignX.LEFT, RGB.WHITE); tp.setText("Press left & right to move."); final Num shadowOffset = tp.height().div(16); - tp.setShadow(Color.RED, Vect.make(shadowOffset, shadowOffset)); + tp.setShadow(RGB.RED, Vect.make(shadowOffset, shadowOffset)); layout.add(tp); } diff --git a/src/mightypork/rogue/world/PlayerControl.java b/src/mightypork/rogue/world/PlayerControl.java index 4ef9aee..54d9db0 100644 --- a/src/mightypork/rogue/world/PlayerControl.java +++ b/src/mightypork/rogue/world/PlayerControl.java @@ -117,7 +117,6 @@ public abstract class PlayerControl { } //2nd try to click tile - System.out.println("do click: " + Coord.fromVect(pos)); return getLevel().getTile(Coord.fromVect(pos)).onClick(); } diff --git a/src/mightypork/rogue/world/PlayerInfo.java b/src/mightypork/rogue/world/PlayerInfo.java index c87aa4c..9cdb72c 100644 --- a/src/mightypork/rogue/world/PlayerInfo.java +++ b/src/mightypork/rogue/world/PlayerInfo.java @@ -91,10 +91,22 @@ public class PlayerInfo implements IonObjBundled { } - public Item getEquippedWeapon() + public int getSelectedWeaponIndex() + { + return selectedWeapon; + } + + + public Item getSelectedWeapon() { if (selectedWeapon == NO_WEAPON) return null; return inventory.getItem(selectedWeapon); } + + public void selectWeapon(int selectedWeapon) + { + this.selectedWeapon = selectedWeapon; + } + } diff --git a/src/mightypork/rogue/world/World.java b/src/mightypork/rogue/world/World.java index 153e016..ddee98a 100644 --- a/src/mightypork/rogue/world/World.java +++ b/src/mightypork/rogue/world/World.java @@ -18,6 +18,7 @@ import mightypork.gamecore.util.math.timing.Pauseable; import mightypork.rogue.world.entity.Entities; import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.item.Item; +import mightypork.rogue.world.item.ItemType; import mightypork.rogue.world.level.Level; @@ -171,20 +172,62 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea public int getAttackStrength() { - final Item weapon = playerInfo.getEquippedWeapon(); + final Item weapon = playerInfo.getSelectedWeapon(); if (weapon == null) return PlayerInfo.BARE_ATTACK; return Math.min(weapon.getAttackPoints(), playerInfo.BARE_ATTACK); } + + public boolean eatFood(Item itm) + { + if (itm == null || itm.isEmpty() || itm.getType() != ItemType.FOOD) return false; + + if (getHealth() < getHealthMax()) { + + playerEntity.health.addHealth(itm.getFoodPoints()); + + return true; + } + + + return false; + } + + + public void selectWeapon(int selected) + { + playerInfo.selectWeapon(selected); + } + + + public int getSelectedWeapon() + { + return playerInfo.getSelectedWeaponIndex(); + } + + + public void tryToEatSomeFood() + { + for (int i = 0; i < getInventory().getSize(); i++) { + final Item itm = getInventory().getItem(i); + if (itm == null || itm.isEmpty()) continue; + + final Item slice = itm.split(1); + if (!eatFood(slice)) itm.addItem(slice); + if (itm.isEmpty()) getInventory().setItem(i, null); + return; + } + } + } // not saved stuffs private final PlayerFacade player = new PlayerFacade(); private Entity playerEntity; private BusAccess bus; - private boolean paused; + private int pauseDepth = 0; private final ArrayList levels = new ArrayList<>(); @@ -209,7 +252,7 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea @Override public boolean doesDelegate() { - return !paused; + return !isPaused(); } @@ -324,21 +367,21 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea @Override public void pause() { - paused = true; + pauseDepth++; } @Override public void resume() { - paused = false; + if (pauseDepth > 0) pauseDepth--; } @Override public boolean isPaused() { - return paused; + return pauseDepth > 0; } diff --git a/src/mightypork/rogue/world/entity/entities/RatEntity.java b/src/mightypork/rogue/world/entity/entities/RatEntity.java index 898a45a..93ace9f 100644 --- a/src/mightypork/rogue/world/entity/entities/RatEntity.java +++ b/src/mightypork/rogue/world/entity/entities/RatEntity.java @@ -71,11 +71,16 @@ public class RatEntity extends Entity { public void onKilled() { super.onKilled(); - + } + + + @Override + public void onCorpseRemoved() + { // drop rat meat final Item meat = Items.MEAT.createItem(); - getLevel().getTile(getCoord()).dropItem(meat); + getLevel().dropNear(getCoord(), meat); } } diff --git a/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java b/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java index 2d26d79..007cf90 100644 --- a/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java +++ b/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java @@ -102,6 +102,12 @@ public class EntityModuleHealth extends EntityModule { } + public void addHealth(int healthPoints) + { + setHealth(health + healthPoints); + } + + public void fill() { setHealth(maxHealth); diff --git a/src/mightypork/rogue/world/events/WorldPauseRequest.java b/src/mightypork/rogue/world/events/WorldPauseRequest.java index 30980a5..d2ffa94 100644 --- a/src/mightypork/rogue/world/events/WorldPauseRequest.java +++ b/src/mightypork/rogue/world/events/WorldPauseRequest.java @@ -12,10 +12,36 @@ import mightypork.rogue.world.World; */ public class WorldPauseRequest extends BusEvent { + public static enum PauseAction + { + PAUSE, RESUME, TOGGLE; + } + + private final PauseAction op; + + + public WorldPauseRequest(PauseAction op) + { + super(); + this.op = op; + } + @Override protected void handleBy(World handler) { + if (op == PauseAction.PAUSE) { + handler.pause(); + return; + } + + if (op == PauseAction.RESUME) { + handler.resume(); + return; + } + + // else + // toggle paused state if (!handler.isPaused()) { handler.pause(); diff --git a/src/mightypork/rogue/world/gen/LevelGenerator.java b/src/mightypork/rogue/world/gen/LevelGenerator.java index 2c55f8d..dff8ee7 100644 --- a/src/mightypork/rogue/world/gen/LevelGenerator.java +++ b/src/mightypork/rogue/world/gen/LevelGenerator.java @@ -10,10 +10,7 @@ import mightypork.rogue.world.entity.Entities; import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.gen.rooms.Rooms; import mightypork.rogue.world.gen.themes.ThemeBrick; -import mightypork.rogue.world.item.Item; -import mightypork.rogue.world.item.Items; import mightypork.rogue.world.level.Level; -import mightypork.rogue.world.tile.Tile; public class LevelGenerator { @@ -65,18 +62,18 @@ public class LevelGenerator { } } - for (int i = 0; i < 4 + complexity + rand.nextInt(1 + complexity); i++) { - - final Item meat = Items.MEAT.createItem(); - - for (int j = 0; j < 20; j++) { - pos.x = rand.nextInt(lvl.getWidth()); - pos.y = rand.nextInt(lvl.getHeight()); - - final Tile t = lvl.getTile(pos); - if (t.dropItem(meat)) break; - } - } +// for (int i = 0; i < 4 + complexity + rand.nextInt(1 + complexity); i++) { +// +// final Item meat = Items.MEAT.createItem(); +// +// for (int j = 0; j < 20; j++) { +// pos.x = rand.nextInt(lvl.getWidth()); +// pos.y = rand.nextInt(lvl.getHeight()); +// +// final Tile t = lvl.getTile(pos); +// if (t.dropItem(meat)) break; +// } +// } return lvl; diff --git a/src/mightypork/rogue/world/gen/ScratchMap.java b/src/mightypork/rogue/world/gen/ScratchMap.java index 1f9c622..cbbd0a4 100644 --- a/src/mightypork/rogue/world/gen/ScratchMap.java +++ b/src/mightypork/rogue/world/gen/ScratchMap.java @@ -149,16 +149,16 @@ public class ScratchMap { switch (rand.nextInt(4)) { case 0: - center.x += 1 + rand.nextInt(critical ? 6 : 4); + center.x += 1 + (failed_total / 50); break; case 1: - center.x -= 1 + rand.nextInt(critical ? 6 : 4); + center.x -= 1 + (failed_total / 50); break; case 2: - center.y += 1 + rand.nextInt(critical ? 6 : 4); + center.y += 1 + (failed_total / 50); break; case 3: - center.y -= 1 + rand.nextInt(critical ? 6 : 4); + center.y -= 1 + (failed_total / 50); } final RoomDesc rd = rb.buildToFit(this, theme, rand, center); @@ -173,14 +173,14 @@ public class ScratchMap { clampBounds(); nodes.add(center); - Log.f3("placed room: " + rd.min + " -> " + rd.max); +// Log.f3("placed room: " + rd.min + " -> " + rd.max); return; } else { failed++; failed_total++; - if (failed > 200) { + if (failed > 400) { Log.w("Faild to build room."); if (critical) { @@ -309,7 +309,7 @@ public class ScratchMap { public void buildCorridors() { - Log.f3("Building corridors."); +// Log.f3("Building corridors."); Coord start = nodes.get(0); final Set starts = new HashSet<>(); @@ -328,7 +328,7 @@ public class ScratchMap { private void buildCorridor(Coord node1, Coord node2) { - Log.f3("Building corridor " + node1 + " -> " + node2); +// Log.f3("Building corridor " + node1 + " -> " + node2); final List steps = pathf.findPath(node1, node2); if (steps == null) { @@ -539,7 +539,7 @@ public class ScratchMap { final Coord entrance = new Coord(enterPoint.x - genMin.x, enterPoint.y - genMin.y); level.setEnterPoint(entrance); - System.out.println("Entrance = " + entrance + ", original: " + enterPoint + ", minG=" + genMin + ", maxG=" + genMax); +// System.out.println("Entrance = " + entrance + ", original: " + enterPoint + ", minG=" + genMin + ", maxG=" + genMax); final Coord exit = new Coord(exitPoint.x - genMin.x, exitPoint.y - genMin.y); level.setExitPoint(exit); diff --git a/src/mightypork/rogue/world/gui/MapView.java b/src/mightypork/rogue/world/gui/MapView.java index 03d0398..937a4bc 100644 --- a/src/mightypork/rogue/world/gui/MapView.java +++ b/src/mightypork/rogue/world/gui/MapView.java @@ -8,9 +8,6 @@ import java.util.Set; import mightypork.gamecore.eventbus.clients.DelegatingClient; import mightypork.gamecore.eventbus.events.Updateable; import mightypork.gamecore.gui.components.InputComponent; -import mightypork.gamecore.input.Keys; -import mightypork.gamecore.input.events.KeyEvent; -import mightypork.gamecore.input.events.KeyListener; import mightypork.gamecore.input.events.MouseButtonEvent; import mightypork.gamecore.input.events.MouseButtonListener; import mightypork.gamecore.render.Render; @@ -35,7 +32,7 @@ import mightypork.rogue.world.gui.interaction.MapInteractionPlugin; * * @author MightyPork */ -public class MapView extends InputComponent implements DelegatingClient, KeyListener, MouseButtonListener, Updateable, WorldAscendRequestListener, +public class MapView extends InputComponent implements DelegatingClient, MouseButtonListener, Updateable, WorldAscendRequestListener, WorldDescendRequestListener { private static final double transition_time = 0.8; @@ -152,20 +149,15 @@ public class MapView extends InputComponent implements DelegatingClient, KeyList } - @Override - public void receive(KeyEvent event) + public void toggleMag() { - if (event.getKey() == Keys.Z && event.isDown()) { - if (zoom_in) { - zoom.fadeIn(); - zoom_in = false; - } else { - zoom.fadeOut(); - zoom_in = true; - } + if (zoom_in) { + zoom.fadeIn(); + zoom_in = false; + } else { + zoom.fadeOut(); + zoom_in = true; } - - // don't consume key events, can be useful for others. } diff --git a/src/mightypork/rogue/world/gui/interaction/MIPKeyboard.java b/src/mightypork/rogue/world/gui/interaction/MIPKeyboard.java index 6ba6b7a..d8b0d6b 100644 --- a/src/mightypork/rogue/world/gui/interaction/MIPKeyboard.java +++ b/src/mightypork/rogue/world/gui/interaction/MIPKeyboard.java @@ -17,6 +17,7 @@ import mightypork.rogue.world.gui.MapView; public class MIPKeyboard extends MapInteractionPlugin implements PlayerStepEndListener, KeyListener, Updateable { private static final int[] keys = { Keys.LEFT, Keys.RIGHT, Keys.UP, Keys.DOWN }; + private static final int[] keys2 = { Keys.A, Keys.D, Keys.W, Keys.S }; private static final Step[] sides = { Sides.W, Sides.E, Sides.N, Sides.S }; @@ -48,7 +49,7 @@ public class MIPKeyboard extends MapInteractionPlugin implements PlayerStepEndLi if (evt.isDown() || mapView.plc.getPlayer().isMoving()) return; // not interested for (int i = 0; i < 4; i++) { - if (evt.getKey() == keys[i]) { + if (evt.getKey() == keys[i] || evt.getKey() == keys2[i]) { mapView.plc.clickTile(sides[i]); } } @@ -62,7 +63,7 @@ public class MIPKeyboard extends MapInteractionPlugin implements PlayerStepEndLi if (mapView.plc.getPlayer().getMoveProgress() < 0.8) return false; for (int i = 0; i < 4; i++) { - if (InputSystem.isKeyDown(keys[i])) { + if (InputSystem.isKeyDown(keys[i]) || InputSystem.isKeyDown(keys2[i])) { final Step side = sides[i]; if (mapView.plc.canGo(side)) { diff --git a/src/mightypork/rogue/world/item/items/ItemMeat.java b/src/mightypork/rogue/world/item/items/ItemMeat.java index 24758c0..c4e74bf 100644 --- a/src/mightypork/rogue/world/item/items/ItemMeat.java +++ b/src/mightypork/rogue/world/item/items/ItemMeat.java @@ -25,7 +25,7 @@ public class ItemMeat extends ItemBaseFood { @Override public int getFoodPoints() { - return 4; + return 2; } } diff --git a/src/mightypork/rogue/world/level/Level.java b/src/mightypork/rogue/world/level/Level.java index 2c46622..5ef4c88 100644 --- a/src/mightypork/rogue/world/level/Level.java +++ b/src/mightypork/rogue/world/level/Level.java @@ -26,6 +26,7 @@ import mightypork.rogue.world.entity.Entities; import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.EntityType; import mightypork.rogue.world.entity.entities.PlayerEntity; +import mightypork.rogue.world.item.Item; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.Tiles; @@ -59,6 +60,8 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl } + private static final Random rand = new Random(); + public static final int ION_MARK = 53; private static final Comparator ENTITY_RENDER_CMP = new EntityRenderComparator(); @@ -277,6 +280,7 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl for (final Entity e : toRemove) { removeEntity(e); + e.onCorpseRemoved(); } } @@ -546,18 +550,12 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl Entity closest = null; double minDist = Double.MAX_VALUE; - if (type == EntityType.MONSTER) System.out.println("Finding entity in range " + radius + " of " + pos); - for (final Entity e : entityList) { if (e.isDead()) continue; if (e.getType() == type) { final double dist = e.pos.getVisualPos().dist(pos).value(); - if (type == EntityType.MONSTER && dist < radius * 2) { - System.out.println("Entity " + e + ", dist: " + dist + ", standing at: " + e.pos.getCoord() + ", visual: " + e.pos.getVisualPos()); - } - if (dist <= radius && dist < minDist) { minDist = dist; closest = e; @@ -656,4 +654,17 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl { return isListening(); } + + + public boolean dropNear(Coord coord, Item itm) + { + if (getTile(coord).dropItem(itm)) return true; + + for (int i = 0; i < 6; i++) { + final Coord c = coord.add(-1 + rand.nextInt(3), -1 + rand.nextInt(3)); + if (getTile(c).dropItem(itm)) return true; + } + + return false; + } } diff --git a/src/mightypork/rogue/world/tile/tiles/TileWithItems.java b/src/mightypork/rogue/world/tile/tiles/TileWithItems.java index c3ba64d..8e2bf3c 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileWithItems.java +++ b/src/mightypork/rogue/world/tile/tiles/TileWithItems.java @@ -96,4 +96,20 @@ public abstract class TileWithItems extends Tile { { return !items.isEmpty(); } + + + @Override + public boolean onClick() + { + if (hasItem()) { + final Item item = pickItem(); + if (getWorld().getPlayer().getInventory().addItem(item)) { + // player picked item + } else { + dropItem(item); // put back. + } + return true; + } + return false; + } }